SQL優化

  最近優化一批接口,之前只優化過MySQL數據庫語句,它和SQL SERVER的差別還是很大的,記錄一下優化後時間差別最大的兩個接口。

接口一:

  根據條件查詢十個分表,SQL語句處理後如下,其中查詢條件不止三個,還有一些其他。優化前:75s

select  out_trade_no,total_fee, liquidator_commission_fee  from [BankPayOrder_4_0] where 1=1 AND username like '%用戶名稱%' AND total_fee >=10 AND total_fee <=500 AND  Convert(nvarchar(12),addtime,112) between '20190401' and '20190429'
union all
select  out_trade_no,total_fee, liquidator_commission_fee  from [BankPayOrder_4_1] where 1=1 AND username like '%用戶名稱%' AND total_fee >=10 AND total_fee <=500 AND  Convert(nvarchar(12),addtime,112) between '20190401' and '20190429'
union all
select  out_trade_no,total_fee, liquidator_commission_fee  from [BankPayOrder_4_2] where 1=1 AND username like '%用戶名稱%' AND total_fee >=10 AND total_fee <=500 AND  Convert(nvarchar(12),addtime,112) between '20190401' and '20190429'
union all
select  out_trade_no,total_fee, liquidator_commission_fee  from [BankPayOrder_4_3] where 1=1 AND username like '%用戶名稱%' AND total_fee >=10 AND total_fee <=500 AND  Convert(nvarchar(12),addtime,112) between '20190401' and '20190429'
union all
select  out_trade_no,total_fee, liquidator_commission_fee  from [BankPayOrder_4_4] where 1=1 AND username like '%用戶名稱%' AND total_fee >=10 AND total_fee <=500 AND  Convert(nvarchar(12),addtime,112) between '20190401' and '20190429'
union all
select  out_trade_no,total_fee, liquidator_commission_fee  from [BankPayOrder_4_5] where 1=1 AND username like '%用戶名稱%' AND total_fee >=10 AND total_fee <=500 AND  Convert(nvarchar(12),addtime,112) between '20190401' and '20190429'
union all
select  out_trade_no,total_fee, liquidator_commission_fee  from [BankPayOrder_4_6] where 1=1 AND username like '%用戶名稱%' AND total_fee >=10 AND total_fee <=500 AND  Convert(nvarchar(12),addtime,112) between '20190401' and '20190429'
union all
select  out_trade_no,total_fee, liquidator_commission_fee  from [BankPayOrder_4_7] where 1=1 AND username like '%用戶名稱%' AND total_fee >=10 AND total_fee <=500 AND  Convert(nvarchar(12),addtime,112) between '20190401' and '20190429'
union all
select  out_trade_no,total_fee, liquidator_commission_fee  from [BankPayOrder_4_8] where 1=1 AND username like '%用戶名稱%' AND total_fee >=10 AND total_fee <=500 AND  Convert(nvarchar(12),addtime,112) between '20190401' and '20190429'
union all
select  out_trade_no,total_fee, liquidator_commission_fee  from [BankPayOrder_4_9] where 1=1 AND username like '%用戶名稱%' AND total_fee >=10 AND total_fee <=500 AND  Convert(nvarchar(12),addtime,112) between '20190401' and '20190429'

優化:

  優化點一:如果username字段有索引,但是like後面第一個爲"%",查詢也不會走索引。就算username字段沒有索引,like後面第一個跟“%”和不是“%”的查詢時間差別也很大,所以最好不使用。但是這樣會導致需求變更了,導致可能查詢不到想要查的。綜合一下,另寫了一個接口,通過用戶名稱模糊查詢到用戶Id,然後使用者選擇一個用戶,將此用戶的Id傳入。

  優化點二:由於查詢時,時間段是必傳字段,所以在時間字段上加上聚集索引(表之前的結構是另外兩個字段訂單號、商戶ID組成的聚集索引,實際並沒有什麼用,也發揮不了聚集索引的優點)。這裏指出,如果將時間字段設置爲非聚集索引,可能SQL SERVER並不走這個索引,只有當查詢的時間段很短的時候,纔會走時間的非聚集索引。

  優化點三:設置了時間聚集索引,通過SQL SERVER的執行計劃發現,SQL SERVER走的是時間聚集索引掃描(如圖一),導致的原因是Convert將時間裝換爲字符串格式了。將Convert刪除,查詢條件改爲時間格式,通過執行計劃看到此時就走聚集索引查找(如圖二)

                      圖一

                       圖二

  優化後查詢時間1天,300ms。由於設置的是時間聚合索引,所以時間的跨度越大,耗時越久,查詢一個月的數據,耗時5s左右,因爲接口是運營做統計使用,已經到能接受的程度了。

接口二:

  優化前耗時2s,SQL語句如下:

SELECT
    A.*,
    B.LableName,
    C.Name AS CustomerName,
    D.Company AS FatherName,
    AE.BonusActivityID,
    BO.ActivityName,
    AE.IsBonus 
FROM
    Sys_Agents A
    LEFT JOIN Sys_AgentLable B ON A.AgentLabelID= B.LableID    
    LEFT JOIN AgentExtend AE ON A.AgentsID= AE.AgentsID    
    LEFT JOIN BonusActivities BO ON AE.BonusActivityID= BO.ActivityID   
    LEFT JOIN Agents_Customer C ON A.CustomerID= C.ID    
    LEFT JOIN Sys_Agents D ON A.FatherId= D.AgentsID    
WHERE
    1 = 1 
    and A.Company like '%衆恆科技有限公司%'
    AND A.IsOEM=0
    AND A.AgentLevel=1
    AND CONVERT ( nvarchar ( 10 ), A.EndTime, 112 ) >'20190416'
    AND CONVERT ( nvarchar ( 10 ), A.EndTime, 112 ) <='20191222'
    AND A.CustomerID=0 
    AND A.State=1 

  優化點一:like,處理方式和第一個相同。

  優化點二:convert ,使用時間格式。

  優化點三:Sys_Agents表的字段不需要全部返回,全部字段有50多個。(怎麼會有這麼多字段???可能是歷史原因吧)

  優化點四:由於是連接查詢,不論是交叉聯接、左聯接、右聯接、內聯接都會先產生笛卡爾積,然後過濾條件。所以將Where條件之後涉及的表現查詢出來放到臨時表中,在連接查詢,減少笛卡爾積。

  優化後 300ms左右。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章