此博客介绍了简单但有用的提示和优化,以提高存储过程的性能。
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采取的共享锁。
请遵循这些提示,让我知道它如何提高程序性能。将返回一些更多提示和最佳实践。