尝试优化执行时间较长的查询
Posted
技术标签:
【中文标题】尝试优化执行时间较长的查询【英文标题】:Attempting to optimize a query that is taking a long time to execute 【发布时间】:2018-09-27 21:19:22 【问题描述】:根据以下查询的数据量,我的返回时间很慢。
mysql> explain select *
from worker_location
where gate_id not in (
SELECT gate_id from worker_address
);
+----+--------------------+---------------------+-------+---------------------------+---------------------------+---------+------+---------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------------+---------------------+-------+---------------------------+---------------------------+---------+------+---------+--------------------------+
| 1 | PRIMARY | worker_location | ALL | NULL | NULL | NULL | NULL | 527347 | Using where |
| 2 | DEPENDENT SUBQUERY | worker_address | index | gate_id_idx | gate_id_ix | 48 | NULL | 3041342 | Using where; Using index |
+----+--------------------+---------------------+-------+---------------------------+---------------------------+---------+------+---------+--------------------------+
2 rows in set (0.00 sec)
我尝试使用左连接,但得到了相同的计划,但速度没有任何好处。
mysql> explain select *
from worker_location wl
left join worker_address wa ON wl.gate_id=wa.gate_id
where wa.gate_id is null;
+----+-------------+-------+------+---------------+------+---------+------+---------+----------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+---------+----------------------------------------------------+
| 1 | SIMPLE | wl | ALL | NULL | NULL | NULL | NULL | 527347 | NULL |
| 1 | SIMPLE | wa | ALL | NULL | NULL | NULL | NULL | 3041342 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+-------+------+---------------+------+---------+------+---------+----------------------------------------------------+
2 rows in set (0.00 sec)
有没有办法进一步优化这个查询?
【问题讨论】:
确保只选择您需要的列。不要使用 * 并获取您不需要的不必要的列。 所有列都需要。 你有worker_location.gate_id
列的索引吗?
是的,所有列都已编入索引。
无能为力。可以尝试增加会话join_buffer_size,BNL和BKA
【参考方案1】:
在您的解释输出中看到两个问题:
没有使用索引 - 请参阅“possible_keys”和“key”列
触发了“阻止嵌套循环”优化,可能会遇到bag
你可以尝试使用 index hints 玩游戏
和/或尝试通过以下方式禁用 bnl:
SET SESSION optimizer_switch='block_nested_loop=off';
【讨论】:
【参考方案2】:一些分析:
您必须要触摸第一个表格的大约 527347 行。 对于其中的每一个,它都会检查另一个表。 为什么gate_id
这么大? 48 字节??
第一个查询(NOT IN)使用索引(“使用索引”),因此对于 527347 次随机查找相当有效。
第二个查询 (LEFT JOIN) 加载整个索引。这可能比访问表格 527347 次更有效,具体取决于缓存的内容。
第三种方法:
select *
from worker_location AS wl
where NOT EXISTS ( SELECT 1 FROM worker_address WHERE gate_id = wl.gate_id );
每个变体需要多长时间?
如需进一步讨论,请提供两个表的SHOW CREATE TABLE
和innodb_buffer_pool_size
的值。这可能会导致其他优化技术。
【讨论】:
以上是关于尝试优化执行时间较长的查询的主要内容,如果未能解决你的问题,请参考以下文章