|
我创建了9个表的使用INNER JOIN的SQL无论如何,这个命令将需要很长时间(超过五分钟)。所以我的同事建议我INNER JOIN更改为LEFT# g( _9 a. V# N7 x. S
JOIN,虽然我知道,但是LEFT JOIN性能更好。更改后,查询速度显著提高。
+ D) V+ B/ g& Y我想知道为什么LEFT JOIN比INNER JOIN快?
/ M6 ^, J1 o, Q* U( Q我的SQL命令看起来象下面这样: SELECT * FROM A INNER JOIN B ON ... INNER JOIN C ON ...INNER JOIN D等
8 i3 Q. a0 y; d% M2 n! _. V$ @更新: 这是我对结构的简要介绍。
& J: \% u# g: f2 V/ O. r* JFROM sidisaleshdrmly a -- NOT HAVE PK AND FK INNER JOIN sidisalesdetmly b -- THIS TABLE ALSO HAVE NO PK AND FK ON a.CompanyCd = b.CompanyCd AND a.SPRNo = b.SPRNo AND a.SuffixNo = b.SuffixNo AND a.dnno = b.dnno INNER JOIN exFSlipDet h -- PK = CompanyCd,FSlipNo,FSlipSuffix,FSlipLine ON a.CompanyCd = h.CompanyCd AND a.sprno = h.AcctSPRNo INNER JOIN exFSlipHdr c -- PK = CompanyCd,FSlipNo,FSlipSuffix ON c.CompanyCd = h.CompanyCd AND c.FSlipNo = h.FSlipNo AND c.FSlipSuffix = h.FSlipSuffix INNER JOIN coMappingExpParty d -- NO PK AND FK ON c.CompanyCd = d.CompanyCd AND c.CountryCd = d.CountryCd INNER JOIN coProduct e -- PK = CompanyCd,ProductSalesCd ON b.CompanyCd = e.CompanyCd AND b.ProductSalesCd = e.ProductSalesCd LEFT JOIN coUOM i -- PK = UOMId ON h.UOMId = i.UOMId INNER JOIN coProductOldInformation j -- PK = CompanyCd,BFStatus,SpecCd ON a.CompanyCd = j.CompanyCd AND b.BFStatus = j.BFStatus AND b.ProductSalesCd = j.ProductSalesCd INNER JOIN coProductGroup1 g1 -- PK = CompanyCd,ProductCategoryCd,UsedDepartment,ProductGroup1Cd ON e.ProductGroup1Cd = g1.ProductGroup1Cd INNER JOIN coProductGroup2 g2 -- PK = CompanyCd,ProductCategoryCd,UsedDepartment,ProductGroup2Cd ON e.ProductGroup1Cd = g2.ProductGroup1Cd 2 w$ A8 g" Q& ~% C; U
解决方案: $ M4 M0 ~8 C! s3 K
ALEFT JOIN绝对不会比A快INNER JOIN。事实上,它相对较慢。根据定义,外部连接(LEFT JOIN或RIGHTJOIN)所有的工作都必须完成INNERJOIN以及结果null额外的扩展工作。仅仅因为结果集的大小,我们也希望回到更多的行,从而进一步增加了总执行时间。
& {: f+ O' E0 K# @2 M4 w" V) i(而且即使LEFT JOIN 是 在更快的 特定 在这种情况下,由于一些难以想象的因素,它并不等同于功能INNERJOIN,所以你不能简单地改变所有其他例子!)
! o s, H: r# b你的性能问题很可能位于其他地方,比如没有正确的索引候选人键或外部键。有很多地方可以添加9个表,所以减速几乎可以在任何地方进行。如果您发布架构,我们可以提供更多详细信息。
9 Z7 t7 b- J( ~/ ^' w5 i& v1 U编辑:
y7 \0 p- W; k8 q* Y0 L/ o a进一步思考这一点,我可以想到一种情况,aLEFT JOIN可能比快INNER JOIN,在这种情况下:
. ~5 F) Z! ? r" p1 H; Q: f* s$ m一些表是 非常 小(比如10行);4 m! R4 y ]# S2 l. @
没有足够的索引来覆盖查询。考虑以下示例:9 p6 b# H: t0 l5 q" l! e
CREATE TABLE #Test1( ID int NOT NULL PRIMARY KEY, Name varchar(50) NOT NULL)INSERT #Test1 (ID,Name) VALUES (1,'One')INSERT #Test1 (ID,Name) VALUES (2,'Two')INSERT #Test1 (ID,Name) VALUES (3,'Three')INSERT #Test1 (ID,Name) VALUES (4,'Four')INSERT #Test1 (ID,Name) VALUES (5,'Five')CREATE TABLE #Test2( ID int NOT NULL PRIMARY KEY, Name varchar(50) NOT NULL)INSERT #Test2 (ID,Name) VALUES (1,'One')INSERT #Test2 (ID,Name) VALUES (2,'Two')INSERT #Test2 (ID,Name) VALUES (3,'Three')INSERT #Test2 (ID,Name) VALUES (4,'Four')INSERT #Test2 (ID,Name) VALUES (5,'Five')SELECT *FROM #Test1 t1INNER JOIN #Test2 t2ON t2.Name = t1.NameSELECT *FROM #Test1 t1LEFT JOIN #Test2 t2ON t2.Name = t1.NameDROP TABLE #Test1DROP TABLE #Test2如果操作此命令并查看执行计划,则会发现INNER JOIN查询确实比花费更多LEFT JOIN,这是因为它满足了上述两个条件。SQL
8 @) i8 l! }4 j. aServer希望散列匹配INNER JOIN,但是嵌套循环LEFT JOIN。前者 通常 快多了,但是因为行数很小 并且
3 R1 A) M; O) g' ^& W5 q, w没有索引可用,因此哈希运算被证明是查询中最昂贵的部分。
. z* f6 `# m: X, l通过使用你最喜欢的编程语言来编写程序,你可以在五个元素的列表与五个元素的哈希表)上找到大量的搜索,你可以看到相同的效果。由于大小,散列表的版本实际上更慢。但由于哈希表的速度较慢,将其添加到50个元素或5000个元素中O(N)对O(1)。' f! F f2 t) L
但将此查询改为ID列而不是列Name,你会看到一个完全不同的故事。在这种情况下,它是两个查询嵌套循环,但INNERJOIN版本可以取代聚簇索引扫描和寻求-这意味着这只是 一个数量级 速度更快。2 g. p7 C5 o+ Q4 B0 k3 V/ B
因此,结论或多或少是我上面提到的。这几乎肯定是一个索引或索引覆盖问题,可能与一个或多个非常小的表相结合。在这种情况下,SQL
8 B' y. o8 z+ r9 wServer有时 可能 为而INNER JOIN不要选择更糟糕的执行计划LEFT JOIN。 |
|