如何提高大型左外连接的性能?
Posted
技术标签:
【中文标题】如何提高大型左外连接的性能?【英文标题】:How to improve performance on large left outer join? 【发布时间】:2016-12-19 15:06:31 【问题描述】:这些是我的桌子:
Source_Artikelen - 列:文章 - 描述(1.438.171 条记录)
Source_LevArt - 列:文章 - 制造商部件号(1.751.801 记录)
...这是我正在执行的查询
SELECT a.Artikel,a.Omschrijving, l.Artikel_Leverancier
FROM Source_Artikelen AS a
LEFT OUTER JOIN Source_LevArt AS l
ON a.Artikel Like l.Artikel
在我手动取消之前,这个查询今晚运行了 20 多个小时。
那我想做什么?
我想列出我的表 Source_Artikelen 中的所有文章。然后我想看看 Source_LevArt 中是否有制造商零件号。
并非所有来自 Source_Artikelen 的文章都出现在 Source_LevArt 中 有时在一篇文章的 Source_LevArt 中有多个制造商部件号这就是为什么我需要使用 LEFT OUTER JOIN。
我已经尝试了一些关于索引的方法,但它并没有真正的帮助。可能我做错了什么。
我真的需要一些帮助,因为这只是我正在编写的查询的开始。 稍后我将不得不添加 2 个其他(大)标签作为左外连接...
2016 年 19 月 12 日更新 16:24: 嗨 piet.t
SELECT TOP(20) a.Artikel,a.Omschrijving, l.Artikel_Leverancier
FROM Source_Artikelen AS a
LEFT JOIN Source_LevArt AS l
ON a.Artikel LIKE l.Artikel
这需要 9 秒
SELECT TOP(20) a.Artikel,a.Omschrijving, l.Artikel_Leverancier
FROM Source_Artikelen AS a
LEFT JOIN Source_LevArt AS l
ON a.Artikel = l.Artikel
这需要 1 秒!
我真的不知道有什么区别,因为我没有使用通配符。
【问题讨论】:
Source_Artikelen .Artikel 是主键,Source_LevArt.Artikel 是外键吗?您还可以在“ON”(无 where 子句)后用“AND”表示“AND”“制造商零件编号”不为空。用包含零件号的字段替换报价中的内容。 (假设 source_levArt 中的一些记录可能为空。那么应该发生的是在连接发生之前将过滤器应用于第二个表,从而减少查询必须连接的记录数。 我要做的第一件事是去掉连接条件中的like
,因为你似乎只想要完全匹配,所以试试ON a.Artikel = l.Artikel
,看看这是否加快了速度.
@vlatro “我真的不知道有什么不同,因为我没有使用通配符。”你知道,但 SQL 处理器不知道,因为 l.Artikel
的内容中可能隐藏了 %
或 _
谢谢@piet.t
【参考方案1】:
这里由 Paul White 介绍:Dynamic Seeks and Hidden Implicit Conversions
即使在完全匹配的情况下使用 like 也会进行动态搜索。这意味着在执行时知道要搜索的列,而不是在编译时。
下面是如何为我的下面示例中的表格派生列..
[Expr1005] = 标量运算符(CONVERT_IMPLICIT(varchar(12),[Aegon_X].[Sales].[Orders].[custid] as [o].[custid],0)), [Expr1006] = 标量运算符(LikeRangeStart(CONVERT_IMPLICIT(varchar(12),[Aegon_X].[Sales].[Orders].[custid] as [o].[custid],0)) ), [Expr1007] = 标量运算符(LikeRangeEnd(CONVERT_IMPLICIT(varchar(12),[Aegon_X].[Sales].[Orders].[custid] as [o].[custid],0)) ), [Expr1008] = 标量运算符(LikeRangeInfo(CONVERT_IMPLICIT(varchar(12),[Aegon_X].[Sales].[Orders].[custid] as [o].[custid],0)) )
以下是保罗所描述的,这些是如何推导出来的
上方的工具提示显示计算标量使用三个内部函数,LikeRangeStart、LikeRangeEnd 和 LikeRangeInfo。
前两个函数将范围描述为开区间。第三个函数返回一组以整数编码的标志,这些标志在内部用于定义存储引擎的某些搜索属性。下面的工具提示显示了在由 LikeRangeStart 和 LikeRangeEnd 的结果描述的开区间上的搜索,以及残差谓词“LIKE @Like”的应用。
总而言之,使用like SQL 使用动态搜索在编译时派生搜索属性..
以下示例显示不同的计划
使用类似: 我真的不知道有什么区别,因为我没有使用通配符。
select top 10* from sales.orders o
join
sales.customers c
on c.custid like o.custid
计划:
现在使用完全匹配时..
select top 10* from sales.orders o
join
sales.customers c
on c.custid =o.custid
你可以看到合并加入计划
【讨论】:
【参考方案2】:使用 = 而不是喜欢。
这 2 个索引应该为您提供最佳的 Select 性能。
CREATE INDEX idx ON Source_Artikelen(Artikel) INCLUDE(Omschrijving);
CREATE INDEX idx ON Source_LevArt(Artikel) INCLUDE(Artikel_Leverancier);
如果您实施它们并再次尝试您的 SELECT,您能上传一份您的执行计划吗?
【讨论】:
以上是关于如何提高大型左外连接的性能?的主要内容,如果未能解决你的问题,请参考以下文章