2017-09-05 5 views
1

Cela me rend fou. J'ai une petite table SQL Server 2012 avec les colonnes suivantes:La table SQL Server ne parvient pas à mettre à jour

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 

Il y a 583 lignes dans la table.

Voici le problème:

  1. je peux SELECT * sans problème
  2. je peux INSERT INTO sans problème
  3. Cependant, quand je lance la requête suivante, tout explose:

    UPDATE tblElinesNewsletter 
    SET NewsletterSent = 1, 
        DateSent = GETDATE(), 
        ApprovalPending = 0 
    WHERE (NewsletterSent = 0) 
    

Chaque fois que je lance l'abo code ve, j'obtiens une erreur de timeout. L'erreur de délai d'expiration est la même si je l'exécute à partir de la page ASP.NET ou de SQL Server Management Studio.

De plus, si je clique avec le bouton droit de la souris sur SSMS et que je choisis "Modifier les 200 premières lignes ...", la grille sera affichée et je pourrai éditer. Mais dès que je clique et que j'effectue la mise à jour, ça explose.

J'ai essayé ce qui suit déjà:

  1. Reconstruire l'index
  2. Créer une table de marque nouvelle avec les mêmes données de schéma et de transfert là-bas
  3. Redémarrez le serveur
  4. Aller au Home Depot et d'acheter une grande boîte de spackle pour réparer les trous dans le mur de bureau (de me frapper la tête contre)

Ce n'est pas un grande table. Il stocke simplement du HTML pour un bulletin d'information électronique.

Cela n'a pas toujours été le cas et cela n'a commencé que quelques mois plus tôt. Cela a bien fonctionné avant cela. Maintenant, tout ce qui précède dit, voici le kicker: il ne le fait pas tout le temps. Parfois cela fonctionne. Ce qui a été remarqué, c'est que s'il y a un bulletin plus long dans le tableau, cela ne semble pas fonctionner, si le bulletin est très court. Ce sont des newsletters simples et pas trop de fantaisie, en voici une ici: http://unitedafa.org/news/elines/view/?id=104169

Ceci tire de la base de données/table que je discute ci-dessus.

Cette installation de SQL Server se trouve sur une boîte Windows Server 2012 avec 6 Go de RAM et n'exécute que quelques sites Web qui n'obtiennent pas beaucoup de trafic. Une chose que je remarque en essayant de déboguer ceci, est que quand j'exécute la procédure stockée de SQL Server de la page Web d'ASP.NET, quand elle échoue, ceci semble geler le SQL Server et Je ne peux pas exécuter la même procédure stockée dans SSMS. Cependant, une fois que je redémarre le serveur, je peux alors ouvrir SSMS et exécuter la procédure stockée. Encore une fois, si j'exécute la procédure stockée à partir de la page Web, il gèle à nouveau le serveur et je ne peux exécuter aucune requête de mise à jour sur cette table.

Juste pour référence, voici la procédure stockée réelle qui est appelé à partir de la page:

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 

Aussi, voici le script 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 

Toute idée sur la terre que je fais faux? BTW, je ne suis pas un administrateur de base de données et plus familier avec le code Web ASP.NET, etc., plus de déclarations SQL.

Toute aide ou conseil serait apprécié!

- Chris

PS, voici quelques informations supplémentaires:

plan d'exécution de requêtes SQL Server sur le Proc stocké:

[Plan d'exécution SQL Server Capture d'écran] [1]

Voici quelques informations supplémentaires:

  1. Espace disque suffisant.
  2. Il n'y a pas d'autres processus concurrents.

La proc stockée est en fait exécutée dans une séquence avec deux autres avant elle. Voici le code de la page exécution:

Protected Sub btnSubmit_Click(sender As Object, e As EventArgs) Handles btnSubmit.Click 

    Call WriteNewsletterFile() 

    Call SendNewsletter() 

    Call UpdateRecord() 

End Sub 

Ainsi, le WriteNewsletterFile() et le SendNewsletter() des sous-routines fonctionnent très bien. Il explose sur le sous-programme UpdateRecord. Voici le code pour chacune des routines:

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 

Et voici le code pour le SendElines Subroutine:

 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 

Je tiens à souligner que les SendElines() stored proc est sur une autre base de données (mais sur le même serveur). Encore une fois cependant, pour être clair, les deux premiers sous-programmes fonctionnent bien. C'est juste le sProc_Elines_Send_MarkComplete qui explose.

Voici le code pour 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 [email protected]', 16, 1) 
END CATCH 

est ici les résultats de la DBCC OPENTRAN je courais. Les deux premiers processus stockés (sProc_Elines_Send_GetContentPending et sProc_SendElines) ont été exécutés avec succès. Toutefois, lorsque sProc_Elines_Send_MarkComplete a été exécuté et bloqué, j'ai exécuté le DBCC OPENTRAN qui contenait le message: "Aucune transaction ouverte active". Capture d'écran jointe: Here's the DBCC OPENTRAN screenshot

+1

Y a-t-il des triggers sur cette table? Aussi, pouvez-vous poster le message d'erreur exact que vous obtenez? – Sparrow

+0

Votre table n'a pas de colonne 'IDENTITY'. peut-être que ça va aider? (PS Je ne suis pas non plus un DBA) – VDWWD

+2

Un timeout sur une petite table suggère un blocage. –

Répondre

1

Dans ce code

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

Conn.Close() 
Conn.Dispose() 

vous ne fermez pas et jetez le lecteur. Je ne connais pas les internes de SqlConnection et SqlDataReader, mais un lecteur ouvert peut provoquer le conn.Close() n'a aucun effet. Si le lecteur est ouvert, cela signifie que les enregistrements et les tables lus par sProc_Elines_Send_GetContentPending sont probablement verrouillés, ce qui signifie que les verrous ne sont pas libérés, même si les enregistrements ne sont plus accessibles.

Vous devez également consulter l'instruction Using (voir this question) pour gérer les connexions, les commandes et les lecteurs.

De plus, vous avez une boucle While, mais ne traitez qu'un seul enregistrement. Et si le lecteur ne retourne pas un enregistrement, vous vous retrouvez avec beaucoup de variables non initialisées. Mais ce n'est pas lié à votre problème de verrouillage.

+0

Salut @devio: D'après ce que je peux voir dans le code, il semble que la connexion DB est en cours de fermeture. Voici un extrait du code ci-dessus: Si Rdr.HasRows Then While Rdr.Lire newsId = Rdr ("id") NewsletterSubject = Rdr ("SubjectNewsletter") NewsletterHeader = Rdr ("ContentHeader") NewsletterContent = Rdr ("ContentNewsletter") NewsletterFooter = Rdr ("ContentFooter") Fin Alors que End If Conn.Close() Conn.Dispose() Cmd.Dispose() –

+0

"de ce que nous pouvons tous voir dans le code", le code fonctionne très bien. – devio

0

La requête semble correcte, et si vous avez moins de 1k lignes, je ne sais pas pourquoi cela finirait par expirer.

Une chose que vous pouvez essayer est d'ajouter une variable en haut, et d'ajouter CAST (GETDATE() AS smalldatetime) dans cela. Ensuite, utilisez la variable dans votre mise à jour.

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

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

Je ne suis pas sûr que ça va faire quoi que ce soit, mais l'idée est de stocker la valeur de la date dans une constante, plutôt que de l'avoir évalué dans la clause WHERE.

+0

Merci SchmitzIT, j'ai essayé ça et ça a explosé à nouveau. J'ai également modifié l'instruction UPDATE pour qu'elle soit simplement UPDATE tblElinesNewsletter SET ApprovalPending = 0. Les deux ont échoué. –

+0

Que se passe-t-il lorsque vous affichez le plan d'exécution estimé dans SSMS? Qu'est-ce que c'est? La seule chose que je peux penser est que les colonnes nvarchar (max) posent problème, car elles sont considérées comme des blobs. Mais vous ne touchez pas ceux avec la déclaration de mise à jour. – SchmitzIT

+0

Ouais, c'est la chose folle. Maintenant, je vais sembler ignorant: où/comment puis-je tirer un plan d'exécution d'estimation? –

0

Tous:

Tout d'abord, merci pour votre aide/assistance. C'était vraiment la première fois que j'utilisais ce forum avec un problème aussi important. J'aurais aimé pouvoir TOUTES les réponses, car elles ont toutes aidé à brosser un tableau plus clair de ce qui se passait.

J'ai résolu le problème en partie par ce que Devio a dit à propos des connexions qui ne sont pas fermées. Creuser dans la page .NET plus loin, j'ai trouvé qu'il y avait un appel de base de données d'état de session qui a géré la sécurité de la page. Cela venait d'un tag iframe et en fait sur une page DIFFERENTE utilisant la même chaîne de connexion et la même base de données. Apparemment, cette chaîne de connexion ne s'est pas fermée et est restée ouverte avec la même base de données et la même table globale. Ensuite, le proc sProc_Elines_Send_GetContentPending a tenté de s'exécuter - ce qu'il semblait faire, tout comme le proc sProc_SendElines. Cependant, lorsque le proc sProc_Elines_Send_MarkComplete a tenté de s'exécuter, il a échoué car j'ai mentionné eariler.

Quand je réécrit le code de connexion de base de données à ajouter aux déclarations suivantes:

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

Il a fermé alors la sécurité de session connexion de base de données Etat, qui a ensuite permis à tous les trois des autres procédures stockées pour exécuter. Donc, encore une fois, cela a résolu le problème et la genèse de me l'expliquer provenait de la suggestion de connexion étroite de Devio.

J'espère avoir fait la fermeture de cette question avec le protocole Stack Overflow correct et s'il vous plaît laissez-moi savoir si j'ai raté quelque chose. Merci encore tout le monde. Tu es le meilleur!

- Chris

+0

bon de vous lire traqué;) – devio