此博客介紹了簡單但有用的提示和優化,以提高存儲過程的性能。
0.with recompile:重編譯
exec uspGetSalesInfoForDateRange ‘1/1/2009’, 31/12/2009 with recompile
1.使用SET NOCOUNT ON
SQL Server在運行select或DML操作時返回信息性消息。如果一個過程有許多這樣的語句,游標或while循環SQL Server將顯示許多此類消息,增加網絡流量。可以使用SET NOCOUNT ON來抑制這些消息,並可以通過減少網絡流量來提高性能。
2.使用完全限定的程序名稱
完全限定的對象名稱是database.schema.objectname。當存儲過程作為schemaname.procedurename調用時,SQL Server可以快速查找已編譯的計划,而不是在未指定schemaname時查找其他模式中的過程。這可能不會對性能產生很大的推動作用,但應該遵循最佳實踐。過程中的所有對象也應該稱為schemaname.objectname。
3. sp_executesql而不是Execute用於動態查詢
sp_executesql允許重用緩存計划並防止SQL注入。我們來看一個計划重用的例子。
1
2
3
4
5
6
7
8
9
10
|
DBCC FREEPROCCACHE
GO
Declare
@dynamic_sql varchar(max),
@salesorderid int
SET @salesorderid=43660
SET @dynamic_sql=' SELECT * FROM Sales.SalesOrderDetail where SalesOrderID='
+ CAST(@salesorderid AS VARCHAR(100))
EXECUTE(@dynamic_sql)
|
上面的查詢使用EXECUTE命令為salesorderid 43660和43661的兩個值執行動態查詢。讓我們分析緩存的計划。
如上面的快照所示,兩個salesorderids有兩個單獨的計划。現在讓我們使用sp_execute SQL執行相同的查詢並分析緩存的計划。
1
2
3
|
DECLARE @dynamic_sql NVARCHAR(100)
SET @dynamic_sql = N'SELECT * FROM Sales.SalesOrderDetail where SalesOrderID=@salesorderid'
EXECUTE sp_executesql @dynamic_sql, N'@salesorderid int', @salesorderid = 43661
|
上面的查詢使用sp_executesql為2個不同的salesorderid值執行動態查詢。我們來分析一下緩存的計划。
如上面的快照所示,只緩存了一個計划,並用於salesorderid的不同值。
4.使用IF EXISTS AND SELECT
IF EXISTS用於檢查記錄,對象等的存在。並且是一個方便的語句,用於提高查詢的性能,其中一個只想檢查表中記錄的存在而不是在查詢中使用該記錄/行。這樣做的時候使用IF EXISTS(來自mytable的SELECT 1)而不是IF EXISTS(從mytable中選擇*),因為我們感興趣的只是檢查記錄/ s的存在。因此,如果查詢返回1,則記錄存在,否則不存在。無需返回所有列值。
5.避免將用戶存儲過程命名為sp_procedurename。
如果存儲過程以sp_開頭,則SQL Server首先在master數據庫中搜索它,然后在當前用戶數據庫中搜索它。這可能會導致輕微的性能問題,而且如果master數據庫中存在具有相同名稱的存儲過程,則可能導致錯誤的結果。
6.盡可能使用基於集合的查詢。
T-SQL是一種基於集合的語言,因此循環在這里不能很好地工作。僅當基於集合的查詢要么昂貴或無法制定時,才使用游標和while循環。
7.保持交易簡短明快
事務越長,根據隔離級別保持鎖定的時間越長。這可能會導致死鎖和阻塞。打開一個新的查詢窗口並執行以下查詢
1
2
3
4
5
6
|
use AdventureWorks2014
GO
BEGIN TRANSACTION
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
SELECT * FROM Sales.SalesOrderDetail
|
請注意查詢的會話ID。打開一個新的查詢窗口並執行以下查詢。記下查詢的會話ID。
1
2
3
|
begin tran
Update Sales.SalesOrderDetail
SET OrderQty=50 WHERE SalesOrderDetailID=1
|
以上更新查詢將等待共享鎖上的選擇查詢。讓我們分析這兩個會話的鎖。
如上面的快照所示,會話58更新查詢正在等待會話57采取的共享鎖。
請遵循這些提示,讓我知道它如何提高程序性能。將返回一些更多提示和最佳實踐。