三、連接查詢部分
--------------------嵌套循環-------------------- /* UserInfo表數據少、Coupon表數據多
嵌套循環可以理解為就是兩層For循環,外層For會循環其中的每一項,內層For進行匹配,
相應的外層For對應外部輸入表,執行計划的圖示排在上面,內層For對應內部出入表,執行計划的圖示排在下面,
外部表每一行都要使用來匹配,而內部表卻不一定每一行都在匹配中被使用,所以,
1、外部表輸入越小越好,也可以利用索引來減少輸入行數
2、內部表匹配則可以利用索引來減少匹配條件的范圍,盡快獲取匹配行
3、多大多數情況下,查詢優化器會自動更替結果集小的表為外部,大的為內部
當兩個Join的表外部輸入結果集比較小,而內部輸入所查找的表非常大時,查詢優化器更傾向於選擇循環嵌套方式。 */ SELECT * FROM dbo.UserInfo AS u INNER JOIN dbo.Coupon AS c ON u.Id = c.UserId
--------------------合並連接-------------------- /*
UserInfo表數據少、Coupon表數據多 不同於循環嵌套的是,合並連接是從每個表僅僅執行一次訪問,對於兩個輸入列都有序的情況下,合並連接的效率更高,
其中排序的的重要性毋庸置疑了,B樹中的葉層就是按照一定的邏輯順序維護的。也就是說,聚集索引和非聚集覆蓋索引,
都可以通過對葉層的有序掃描以較小的代價就可以獲取有序的數據。在這種情況下,就算輸入表的規模比較大,合並聯接也相當給力。
如果計划分析器確定連接的一側記錄集中的元素是唯一確定的,那么就會采用一對多的匹配方式(多指另一側的元素會有重復),
在這種情況下,合並排序效率應該是幾種連接方式中最高的。但如果所需的數據列並不存在上述的條件的時候,對於較大的輸入來說排序
往往是一個開銷非常大的操作(因為基於比較的排序最快也就是n log n的),因此優化器通常不會在這種情況下選用合並聯接。
但是對於較小的輸入排序的消耗還是可以接受的。合並連接需要雙方有序,並且要求join的條件為等號,如果輸入數據的雙方無序,
則查詢分析器不會選擇合並連接,我們也可以通過索引提示強制使用合並連接,這就是SQL語句為什么要加OPTION(MERGE JOIN)的原因 */ CREATE NONCLUSTERED INDEX Index_Coupon_UserId ON dbo.Coupon(UserId) --DROP INDEX Index_Coupon_UserId ON dbo.Coupon
SELECT * FROM dbo.UserInfo AS u INNER JOIN dbo.Coupon AS c ON u.Id = c.UserId --OPTION(MERGE JOIN)
--------------------哈希連接-------------------- /* 散列連接同樣僅僅只需要只訪問1次雙方的數據。散列連接通過在內存中建立散列表實現。 這比較消耗內存,如果內存不足還會占用tempdb。但並不像合並連接那樣需要雙方有序。 刪除掉UserInfo的主鍵及其中的聚集索引,在執行以下SQL 要刪除掉聚集索引,否則兩個有序輸入SQL Server會選擇代價更低的合並連接。 SQL Server利用兩個上面的輸入生成哈希表,下面的輸入來探測,可以在屬性窗口看到這些信息, 通常來說,所求數據在其中一方或雙方沒有排序的條件達成時,會選用哈希匹配。 */ ALTER TABLE dbo.UserInfo DROP CONSTRAINT PK_UserInfo_Id --刪除主鍵 --DROP INDEX Index_UserInfo_Name --刪除聚集索引 --ALTER TABLE dbo.UserInfo ADD CONSTRAINT PK_UserInfo_Id PRIMARY KEY CLUSTERED(Id) --創建主鍵 SELECT * FROM dbo.UserInfo AS u INNER JOIN dbo.Coupon AS c ON u.Id = c.UserId
--------------------多表並行-------------------- /* 當多個表連接時,SQL Server還允許在多CPU或多核的情況下允許查詢並行,這樣無疑提高了效率。 */ SELECT * FROM dbo.UserInfo AS u INNER JOIN dbo.Coupon AS c ON u.Id = c.UserId INNER JOIN dbo.OneWayAirPolicy_20w AS o ON u.Id = o.PId