如何减轻查询跨数据库视图的存储过程中的锁定

时间:2012-02-22 02:55:00

标签: sql-server sql-server-2005 stored-procedures locking

我有一个在链接服务器上加入SQL Server表的视图。链接服务器存在某些限制,这意味着我无法在视图上创建索引,并且存在昨晚锁定数据库的存储过程,即使它只执行选择。存储过程由.NetTiers生成(我已从两个select语句中删除了十几列):

CREATE PROCEDURE [AbnormalReadingSource_Get]
(
    @WhereClause varchar (2000)  ,
    @OrderBy varchar (2000)  ,
    @PageIndex int   ,
    @PageSize int   
)
AS
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
BEGIN
    DECLARE @PageLowerBound int
    DECLARE @PageUpperBound int

    -- Set the page bounds
    SET @PageLowerBound = @PageSize * @PageIndex
    SET @PageUpperBound = @PageLowerBound + @PageSize

    IF (@OrderBy is null or LEN(@OrderBy) < 1)
    BEGIN
        -- default order by to first column
        SET @OrderBy = '[Result]'
    END

    -- SQL Server 2005 Paging
    declare @SQL as nvarchar(4000)
    SET @SQL = 'WITH PageIndex AS ('
    SET @SQL = @SQL + ' SELECT'
    IF @PageSize > 0
    BEGIN
        SET @SQL = @SQL + ' TOP ' + convert(nvarchar, @PageUpperBound)
    END
    SET @SQL = @SQL + ' ROW_NUMBER() OVER (ORDER BY ' + @OrderBy + ') as RowIndex'
    SET @SQL = @SQL + ', [Result]'
    SET @SQL = @SQL + ' FROM [AbnormalReadingSource]'
    IF LEN(@WhereClause) > 0
    BEGIN
        SET @SQL = @SQL + ' WHERE ' + @WhereClause
    END
    SET @SQL = @SQL + ' ) SELECT'
    SET @SQL = @SQL + ' [Result],'
    SET @SQL = @SQL + ' FROM PageIndex'
    SET @SQL = @SQL + ' WHERE RowIndex > ' + convert(nvarchar, @PageLowerBound)
    IF @PageSize > 0
    BEGIN
        SET @SQL = @SQL + ' AND RowIndex <= ' + convert(nvarchar, @PageUpperBound)
    END
    exec sp_executesql @SQL

    -- get row count
    SET @SQL = 'SELECT COUNT(*) as TotalRowCount'
    SET @SQL = @SQL + ' FROM [AbnormalReadingSource]'
    IF LEN(@WhereClause) > 0
    BEGIN
        SET @SQL = @SQL + ' WHERE ' + @WhereClause
    END
    exec sp_executesql @SQL

END

数据库事务隔离级别为READ COMMITTED,因此不必在存储过程中设置隔离级别,而是在用于生成存储过程的.NetTiers模板中。我可以使用 readpast 提示来避免发生锁定吗?使用 readpast 时,是否需要提供任何其他提示?

3 个答案:

答案 0 :(得分:2)

您可以尝试使用READPAST,但请记住它不会允许“脏”读取,因此如果某些内容暂时被锁定,您的结果集可能会遗漏某些记录。

同样,您可以尝试使用以下选择语句:WITH(NOLOCK)

NOLOCK将读取“脏”数据,但之后您将面临被回滚的风险。

两者都会避免阻塞,两者都有其优点和缺点。

本文应有助于澄清:
http://www.techrepublic.com/article/using-nolock-and-readpast-table-hints-in-sql-server/6185492

答案 1 :(得分:2)

与此查询一起运行 SQL事件探查器,然后将其提供给数据库引擎优化顾问。如果您可以解决此问题或改进索引,请不要更改隔离级别。

您可以在链接服务器上创建视图,但这些链接服务器必须都是SQL Server ,并且索引视图中不允许跨数据库查询。

也许这个程序不应该通过视图运行。

http://msdn.microsoft.com/en-us/library/ms191432.aspx

很棒的锁定文章

http://support.microsoft.com/kb/75722 http://support.microsoft.com/kb/323630

不要在存储过程中使用单词sp,那些为系统存储过程保留会导致较小的开销。

游标很糟糕,但更好的索引是主要的解决方案,当然Tuning Advisor会自动为您编写脚本,这意味着您需要完全绕过视图来利用。

创建有关此流程的故障警报,以便您和您的联合经理在您通过SSIS SMTP任务离开办公室时知道此任务是否失败。

“要从其他服务器重复获取数据,创建链接服务器,然后使用OPENQUERY函数或使用4部分命名。如果您不遵守T-SQL,那么最好使用导入/导出向导,并且您可以将其保存为SSIS包以供将来使用。“ - SQL Server MVP Pinal Dave

关于锁定和潜在的死锁

您可以用来解决死锁的典型方法包括:

  • 添加和删除索引。
  • 添加索引提示。
  • 修改应用程序以类似模式访问资源。
  • 从触发器等事务中删除活动。
  • 保持交易尽可能短。

    在SQL Server中,您还可以使用以下任一方法最小化锁定争用,同时保护事务免受未提交数据修改的脏读:

    • READ COMMITTED隔离级别,READ_COMMITTED_SNAPSHOT数据库选项设置为ON。
    • SNAPSHOT隔离级别。

加载SQL事件探查器,重点关注锁定,启动专门针对该数据库的死锁脚本并将其提供给数据库引擎优化顾问,并查看建议。

<强>脚注http://support.microsoft.com/kb/832524

[[1]:http://support.microsoft.com/kb/832524

http://www.codeproject.com/Articles/42547/SQL-SERVER-How-To-Handle-Deadlock

之前的Stackoverflow锁定问题how to solve deadlock problem?

答案 2 :(得分:1)

为什么不把TRANSACTION ISOLATION LEVEL设置为READ UNCOMMITTED,你几乎可以得到与使用READPAST或NOLOCK相同的结果

我知道你说过程是由.NetTiers生成的,但既然你说你可以添加一个查询提示(readpast),我假设你也可以改变隔离级别。