一般来说,使用JOIN选择行与EXISTS where子句之间是否存在性能差异?搜索各种Q& A网站表明联接更有效率,但我记得很久以前在Teradata中学习EXISTS更好。
我确实看到其他SO答案,例如this和this,但我的问题是针对Teradata的。
例如,考虑这两个返回相同结果的查询:
select svc.ltv_scr, count(*) as freq
from MY_BASE_TABLE svc
join MY_TARGET_TABLE x
on x.srv_accs_id=svc.srv_accs_id
group by 1
order by 1
- 和 -
select svc.ltv_scr, count(*) as freq
from MY_BASE_TABLE svc
where exists(
select 1
from MY_TARGET_TABLE x
where x.srv_accs_id=svc.srv_accs_id)
group by 1
order by 1
两个表上的主索引(唯一)是'srv_accs_id'。 MY_BASE_TABLE相当大(2亿行),MY_TARGET_TABLE相对较小(200,000行)。
EXPLAIN计划中存在一个显着差异:第一个表示两个表通过RowHash匹配扫描加入“,第二个通过全部表示” - 扫描“。两者都说它是“全AMP加入步骤”,总估计时间相同(0.32秒)。
两个查询都执行相同的操作(我使用的是Teradata 13.10)。
一个类似的实验,用于查找将LEFT OUTER JOIN与相应的IS NULL where子句与NOT EXISTS子查询进行比较的非匹配确实显示性能差异:
select svc.ltv_scr, count(*) as freq
from MY_BASE_TABLE svc
left outer join MY_TARGET_TABLE x
on x.srv_accs_id=svc.srv_accs_id
where x.srv_accs_id is null
group by 1
order by 1
- 和 -
select svc.ltv_scr, count(*) as freq
from MY_BASE_TABLE svc
where not exists(
select 1
from MY_TARGET_TABLE x
where x.srv_accs_id=svc.srv_accs_id)
group by 1
order by 1
第二个查询计划更快(如EXPLAIN所述,2.21对2.14秒)。
我的例子可能太微不足道了,看不出差异;我只是在寻找编码指导。
答案 0 :(得分:5)
NOT EXISTS比使用LEFT OUTER JOIN更有效地排除使用IS NULL条件从参与表中丢失的记录,因为优化器将选择使用带有NOT EXISTS谓词的排除MERGE JOIN。
虽然您的第二次测试没有为数据集产生令人印象深刻的结果,但是当您的数据量增加时,您使用NOT EXISTS对LEFT JOIN的性能提升非常明显。请记住,表格需要由参与NOT EXISTS连接的列进行哈希分布,就像在LEFT JOIN中一样。因此,数据倾斜会影响EXCLUSION MERGE JOIN的性能。
修改强>
通常,我会将EXISTS作为IN的替代品,而不是用它来重写连接解决方案。当参与逻辑比较的列可以为NULL时尤其如此。这并不是说你不能用EXISTS代替INNER JOIN。而不是排除加入,你将最终得到一个包含加入。 INNER JOIN本质上是一个包含连接开头。我确信我会忽略一些细微差别,但如果您想花时间阅读它们,可以在手册中找到它们。