为啥这个简单的左连接需要永远执行?

Posted

技术标签:

【中文标题】为啥这个简单的左连接需要永远执行?【英文标题】:why is this simple left join taking forever to execute?为什么这个简单的左连接需要永远执行? 【发布时间】:2012-12-12 03:23:45 【问题描述】:

我正在对旧的 mysql 数据库运行查询,并且许多查询花费的时间远远超过应有的时间。比如这个,ad_vehicle 有 60000 行,id_ad_link 有 25000

SELECT * FROM autotalk_identicar_old.ad_vehicle 
left join autotalk_identicar_old.id_ad_link on autotalk_identicar_old.ad_vehicle.vehiclekey=autotalk_identicar_old.id_ad_link.rbvehiclekey;

持续时间是 2.323 秒,在执行 12 分钟后 fetch 仍在进行(使用 mysql 工作台,但不确定这是否有任何区别)。在 vm 中运行,我的 amd 四核 3 核 @ 3.4ghz 和 1gb 内存

我认为没有任何索引/主键,但这会产生如此大的不同吗?

ad_vehicle 的前几行

A145 00AA, PV, ALFA, 145, 2000, 3HBm, 1.6, , , , , P, , 5, 1596, , , 32995,  , , 3HBm 1.6p
A145 00AB, PV, ALFA, 145, 2000, 3HBm, 1.7, , , , , P, , 5, 1712, , , 41995,  , , 3HBm 1.7p
A145 01AA, PV, ALFA, 145, 2001, 3HBm, 1.6, , , , , P, , 5, 1596, , , 32995,  , , 3HBm 1.6p
A145 01AB, PV, ALFA, 145, 2001, 3HBm, 1.7, , , , , P, , 5, 1712, , , 41995,  , , 3HBm 1.7p
A145 02AA, PV, ALFA, 145, 2002, 3HBm, 1.6, , , , , P, , 5, 1596, , , 32995,  , , 3HBm 1.6p
A145 02AB, PV, ALFA, 145, 2002, 3HBm, 1.7, , , , , P, , 5, 1712, , , 41995,  , , 3HBm 1.7p
A145 95AA, PV, ALFA, 145, 1995, 3HBm, 1.6, , L, , , P, , 4, 1596, , , 32995,  , , 3HBm 1.6p L
A145 95AB, PV, ALFA, 145, 1995, 3HBm, 1.7, ELEGANTE, L, , , P, , 4, 1712, , , 41995,  , , 3HBm 1.7p ELEGANTE L
A145 96AA, PV, ALFA, 145, 1996, 3HBm, 1.6, , L, , , P, , 4, 1596, , , 32995,  , , 3HBm 1.6p L
A145 96AB, PV, ALFA, 145, 1996, 3HBm, 1.7, ELEGANTE, L, , , P, , 4, 1712, , , 41995,  , , 3HBm 1.7p ELEGANTE L
A145 97AA, PV, ALFA, 145, 1997, 3HBm, 1.6, , L, , , P, , 4, 1596, , , 32995,  , , 3HBm 1.6p L
A145 97AB, PV, ALFA, 145, 1997, 3HBm, 1.7, ELEGANTE, L, , , P, , 4, 1712, , , 41995,  , , 3HBm 1.7p ELEGANTE L
A145 98AA, PV, ALFA, 145, 1998, 3HBm, 1.6, , L, , , P, , 4, 1596, , , 32995,  , , 3HBm 1.6p L
A145 98AB, PV, ALFA, 145, 1998, 3HBm, 1.7, ELEGANTE, L, , , P, , 4, 1712, , , 41995,  , , 3HBm 1.7p ELEGANTE L
A145 98AC, PV, ALFA, 145, 1998, 4SDm, 2.5, , , , , P, , 5, 2492, , , 65998,  , , 4SDm 2.5p
A145 99AA, PV, ALFA, 145, 1999, 3HBm, 1.7, ELEGANTE, L, , , P, , 4, 1712, , , 41995,  , , 3HBm 1.7p ELEGANTE L
A145 99AB, PV, ALFA, 145, 1999, 3HBm, 1.6, , L, , , P, , 4, 1596, , , 32995,  , , 3HBm 1.6p L
A146 00AA, PV, ALFA, 146, 2000, 5HBm, 1.6, , TS, , , P, , 5, 1596, , , 37995,  , , 5HBm 1.6p TS
A146 01AA, PV, ALFA, 146, 2001, 5HBm, 1.6, , TS, , , P, , 5, 1596, , , 38995,  , , 5HBm 1.6p TS

id_ad_link 的前几行

4   10  DHJT 94AA   1994    REDUNDANT   HIJET
12  971 A33  95AA   1995    REDUNDANT   ALFA33
13  971 A33  95AB   1995    REDUNDANT   ALFA33
14  971 A33  95AC   1995    REDUNDANT   ALFA33
61  973 A146 95AB   1995    REDUNDANT   146
60  973 A146 95AA   1995    REDUNDANT   146
59  973 A145 02AB   2002    REDUNDANT   145
58  973 A145 02AA   2002    REDUNDANT   145
57  973 A145 01AB   2001    REDUNDANT   145
56  973 A145 01AA   2001    REDUNDANT   145
55  973 A145 00AB   2000    REDUNDANT   145
54  973 A145 99AB   1999    REDUNDANT   145
53  973 A145 99AA   1999    REDUNDANT   145
52  973 A145 98AC   1998    REDUNDANT   145
45  973 A145 95AB   1995    REDUNDANT   145
44  973 A145 95AA   1995    REDUNDANT   145
70  973 A146 98AB   1998    REDUNDANT   146
71  973 A146 98AC   1998    REDUNDANT   146
72  973 A146 99AA   1999    REDUNDANT   146
73  973 A146 00AA   2000    REDUNDANT   146

更新:

这是

的结果
explain SELECT * FROM autotalk_identicar_old.ad_vehicle 
left join autotalk_identicar_old.id_ad_link on autotalk_identicar_old.ad_vehicle.vehiclekey=autotalk_identicar_old.id_ad_link.rbvehiclekey;

id, select_type, table,       type,    possible_keys, key,  key_len, ref, rows,   Extra
'1', 'SIMPLE', 'ad_vehicle', 'ALL',        NULL,     NULL,   NULL,  NULL, '60433', ''
'1', 'SIMPLE', 'id_ad_link', 'ALL',        NULL,     NULL,   NULL,  NULL, '25571', ''

【问题讨论】:

你能把这两个执行的结果贴出来吗? DESC ad_vehicle;DESC id_ad_link。还有这个,EXPLAIN SELECT * FROM autotalk_identicar_old.ad_vehicle left join autotalk_identicar_old.id_ad_link on autotalk_identicar_old.ad_vehicle.vehiclekey = autotalk_identicar_old.id_ad_link.rbvehiclekey; 绝对,用于连接各个表的任何列上的索引都将提高性能。构建这些,然后再次尝试查询。 编辑问题,结果为“解释...” 【参考方案1】:

尝试在外键上创建索引:

create index id_ad_link_rbvehiclekey_index on id_ad_link(rbvehiclekey);

没有这个索引,ad_vehicle 的每一行都会导致id_ad_link 上的全表扫描。索引,ad_vehicle 的每一行都会导致几个索引页被访问(可能在内存中)并且读取连接的行的页面很少,因为索引存储页面以查找行。

最小化磁盘 I/O 对性能至关重要,因为它至少比内存操作慢 1000 倍。

索引有很大的不同,尤其是在用于连接的列上(如外键)

【讨论】:

我只能说哇...我听说过对加速数据库的主键和索引的引用,但我从来没有想过它会产生如此巨大的差异! 60819 行返回 |持续时间 0.000 获取 1.108。谢谢你好先生:) 只是出于好奇,我假设 MySQL 会在处理它之前将整个表加载到内存中......考虑到它很容易 是的,我知道你的意思。我不知道它在幕后使用了什么实现,但也许这只是它选择不做的事情

以上是关于为啥这个简单的左连接需要永远执行?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我可以从 NULL 列的左连接中选择一些东西?(用人为的例子在本地重现它,可能是一个错误!)

当 B 与 A 匹配时,在表 A 上左连接表 B 是瞬时的,但在没有匹配时需要永远(> 1 分钟)。为啥是这样?

显示具有多个需要累积的值的左连接

太多的左连接是代码味道吗?

mysql数据库的左连接,右连接,内链接。

带有附加左表过滤器的左连接性能