SELECT * FROM AdventureWorks.Sales.SalesOrderHeader WHERE SalesOrderID = 56000; GO |
如果你使用下面的SELECT語句來查看一個只包含用于上面語句的緩存計(jì)劃的、干凈的緩沖池,那么你會看到查詢優(yōu)化器將T-SQL查詢重寫為一個參數(shù)化T-SQL語句:
SELECT stats.execution_count AS cnt, p.size_in_bytes AS [size], [sql].[text] AS [plan_text] FROM sys.dm_exec_cached_plans p OUTER APPLY sys.dm_exec_sql_text (p.plan_handle) sql JOIN sys.dm_exec_query_stats stats ON stats.plan_handle = p.plan_handle; GO |
cnt size plan_text
--- ------- --------------------------------------------------------------
1 49152 (@1 int)SELECT * FROM [AdventureWorks].[Sales].[SalesOrderHeader]
WHERE [SalesOrderID]=@1
如果你看看上面輸出中的plan_text字段,你會看到它不像原來的T-SQL文本。如前所述,查詢優(yōu)化器將這個查詢重新編寫為一個參數(shù)化T-SQL語句。在這里,你可以看到它現(xiàn)在有一個數(shù)據(jù)類型為(int)的變量(@1),它在之前的SELECT語句中被定義的。另外在plan_text的末尾, 值“56000”被替換為變量@1。既然這個T-SQL語句被重寫了,而且被存儲為一個緩存計(jì)劃,那么如果未來一個T-SQL命令和它大致相同,只有SalesOrderID字段被賦的值不同的話,它就可以被用于重用。讓我們在動作中看看它。
如果我在我的機(jī)器上運(yùn)行下面的命令:DBCC FREEPROCCACHE; GO SELECT * FROM AdventureWorks.Sales.SalesOrderHeader WHERE SalesOrderID = 56000; GO SELECT * FROM AdventureWorks.Sales.SalesOrderHeader WHERE SalesOrderID = 56001; GO SELECT stats.execution_count AS cnt, p.size_in_bytes AS [size], [sql].[text] AS [plan_text] FROM sys.dm_exec_cached_plans p OUTER APPLY sys.dm_exec_sql_text (p.plan_handle) sql JOIN sys.dm_exec_query_stats stats ON stats.plan_handle = p.plan_handle; GO 我從最后的SELECT語句得到下面的輸出,(注意,輸出被重新格式化以便它更易讀): cnt size plan_text --- -------- -------------------------------------------------------------- 2 49152 (@1 int)SELECT * FROM AdventureWorks].[Sales].[SalesOrderHeader] WHERE [SalesOrderID]=@1 |
數(shù)據(jù)庫配置選項(xiàng)PARAMETERIZATION可以影響T-SQL語句怎樣被自動地參數(shù)化。對于這個選項(xiàng)有兩種不同的設(shè)置,SIMPLE和FORCED。當(dāng)PARAMETERIZATION設(shè)置被設(shè)置為SIMPLE時,只有簡單的T-SQL語句才會被參數(shù)化。要介紹這個,看下下面的命令:
SELECT SUM(LineTotal) AS LineTotal FROM AdventureWorks.Sales.SalesOrderHeader H JOIN AdventureWorks.Sales.SalesOrderDetail D ON D.SalesOrderID = H.SalesOrderID WHERE H.SalesOrderID = 56000 |
當(dāng)你設(shè)置數(shù)據(jù)庫選項(xiàng)為使用FORCE PARAMETERIZATION時,查詢優(yōu)化器試圖參數(shù)化所有的查詢,而不僅僅是簡單的查詢。你可能會認(rèn)為這很好。但是在某些情況下,當(dāng)數(shù)據(jù)庫設(shè)置PARAMETERIZATION為FORCED時,查詢優(yōu)化器將選擇不是很理想的查詢計(jì)劃。當(dāng)數(shù)據(jù)庫設(shè)置PARAMETER為FORCED時,它改變查詢中的字面常量。這可能導(dǎo)致當(dāng)查詢中涉及計(jì)算字段時索引和索引視圖不被選中參與到執(zhí)行計(jì)劃中,從而導(dǎo)致一個無效的計(jì)劃。FORCED PARAMETERIZATION選項(xiàng)可能是改進(jìn)具有大量類似的、傳遞過來的參數(shù)稍有不同的查詢的數(shù)據(jù)庫性能的一個很好的解決方案。一個在線銷售應(yīng)用程序,它的客戶對你的產(chǎn)品執(zhí)行大量的類似搜索, 產(chǎn)品值不同,這可能是一個能夠受益于FORCED PARAMETERIZATION的很好的應(yīng)用程序類型。
不是所有的查詢從句都會被參數(shù)化。例如查詢的TOP、TABLESAMPLE、 HAVING、GROUP BY、ORDER BY、OUTPUT...INTO或FOR XML從句不會被參數(shù)化。使用sp_execute_sql來參數(shù)化你的T-SQL
你不需要依賴于數(shù)據(jù)庫的PARAMETERIZATION選項(xiàng)來使得查詢優(yōu)化器參數(shù)化一個查詢。你可以參數(shù)化你自己的查詢。你通過重新編寫你的T-SQL語句并使用“sp_executesql”系統(tǒng)存儲過程執(zhí)行重寫的語句來實(shí)現(xiàn)。正如已經(jīng)看到的,上面包括一個“JOIN”從句的SELECT語句在數(shù)據(jù)庫的PARAMETERIZATION設(shè)置為SIMPLE時沒有被自動參數(shù)化。讓我重新編寫這個查詢以便查詢優(yōu)化器將創(chuàng)建一個可重用的參數(shù)化查詢執(zhí)行計(jì)劃。
為了說明,讓我們看兩個類似的、不會被自動參數(shù)化的T-SQL語句,并創(chuàng)建兩個不同的緩存執(zhí)行計(jì)劃。然后我將重新編寫這兩個查詢使得它們都使用相同的緩存參數(shù)化執(zhí)行計(jì)劃。
讓我們看看這個代碼:
DBCC FREEPROCCACHE GO SELECT SUM(LineTotal) AS LineTotal FROM AdventureWorks.Sales.SalesOrderHeader H JOIN AdventureWorks.Sales.SalesOrderDetail D ON D.SalesOrderID = H.SalesOrderID WHERE H.SalesOrderID = 56000 GO SELECT SUM(LineTotal) AS LineTotal FROM AdventureWorks.Sales.SalesOrderHeader H JOIN AdventureWorks.Sales.SalesOrderDetail D ON D.SalesOrderID = H.SalesOrderID WHERE H.SalesOrderID = 56001 GO SELECT stats.execution_count AS cnt, p.size_in_bytes AS [size], LEFT([sql].[text], 200) AS [plan_text] FROM sys.dm_exec_cached_plans p OUTER APPLY sys.dm_exec_sql_text (p.plan_handle) sql JOIN sys.dm_exec_query_stats stats ON stats.plan_handle = p.plan_handle; GO |
cnt size plan_text --- ----------- ------------------------------------------------------------------------------- 1 49152 SELECT SUM(LineTotal) AS LineTotal FROM AdventureWorks.Sales.SalesOrderHeader H JOIN AdventureWorks.Sales.SalesOrderDetail D ON D.SalesOrderID = H.SalesOrderID WHERE H.SalesOrderID = 56001 1 49152 SELECT SUM(LineTotal) AS LineTotal FROM AdventureWorks.Sales.SalesOrderHeader H JOIN AdventureWorks.Sales.SalesOrderDetail D ON D.SalesOrderID = H.SalesOrderID WHERE H.SalesOrderID = 56000 |
DBCC FREEPROCCACHE; GO EXEC sp_executesql N'SELECT SUM(LineTotal) AS LineTotal FROM AdventureWorks.Sales.SalesOrderHeader H JOIN AdventureWorks.Sales.SalesOrderDetail D ON D.SalesOrderID = H.SalesOrderID WHERE H.SalesOrderID = @SalesOrderID', N'@SalesOrderID INT', @SalesOrderID = 56000; GO EXEC sp_executesql N'SELECT SUM(LineTotal) AS LineTotal FROM AdventureWorks.Sales.SalesOrderHeader H JOIN AdventureWorks.Sales.SalesOrderDetail D ON D.SalesOrderID = H.SalesOrderID WHERE H.SalesOrderID = @SalesOrderID', N'@SalesOrderID INT', @SalesOrderID = 56001; GO SELECT stats.execution_count AS exec_count, p.size_in_bytes AS [size], [sql].[text] AS [plan_text] FROM sys.dm_exec_cached_plans p OUTER APPLY sys.dm_exec_sql_text (p.plan_handle) sql JOIN sys.dm_exec_query_stats stats ON stats.plan_handle = p.plan_handle; GO |
現(xiàn)在當(dāng)我運(yùn)行上面的代碼時,我從DMV SELECT語句得到下面的輸出(注意,輸出被重新格式化了,以便它更易讀):
cnt size plan_text --- ----------- ----------------------------------------------------------------------------------------- 2 49152 (@SalesOrderID INT)SELECT SUM(LineTotal) AS LineTotal FROM AdventureWorks.Sales.SalesOrderHeader H JOIN AdventureWorks.Sales.SalesOrderDetail D ON D.SalesOrderID = H.SalesOrderID WHERE H.SalesOrderID = @SalesOrderID |
使用參數(shù)化查詢來節(jié)省資源和優(yōu)化性能
在語句可以被執(zhí)行之前,每個T-SQL語句都需要被評估,而且需要建立一個執(zhí)行計(jì)劃。創(chuàng)建執(zhí)行計(jì)劃會占用寶貴的CPU資源。當(dāng)執(zhí)行計(jì)劃被創(chuàng)建后,它使用內(nèi)存空間將它存儲在過程緩存中。降低CPU和內(nèi)存使用的一個方法是利用參數(shù)化查詢。盡管數(shù)據(jù)庫可以被設(shè)置為對所有查詢FORCE參數(shù)化,但是這不總是最好的選擇。通過了解你的哪些T-SQL語句可以被參數(shù)化然后使用sp_executesql存儲過程,你可以幫助SQL Server節(jié)省資源并優(yōu)化你的查詢的性能。
標(biāo)簽:晉城 延邊 嘉興 澳門 合肥 日照 保定 三明
巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《SQLServer 參數(shù)化查詢經(jīng)驗(yàn)分享》,本文關(guān)鍵詞 SQLServer,參數(shù),化,查詢,經(jīng)驗(yàn),;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請?zhí)峁┫嚓P(guān)信息告之我們,我們將及時溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。