MySQL:如果使用LIMIT 1而不是LIMIT 5,查询执行速度会大大降低

时间:2013-03-17 11:14:59

标签: mysql performance indexing limit

如果我将查询限制为1而不是5,我注意到速度急剧下降。

SELECT he. *
FROM homematic_events he
WHERE he.homematic_devices_id =30
ORDER BY id DESC
LIMIT 1 

而不是

SELECT he. *
FROM homematic_events he
WHERE he.homematic_devices_id =30
ORDER BY id DESC
LIMIT 5

我的表包含大约12,000,000行,具有以下结构:

CREATE TABLE IF NOT EXISTS `homematic_events` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `homematic_devices_id` int(11) DEFAULT NULL,
  `address` char(16) COLLATE utf8_unicode_ci NOT NULL,
  `interface_id` char(16) COLLATE utf8_unicode_ci NOT NULL,
  `key` char(32) COLLATE utf8_unicode_ci NOT NULL,
  `value` float(12,2) NOT NULL,
  `timestamp` datetime NOT NULL,
  PRIMARY KEY (`id`),
  KEY `timestamp` (`timestamp`),
  KEY `address` (`address`),
  KEY `key` (`key`),
  KEY `homematic_devices_id` (`homematic_devices_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=12637557 ;

这些是对LIMIT 5的速度测量的解释:

  mysql> EXPLAIN SELECT he. * FROM homematic_events he WHERE he.homematic_devices_id =30 ORDER BY id DESC LIMIT 5;
  +----+-------------+-------+------+----------------------+----------------------+---------+-------+------+-----------------------------+
  | id | select_type | table | type | possible_keys        | key                  | key_len | ref   | rows | Extra                       |
  +----+-------------+-------+------+----------------------+----------------------+---------+-------+------+-----------------------------+
  |  1 | SIMPLE      | he    | ref  | homematic_devices_id | homematic_devices_id | 5       | const | 4171 | Using where; Using filesort |
  +----+-------------+-------+------+----------------------+----------------------+---------+-------+------+-----------------------------+


starting                          0.000010
checking query cache for query    0.000030
Opening tables                    0.000007
System lock                       0.000004
Table lock                        0.000015
init                              0.000019
optimizing                        0.000007
statistics                        0.000098
preparing                         0.000012
executing                         0.000002
Sorting result                    0.022965
Sending data                      0.000047
end                               0.000004
query end                         0.000002
freeing items                     0.000302
storing result in query cache     0.000009
logging slow query                0.000002
cleaning up                       0.000003

这些是对LIMIT 1的速度测量的解释:

mysql> EXPLAIN SELECT he. * FROM homematic_events he WHERE he.homematic_devices_id =30 ORDER BY id DESC LIMIT 1;
+----+-------------+-------+-------+----------------------+---------+---------+------+------+-------------+
| id | select_type | table | type  | possible_keys        | key     | key_len | ref  | rows | Extra       |
+----+-------------+-------+-------+----------------------+---------+---------+------+------+-------------+
|  1 | SIMPLE      | he    | index | homematic_devices_id | PRIMARY | 4       | NULL | 3029 | Using where |
+----+-------------+-------+-------+----------------------+---------+---------+------+------+-------------+

starting                              0.000010
checking query cache for query        0.000034
Opening tables                        0.000009
System lock                           0.000004
Table lock                            0.000015
init                                  0.000020
optimizing                            0.000008
statistics                            0.000069
preparing                             0.000016
executing                             0.000002
Sorting result                        0.000005
Sending data                        502.290180
end                                   0.000010
query end                             0.000003
freeing items                         0.000293
logging slow query                    0.000004
logging slow query                    0.000002
cleaning up                           0.000003

有人可以向我解释这种行为吗?我提到它是由于不同的索引是LIMIT 1的udes的结果。但是为什么mysql对不同的LIMIT值使用不同的键?

3 个答案:

答案 0 :(得分:8)

使用LIMIT 1,我猜测查询分析器会压缩主键并找到homematic_devices_id =30的最后一条记录 - 可能是因为分析器知道“排序”操作会更昂贵。

当你限制5时,我猜测查询分析器决定先找到记录,然后对它们进行排序。如果你想加快操作速度,可以在homematic_devices_id和ID上创建一个索引,如下所示:ALTER TABLE homematic_events_test ADD INDEX ( homematic_devices_id, id ) - 首先设置设备ID,你可以容纳“Where”子句,ID列可以帮助SORT

答案 1 :(得分:3)

出于某种原因,MySQL以某种方式更快地使用主键ID来访问这些行而不是索引。即使您具有的查询专门使用了构建homematic_devices_id索引的字段。我也觉得奇怪的是,第二种情况下的MySQL在homematic_devices_id下只有possible_keys,但后来选择了PRIMARY。通常,MySQL将在该列中显示PRIMARY和其他可能的索引。

它是否可能是数据相关的问题?您是否尝试过使用其他device_ids查询?

尝试在两种情况下都使用FORCE INDEX,看看是否可以解决问题。

答案 2 :(得分:1)

我的假设是当你和order by结合limit 1时,请求在内部被视为max()(或分钟),可以使用索引立即到达,当你要求limit 5时,必须先完成排序。