1. 程式人生 > >MSSQL優化(TUNING&OPTMIZATION&優化)之——計劃重用(plan reusing)

MSSQL優化(TUNING&OPTMIZATION&優化)之——計劃重用(plan reusing)

原來 har 完整 char 即使 name 超過 query tom

Oracle中,為了減少系統內的硬解析,從而節省系統資源,有綁定變量、計劃共享(通過cursor_sharing參數)等一系列措施。那麽,SQL Server作為三大商業關系庫之一,是否也存在這樣的機制呢?答案是肯定的,下面,我們就一起來看看SQL Server系統中的類似機制。

SQL Server主要通過如下四個機制來緩沖之前執行過的查詢的執行計劃,以避免這些查詢的再次編譯,從而節省系統資源。

1)臨時查詢緩沖(Ad hoc query caching);

2)自動參數化(parameterize automatically);

3)準備查詢(prepared queries);

4)編譯對象(compiled objects);

下面,分別對SQL Server著四個機制介紹如下:

1)臨時查詢緩沖

SQL Server2005以前,臨時計劃偶爾也會被緩沖,但是我們不能指望這個特性發揮太多效果。即使後續版本中,當SQL Server緩沖臨時計劃時,被緩沖的這些計劃也只有在隨後的批處理文本和這些計劃的文本完全匹配時,才能被重用。我們可以通過如下SQL語句來查詢被緩沖的臨時查詢計劃的被重用情況:

SELECT usecounts, cacheobjtype, objtype, [text]
FROM sys.dm_exec_cached_plans P
CROSS APPLY sys.dm_exec_sql_text (plan_handle)

WHERE cacheobjtype = ‘Compiled Plan‘
AND [text] NOT LIKE ‘%dm_exec_cached_plans%‘;

為了改善被緩沖的臨時查詢計劃重用狀況不佳的問題,SQL Server提供了一種特性,稱之為臨時負載優化選項(Optimize for Ad Hoc Workloads option),我們可以通過如下方式開啟它:

EXEC sp_configure ‘optimize for ad hoc workloads‘, 1;
RECONFIGURE;

GO

你也可以通過SQL Server management studio中服務器屬性的高級頁面開啟這個特性。該特性被打開後,相同的臨時查詢第一次被編譯時,會在計劃緩沖中產生該語句的編譯計劃根(compiled plan stub),該計劃根所占內存空間不會超過300個字節,包含指向該查詢文本的指針。當該查詢再次被編譯時,被緩沖的計劃根會被編譯計劃代替,而該編譯計劃比原來的計劃根要大很多,要占用兩個頁大小的內存空間。

可以通過如下查詢獲取該特性開啟後,被緩沖的編譯計劃根和編譯計劃的信息:

SELECT usecounts, cacheobjtype, objtype, size_in_bytes, [text]
FROM sys.dm_exec_cached_plans P
CROSS APPLY sys.dm_exec_sql_text (plan_handle)
WHERE cacheobjtype LIKE ‘Compiled Plan%‘
AND [text] NOT LIKE ‘%dm_exec_cached_plans%‘;

該特性開啟後,還可以通過如下命令關閉:

EXEC sp_configure ‘optimize for ad hoc workloads‘, 0;
RECONFIGURE;
GO

也可以通過SQL Server management studio中服務器屬性的高級頁面關閉該特性。

2)自動參數化

說到參數化,SQL Server又將其分為簡單參數化(Simple parameterization)和強制參數化(Forced parameterization)兩種情形。這有點類似Oracle中的cursor_sharing參數的使用。下面,我們就先說說簡單參數化,簡單參數化也是SQL Server的默認設置和行為。有時,SQL Server會地自動將查詢中的常數參數化,隨後的查詢如果和參數化後的查詢語句一樣,將會重用之前參數化查詢的緩沖的執行計劃。同樣,我們也可以通過如下語句對參數化的行為進行查詢和分析:

SELECT usecounts, cacheobjtype, objtype, size_in_bytes, [text]
FROM sys.dm_exec_cached_plans P
CROSS APPLY sys.dm_exec_sql_text (plan_handle)
WHERE cacheobjtype = ‘Compiled Plan‘
AND [text] NOT LIKE ‘%dm_exec_cached_plans%‘;
GO

結果中,針對每個帶常數的查詢,會產生一個被緩沖的編譯計劃,這些臨時查詢作為殼查詢(shell query)的編譯計劃被緩沖,目的就是為了後續相同常數查詢發現查詢的參數化版本更容易些,這些常數查詢被緩沖的編譯計劃占用內存空間較小,大概為兩個頁大小,也並不包含完全的編譯計劃。而針對所有這些常數查詢,系統也會生成一個參數化的查詢,該查詢稱為準備查詢(prepared query),這個準備查詢的編譯計劃才是完整的編譯計劃,因此,占用內存空間也會更大些,大概為四個頁大小。

說完了簡單參數化,下面,我們說說強制參數化。

有時,你的應用用了很多類似的語句,而且,你認為可能會從編譯計劃重用中獲益,但遺憾的是,系統並不能將這些類似的語句參數化。此時,SQL Server提供了一個數據庫選項,那就是PARAMETERIZATION FORCED,可通過如下命令對該選項進行設置:

ALTER DATABASE <database_name> SET PARAMETERIZATION FORCED;

設置該選項後,SQL Server就會將相關查詢中常數參數化,但也會有些例外,具體可查詢微軟官方或其他文檔。值得註意的是,這種為了重用緩沖編譯計劃,將查詢中常數一概參數化的做法,有時也可能會帶來嚴重的性能問題,因此,實際應用時,一定要具體問題具體分析。

3)準備查詢

如上所述,SQL Server參數化的查詢可以在計劃緩沖區中生成準備查詢類型的編譯計劃。此外,另外兩種方法也可以生成準備查詢類型的編譯計劃。但是,他們和SQL Server參數化的查詢不同,這兩種方法中用戶可以自己決定參數的數據類型。其一是通過T-SQL批處理調用sp_executesql內置過程;其二是通過客戶端應用使用準備和執行方法。這兩種方法,有點類似Oracle中的綁定變量使用。

sp_executesql過程:使用該過程要求用戶確定參數和它們的數據類型,具體語法如下所示:

sp_executesql @batch_text, @batch_parameter_definitions,param1,...paramN

只要通過相同@batch_test和@batch_parameter_definitions參數值調用該過程,就會重用緩沖中的統一編譯計劃。例如:

EXEC sp_executesql N‘SELECT c2, c3, c4 FROM test.t1 WHERE c1 = @p‘, N‘@p int‘, 1;

EXEC sp_executesql N‘SELECT c2, c3, c4 FROM test.t1 WHERE c1 = @p‘, N‘@p int‘, 2;

EXEC sp_executesql N‘SELECT c2, c3, c4 FROM test.t1 WHERE c1 = @p‘, N‘@p int‘, 3;

準備和執行方法:該方法和sp_executesql過程類似,但不盡相同。該方法並不需要運行時每次都要傳送全部批命令文本,而是,只要在準備階段傳送一次即可,然後,返回的句柄可供每次運行批命令時使用。然而,該方法會在計劃緩存區生成準備查詢的編譯計劃,但並不會生成類似自動參數化中相應的臨時殼查詢計劃。同樣,我們可以通過如下查詢獲取編譯計劃相關信息:

SELECT usecounts, cacheobjtype, objtype, size_in_bytes, [text]
FROM sys.dm_exec_cached_plans P
CROSS APPLY sys.dm_exec_sql_text (plan_handle)
WHERE cacheobjtype = ‘Compiled Plan‘
AND [text] NOT LIKE ‘%dm_exec_cached_plans%‘;
GO

4)編譯對象

計劃緩存區中,除了包含之前講到的臨時查詢編譯計劃和準備查詢的編譯計劃,還包含第三種編譯計劃,那就是過程類型(PROC),該類型計劃主要由存儲過程、用戶定義的標量函數和多語句表值函數等,用戶可以完全控制這些對象參數的值和類型。這些對象的成功執行,都會重用計劃緩存的之前運行的相同對象的編譯計劃。然而,用戶也可以通過選項或重建,來強制這類對象生成新的編譯計劃,例如:

--存儲過程

EXEC P_Test ‘EM‘;
GO
EXEC P_Test ‘IN‘;
GO
EXEC P_Test ‘IN‘ WITH RECOMPILE;

--函數

DECLARE @p1 char(11);
EXEC @p1= test. f_test ‘123456789‘;
SELECT @p1;
GO
DECLARE @p1 char(11);
EXEC @p1 = test. f_test ‘987654321‘;
SELECT @p1;
GO
DECLARE @p1(11);
EXEC @p1 = test.f_test ‘987612345‘ WITH RECOMPILE;

同樣,我們可以通過如下查詢語句獲取編譯計劃相關信息:

SELECT usecounts, cacheobjtype, objtype, size_in_bytes, [text]
FROM sys.dm_exec_cached_plans P
CROSS APPLY sys.dm_exec_sql_text (plan_handle)
WHERE cacheobjtype = ‘Compiled Plan‘
AND [text] NOT LIKE ‘%dm_exec_cached_plans%‘;
GO

MSSQL優化(TUNING&amp;OPTMIZATION&amp;優化)之——計劃重用(plan reusing)