【发布时间】:2018-10-29 19:41:19
【问题描述】:
我有两个名为 ny_clean(3454602 个条目)和pickup_0_ids_temp_table(2739268 个条目)的表,它们都有一个 id CHAR(11) 列,这是一个主键,并且在它上面有一个 BTREE 索引(MySQL 5.7)。
pickup_0_ids_temp_table 中的“id”列是 ny_clean 的子集,我想得到一个 ny_clean 的结果,而没有来自pickup_0_ids_temp_table 的 id 值。
选项 1:
解释 选择 * FROMpick_0_ids_temp_table 作为 t 加入 ny_clean 作为 n ON n.id != t.id; +----+-------------+----------+------------+------ -+---------------+-------------------+---------+-- ----+----------+----------+------------ -----------------------------------------+ |编号 |选择类型 |表|隔断 |类型 |可能的键 |关键 | key_len |参考 |行 |过滤 |额外 | +----+-------------+----------+------------+------ -+---------------+-------------------+---------+-- ----+----------+----------+------------ -----------------------------------------+ | 1 |简单 |吨 |空 |索引 |空 |初级 | 11 |空 | 2734512 | 100.00 |使用索引 | | 1 |简单 | ny_clean |空 |索引 |空 | btree_pk_ny_clean | 11 |空 | 3445904 | 90.00 |使用哪里;使用索引;使用连接缓冲区(块嵌套循环)| +----+-------------+----------+------------+------ -+---------------+-------------------+---------+-- ----+----------+----------+------------ -----------------------------------------+选项 2:
解释 选择 * FROM ny_clean 作为 n 在哪里 n.id 不在 ( 选择编号 从pickup_0_ids_temp_table); +----+--------------------+------------ --+------------+-----------------+---------------- --------+----------+---------+------+---------+---- ------+--------------+ |编号 |选择类型 |表|隔断 |类型 |可能的键 |关键 | key_len |参考 |行 |过滤 |额外 | +----+--------------------+------------ --+------------+-----------------+---------------- --------+----------+---------+------+---------+---- ------+--------------+ | 1 |初级 | n |空 |全部 |空 |空 |空 |空 | 3445904 | 100.00 |使用位置 | | 2 |依赖子查询 | Pickup_0_ids_temp_table |空 |唯一子查询 |初级,btree_pickup_0 |初级 | 11 |功能 | 1 | 100.00 |使用索引 | +----+--------------------+------------ --+------------+-----------------+---------------- --------+----------+---------+------+---------+---- ------+--------------+然后我在这个更大的查询中使用其中一个选项
解释 插入到 y 选择 id、pickup_longitude、pickup_latitude 从 x 加入 (选项 1 或 2)作为 z 开 z.id = x.id;当我在较大的查询中使用选项 1 时,它运行了两天,但没有完成。另一方面,选项 2 在不到 30 分钟的时间内完成了这项工作
我的问题:为什么会这样? 根据 MySQL 文档 (https://dev.mysql.com/doc/refman/5.7/en/subquery-materialization.html),我怀疑这是由于子查询的具体化,但我该如何检查呢?
我对 EXPLAIN 输出的解释有误吗?因为据此判断,我希望选项 1 更快,因为它在两个表上都使用索引
还是与更大的查询有关?
提前致谢
【问题讨论】:
-
第一个解释有
Using join buffer (Block Nested Loop),这意味着记录在两个嵌套循环中匹配。这当然不好 -
n.id != t.id可能会被重写为n.id < t.id AND n.id > t.id然后优化器应该选择范围扫描 -
@RaymondNijland 我第一次听说这是一个优化技巧。
-
@JuanCarlosOropeza 是的,它应该是 OR 而不是
n.id < t.id OR n.id > t.id.. 不确定重写是否可以在没有示例数据的情况下开箱即用.. -
“我第一次听说这是一个优化技巧”@JuanCarlosOropeza 嗯,它接缝了现代 MySQL 5.7+ 版本优化
!=已经作为范围扫描它接缝。 db-fiddle.com/f/czMTmRHZxtSAXKdsGSWkrW/2