SQL Server裡簡單引數化的痛苦

2021-09-07 01:57:04 字數 4048 閱讀 8312

原文:

sql server裡簡單引數化的痛苦

在今天的文章裡,我想談下對於即席sql語句(ad-hoc sql statements),sql server使用的簡單引數化(****** parameterization)的一些特性和***。首先,如果你的sql語句包含這些,簡單引數化不會發生:

一般來說,如果你處理所謂的安全執行計畫(safe execution plan),sql server自動引數化你的sql語句:不管提供的引數值,查詢總必須通向一樣的執行計畫。如果你的執行計畫裡有書籤查詢,這就是不可能的例子。因為臨界點定義了是否進行書籤查詢還是全表/聚集索引掃瞄。

如果sql server能自動引數化你的sql語句,你還是要考慮下sql server引入的自動引數化sql語句的一些***。我們來看乙個具體的例子。下列查詢建立乙個表,執行乙個會被sql server自動引數化的簡單sql語句。

1

--create a ****** table

2create

table

orders3(

4 col1 int

identity(1, 1) primary

keynot

null

,5 price decimal(18, 2)6

)7go8

9--this query gets auto parametrized, because it is a ****** query with a safe (consistent) plan

10select

*from

orders

11where price =

5.70

12go

1314

--analyze the plan cache

15select

16 st.text

, 17

qs.execution_count,

18cp.cacheobjtype,

19cp.objtype,

20 cp.*

,21 qs.*

, 22 p.*

23from

sys.dm_exec_cached_plans cp

24cross

25cross

26left

join sys.dm_exec_query_stats qs on qs.plan_handle =

cp.plan_handle

27where st.text

like

'%orders%'28

go

然後當你檢視計畫快取時,你會看到sql server能為你自動引數化sql語句:

(@1 numeric(3,2))select * from [orders] where [price]=@1

但什麼是選擇的作為引數的資料型別?最小可能的那個!在這裡是numeric(3,2)!如果現在你執行下列2個查詢:

1

--execute a slightly different query

2select

*from

orders

3where price =

8.704go

56--execute a slightly different query

7select

*from

orders

8where price =

124.50

9go

sql server能重用為第1個使用8.7值sql語句的引數化sql語句的執行計畫。但用124.50值的第2個sql語句呢?對於這個sql語句快取的計畫不能被重用,因為124.50值不符合numeric(3,2)。在這個情況下,sql server用numeric(5,2)資料型別生成你sql語句的新引數化版本。你剛用你的sql語句的額外的引數化版本汙染了你的計畫快取!當你執行下列語句會變得更糟:

--

execute a slightly different query

select

*from

orders

where price =

1204.50

go

這個會再次給你新的用numeric(6,2)資料型別的新引數化版本——計畫快取裡另乙個版本!當我展示這個行為的時候,很多人都建議我應該用逆序來執行剛才的sql語句。我們通過首先清空計畫快取來試下。

1

--clear the plan cache

2dbcc

freeproccache3go

45--execute a slightly different query

6select

*from

orders

7where price =

1204.508go

910--execute a slightly different query

11select

*from

orders

12where price =

124.50

13go

1415

--execute a slightly different query

16select

*from

orders

17where price =

8.70

18go

然後當你看計畫快取時,沒有任何改變:sql server還生成了3個不同的引數化sql語句——每次都用最小可能的資料型別。

你怎麼做沒有一點關係,即你執行你sql語句的順序:在自動引數化期間,sql server總會選擇最小可能的資料型別。當你依賴sql server這個特性時,好好考慮下。

varchar如何呢?sql server自動引數化包含字元值(例如varchar)的sql語句時,事情會好點。假設有下列表定義和下列2個查詢:

1

--create another table to demonstrate this problem

2create

table

orders33(

4 col1 int

identity(1, 1) primary

keynot

null

,5 col2 varchar(100)6

)7go8

9--clears the plan cache

10dbcc

freeproccache

11go

1213

--a varchar/char column is always auto parametrized to a varchar(8000)

14select

*from

orders3

15where col2 =

'woody'16

go17

18--

a varchar column is always auto parametrized to a varchar(8000)

19select

*from

orders3

20where col2 ='tu

'21go

在這個情況下,sql server用varchar(8000)生成1個自動引數化sql語句——最大可能的資料型別。從剛才例子裡,這是你所期待的行為。有時sql server好事壞事同時做……

當你和簡單sql語句打交道時,自動引數化可以非常棒。但如你在這個文章裡所見,你要知道sql server引入的***。另外sql server的簡單引數化特性還會提供你強制引數化(forced parameterization)功能,這個我會在以後的文章裡介紹。

感謝關注!

SQL Server裡簡單引數化的痛苦

在今天的文章裡,我想談下對於即席sql語句 ad hoc sql statements sql server使用的簡單引數化 parameterization 的一些特性和 首先,如果你的sql語句包含這些,簡單引數化不會發生 一般來說,如果你處理所謂的安全執行計畫 safe execution p...

Sql Server 的引數化查詢

為什麼要使用引數化查詢呢?引數化查詢寫起來看起來都麻煩,還不如用拼接sql語句來的方便快捷。當然,拼接sql語句執行查詢雖然看起來方便簡潔,其實不然。遠沒有引數化查詢來的安全和快捷。今天剛好了解了一下關於sql server 引數化查詢和拼接sql語句來執行查詢的一點區別。引數化查詢與拼接sql語句...

簡單介紹SQL Server裡的閂鎖

在今天的文章裡我想談下sql server使用的更高階的,輕量級的同步物件 閂鎖 latch 閂鎖是sql server儲存引擎使用輕量級同步物件,用來保護多執行緒訪問記憶體內結構。文章的第1部分我會介紹sql server裡為什麼需要閂鎖,在第2部分我會給你介紹各個閂鎖型別,還有你如何能對它們進行...