mysql - 为什么在我的查询中使用 LIMIT 时 MySQL 很慢?

标签 mysql sql performance

我正试图弄清楚为什么我的一个查询很慢以及如何解决它,但我对我的结果有点困惑。

我有一个包含大约 80 列和 775179 行的 orders 表,我正在执行以下请求:

SELECT * FROM orders WHERE id_state = 2 AND id_mp IS NOT NULL ORDER BY creation_date DESC LIMIT 200

在 4.5 秒内返回 38 行

当删除 ORDER BY 时,我得到了很好的改进:

SELECT * FROM orders WHERE id_state = 2 AND id_mp IS NOT NULL LIMIT 200

0.30s 38 行

但是在不触及 ORDER BY 的情况下删除 LIMIT 我会得到更好的结果:

SELECT * FROM orders WHERE id_state = 2 AND id_mp IS NOT NULL ORDER BY creation_date DESC

0.10 秒内 38 行 (??)

为什么我的 LIMIT 这么饿?

更进一步

我在发送答案之前尝试了一些事情,在注意到我在 creation_date 上有一个索引(这是一个 datetime)后,我删除了它并在第一个查询现在在 0.10 秒内运行。这是为什么呢?

编辑

猜得好,我在 where 的其他列上都有索引。

mysql> explain SELECT * FROM orders WHERE id_state = 2 AND id_mp IS NOT NULL ORDER BY creation_date DESC LIMIT 200;
+----+-------------+--------+-------+------------------------+---------------+---------+------+------+-------------+
| id | select_type | table  | type  | possible_keys          | key        | key_len | ref  | rows | Extra       |
+----+-------------+--------+-------+------------------------+---------------+---------+------+------+-------------+
|  1 | SIMPLE      | orders | index | id_state_idx,id_mp_idx | creation_date | 5       | NULL | 1719 | Using where |
+----+-------------+--------+-------+------------------------+---------------+---------+------+------+-------------+

集合中的 1 行(0.00 秒)

mysql> explain SELECT * FROM orders WHERE id_state = 2 AND id_mp IS NOT NULL ORDER BY creation_date DESC;
+----+-------------+--------+-------+------------------------+-----------+---------+------+-------+----------------------------------------------------+
| id | select_type | table  | type  | possible_keys          | key       | key_len | ref  | rows  | Extra                                              |
+----+-------------+--------+-------+------------------------+-----------+---------+------+-------+----------------------------------------------------+
|  1 | SIMPLE      | orders | range | id_state_idx,id_mp_idx | id_mp_idx | 3       | NULL | 87502 | Using index condition; Using where; Using filesort |
+----+-------------+--------+-------+------------------------+-----------+---------+------+-------+----------------------------------------------------+

最佳答案

索引不一定会提高性能。为了更好地了解正在发生的事情,如果您为不同的查询包含 explain 会有所帮助。

我最好的猜测是您在 id_state 甚至 id_state, id_mp 中有一个索引,可用于满足 where 子句.如果是这样,没有 order by 的第一个查询将使用此索引。它应该很快。即使没有索引,这也需要对 orders 表中的页面进行顺序扫描,这仍然非常快。

然后,当您在 creation_date 上添加索引时,MySQL 决定使用该索引代替 order by。这需要读取索引中的每一行,然后获取相应的数据页以检查 where 条件并返回列(如果有匹配项)。这种读取效率非常低,因为它不是按“页面”顺序而是按索引指定的顺序。随机读取可能非常低效。

更糟糕的是,即使您有 limit,您仍然需要读取 整个 表,因为需要整个结果集。尽管您保存了对 38 条记录的排序,但您创建了一个非常低效的查询。

顺便说一句,如果 orders 表不适合可用内存,这种情况会变得更糟。然后,您会遇到一种称为“抖动”的情况,其中每条新记录都倾向于生成新的 I/O 读取。因此,如果一个页面上有 100 条记录,则该页面可能需要被读取 100 次。

您可以通过在 orders(id_state, id_mp, creation_date) 上建立索引来使所有这些查询运行得更快。 where 子句将使用前两列,order by 将使用最后一列。

关于mysql - 为什么在我的查询中使用 LIMIT 时 MySQL 很慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17747871/

相关文章:

php - 无法让 PHP 在 MySQL 更新中写入文件路径

php - 从数据库中检索前 10 个

sql - 返回两个十进制值之间的所有值

php - 确保我在 Laravel 5 中获得了正确的外键语法

c# - 为什么 LINQ .Where(predicate).First() 比 .First(predicate) 快?

MySQL选择优化

MYSQL GROUP_CONCAT 与 ORDER BY 奇怪的排序结果

python - 在 4 个 CPU 上执行 CPU 绑定(bind)任务时,20 个进程中的 400 个线程优于 4 个进程中的 400 个线程

ios - CAShapeLayer - 具有显式路径的性能

mysql - 如何从MySQL中的数据库中找出表和字段