SQL Server存储过程会降低查询速度

时间:2014-07-30 20:10:53

标签: asp.net-mvc sql-server-2008 asp.net-mvc-4 stored-procedures transactions

2014年8月19日 - 这个问题仍然存在。现在看来,即使我没有运行存储过程,也会发生这种情况。我还没有足够的经验知道什么样的事情会导致SQL服务器像这样减速。


我有一个对我来说很奇怪的问题。两件似乎无关的事情现在两次相关。

首先,我在 SQL Server 2008 Express R2 中有一个存储过程,它包含在一个事务中(下面的代码)。在交易中,

  • 将某个日期之前的记录从日志表复制到日志存档表中。
  • 然后从日志表中删除记录。

数据库位于专用托管服务器上。

其次,我有一个网站页面,通过 AJAX 加载三个 HTML 表。后面的代码是从日志表所在的同一数据库中读取,但没有任何数据库表重叠。查询通过 LINQ-to-Entities 使用 实体框架 执行.6。它们有些复杂,但是在正常情况下,一旦 AJAX 呼叫启动,每个HTML表格加载时间不到5秒。该网站位于共享托管服务器上。

网站上的其他任何信息都不会缓慢。只有这2个。

出于某种原因,在我执行存储过程后,网页上的 AJAX 查询运行的时间太长,以至于超时并且没有数据加载。我不得不打开超时窗口180秒,以便他们甚至有机会在超时之前加载。

我能够将查询带回"正常"的唯一方法速度是停止 SQL Server服务 ,然后再次启动它。之后,网页加载速度很快。

我担心的是,我创建的存储过程导致某些内容在 SQL Server 或内存问题或某些内容中挂起。

这是存储过程:

USE [Main]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:      Jason Watts
-- Create date: 7/30/2014
-- Description: Archives every record in ErrorLogs 
--              older than 2 months into the 
--              ErroLogsArchive table.
-- =============================================
ALTER PROCEDURE [dbo].[ArchiveErrorLogs] 
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    -- Init variables and error code
    Declare @TransactionCountOnEntry int;
    Declare @ErrorCode int;
    Select @ErrorCode = @@Error;

    -- Begin transaction processing for rollback option
    If @ErrorCode = 0
    Begin
       Select @TransactionCountOnEntry = @@TranCount;
       BEGIN TRANSACTION;
    End

    -- Get the current date/time
    Declare @ArchiveDT datetime;
    SELECT @ArchiveDT = DATEADD(m, -2, GETDATE());

    -- Copy the records from ErrorLogs to ErrorLogsArchive
    If @ErrorCode = 0
    Begin
        INSERT INTO ErrorLogsArchive (Area,Library,Method,ErrorLevel,[Message],Stacktrace,LogDate)
        SELECT Area,Library,Method,ErrorLevel,[Message],Stacktrace,LogDate
        FROM ErrorLogs
        WHERE LogDate <= @ArchiveDT;

        Select @ErrorCode = @@ERROR;
    End

    -- Delete the records from ErrorLogs
    If @ErrorCode = 0
    Begin
        DELETE FROM ErrorLogs
        WHERE LogDate <= @ArchiveDT;

        Select @ErrorCode = @@ERROR;
    End

    -- End the transaction
    If @@TranCount > @TransactionCountOnEntry
    Begin
       If @ErrorCode = 0
          COMMIT TRANSACTION;
       Else
          ROLLBACK TRANSACTION;
    End

    -- Return
    Return @ErrorCode;
END

在我今天早上运行程序之前,原始日志表有150万条记录。我第一次走的是3个月以上,成功移动了700,000条记录。虽然跑了大概5分半钟。然后我将它降低到2个月,并在大约1.5分钟内再移动了200,000条记录。

每次运行后,网页表加载速度变慢,然后在重新启动SQL Server服务后恢复正常。我不明白可能导致减速的原因。如果它没有发生过两次,我就不会认为它们是相关的。

更新

正如我上面提到的,相同的2个查询现在运行缓慢,我还没有执行归档功能。我觉得这里有一些简单的问题,我只是不知道它可能是什么。

1 个答案:

答案 0 :(得分:3)

Ghost Cleanup 导致您的性能下降。

阅读 Ghost cleanup in depth

简而言之,删除操作不会删除/删除行。 “删除”行被标记为删除,然后(逐渐地),“存储器”一次被重新分配1-10页。这是SQL Server的“优化”。


执行计划

由于 Execution Plan 读取)试图“抓住”已删除的行,这种过时的垃圾收集工作变得更加复杂。结果是有问题的群集F 类似于但不是退出死锁。

您可以使用 DBCC FREEPROCCACHE

删除执行计划

重影清理中的已知错误:

更糟糕的是,SQL Server无法正确处理数百万中的幻影记录存在一个已知错误

ghost_record_count values keep increasing in SQL Server 2008 R2 or in SQL Server 2008


重新启动SQL Server:

我怀疑,除了刷新所有执行计划外,新启动的 SQL Server 更重视立即“清理”鬼影。


跟进

来自SQLMag,When a Delete isn’t Really a Delete

  

那么删除的记录什么时候删除?删除记录的行为不会将该记录放在ghost清理任务的工作队列中。直到SQL Server存储引擎再次读取已删除记录所在的数据库页面,该页面才会排队等待删除明确的重影记录。   ghost清理任务将查看其要做的事情的队列,如果它是空的,它将处理实例上的数据库的一部分以查看数据库是否具有要删除的ghost记录。确保ghost记录使用的空间快速释放的唯一方法是执行诸如表扫描或索引重建之类的操作,以便存储引擎访问表中的所有页面并将ghost记录排队等待去除。

  • 似乎受影响的表与日志表位于同一“页面”。

  • 我从中收集到,有选择权。表格扫描可能会有所帮助。