選單
GSS 技術部落格
在這個園地裡我們將從技術、專案管理、客戶對談面和大家分享我們多年的經驗,希望大家不管是喜歡或是有意見,都可以回饋給我們,讓我們有機會和大家對話並一起成長!
若有任何問題請來信:gss_crm@gss.com.tw
6 分鐘閱讀時間 (1129 個字)

SQL Where 條件中,有很多的 OR 查詢效能問題

SQL Where 條件中,有很多的 OR 查詢效能問題


我們在取 Workflow 的待辦事項時,會從 Work 的待辦資料中,依這個使用者的代號、部門主管、角色或是部門 + 角色的條件來取得這個人的待辦資料。

所以整個 SQL 中 Where 條件中會有很多的 OR,像這種很多 OR 的查詢效能要如何解決呢?



整個 SQL 類似如下,
SELECT   …..
FROM WORKLIST_IV WITH ( READPAST )
WHERE ( ( PTCP_KIND = N'1' AND PTCP_COMP_ID = N655
AND PTCP_USR = N'S122484051' )
OR ( ( PTCP_KIND = N'3' AND PTCP_DOMAIN_ID = N'GSS' AND PTCP_COMP_ID = N655
)
AND ( (PTCP_OU = N'379132200C2202' AND PTCP_RELKIND = N'1')
)
)
OR ( ( PTCP_KIND = N'2' AND PTCP_DOMAIN_ID = N'GSS' AND PTCP_COMP_ID = N655
)
AND ( ( PTCP_ROL = N'ODDeskUsr_Rol_4' AND PTCP_RELKIND = N'1' )
OR ( PTCP_ROL = N'ODDeskUsr_Rol_4_379132200C2202' AND PTCP_RELKIND = N'1' )
OR ( PTCP_ROL = N'SWS_OuExamRol' AND PTCP_RELKIND = N'1' )
OR ( PTCP_ROL = N'SWS_OuExamRol_379132200C22AA' AND PTCP_RELKIND = N'1' )
OR ( PTCP_ROL = N'SWSProcesser_Rol' AND PTCP_RELKIND = N'1' )
)
)
OR ( ( PTCP_KIND = N'5' AND PTCP_DOMAIN_ID = N'GSS' AND PTCP_COMP_ID = N655
)
AND ( ( PTCP_OU = N'379132200C2202' AND PTCP_ROL = N'ODDeskUsr_Rol_4' AND PTCP_RELKIND = N'1' )
OR ( PTCP_OU = N'379132200C2202' AND PTCP_ROL = N'ODDeskUsr_Rol_4_379132200C2202' AND PTCP_RELKIND = N'1' )
OR ( PTCP_OU = N'379132200C2202' AND PTCP_ROL = N'SWS_OuExamRol' AND PTCP_RELKIND = N'1' )
OR ( PTCP_OU = N'379132200C2202' AND PTCP_ROL = N'SWS_OuExamRol_379132200C22AA' AND PTCP_RELKIND = N'1' )
OR ( PTCP_OU = N'379132200C2202' AND PTCP_ROL = N'SWSProcesser_Rol' AND PTCP_RELKIND = N'1' )
)
)
);
執行計畫如下,


疑,這麼多的 OR,依以往的經驗,就將 Where 都加到 index 之中,如下,
CREATE NONCLUSTERED INDEX IDX_WKITEM_PTCP_I_RM
ON [dbo].[WKITEM_PTCP_I] ([PTCP_COMP_ID],[PTCP_KIND],[PTCP_USR],[PTCP_ROL],[PTCP_ACTN_STATE])
INCLUDE ([WKITEM_ID],[PTCP_ID],[PTCP_NAME],[PTCP_DESC],[PTCP_DOMAIN_ID],[PTCP_OU],[PTCP_GRP],[PTCP_RELKIND],[PTCP_PRO_STATE],[PTCP_RECV_TIME],[PTCP_COMM])
結果執行計畫好不到那裡去,如下,

-- 請先將前面建立的這個 index drop掉哦!​

那是不是不要拆 SQL 的寫法,分別針對 OR 去用各別的 SQL ,再 union 起來呢?

後來公司的天空大大,分別建立了3個 index 後就成功化解了這個一次會先將一堆資料取出來後,再透過 篩選 出資料的問題。以下筆者就來分享 Sky 成功化解這個 Where 很多 OR 的問題。

先依每個 OR 中,有相同欄位的部份來建立各別的 index ,如下,



所以我們可以建立 4 個 index, 如下,
CREATE INDEX IX_WKITEM_PTCP_USR ON WKITEM_PTCP_I(PTCP_KIND, PTCP_USR, PTCP_COMP_ID) 
CREATE INDEX IX_WKITEM_PTCP_OU_1 ON WKITEM_PTCP_I(PTCP_KIND, PTCP_OU, PTCP_RELKIND)
CREATE INDEX IX_WKITEM_PTCP_ROL ON WKITEM_PTCP_I(PTCP_KIND, PTCP_ROL, PTCP_RELKIND)
CREATE INDEX IX_WKITEM_PTCP_OU_2 ON WKITEM_PTCP_I(PTCP_KIND, PTCP_OU, PTCP_RELKIND, PTCP_ROL)
建立完成後,再執行SQL,看一下執行計畫為何,如下,


成功的化解掉先取出一堆資料後再「篩選」的問題,只是有些 index 會有 索引鍵查閱(key lookup)。

要解 索引鍵查閱(key lookup)的問題,我們可以使用 Include Index 。所以我們可以查看原本那些 OR 中,那些非相同的欄位,將它們加到 Include Index 之中,如下,


所以 index 改成如下,
--其他的 OR 還有其他的 WHERE 條件,也放在 INCLUDE 之中 CREATE INDEX IX_WKITEM_PTCP_OU_1 ON WKITEM_PTCP_I(PTCP_KIND, PTCP_OU, PTCP_RELKIND) 
INCLUDE (PTCP_DOMAIN_ID, PTCP_COMP_ID);
CREATE INDEX IX_WKITEM_PTCP_ROL ON WKITEM_PTCP_I(PTCP_KIND, PTCP_ROL, PTCP_RELKIND)
INCLUDE (PTCP_DOMAIN_ID, PTCP_COMP_ID);
CREATE INDEX IX_WKITEM_PTCP_OU_2 ON WKITEM_PTCP_I(PTCP_KIND, PTCP_OU, PTCP_RELKIND, PTCP_ROL)
INCLUDE ( PTCP_DOMAIN_ID, PTCP_COMP_ID);
執行計畫如下,


這樣我們就解掉了 索引鍵查閱(key lookup)的問題,但執行計畫之前可以發現,index 並沒有用到 IX_WKITEM_PTCP_OU_1 ,只有用到了 IX_WKITEM_PTCP_OU_2。

所以我們可以將 IX_WKITEM_PTCP_OU_1 刪掉,並將 IX_WKITEM_PTCP_OU_2 改成 IX_WKITEM_PTCP_OU,如下,
drop index IX_WKITEM_PTCP_OU_1 ON WKITEM_PTCP_I;EXEC sp_rename N'WKITEM_PTCP_I.IX_WKITEM_PTCP_OU_2', N'IX_WKITEM_PTCP_OU', N'INDEX';
再看一下執行計畫, IX_WKITEM_PTCP_OU_2 的名稱就改成了 IX_WKITEM_PTCP_OU,如下,


如果加入 include index 欄位後,還是有 key lookup 的話,可以再看一下那個 View 中那個 Table 的 Join Key 哦!

註:本篇是依 天空大大建議的 index , 筆者依公司DB狀況測試調整,各位調整時也請依實際環境狀況調整哦!

所以最後新增的index 有3個,如下,
CREATE INDEX IX_WKITEM_PTCP_USR ON WKITEM_PTCP_I(PTCP_KIND, PTCP_USR, PTCP_COMP_ID)
--其他的 OR 還有其他的 WHERE 條件,也放在 INCLUDE 之中 CREATE INDEX IX_WKITEM_PTCP_ROL ON WKITEM_PTCP_I(PTCP_KIND, PTCP_ROL, PTCP_RELKIND)
INCLUDE (PTCP_DOMAIN_ID, PTCP_COMP_ID);
CREATE INDEX IX_WKITEM_PTCP_OU ON WKITEM_PTCP_I(PTCP_KIND, PTCP_OU, PTCP_RELKIND, PTCP_ROL)
INCLUDE (PTCP_DOMAIN_ID, PTCP_COMP_ID);
 
AP Server連接File Server出現異常錯誤
GitLab與Jenkins的整合

相關文章

 

評論

尚無評論
已經注冊了? 這裡登入
Guest
2024/05/03, 週五

Captcha 圖像