【问题标题】:MySQL: Dramatically slower query execution if use LIMIT 1 instead of LIMIT 5MySQL:如果使用 LIMIT 1 而不是 LIMIT 5,查询执行速度会大大降低
【发布时间】:2013-03-05 19:18:06
【问题描述】:

我注意到如果我将查询限制为 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

谁能向我解释一下这种行为?我提到这是由于 udes 与 LIMIT 1 的不同索引的结果。但是为什么 mysql 对不同的 LIMIT 值使用不同的键?

【问题讨论】:

  • 明确地说,您是说使用 LIMIT 1 的查询比使用 LIMIT 5 的查询花费 更长 对吧?
  • 没错 - 在这种情况下大约长 20,000 倍 ;-)

标签: mysql performance indexing limit


【解决方案1】:

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

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

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

【讨论】:

  • 你是对的。语句选择他。 * FROM homematic_events he FORCE INDEX (homematic_devices_id) WHERE he.homematic_devices_id =30 ORDER BY id DESC LIMIT 1 工作正常!谢谢
【解决方案2】:

我的假设是,当您将和order bylimit 1 结合使用时,请求在内部被视为max()(或最小值),可以通过索引立即到达,而当您请求limit 5,必须先完成订购。

【讨论】:

    【解决方案3】:

    使用 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 列有助于排序

    【讨论】:

    • 你提到 ALTER TABLE homematic_events_test ADD INDEX (id, homematic_devices_id)?
    • 为什么限制 1 有“发送数据 502.290180”它在这一点上找到了数据等,它将它发送回曾经请求它的地方
    • 你是对的。我尝试了一段时间,因为索引的创建非常慢。现在mysql默认使用“LIMIT 1”-查询获取新索引而不强制它。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-06-19
    • 2012-06-08
    • 1970-01-01
    • 2017-12-02
    • 2020-04-21
    • 2016-04-17
    • 2015-07-31
    相关资源
    最近更新 更多