ORDER BY 中查询非常慢,LIMIT 范围较大
Posted
技术标签:
【中文标题】ORDER BY 中查询非常慢,LIMIT 范围较大【英文标题】:Very slow query in ORDER BY with larger LIMIT range 【发布时间】:2013-11-06 12:02:03 【问题描述】:mysql 5.6、64 位、RHEL 5.8 使用 ORDER BY 和 LIMIT 'row_count'(或 LIMIT 0,'row_count')对大型表进行查询。如果 'row_count' 大于结果集的实际计数,将非常非常慢。
案例1:下面的查询非常快(没有'LIMIT'):
mysql> SELECT * FROM syslog WHERE
(ReportedTime BETWEEN '2013-11-04' AND '2013-11-05') AND
Priority<3 AND Facility=1 ORDER BY id DESC;
+---
| ...
6 rows in set (0.01 sec)
案例2:下面的查询也很快('LIMIT 5'):
mysql> SELECT * FROM syslog WHERE
(ReportedTime BETWEEN '2013-11-04' AND '2013-11-05') AND
Priority<3 AND Facility=1 ORDER BY id DESC LIMIT 5;
+---
| ...
5 rows in set (0.42 sec)
案例3:下面的查询非常非常慢('LIMIT 7',可以使用任何'row_count'值> 6):
mysql> SELECT * FROM syslog WHERE
(ReportedTime BETWEEN '2013-11-04' AND '2013-11-05') AND
Priority<3 AND Facility=1 ORDER BY id DESC LIMIT 7;
+---
| ...
6 rows in set (28 min 7.24 sec)
差异只是个别(无限制)、“限制 5”和“限制 7”。 为什么案例 3 这么慢? 案例3的部分调查:
-
运行命令“SHOW PROCESS”,查询的状态保存在“发送数据”中
检查了服务器内存,它仍然足够可用。
在运行查询之前将 SESSION 缓冲区 'read_buffer_size'、'read_rnd_buffer_size'、'sort_buffer_size' 扩展到非常大的数量(到 16MB),但没有帮助。
同样只查询“id”列(
SELECT id FROM syslog ....
),但结果相同。
在查询运行期间,在另一个 mysql 连接中引发了相同的查询,但 row_count
在不同的条件下,例如延长时间范围BETWEEN '2013-10-03' to '2013-11-05'
以获得结果行数149。使用LIMIT 140
,速度很快。使用LIMIT 150
,它非常非常慢。好奇怪。
目前在实践中,在我们的网站中,程序首先获取实际结果行数(SELECT COUNT(*) FROM ...
,No ORDER BY,No LIMIT),然后以不超过实际行的 LIMIT 'row_count' 值进行查询伯爵刚刚得到。丑。
案例 3 的解释:
-+-----..-+----..+-------+-----..+--------+---------+-----+-----+------------+
| sele.. | table| type | poss..| key | key_len | ref | rows| Extra |
-+-----..-+----..+-------+-----..+--------+---------+-----+-----+------------+
| SIMPLE | syslo| index | ... | PRIMARY| 8 | NULL| 132 | Using where|
-+-----..-+----..+-------+-----..+--------+---------+-----+-----+------------+
1 row in set (0.00 sec)
表定义:
CREATE TABLE syslog (
id BIGINT NOT NULL AUTO_INCREMENT,
ReceivedAt TIMESTAMP NOT NULL DEFAULT 0,
ReportedTime TIMESTAMP NOT NULL DEFAULT 0,
Priority SMALLINT,
Facility SMALLINT,
FromHost VARCHAR(60),
Message TEXT,
InfoUnitID INT NOT NULL DEFAULT 0,
SysLogTag VARCHAR(60) NOT NULL DEFAULT '',
PRIMARY KEY (id),
KEY idx_ReportedTime_Priority_id (ReportedTime,Priority,id),
KEY idx_Facility (Facility),
KEY idx_SysLogTag (SysLogTag(16)),
KEY idx_FromHost (FromHost(16))
);
【问题讨论】:
您是否也尝试过在Facility
上添加索引?这是 InnoDB 或 MyISAM 还是其他类似 Archive 的东西?
向我们展示需要更多时间的查询的解释计划
这里的主要问题,如果索引会影响查询,第一种和第二种情况也应该很慢。对? LIMIT 6(快)和 LIMIT 7(非常慢)之间的巨大性能差异。
解释说它只使用了主键
我在 InnoDB 和 MyISAM 中都试过了。遇到了同样的问题。
【参考方案1】:
Mysql 以其围绕ORDER BY DESC + LIMIT
子句的行为而闻名。
见:http://www.mysqlperformanceblog.com/2006/09/01/order-by-limit-performance-optimization/
请尝试:
SELECT *
FROM syslog FORCE INDEX (Facility)
WHERE
ReportedTime BETWEEN '2013-11-04' AND '2013-11-05'
AND Priority<3
AND Facility=1
ORDER BY id DESC
LIMIT 7;
您需要强制使用第一次查询中使用的索引。 (从他们的解释计划中获取,KEY 列)
【讨论】:
我加了FORCE INDEX (idx_ReportedTime_Priority_id)
。它变得正常而且很快。我不知道 MySQL 的内部以及为什么从 LIMIT 5
到 LIMIT 6
会如此不同。非常感谢。以上是关于ORDER BY 中查询非常慢,LIMIT 范围较大的主要内容,如果未能解决你的问题,请参考以下文章
使用 LEFT JOIN 和 ORDER BY...LIMIT 查询慢,使用 Filesort