奇怪的查询速度问题

时间:2015-07-29 01:07:02

标签: mysql performance select query-optimization

我的表总共有2,707,047行。

SELECT * FROM messages WHERE status = 1 AND room_id IN (14, 16, 19, 21, 23, 24, 31, 32, 33, 36, 37, 39, 40, 45, 46, 54, 55, 56, 58, 59, 61, 65, 66, 70, 71, 73, 76, 78, 84, 85, 86, 94, 95, 96, 97, 98, 101, 106, 113, 114, 117, 118, 120, 121, 122, 131, 134, 136, 138, 139, 140, 141, 144, 145, 146, 147, 148, 149, 150, 153, 154, 155, 156, 157, 158, 159, 160, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 208, 209, 210, 212, 213, 214, 215, 217, 218) ORDER BY post_date DESC LIMIT 0, 1

需要0.0059秒

SELECT * FROM messages WHERE status = 1 AND room_id IN (40) ORDER BY post_date DESC LIMIT 0, 1

需要0.0078秒

SELECT * FROM messages WHERE status = 1 AND room_id IN (39) ORDER BY post_date DESC LIMIT 0, 1

需要0.0510秒

但为什么?

首次查询的EXPLAIN(多个room_ids) explain for first query

第二次查询的EXPLAIN(room_id 39) room_id 39

第三次查询的EXPLAIN(room_id 40) room_id 40

2 个答案:

答案 0 :(得分:2)

第二次和第三次查询的最佳索引是:messages(status, room_id, post_date)。有了这个索引,我希望性能几乎相同。

如果没有索引,查询将获得与where子句匹配的行,然后对它们进行排序。好吧,如果39号房间的行数比40号房间多,那么排序需要更长的时间。

您的问题中未包含其他有用信息。 。 。例如查询的“解释”计划或现有索引。但是,有充分的理由将值从39改为40会影响结果。

编辑:

第一个因为偶然事件而很快。由于in条件,MySQL决定status, room_id, post_date上的索引不是最优的。相反,它按降序读取日期的索引,并且恰好找到一个非常快速匹配where条件的行。

第二和第三个性能差异有点神秘。他们建议MySQL正在进行索引扫描,以便在索引的匹配部分中找到最后一个发布日期。但是,考虑到数据不是很大,我不希望性能因数为7。

这些性能特征是否一致?在冷缓存环境中保持差异吗?

答案 1 :(得分:0)

因为您正在使用LIMIT 0, 1,所以较长的IN子句通常会更快地评估(没有索引),因为它可以在找到任何 room_id s,而其他两个查询必须找到指定的 exact room_id

我认为第二个和第三个查询之间的差异可能只取决于扫描中特定room_id发生的位置。