SQL Server表无法更新

时间:2017-09-05 19:07:11

标签: sql asp.net sql-server ssms

这只会让我发疯。我有一个小的SQL Server 2012表,其中包含以下列:

id  int (this is an IDENTITY column)
DateNewsletter  smalldatetime
SubjectNewsletter   varchar(100)
ContentHeader   varchar(MAX)
ContentNewsletter   varchar(MAX)
ContentFooter   varchar(MAX)
NewsletterSent  bit
DateSent    smalldatetime
ApprovalPending bit
PriorityHigh    bit

表格中有583行。

问题在于:

  1. 我可以SELECT *毫无问题
  2. 我可以INSERT INTO毫无问题
  3. 但是,当我运行以下查询时,一切都会爆炸:

    UPDATE tblElinesNewsletter
    SET NewsletterSent = 1,
        DateSent = GETDATE(),
        ApprovalPending = 0
    WHERE (NewsletterSent = 0)
    
  4. 每当我运行上面的代码时,我都会收到超时错误。如果我从ASP.NET页面或从SQL Server Management Studio运行它,则超时错误是相同的。

    此外,如果我从SSMS右键单击并选择“编辑前200行...”,它将显示网格并让我编辑。但是一旦我点击它并且它正在执行更新,它就会爆炸。

    我已经尝试了以下内容:

    1. 重建索引
    2. 创建一个具有相同架构的全新表并在那里传输数据
    3. 重新启动服务器
    4. 去家里的仓库,购买大罐子来修理办公室墙上的洞(从撞我的脑袋)
    5. 这不是一张大桌子。它只是存储电子邮件简报的HTML。

      它并不总是如此,并且仅在几个月前开始。在那之前它运作良好。

      现在,以上所有人都说,这里是踢球者:它不会一直这样做。有时它有效。值得注意的是,如果表格中有更长的时事通讯,那么如果时事通讯很短,它似乎就不起作用了。这些都是简单的简报,而不是太花哨,这里就是一个:http://unitedafa.org/news/elines/view/?id=104169

      这是从我上面讨论的数据库/表中提取的。

      此SQL Server安装位于具有6 GB RAM的Windows Server 2012盒子上,并且只运行一些没有那么多流量的网站。

      我正在注意的一件事是,当我尝试调试它时,是当我从ASP.NET网页执行SQL Server存储过程时,当它失败时,这似乎冻结了SQL Server和我无法在SSMS中运行相同的存储过程。但是,一旦我重新启动服务器,我就可以打开SSMS并执行存储过程。同样,虽然如果我从网页执行存储过程,它会再次“冻结”服务器并且我无法对该表运行任何更新查询。

      仅供参考,这是从页面调用的实际存储过程:

      SET ANSI_NULLS ON
      GO
      SET QUOTED_IDENTIFIER ON
      GO
      -- ======================================================
      -- Author:      Christopher Lee
      -- Create date: 16-Aug-2012
      -- Modify date: 16-Aug-2012
      -- Description: Mark all records as Sent.
      -- ======================================================
      
      ALTER PROCEDURE [dbo].[sProc_Elines_Send_MarkComplete]
      AS
         BEGIN TRANSACTION
      
          UPDATE tblElinesNewsletter
          SET NewsletterSent = 1,
              DateSent = GETDATE(),
              ApprovalPending = 0
          WHERE (NewsletterSent = 0)
      
          COMMIT
      

      此外,这是CREATE TABLE脚本:

      SET ANSI_NULLS ON
      GO
      SET QUOTED_IDENTIFIER ON
      GO
      SET ANSI_PADDING ON
      GO
      
      CREATE TABLE [dbo].[tblElinesNewsletter]
      (
          [id] [int] IDENTITY(100543,1) NOT NULL,
          [DateNewsletter] [smalldatetime] NOT NULL,
          [SubjectNewsletter] [varchar](100) NOT NULL,
          [ContentHeader] [varchar](max) NOT NULL,
          [ContentNewsletter] [varchar](max) NOT NULL,
          [ContentFooter] [varchar](max) NOT NULL,
          [NewsletterSent] [bit] NOT NULL,
          [DateSent] [smalldatetime] NULL,
          [ApprovalPending] [bit] NOT NULL,
          [PriorityHigh] [bit] NOT NULL,
      
           CONSTRAINT [PK_tblElinesNewsletter2] 
               PRIMARY KEY CLUSTERED ([id] ASC)
      ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
      GO
      
      SET ANSI_PADDING OFF
      GO
      
      ALTER TABLE [dbo].[tblElinesNewsletter] 
          ADD CONSTRAINT [DF_tblElinesNewsletter2_PriorityHigh] DEFAULT ((0)) FOR [PriorityHigh]
      GO
      

      知道我到底做错了什么吗?顺便说一句,我不是DBA,而是更熟悉ASP.NET Web代码等,而不仅仅是SQL语句。

      任何帮助或建议都将不胜感激!

      - 克里斯

      PS,这里有一些额外的信息:

      存储过程中的SQL Server查询执行计划:

      [SQL Server执行计划截图] [1]

      以下是其他一些信息:

      1. 有足够的硬盘空间。
      2. 没有其他并发流程。
      3. 存储过程实际上是在它之前以另外两个序列执行的。这是执行页面中的代码:

            Protected Sub btnSubmit_Click(sender As Object, e As EventArgs) Handles btnSubmit.Click
        
            Call WriteNewsletterFile()
        
            Call SendNewsletter()
        
            Call UpdateRecord()
        
        End Sub
        

        因此WriteNewsletterFile()和SendNewsletter()子例程工作正常。它在UpdateRecord子例程中爆炸。这是每个例程的代码:

           Sub WriteNewsletterFile()
        
            Dim NewsID As String = ""
        
            Dim Conn As SqlConnection
            Dim Cmd As SqlCommand
            Dim Rdr As SqlDataReader
            Conn = New SqlConnection(ConfigurationManager.ConnectionStrings("UnitedAFAConnectionStringNSS").ConnectionString)
            Cmd = New SqlCommand()
            Cmd.CommandText = "sProc_Elines_Send_GetContentPending"
            Cmd.CommandType = CommandType.StoredProcedure
            Cmd.Connection = Conn
            Cmd.Connection.Open()
            Rdr = Cmd.ExecuteReader(CommandBehavior.CloseConnection)
        
            If Rdr.HasRows Then
        
                While Rdr.Read
        
                    NewsID = Rdr("id")
                    NewsletterSubject = Rdr("SubjectNewsletter")
                    NewsletterHeader = Rdr("ContentHeader")
                    NewsletterContent = Rdr("ContentNewsletter")
                    NewsletterFooter = Rdr("ContentFooter")
        
                End While
        
            End If
        
            Conn.Close()
            Conn.Dispose()
            Cmd.Dispose()
        
            ' Header
            NewsletterHeaderForEmail = NewsletterHeader.Replace("<p>", "<p style=""font-family: Arial, Helvetica, sans-serif; font-size: 12pt; line-height: 1.3em;margin-bottom:1em"">")
            NewsletterHeaderForEmail = NewsletterHeaderForEmail.Replace("<li>", "<li style=""font-family: Arial, Helvetica, sans-serif; font-size: 12pt; line-height: 1.3em;margin-bottom:1em"">")
            NewsletterHeaderForEmail = NewsletterHeaderForEmail.Replace("[NewsID]", NewsID)
        
            ' Footer
            NewsletterFooterForEmail = NewsletterFooter.Replace("<p>", "<p style=""font-family: Arial, Helvetica, sans-serif; font-size: 12pt; line-height: 1.3em;margin-bottom:1em"">")
            NewsletterFooterForEmail = NewsletterFooterForEmail.Replace("<li>", "<li style=""font-family: Arial, Helvetica, sans-serif; font-size: 12pt; line-height: 1.3em;margin-bottom:1em"">")
        
            ' Content
            NewsletterContentForEmail = NewsletterContent.Replace("<p>", "<p style=""font-family: Arial, Helvetica, sans-serif; font-size: 12pt; line-height: 1.3em;margin-bottom:1em"">")
            NewsletterContentForEmail = NewsletterContentForEmail.Replace("<li>", "<li style=""font-family: Arial, Helvetica, sans-serif; font-size: 12pt; line-height: 1.3em;margin-bottom:1em"">")
            NewsletterContentForEmail = "<table border=""0"" cellpadding=""0"" cellspacing=""0""><tr><td style=""font-family: Arial, Helvetica, sans-serif; font-size: 12pt"">" & NewsletterContentForEmail & "</td></tr></table>"
        
            NewsletterFinalReadyForSending = NewsletterHeaderForEmail & NewsletterContentForEmail & NewsletterFooterForEmail
        
            Dim filePath2 As String = "C:\Programs\SendElines.bat"
            Dim w2 As StreamWriter
            w2 = File.CreateText(filePath2)
            w2.WriteLine("START """" ""C:\Program Files (x86)\Gammadyne Mailer\gm.exe"" /s /n /subject""" & NewsletterSubject & """ /html""C:\Programs\elines.html"" ""C:\Users\Public\Documents\Newsletters\Elines\Sending Template - Elines.mmp""")
            w2.Flush()
            w2.Close()
        
        
            Dim filePath As String = "C:\Programs\elines.html"
            Dim w As StreamWriter
            w = File.CreateText(filePath)
            w.WriteLine(NewsletterFinalReadyForSending)
            w.Flush()
            w.Close()
        
        End Sub
        
        Sub SendNewsletter()
        
                Dim Conn As New SqlConnection(ConfigurationManager.ConnectionStrings("UnitedAFAConnectionStringAfaNewsletters").ConnectionString)
                Dim MySQL As String = "sProc_SendElines"
                Dim Cmd As New Data.SqlClient.SqlCommand(MySQL, Conn)
                Cmd.CommandType = CommandType.StoredProcedure
                Conn.Open()
                Cmd.ExecuteNonQuery()
                Conn.Close()
                Conn.Dispose()
        
        End Sub
        
        Sub UpdateRecord()
        
            Dim Conn As New SqlConnection(ConfigurationManager.ConnectionStrings("UnitedAFAConnectionStringNSS").ConnectionString)
            Dim MySQL As String = "sProc_Elines_Send_MarkComplete"
            Dim Cmd As New Data.SqlClient.SqlCommand(MySQL, Conn)
            Cmd.CommandType = CommandType.StoredProcedure
        
            Conn.Open()
            Cmd.ExecuteNonQuery()
            Conn.Close()
            Conn.Dispose()
        
        End Sub
        

        这是SendElines子例程的代码:

                USE [afanewsletters]
            GO
            /****** Object:  StoredProcedure [dbo].[sProc_SendElines]    Script Date: 9/5/2017 2:51:08 PM ******/
            SET ANSI_NULLS ON
            GO
            SET QUOTED_IDENTIFIER ON
            GO
            -- ======================================================
            -- Author:      Christopher Lee
            -- Create date: 21-Aug-2012
            -- Modify date: 21-Aug-2012
            -- Description: Runs the Elines sending BAT file.
            -- ======================================================
        
            ALTER PROCEDURE [dbo].[sProc_SendElines]
        
            AS
        
            EXEC xp_logevent 67845, 'Send Elines', informational
        

        我应该指出,SendElines()存储过程是在不同的数据库上(但在同一台服务器上)。但是,要清楚的是,前两个子程序工作正常。只是sProc_Elines_Send_MarkComplete爆炸了。

        以下是sProc_Elines_Send_GetContentPending的代码:

            USE [Newsletters]
        GO
        /****** Object:  StoredProcedure [dbo].[sProc_Elines_Send_GetContentPending]    Script Date: 9/6/2017 6:57:06 AM ******/
        SET ANSI_NULLS ON
        GO
        SET QUOTED_IDENTIFIER ON
        GO
        -- ======================================================
        -- Author:      Christopher Lee
        -- Create date: 16-Aug-2012
        -- Modify date: 16-Aug-2012
        -- Description: Get content for Elines for approval.
        -- ======================================================
        
        ALTER PROCEDURE [dbo].[sProc_Elines_Send_GetContentPending]
        
        AS
        
        
        BEGIN TRY
        BEGIN TRANSACTION
        
        SELECT * FROM tblElinesNewsletter
        WHERE     (NewsletterSent = 0)
        
        COMMIT
        END TRY
        BEGIN CATCH
        IF @@TRANCOUNT > 0
        ROLLBACK
          RAISERROR ('Problem with sProc_Elines_Send_GetContentPending, please contact the MEC Webmaster at webmaster@unitedafa.org.', 16, 1)
        END CATCH
        

        这是我运行的DBCC OPENTRAN的结果。前两个存储过程(sProc_Elines_Send_GetContentPending和sProc_SendElines)已成功执行。但是,当sProc_Elines_Send_MarkComplete运行并挂起时,我运行了DBCC OPENTRAN,其中包含以下消息:“没有活动的打开事务。”随附的屏幕截图:Here's the DBCC OPENTRAN screenshot

3 个答案:

答案 0 :(得分:1)

在此代码中

Rdr = Cmd.ExecuteReader(CommandBehavior.CloseConnection)
If Rdr.HasRows Then
    While Rdr.Read
        ....
    End While
End If

Conn.Close()
Conn.Dispose()

你没有关闭并处理读者。我不知道SqlConnectionSqlDataReader的内部,但是一个开放的读者可能会导致conn.Close()无效。

如果阅读器处于打开状态,这意味着sProc_Elines_Send_GetContentPending读取的记录和表可能已被锁定,这意味着即使不再访问记录,也不会释放锁定。

您还应该查看Using语句(请参阅this question)来处理连接,命令和阅读器。

此外,您有一个While循环,但只处理一条记录。如果Reader没有返回记录,你最终会得到许多未初始化的变量。但这与你的锁定问题无关。

答案 1 :(得分:0)

查询看起来很好,如果你的行数少于1k,我不知道为什么它最终会超时。

您可以尝试的一件事是在顶部添加一个变量,并将CAST(GETDATE()AS smalldatetime)添加到其中。然后在更新中使用该变量。

DECLARE @myDate smalldatetime AS CAST(GETDATE() AS smalldatetime)

UPDATE tblElinesNewsletter
SET 
NewsletterSent = 1,
DateSent= myDate ,
ApprovalPending = 0
WHERE NewsletterSent = 0

我不确定它会做什么,但想法是将日期的值存储在常量中,而不是在WHERE子句中进行评估。

答案 2 :(得分:0)

所有

首先,感谢您的帮助/帮助。这是我第一次使用这块电路板时遇到如此广泛的问题。我希望我能够了解所有回复,因为它们都有助于更清晰地描绘出正在发生的事情。

我部分解决了这个问题,Devio说关于连接没有被关闭。进一步深入.NET页面,我发现有一个会话状态数据库调用来管理页面的安全性。这来自iframe标记,实际上是在使用相同连接字符串和数据库的不同页面上。显然,这个连接字符串没有关闭,并且使用相同的数据库和相同的整体表保持打开状态。然后sProc_Elines_Send_GetContentPending proc尝试运行 - 它似乎正在运行,sProc_SendElines proc也是如此。但是当sProc_Elines_Send_MarkComplete proc试图运行时,它就像我提到的那样失败了。

当我重写数据库连接代码以添加到以下语句时:

        Cmd.ExecuteNonQuery()
        Conn.Close()
        Conn.Dispose()

然后关闭安全会话状态数据库连接,然后允许所有其他三个存储过程运行。

所以再一次,这解决了这个问题,并且为我找出它的起因来自Devio的密切联系建议。

我希望我使用正确的Stack Overflow协议来解决这个问题,如果我遗漏了任何内容,请告诉我。再次感谢大家。你是最好的!

- 克里斯