我有一个包含1500万行的messages
表。
以下查询在不到1秒的时间内返回约5百万(但限制在15行)记录:
SELECT messages.* FROM messages
INNER JOIN gateways ON
messages.gateway_id=gateways.id
INNER JOIN orders ON
gateways.order_id=orders.id
WHERE orders.user_id=6500 AND messages.deleted=0
AND messages.type='Out' LIMIT 15;
但是当我在其末尾添加Order By
id DESC
时,它会在约40秒内变得极其缓慢:
SELECT messages.* FROM messages
INNER JOIN gateways ON
messages.gateway_id=gateways.id
INNER JOIN orders ON
gateways.order_id=orders.id
WHERE orders.user_id=6500 AND messages.deleted=0
AND messages.type='Out' ORDER BY messages.id DESC LIMIT 15;
任何帮助都会非常感激。
答案 0 :(得分:1)
模式 NSString *myString = @"@username is me: by using this as sample text";
NSRange range = [myString rangeOfString:@":"];
NSString *newString= [myString substringFromIndex:range.location];
NSLog(@"New String is : %@", newString);
因导致性能问题而臭名昭着。离开SELECT lots_of_stuff ORDER BY something LIMIT small_integer
会导致性能问题消失。为什么?因为带有ORDER BY something
的模式会导致MySQL服务器对大量相当大的行进行排序(在您的情况下为500万行),所以只丢弃其中的少数行。它在您的服务器中使用了大量的RAM,CPU和IO,只是为了丢弃大部分工作。
您最好的选择是在此处使用延迟连接类型的模式,除了ORDER BY
值之外,您只能对其进行排序。使用此子查询来执行此操作。
message.id
这将为您提供15个 SELECT messages.id
FROM messages
INNER JOIN gateways ON messages.gateway_id=gateways.id
INNER JOIN orders ON gateways.order_id=orders.id
WHERE orders.user_id=6500
AND messages.deleted=0
AND messages.type='Out'
ORDER BY messages.id DESC
LIMIT 15
值的精美集合。
下一步是优化此子查询。我建议你在message.id
表上尝试复合覆盖索引,其中包含messages
列。这应该有助于加速它。
您可能还需要其他表上的索引。您应该考虑使用MySQL中的(deleted, type, id, gateway_id)
函数来分析您的表现。
最后,使用少量EXPLAIN
值集合来获取所需的messages.id
行,就像这样。 (这是延迟连接;你推迟获取整行,直到你知道你需要哪些行。这样你就不必messages
整个混乱了。)
修改在ORDER
上添加复合索引,以避免对该表进行全表扫描。这不是很大,但这可能会有所帮助。
gateways (order_id, id)
答案 1 :(得分:1)
我认为
因此,这个:
INNER JOIN gateways ON messages.gateway_id=gateways.id
INNER JOIN orders ON gateways.order_id=orders.id
WHERE orders.user_id=6500 AND messages.deleted=0
可以改为英文:
“获取属于此用户的订单的网关”。
现在,要获取与此用户相关的最新消息,问题是我们可能会有许多不同的gateway_id(根据您的EXPLAIN大约为143),因此我们无法使用索引跳过排序。
嗯,我们可以像O. Jones所说的那样,但是有一个问题。以下是查询的简化版本:
SELECT ... FROM messages
WHERE gateway_id IN (1,2) ORDER BY id DESC LIMIT 10
如果我们在(id,gateway_id)上有索引,那么MySQL很可能会决定按降序扫描它。如果它快速找到10条消息“gateway_id IN(1,2)”那么它会很快。但是,如果这些gateway_ids包含非常旧的消息,或者根本没有消息,则可能需要扫描整个索引。
如果PK关系如我所描述的那样,我将在消息表中实现user_id列,然后允许索引(user_id,message_id),这将使查询时间远低于毫秒。