前文
JOIN
條件範圍時,執行計畫預估值容易不準確,這也間接導致查詢效能不好.
就算有建立Index也會遇到上述問題
假如我們想要提升JOIN
條件範圍效能並讓Index可以發揮最大最用可以怎麼做?
就讓我利用一個範例來跟大家分享.
案例
此範例有使用到三張表
- Product表:擁有1-10編號產品
- ReportPeriod表:存放產每期報表的資訊(時間,和是否產報表)
- T99表:線上產品訂單資訊
1 | CREATE TABLE [dbo].[Product]( |
我們利用
T99.CreateDate
來跟ReportPeriod
判斷是屬於哪期報表.
資料初始化
我們利用亂數產生Sample資料來模擬線上大資料狀況.
ReportPeriod
期別由'2019-08-01'
到'2020-07-31'
因為產生報表以5分鐘為區間,所以可以利用CTE遞迴來幫我們產生資料.
1 | INSERT INTO [dbo].[Product] VALUES (1); |
建立Index
1 | CREATE CLUSTERED INDEX [CIX_ReportPeriod_StartDate] ON [dbo].[ReportPeriod] |
查詢語法
在線上我們會使用UDT當作參數來取得某些期別資訊.
這裡為了方便模擬我使用Table Variable來取代.
1 | set nocount on |
使用上面語法我們只需查詢三個期別資料,但看執行計畫時能發現,ReportPeriod使用的Clustered預估資訊有1百多萬筆
Q:我明明有對於條件建立Index,但為什麼預估值卻會跑真那麼嚴重?
1 | CREATE CLUSTERED INDEX [CIX_ReportPeriod_StartDate] ON [dbo].[ReportPeriod] |
原因出在範圍條件會因為查找範圍過大導致預估值不準確
甚麼意思? 讓我們看看下圖(代表ReportPeriod
內含日期資料)
而我們在JOIN
條件只有t.CreateDate BETWEEN p.StartDate AND p.EndDate
這就會導致,我們需要查找ReportPeriod
日期資料在挑出符合的資料
1 | JOIN [dbo].[ReportPeriod] p ON t.CreateDate BETWEEN p.StartDate AND p.EndDate |
最後就會看到走針的估計值
如何優化?
效能差問題,選擇對Index和撰寫合理的查詢可以改善40%左右問題
我們思考一下如果可以把範圍條件改成精準=
查找條件不就可以更精準預估資訊了?
1 | t.CreateDate BETWEEN p.StartDate AND p.EndDate |
那我們怎麼把上面條件使用=
取代BETWEEN
範圍查詢呢?
這時我們可以利用空間來換取時間
建立一個新的COLUMN
運用算法來計算每個期數StartTime
例如:CreateDate = 2020/01/03 10:08:55
會歸類在2020/01/03 10:05:00
中
1 | ALTER TABLE dbo.T99 ADD PeriodDate AS DATEADD(MINUTE,DATEPART(MINUTE,CreateDate) %5 * -1, |
建立完新COLUMN
後別忘記加入一個Index
給此COLUMN
.
1 | CREATE INDEX IX_PeriodDate_T99 ON dbo.T99( |
最後我們修改一下查詢語法
1 | SELECT p.* |
預估值和讀取值已經可以大幅降低了!!
小結:
在JOIN
範圍條件差效能問題,可以思考一下是否有辦法利用算法或是公式來優化查詢效能,如此次範例一樣.
此文作者:Daniel Shih(石頭)
此文地址: https://isdaniel.github.io/join-index-improve/
版權聲明:本博客所有文章除特別聲明外,均採用 CC BY-NC-SA 3.0 TW 許可協議。轉載請註明出處!