这只会让我发疯。我有一个小的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行。
问题在于:
SELECT *
毫无问题INSERT INTO
毫无问题但是,当我运行以下查询时,一切都会爆炸:
UPDATE tblElinesNewsletter
SET NewsletterSent = 1,
DateSent = GETDATE(),
ApprovalPending = 0
WHERE (NewsletterSent = 0)
每当我运行上面的代码时,我都会收到超时错误。如果我从ASP.NET页面或从SQL Server Management Studio运行它,则超时错误是相同的。
此外,如果我从SSMS右键单击并选择“编辑前200行...”,它将显示网格并让我编辑。但是一旦我点击它并且它正在执行更新,它就会爆炸。
我已经尝试了以下内容:
这不是一张大桌子。它只是存储电子邮件简报的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]
以下是其他一些信息:
存储过程实际上是在它之前以另外两个序列执行的。这是执行页面中的代码:
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
答案 0 :(得分:1)
在此代码中
Rdr = Cmd.ExecuteReader(CommandBehavior.CloseConnection)
If Rdr.HasRows Then
While Rdr.Read
....
End While
End If
Conn.Close()
Conn.Dispose()
你没有关闭并处理读者。我不知道SqlConnection
和SqlDataReader
的内部,但是一个开放的读者可能会导致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协议来解决这个问题,如果我遗漏了任何内容,请告诉我。再次感谢大家。你是最好的!
- 克里斯