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<5(例如'LIMIT 5'),后者的返回仍然很快。
- 在不同的条件下,例如,扩展时间范围
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))
);