SQL Server性能調優雜記(二)----傻瓜機的失效效應續

     上文說道了失效效應。只想說明在Performance Tunning方面只能根據情況來尋求原因並解決。這是一個有意思的過程。大原則是經驗,幫助我們少犯錯誤。因此,糟糕的設計,必然導致性能問題。沒有經驗的程序員必然會寫出糟糕的代碼。但是良好的設計可以彌補程序員的經驗不足。這個到此打住,這個topic涉及品質管理,實在太大了。

     再看一例,失效效應的體現。

     還是上文數說道了2種SQL文寫法產生的執行計劃。我選用一臺雙核的PC,相當於2個單核CPU。

     有一個大表TB_CWB 。記錄約30-40萬。(在生產環境下屬於小數據量,在我的測試中可以看成大表)。表上已經對 fn_Clt_Datetime 做了索引。

1.SQL文一

    select CWB_No,fn_Clt_Datetime,acctId_guid,fn_OrigZone_Id,DestSZMCode,DestZone_Id,CWBType,fn_Clt_Datetime,fn_cwbtype,
    PayType,Payweight,StdPriceweight,StdFreight,IsCalculated,AFterDsctFreight,
    SchgFreight,InvcFreight,Salesamount,SchgDetail,SchgFreight_Remarks
    from OCS_TB_CWB 
    WHERE
    fn_Clt_Datetime between '2008-9-1' and '2008-9-16'

 

   運行結果,發現奇慢無比。需要12秒才能出結果。

   檢查執行計劃,發現用了聚集索引掃描(主鍵),就是相當於選擇了全表掃描的計劃。因爲CBO認爲這句SQL比動用索引還要快。見下圖

 

 

       

2 SQL文二

   存儲過程寫法

   declare @date_from datetime
declare @date_to datetime

set @date_from='2008-9-1'
set @date_to='2008-9-16'
 

select CWB_No,fn_Clt_Datetime,acctId_guid,fn_OrigZone_Id,DestSZMCode,DestZone_Id,CWBType,fn_Clt_Datetime,fn_cwbtype,
PayType,Payweight,StdPriceweight,StdFreight,IsCalculated,AFterDsctFreight,
SchgFreight,InvcFreight,Salesamount,SchgDetail,SchgFreight_Remarks
from OCS_TB_CWB
WHERE
fn_Clt_Datetime between @date_from and @date_to

 

速度也慢。第一次16秒(比全表掃描還慢?有可能),第二次9秒,這還像點話。但是上面SQL文一再執行一遍,也差不多9秒。

說明這2種寫法在這裏情況下大致都差不多。

第2種寫法的執行計劃。非常肯定用到了索引。在這裏我基本傾向於涉及查詢之類的,用存儲過程,CBO失效認爲全表掃描比索引代價小的可能性低。

 

 

3 SQL文三

  對於SQL文一,強制用索引。

--檢查價格計算結果
select CWB_No,fn_Clt_Datetime,acctId_guid,fn_OrigZone_Id,DestSZMCode,DestZone_Id,CWBType,fn_Clt_Datetime,fn_cwbtype,
PayType,Payweight,StdPriceweight,StdFreight,IsCalculated,AFterDsctFreight,
SchgFreight,InvcFreight,Salesamount,SchgDetail,SchgFreight_Remarks
from OCS_TB_CWB
WITH (index(IND_FN_CLT_DATETIME_OF_OCS_TB_CWB))
WHERE
fn_Clt_Datetime between '2008-9-1' and '2008-9-16'

 

運行0秒,天哪,不會吧。趕快看執行計劃

 

執行計劃不經用了索引,還動用了並行裝載數據。爲了公平期間,反覆運行幾次,最慢4秒,基本1秒。

 

在這個案例中。指定值的SQL在CBO看來還不如全表掃描(估計因爲是它已經知道你要找的值,根據數據分佈,發現摸一次索引樹的代價還不如全表掃描更快)。呵呵,但是你強制指定索引,它決定把2個cpu都用上來幫助你獲得最佳性能。

結果成了在這個case中的最佳結果。

 

不過,在大部分情況下,我個人認爲SP的寫法還是比較好的選擇。parse參數的方法(sp_executesql)只有當只變化參數值,可以重用第一次的執行計劃。但是並一定說SQL Server給你的執行計劃就是好的。

總結一下,

1)這個case告訴我們,你建了索引也不會快,因爲SQL Server的CBO會決定不用,這還是和SQL文有關係。

2)硬件強也要看SQL Server是不是考慮用Paralism,而不好的SQL文反而會讓CBO的失效效應出現差的結果。

3)而最後一個case,但是有點對失效效應的利用的意味,讓你把硬件充分發揮出來,倒是有點出奇制勝的效果了。

4)回到正題,良好的設計和代碼控制,纔是性能好的根本保證。而有很多項目組很忽視數據庫設計review和代碼review,是出現性能問題的根本原因。好的品質不是靠測試和後期強人tunning出來的,而是靠良好的設計和管理管出來的。

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