SQL Server 執(zhí)行計劃,是我們分析 SQL 執(zhí)行情況的一大利器,通過它,我們也可以很方面的查看索引的執(zhí)行,在實踐之前,需要了解一些必備技能,以下知識點摘自-看懂 SqlServer 查詢計劃。
SQL Server 有二種索引:聚集索引和非聚集索引。二者的差別在于:【聚集索引】直接決定了記錄的存放位置, 或者說:根據(jù)聚集索引可以直接獲取到記錄。【非聚集索引】保存了二個信息:1.相應索引字段的值,2.記錄對應聚集索引的位置(如果表沒有聚集索引則保存記錄指針)。 因此,如果能通過【聚集索引】來查找記錄,顯然也是最快的。
SQL Server 會有以下方法來查找您需要的數(shù)據(jù)記錄:
【Table Scan】:遍歷整個表,查找所有匹配的記錄行。這個操作將會一行一行的檢查,當然,效率也是最差的。
【Index Scan】:根據(jù)索引,從表中過濾出來一部分記錄,再查找所有匹配的記錄行,顯然比第一種方式的查找范圍要小,因此比【Table Scan】要快。
【Index Seek】:根據(jù)索引,定位(獲?。┯涗浀拇娣盼恢?,然后取得記錄,因此,比起前二種方式會更快。
【Clustered Index Scan】:和【Table Scan】一樣。注意:不要以為這里有個Index,就認為不一樣了。 其實它的意思是說:按聚集索引來逐行掃描每一行記錄,因為記錄就是按聚集索引來順序存放的。 而【Table Scan】只是說:要掃描的表沒有聚集索引而已,因此這二個操作本質上也是一樣的。
【Clustered Index Seek】:直接根據(jù)聚集索引獲取記錄,最快!
所以,當發(fā)現(xiàn)某個查詢比較慢時,可以首先檢查哪些操作的成本比較高,再看看那些操作在查找記錄時, 是不是【Table Scan】或者【Clustered Index Scan】,如果確實和這二種操作類型有關,則要考慮增加索引來解決了。 不過,增加索引后,也會影響數(shù)據(jù)表的修改動作,因為修改數(shù)據(jù)表時,要更新相應字段的索引。所以索引過多,也會影響性能。 還有一種情況是不適合增加索引的:某個字段用0或1表示的狀態(tài)。例如可能有絕大多數(shù)是1,那么此時加索引根本就沒有意義。 這時只能考慮為0或者1這二種情況分開來保存了,分表或者分區(qū)都是不錯的選擇。
應用分析
我們先不建任何索引(除了主鍵 ID 的聚集索引),來看一下上面 SQL 代碼,在 SQL Server 執(zhí)行計劃中的執(zhí)行情況:
從上面的執(zhí)行計劃中,我們可以很直觀的看出差別,所以在寫 SQL 的時候,一定要慎重啊,這邊為了方便展示,我們還是以 ProduceTime 字段進行排序,按照 ID 排序,雖然沒有了 SORT 性能開銷,但是發(fā)現(xiàn)查詢記錄為“Clustered Index Scan”,這是全表查詢的意思,我們理想的應該是“Index Seek”或者“Clustered Index Seek”,因為這種是按照索引查詢,速度最快。按照我們程序員的理解,應該創(chuàng)建一個非聚集索引,比如下面 IX_Product_Provider_State 索引:
“Index Seek”,這就是我們想要的效果,其實關于索引的創(chuàng)建有很多的現(xiàn)實問題,比如組合字段索引和單個字段索引有何不同?就像上面示例中的查詢用例,如果 ProduceTime 排序在其他查詢條件中也存在,是不是應該拉出來創(chuàng)建一個索引?還是像上面一樣,和查詢條件一起創(chuàng)建一個組合字段索引?還有一種情況就是,在一個應用程序查詢中,存在單個字段的查詢,也存在組合字段的查詢,那這時候我們是創(chuàng)建單個字段索引?還是創(chuàng)建組合字段索引呢?這幾個問題,你創(chuàng)建一下索引,然后用“ SQL 執(zhí)行計劃”試試就知道了。 總結 針對上面的查詢用例,我個人覺得,最好的方案是:排序字段使用 ID,按照實際應用場景,提取出需要查詢的字段,避免 SELECT *,這樣會減少在添加“包含性 列”的字段,創(chuàng)建 IX_Product_Provider_State 非聚集索引,索引字段為:ProviderID 和 State,如果 State 的值不是多變的(比如值為 1 和 0),盡量不要創(chuàng)建 State 字段的非聚集索引。 做完這些,你會發(fā)現(xiàn),你的應用程序像飛的一樣。
更多信息請查看IT技術專欄
2025國考·省考課程試聽報名