【发布时间】:2021-12-09 06:48:40
【问题描述】:
我有 2 张桌子,item 和 config。
item 有大约 1500 万行,config 有大约 1000 行。
我想用WHERE 子句连接这两个表并对结果进行排序。
这可能看起来像这样:
SELECT
`t0`.`id`,
`t0`.`item_name`,
`t1`.`id`,
`t1`.`config_name`,
FROM
`item` t0
LEFT OUTER JOIN `config` `t1` ON `t0`.`config_id` = `t1`.`id`
WHERE (`t0`.`config_id` = 678)
ORDER BY
`t0`.`item_name` ASC;
这在约 800 毫秒内成功运行并返回约 50k 行。
我也想分页这个结果,所以我运行相同的查询并添加一个LIMIT:
SELECT
`t0`.`id`,
`t0`.`item_name`,
`t1`.`id`,
`t1`.`config_name`,
FROM
`item` t0
LEFT OUTER JOIN `config` `t1` ON `t0`.`config_id` = `t1`.`id`
WHERE (`t0`.`config_id` = 678)
ORDER BY
`t0`.`item_name` ASC LIMIT 200;
此查询现在需要 5 分钟以上。
我试图了解造成这种差异的原因。
我可以简化查询,完全去掉JOIN,只查询大表来尝试找出变慢的原因:
SELECT
`t0`.`id`,
`t0`.`item_name`,
FROM
`item` t0
WHERE (`t0`.`config_id` = 678)
ORDER BY
`t0`.`item_name` ASC;
此查询运行良好,但同样,添加 LIMIT 会大大增加查询时间。
我该如何解决这个问题或更好地诊断是什么原因造成的?
没有LIMIT的简化查询的执行计划如下:
+----+-------------+-------+------------+------+---------------+-----------+---------+-------+-------+----------+---------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | extra |
+----+-------------+-------+------------+------+---------------+-----------+---------+-------+-------+----------+---------------------------------------+
| 1 | SIMPLE | t0 | NULL | ref | ITEM_FK_1 | ITEM_FK_1 | 8 | const | 98524 | 100.00 | Using index condition; Using filesort |
+----+-------------+-------+------------+------+---------------+-----------+---------+-------+-------+----------+---------------------------------------+
在查询中添加LIMIT 200 会生成这个执行计划:
+----+-------------+-------+------------+-------+---------------+--------------------+---------+------+-------+----------+--------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | extra |
+----+-------------+-------+------------+-------+---------------+--------------------+---------+------+-------+----------+--------------------------+
| 1 | SIMPLE | t0 | NULL | index | ITEM_FK_1 | ITEM_RULE_ITEM_UNQ | 775 | NULL | 31933 | 0.63 | Using where; Using index |
+----+-------------+-------+------------+-------+---------------+--------------------+---------+------+-------+----------+--------------------------+
【问题讨论】:
-
请为这两个查询添加执行计划(
explain select ...的输出)。还要添加现有索引(或创建表语句) - 我假设您在 config_id 和 item_name 上有索引? -
感谢@Solarflare - 添加了执行计划
-
如果你提供
SHOW CREATE TABLE会有所帮助。
标签: mysql sql performance large-data