可以拿来吊打面试官的 SQL Join (三)

2020-06-19 14:36:54 浏览数 (1)

这是本系列第三篇。

点击下面链接,可以阅读上两篇:

可以拿来吊打面试官的 SQL Join (一) 可以拿来吊打面试官的 SQL Join (二)

我在这个系列中,所分享的知识,力求逻辑严谨,实战辅证。但一如所有的文章一样,读者需要自己思考,是否正确无误,是否可以拿来直接作用于生产环境。对于没有理解透彻,就直接用于生产而造成的损失,本人概不负责。

不仅仅是看我的文章,看所有的文章,书籍或者教程,读者朋友们都该用自己的思维,带着批判的眼光,谨慎对待作者发表的观点,切勿盲目轻信。

回到正题,上一讲中,文末留了个预告,这回要讲 WHERE 和 ON 时,对索引的访问方式,以及无索引时,访问效率如何提高。

拿上讲中的例子,来做探讨。基于公平的基础上,我们比较 WHERE 和 ON 的性能,实际可以归纳成比较下两个例子的快慢:

代码语言:javascript复制
SELECT Header.OrderId
    ,   Detail.ProductName
    ,   Detail.Amount 
FROM tblOrderHeader Header 
    INNER JOIN tblOrderDetail Detail 
        ON Header.OrderId = Detail.OrderId 
        AND Detail.Amount > 1000
WHERE Header.OrderDate > '2020-01-01' 

Detail.Amount > 1000 放在 WHERE 中:

代码语言:javascript复制
SELECT Header.OrderId
    ,   Detail.ProductName
    ,   Detail.Amount 
FROM tblOrderHeader Header 
    INNER JOIN tblOrderDetail Detail 
        ON Header.OrderId = Detail.OrderId 
WHERE Header.OrderDate > '2020-01-01' 
    AND Detail.Amount > 1000

从原业务库,复制了一份轻量型的数据。暂时还没加上索引,肯定是不够优化的。正是由于这份原始的数据,我们得以窥探,在没有任何索引的时候,两表怎么优化。

面对调优,我的黄氏三板斧,大家应该都不陌生了。如果是新关注的读者,可以到文末的搜索框里搜索。点击#三板斧#的标签即可。

在这里,用到执行计划。

以上就是二段 SQL 的执行计划。一模一样。

不出意外的,如果没有索引,那么表扫描(Table Scan)是唯一的 Join 解法。平时跟大家说,要懂点英语,要懂点英语,好处就在这里。Table Scan, Hash Match, 下次你面试的时候,听到这些词,就不会胆怯

按照 Table Scan 的图标,点进去,我们会有惊喜。

上面两个执行算子,都使用了 Predicate. Predicate 在这里的作用是条件判断。即筛选满足条件的记录。

Predicate 在 Table Scan 里面出现,说明它仅仅能减少结果数据集,不等于减少从磁盘读到的数据。因为 Table Scan 就说明了,数据的查找方式,是按照全表扫描方式进行的。

有细心的读者,可能会发现,这里有个 Hash Match (Inner Join).

好多读者对 Left Join, Right Join , Full Join 滚瓜烂熟。但对于 Hash Join, Merge Join, Nested Loop Join 是一点概念都没有

这大概就是不好好读书,带来的差别。

回忆下我们这两张表数据的来历,就知道,在Join字段上,并没有加索引。没有索引的情况下,Join 怎么提高性能呢?答案就是 Hash join. 至于它的原理,还有 Merge Join, Nested Loop Join 的内幕,我打算留到后面,找合适的机会再讲。其实,我的知识星球里面,早已写得很明白。

如何给这段 SQL 提高性能? 解决之道在于索引。

代码语言:javascript复制
## 尝试给两表加索引

CREATE INDEX IDX_HEADER ON tblOrderHeader(OrderId)
CREATE INDEX IDX_DETAIL ON tblOrderDetail(OrderId)

## end 

但是呢,加了索引之后,发现执行时间还长了。真别不信,有时候 Table Scan 真要快很多。这就是个例子。

所以,我们继续要加索引:

代码语言:javascript复制
CREATE INDEX IDX_HEADER_ORDER_DATE ON tblOrderHeader(OrderDate)
CREATE INDEX IDX_DETAIL_AMOUNT ON tblOrderDetail(Amount)

索引加对,速度爆表

等到加完索引,再回头比较两个 INNER JOIN, 其实他们的执行计划和速度都是一模一样的。

在本文中,提供了比较两个 Join 写法的思路,还有通过增加索引,提高性能的实战操作经验。现实环境中,条件比上面两个表,要复杂的多。可能需要花费我们一些耐心,才能找到最优解。

上面很多执行计划,其实都只写了一半,大家有可能看得云里雾里。没关系,下一文,我会继续展开讲解下在本章中出现的执行计划操作符。

0 人点赞