使用正確的篩選引數來提高查詢效能

2021-09-07 01:17:01 字數 1843 閱讀 3366

在今天的文章裡我想談下sql server裡與索引相關的特殊效能問題。

假設下列的簡單查詢,在你的日常sql server裡,這樣的查詢你已經看到過幾百遍了:

1

--results in an index scan

2select

*from

sales.salesorderheader

3where

year(orderdate) =

2005

andmonth(orderdate) =74

go

用那個簡單查詢,我們請求在特定年份特定月份裡的銷售資訊。並不複雜。遺憾的是這個查詢效能很差——即使在orderdate列使用了非聚集索引。當你檢視執行計畫時,你會看到查詢優化器選擇了在orderdate列上的非聚集索引,但遺憾的是sql server進行的索引的全掃瞄,而不是高效的查詢操作。

這真不是sql server的侷限性,而是關聯式資料庫的工作和思考方式:)只要你在索引列上使用了表示式(函式呼叫,計算)(即所謂的篩選引數(search argument)),資料庫引擎必須去掃瞄那個索引,而不是進行查詢操作。

在執行計畫裡為了獲得可擴充套件的查詢操作,你必須要換種方式重寫你的查詢來避免datepart函式的呼叫:

1

--results in an index seek

2select

*from

sales.salesorderheader

3where orderdate >=

'20050701

'and orderdate <

'20050801'4

go

從重寫的查詢可以看到,查詢返回同樣的結果,但我們已經剔除了datepart函式的呼叫。當你檢視執行計畫時,你會看到sql server進行了查詢操作——在那個情況下,這個是所謂的區域性範圍掃瞄(partial range scan):sql server查詢到第1個值,然後掃瞄到請求範圍的最有值。如果你想在索引列上下文呼叫函式,你必須保證在查詢裡,這些函式呼叫的執行在你列的右側。我們來看乙個具體的例子。下面查詢把creditcardid索引列轉化為char(4)資料型別:

1

--results in an index scan

2select

*from

sales.salesorderheader

3where

cast(creditcardid as

char(4)) =

'1347'4

go

當你仔細看執行計畫時,你會看到sql server再次掃瞄整個非聚集索引。如果你的表越來越大,這是真不能擴充套件的。如果你在查詢裡在你索引列的右側執行轉化,你就可以在索引列上剔除函式呼叫,sql server就可以進行查詢操作:

1

--results in an index seek

2select

*from

sales.salesorderheader

3where creditcardid =

cast('

1347'as

int)

4go

從這篇文章裡,你可以看到,在你的索引列裡不直接呼叫任何函式或間接呼叫函式是非常重要的。不然的話sql server會掃瞄你的索引,而不是進行高效的查詢操作。而且當你表越來越大時,掃瞄從不擴充套件。

感謝關注。

使用正確的篩選引數來提高查詢效能

假設下列的簡單查詢,在你的日常sql server裡,這樣的查詢你已經看到過幾百遍了 1 results in an index scan 2select from sales.salesorderheader 3where year orderdate 2005 andmonth orderdat...

優化Linux的核心引數來提高伺服器併發處理能力

ps 在伺服器硬體資源額定有限的情況下,最大的壓榨伺服器的效能,提高伺服器的併發處理能力,是很多運維技術人員思考的問題。要提高linux系統下的負載能力,可以使用nginx等原生併發處理能力就很強的web伺服器,如果使用apache的可以啟用其worker模式,來提高其併發處理能力。除此之外,在考慮...

優化Linux的核心引數來提高伺服器併發處理能力

ps 在伺服器硬體資源額定有限的情況下,最大的壓榨伺服器的效能,提高伺服器的併發處理能力,是很多運維技術人員思考的問題。要提高linux 系統下的負載能力,可以使用nginx 等原生併發處理能力就很強的web伺服器,如果使用apache 的可以啟用其worker 模式,來提高其併發處理能力。除此之外...