web-dev-qa-db-fra.com

Comment empêcher le «délai d'expiration de la requête expiré»? (Erreur SQLNCLI11 '80040e31')

J'ai une connexion à une base de données MS SQL Server 2012 en classique ASP (VBScript). Voici ma chaîne de connexion:

Provider=SQL Server Native Client 11.0;Server=localhost;
Database=databank;Uid=myuser;Pwd=mypassword;

Lorsque j'exécute cette commande SQL:

UPDATE [info] SET [stamp]='2014-03-18 01:00:02',
[data]='12533 characters goes here',
[saved]='2014-03-18 01:00:00',
[confirmed]=0,[ip]=0,[mode]=3,[rebuild]=0,
[updated]=1,[findable]=0 
WHERE [ID]=193246;

J'obtiens l'erreur suivante:

Microsoft SQL Server Native Client 11.0 
error '80040e31'
Query timeout expired   
/functions.asp, line 476

La requête SQL est assez longue, le champ de données est mis à jour avec 12533 ​​caractères. La colonne ID est indexée, donc la recherche du poste avec l'ID 193246 devrait être rapide.

Lorsque j'exécute exactement la même expression SQL (copiée et collée) sur SQL Server Management Studio, elle se termine avec succès en un rien de temps. Pas de problème quoi qu'il en soit. Il n'y a donc pas de problème avec le SQL lui-même. J'ai même essayé d'utiliser un objet ADODB.Recordset et de le mettre à jour via cela (pas de SQL auto-écrit) mais j'obtiens toujours la même erreur de timeout.

Si je vais dans Outils> Options> Exécution de requête dans Management Studio, je vois que le délai d’exécution est défini sur 0 (infini). Sous Outils> Options> Concepteurs, je vois que le délai d'expiration de la transaction est défini sur 30 secondes, ce qui devrait être suffisant car le script et la base de données se trouvent sur le même ordinateur ("localhost" est dans la chaîne de connexion).

Qu'est-ce qui se passe ici? Pourquoi puis-je exécuter le SQL dans Management Studio mais pas dans mon code ASP?


Edit: J'ai essayé de définir le délai d'expiration de 30 secondes dans l'onglet Concepteurs à 600 secondes juste pour être sûr, mais j'obtiens toujours la même erreur (se produit après 30 secondes de chargement de la page btw).

Voici le code que j'utilise pour exécuter le SQL sur la page ASP:

Set Conn = Server.CreateObject("ADODB.Connection")
Conn.Open "Provider=SQL Server Native Client 11.0;
Server=localhost;Database=databank;Uid=myuser;Pwd=mypassword;"
Conn.Execute "UPDATE [info] SET [stamp]='2014-03-18 01:00:02',
[data]='12533 characters goes here',[saved]='2014-03-18 01:00:00',
[confirmed]=0,[ip]=0,[mode]=3,[rebuild]=0,[updated]=1,[findable]=0 
WHERE [ID]=193246;"

Edit 2: Utilisation de Conn.CommandTimeout = 0 pour donner un temps d'exécution infini à la requête ne fait rien, il fait juste exécuter la requête pour toujours. Attendu 25 minutes et il était toujours en cours d'exécution.

J'ai ensuite essayé de séparer le SQL en deux instructions SQL, la mise à jour des données longues dans l'une et les autres mises à jour dans l'autre. Il ne mettrait toujours pas à jour le champ de données long, il a juste un délai d'expiration.

J'ai essayé cela avec deux chaînes de connexion supplémentaires:

Driver={SQL Server};Server=localhost;Database=databank;Uid=myuser;Pwd=mypassword;
Driver={SQL Server Native Client 11.0};Server=localhost;Database=databank;Uid=myuser;Pwd=mypassword;

Ça n'a pas marché. J'ai même essayé de changer les données en 12533 ​​A juste pour voir si les données réelles causaient le problème. Non, même problème.

Ensuite, j'ai découvert quelque chose d'intéressant: j'ai essayé d'exécuter le court SQL d'abord, avant la longue mise à jour du champ de données. Il a également obtenu une exception de délai d'expiration de la requête ...

Mais pourquoi? Il a si peu de choses à mettre à jour (toute l'instruction SQL contient moins de 200 caractères). Enquêtera plus avant.


Edit 3: Je pensais que cela avait peut-être quelque chose à voir avec la connexion mais je n'ai rien trouvé de mal. J'ai même essayé de changer la chaîne de connexion pour utiliser le compte sa, mais cela n'a pas fonctionné, mais le délai de requête a expiré.

Ça me rend fou. Il n'y a pas de solution, pas de solution de contournement et pire encore aucune idée!


Edit 4: Je suis allé à Outils> Options> Concepteurs dans Management Studio et j'ai coché la case "Empêcher l'enregistrement des modifications qui nécessitent une recréation de table". Ça n'a rien fait.

J'ai essayé de changer le type de données de la colonne "data" de "nvarchar (MAX)" au type "ntext" inférieur (je deviens désespéré). Ça n'a pas marché.

J'ai essayé d'exécuter le plus petit changement sur le poste auquel je pouvais penser:

UPDATE [info] SET [confirmed]=0 WHERE [ID]=193246;

Cela définirait une colonne de bits sur false. Ça n'a pas marché. J'ai essayé d'exécuter exactement la même requête dans Management Studio et cela a fonctionné parfaitement.

Jetez-moi quelques idées si vous les avez parce que je suis en train de manquer pour de bon maintenant.


Edit 5: J'ai également essayé la chaîne de connexion suivante:

Provider=SQLOLEDB.1;Password=mypassword;Persist Security Info=True;User ID=myuser;Initial Catalog=databank;Data Source=localhost

Ça n'a pas marché. Seulement essayé de mettre confirmé à faux mais a encore obtenu un temps mort.


Edit 6: J'ai maintenant tenté de mettre à jour un message différent dans le même tableau:

UPDATE [info] SET [confirmed]=0 WHERE [ID]=1;

Il a également donné l'erreur de temporisation. Alors maintenant, nous savons que ce n'est pas un message spécifique.

Je suis en mesure de mettre à jour les messages dans d'autres tableaux dans la même base de données "banque de données" via ASP. Je peux également mettre à jour des tables dans d'autres bases de données sur localhost.

Pourrait-il y avoir quelque chose de cassé avec la table [info]? J'ai utilisé l'assistant MS Access pour déplacer automatiquement les données d'Access vers MS SQL Server 2012, il a créé des colonnes de type de données "ntext" et je suis allé manuellement et changé cela en "nvarchar (MAX)" car ntext est déconseillé. Quelque chose aurait-il pu tomber en panne? Cela m'a obligé à recréer la table lorsque j'ai changé le type de données.

Je dois dormir un peu mais je reviendrai sûrement demain si quelqu'un m'a répondu. Veuillez le faire, même si vous n'avez que quelque chose d'encourageant à dire.


Edit 7: Édition rapide avant de se coucher. J'ai également essayé de définir le fournisseur comme "SQLNCLI11" dans la chaîne de connexion (en utilisant le nom DLL au lieu du nom du fournisseur réel). Cela ne fait aucune différence. La connexion est créée tout aussi bien mais le le délai d'attente se produit toujours.

De plus, je n'utilise pas MS SQL Server 2012 Express (pour autant que je sache, "Express" n'a été mentionné nulle part lors de l'installation). C'est tout.

Si cela vous aide, voici les informations "Aide"> "À propos ..." fournies par Management Studio:

Microsoft SQL Server Management Studio: 11.0.2100.60  
Microsoft Analysis Services Client Tools: 11.0.2100.60  
Microsoft Data Access Components (MDAC): 6.3.9600.16384  
Microsoft MSXML: 3.0 5.0 6.0   
Microsoft Internet Explorer: 9.11.9600.16521  
Microsoft .NET Framework: 4.0.30319.34011  
Operating System: 6.3.9600

Edit 8 (également connu sous le nom de "les programmeurs ne dorment jamais")

Après avoir essayé certaines choses, j'ai finalement essayé de fermer la connexion à la base de données et de la rouvrir juste avant d'exécuter les instructions SQL. Cela a fonctionné tout d'un coup. Qu'est-ce que ...?

J'ai eu mon code dans un sous-programme et il s'avère qu'en dehors de celui-ci, le message que j'essayais de mettre à jour était déjà ouvert! Donc, la raison du délai d'attente était que le message ou la table entière a été verrouillé par la même connexion qui a essayé de le mettre à jour. La connexion (ou thread CPU) attendait donc un verrou qui ne se déverrouillerait jamais.

Je déteste quand il s'avère si simple après avoir essayé si dur.

Le poste avait été ouvert en dehors du sous-programme par ce simple code:

Set RecSet = Conn.Execute("SELECT etc")

J'ai juste ajouté ce qui suit avant d'appeler le sous-programme.

RecSet.Close
Set RecSet = Nothing

La raison pour laquelle cela ne m'est jamais venu à l'esprit est simplement parce que cela était autorisé dans MS Access mais maintenant j'ai changé pour MS SQL Server et ce n'était pas si gentil (ou bâclé, plutôt). Le RecSet créé par Conn.Execute () n'avait jamais créé de publication verrouillée dans la base de données auparavant, mais maintenant tout d'un coup, il l'a fait. Pas trop étrange puisque la chaîne de connexion et la base de données réelle avaient changé.

J'espère que ce message évite à quelqu'un d'autre des maux de tête si vous migrez de MS Access vers MS SQL Server. Bien que je ne puisse pas imaginer qu'il reste de nombreux utilisateurs d'Access dans le monde de nos jours.

13
user3435078

Il s'avère que le message (ou plutôt la table entière) a été verrouillé par la même connexion que celle avec laquelle j'ai essayé de mettre à jour le message.

J'avais un jeu d'enregistrements ouvert du message créé par:

Set RecSet = Conn.Execute()

Ce type de jeu d'enregistrements est censé être en lecture seule et lorsque j'utilisais MS Access comme base de données, il n'a rien verrouillé. Mais apparemment, ce type de jeu d'enregistrements a verrouillé quelque chose sur MS SQL Server 2012 parce que lorsque j'ai ajouté ces lignes de code avant d'exécuter l'instruction UPDATE SQL ...

RecSet.Close
Set RecSet = Nothing

... tout fonctionnait très bien.

Donc, l'essentiel est d'être prudent avec les jeux d'enregistrements ouverts - même s'ils sont en lecture seule, ils pourraient verrouiller votre table des mises à jour.

12
user3435078