[SQL SERVER][Performance]善用 FORCESEEK 資料表提示

[SQL SERVER][Performance]善用 FORCESEEK 資料表提示

有些查詢陳述句總是讓查詢最佳化程式使用index or table scan 操作來處理,

以前SQL 2000/2005 你可能會用 index hint 讓查詢最佳化程式選擇特定index,

來達到改善查詢效能(可能改用 index seek 操作...等),

但現在SQL2008 多了 FORCESEEK 資料表提示這個好功能,

讓你可以強制查詢一率都使用Index Seek 操作來處理,

下面我也會貼上前幾天使用 FORCESEEK hint 解決一個查詢問題。

 

先來說說INDEX hint和FORCESEEK hint有什麼不同?

INDEX hint:

強制查詢最佳化程式只使用所指定的索引來存取相關資料表或檢視表。

 

FORCESEEK hint:

強制查詢最佳化程式只使用 Index Seek 操作來存取相關資料表或檢視表。

 

FORCESEEK 注意事項:

image

(擷取線上叢書)

 

問題:

開發人員向DBA反應,為什麼SQL Server總是使用 Index Scan 來處理。

這裡我大概模擬當時的Table Layout 、資料量和 前端應用程式的SQL Statement

Table Layout:

image

 

NonClusted Index Layout:

select
    ind.name, ind.index_id, ic.index_column_id, col.name,
    ind.*, ic.*, col.*
from 
    sys.indexes ind
inner join 
    sys.index_columns ic on 
      ind.object_id = ic.object_id and ind.index_id = ic.index_id
inner join
    sys.columns col on
      ic.object_id = col.object_id and ic.column_id = col.column_id 
inner join
    sys.tables t on 
      ind.object_id = t.object_id
where 
    ind.is_primary_key = 0 
    and ind.is_unique = 0 
    and ind.is_unique_constraint = 0
    and t.is_ms_shipped = 0    
    and t.name='ap_log'
order by
    t.name, ind.name, ind.index_id, ic.index_column_id

 

 

 

 

image

 

這裡我門主要看nidx_1

image

image

 

資料總筆數:194055

image

 

前端AP  SQL Statement 如下(前端AP使用參數化):

declare @myid varchar(10);
set @myid='RichChou' ;
select ApLogId,LogDate,LoginId,LineNumber,LogMessage
from dbo.AP_LOG
where LoginId =@myid
order by LogDate asc

 

 

 

 

 

image

CPU時間:266 ms ,經過時間:4745 ms。

 

image

預估成本:17.4167

 

可以看到這次返回18487 筆資料(選擇性還滿高的),

但查詢最佳化程式認為使用Index Scan所花費的成本較Index Seek還低,

所以使用Index Scan 操作來處理,這時開發人員就會抱怨,那 nidx_1 是建立好看的嗎?

 

到這裡我想你應該看出問題在那了,明明選擇性夠高也有使用參數化且相關Index也建立了

但查詢最佳化程式卻選用 Index Scan的操作,

或許你可能會覺得使用Index hint來改善也可以吧,

但如同我前面所說Index hint 和FORCESEEK hint差異,

使用FORCESEEK hint 彈性會來的比較大點(而且使用了 index hint 並不見得就會使用index seek 操作),

因為你無法確認那天你指定的with (index(nidx_1))會不會被改了名稱..等之類的靈異問題。

 

使用FORCESEEK

declare @myid varchar(20);
set @myid='RichChou' ;
select ApLogId,LogDate,LoginId,LineNumber,LogMessage
from dbo.AP_LOG with(FORCESEEK) 
where LoginId =@myid
order by LogDate asc

 

 

 

 

image

CPU時間:202 ms ,經過時間:950 ms。

 

image

預估成本:142.445

 

結論:

可以看到經過時間從4745(ms) 降低為 950(ms),整整少了3795(ms)且IO也大為降低,

如果你的查詢陳述句選擇性夠高的話,不要懷疑 Index Seek 操作絕對是首選。

 

 

參考

使用 FORCESEEK 資料表提示