Un scan constant prend 0 seconde ou 2-3 minutes

9

Une requête comme celle ci-dessous qui est garantie de ne retourner aucune ligne, prend de 0 à 160 secondes sur l'un de nos serveurs:

select col1, col2, col3
from tab1
where 0 = 1

Il y a deux semaines, cela s'est produit six fois dans un intervalle de 48 heures. La semaine dernière, la même requête a pris ~ 0 seconde. J'ai des journaux des SQL de notre application mais je n'ai pas encore trouvé de suspects. En outre, je pensais qu'une requête de type 0/1 où 0 = 1 ne touchait jamais les pages de données, donc elle devrait être résistante aux verrous de données au niveau ligne / page / table? Le schéma n'est touché par aucun SQL (connu).

Étant donné que le problème n'est pas cohérent et que le serveur est soumis à une charge très élevée, j'aimerais comprendre la théorie derrière ce qui se passe avant d'attacher SQL profiler. D'autres requêtes s'exécutent sans problème pendant ces délais. Un problème connu dans l'application est un nombre élevé de requêtes SQL créées dynamiquement - environ 200 000 requêtes uniques de 850 000 requêtes totales (enregistrées) sur une période de 48 heures, cela peut-il provoquer des problèmes comme celui-ci?

Le serveur exécute l'édition standard de SQL Server 2005, 96 Go de RAM, des disques sur SAN et 4 processeurs / 16 cœurs. Les fichiers de base de données et les groupes de fichiers sont bien optimisés et ne devraient pas poser de problème (mais nous examinons cela séparément).

Tous les pointeurs où chercher sont grandement appréciés.

Edit: parfait! Relu la requête pour ajouter le plan d'exécution, et cela a pris 1min 35secs. Voici le plan d'exécution et la capture d'écran montrant la durée de la requête: Plan de requête

Edit 2: statistiques des détails de temps pour une deuxième exécution. Semble être constamment lent en ce moment, nous allons donc attacher profiler et perfmon:

SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 97402 ms.
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.
EventHorizon
la source
Pourriez-vous s'il vous plaît inclure le plan d'exécution? CTRL + M dans la fenêtre de requête avant exécution.
Craig Efrein
2
Serait-ce un problème de verrouillage? Instructions DML d'autres sessions bloquant la sélection sur la table (ce qui est le comportement par défaut dans SQL Server 2005)
a_horse_with_no_name
Il n'y a pas d'instructions DML connues, ce qui est la seule cause à laquelle je peux penser, mais nous étudions toujours cela. Le plan d'exécution est ajouté à la question.
EventHorizon
D'après ce que j'ai lu, ce n'est qu'un de ces plans d'exécution triviaux que MSSQL utilise pour éviter de lire des tas et des index lorsque l'optimiseur sait qu'il n'y a pas de lignes à renvoyer
Craig Efrein
1
J'ai vu une affaire qui ressemblait beaucoup à ça. Il s'est avéré déclencher des statistiques de mise à jour (les statistiques de mise à jour automatique ont été activées et le plan de maintenance a été rompu).
Joshua

Réponses:

18

Il semble que même avec une ... WHERE 0 = 1clause, il y aura toujours une exigence pour un ISverrou shared ( ) intentionnel sur la table. Prouvons cela:

Je vais commencer par créer une table de test:

use TestDb1;
go

create table dbo.MyTestTable1
(
    Id int identity(1, 1) not null,
    SomeInt int not null
);
go

insert into dbo.MyTestTable1 (SomeInt)
values (10), (20), (30), (40), (50);
go

Maintenant que j'ai ma table de test, en une seule session (fenêtre de requête) je vais exécuter ce qui suit pour mettre un Xverrou exclusif ( ) dbo.MyTestTable1:

use TestDb1;
go

begin tran;
    select
        Id, SomeInt
    from dbo.MyTestTable1 with (tablockx);
--commit tran;

Je peux vérifier le verrou exclusif en regardant le sys.dm_tran_locksDMV. Ensuite, dans une autre session (nouvelle fenêtre de requête), je fais exactement ce que fait votre requête:

use TestDb1;
go

select
    Id, SomeInt
from dbo.MyTestTable1
where 0 = 1;

À première vue, je vois qu'il ne se termine pas. En regardant sys.dm_exec_requests, je vois exactement pourquoi c'est le cas:

select
    r.session_id,
    r.status,
    r.wait_type,
    r.wait_time,
    r.wait_resource,
    r.blocking_session_id
from sys.dm_exec_requests r
cross apply sys.dm_exec_sql_text(r.sql_handle) st
where st.text like '%where 0 = 1%'
and r.session_id <> @@spid;

entrez la description de l'image ici

Je peux voir ici que ma ... WHERE 0 = 1requête attend un ISverrou pour cet objet (cet object_id se traduit par dbo.MyTestTable1).

Je ne dis nullement que la concurrence est votre problème, mais par les sons que vous en présentez les symptômes. L'exemple ci-dessus est de prouver que vous n'êtes pas exempté de verrouillage et de blocage, même avec une WHEREclause qui ne renverra jamais de données.

Tout ce que nous pouvons faire est de deviner, donc ce que vous devez faire quand cela "prend beaucoup de temps" est de voir exactement ce que fait cette demande qui prend si longtemps. S'il attend quelque chose, voyez ce qu'il attend.

Thomas Stringer
la source
1

En fonction de l'épaisseur et du thread exigeant vos requêtes, votre système peut simplement mettre cette requête en file d'attente. Le nombre de travailleurs par défaut (c'est-à-dire le nombre de threads SQL Server simultanés) pour votre configuration doit être d'environ 700.

Consultez sys.dm_os_schedulers et sys.dm_os_waiting_tasks pour voir si cela pourrait être un problème.

Sascha Rambeaud
la source
Une bonne suggestion, mais le problème a fini par être un verrou stupide après tout.
EventHorizon
Je n'étais pas vraiment convaincu, puisque 700 travailleurs, c'est beaucoup, mais c'était facile à vérifier (et donc à exclure)
Sascha Rambeaud