Una exploración constante tarda 0 segundos o 2-3 minutos

9

Una consulta como la siguiente que está garantizada para no devolver ninguna fila, toma de 0 a 160 segundos en uno de nuestros servidores:

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

Hace dos semanas, esto sucedió seis veces en un intervalo de 48 horas. La semana pasada la misma consulta tomó ~ 0 segundos. Tengo registros de los SQL de nuestra aplicación, pero todavía no he encontrado ningún sospechoso. Además, pensé que una consulta de tipo 0 / donde 0 = 1 nunca llegaba a las páginas de datos, por lo que debería ser resistente a los bloqueos de datos de fila / página / tabla. El esquema no es tocado por ningún SQL (conocido).

Dado que el problema no es consistente, y el servidor está bajo una carga muy pesada, me gustaría entender la teoría detrás de lo que está sucediendo antes de conectar el generador de perfiles SQL. Otras consultas se ejecutan sin problemas durante estos retrasos. Un problema conocido en la aplicación es una gran cantidad de consultas SQL creadas dinámicamente: alrededor de 200k consultas únicas de 850k consultas totales (registradas) durante un período de 48 horas, ¿puede esto causar problemas como este?

El servidor ejecuta la edición estándar de SQL Server 2005, 96 GB de RAM, discos en SAN y 4 CPU / 16 núcleos. Los archivos de base de datos y los grupos de archivos están bien optimizados y no deberían ser un problema (pero estamos analizando esto por separado).

Cualquier puntero donde mirar es muy apreciado.

Editar: ¡Perfecto! Reproduje la consulta para agregar el plan de ejecución, y tardó 1 minuto y 35 segundos. Aquí está el plan de ejecución y la captura de pantalla que muestra la duración de la consulta: Plan de consulta

Edición 2: detalles de tiempo de estadísticas para una segunda ejecución. Parece ser constantemente lento en este momento, por lo que adjuntaremos profiler y 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.
EventoHorizonte
fuente
¿Podría por favor incluir el plan de ejecución? CTRL + M en la ventana de consulta antes de la ejecución.
Craig Efrein
2
¿Podría ser un problema de bloqueo? Declaraciones DML de otras sesiones que bloquean la selección en la tabla (que es el comportamiento predeterminado en SQL Server 2005)
a_horse_with_no_name
No hay ninguna declaración DML conocida, que es la única causa en la que puedo pensar, pero aún estamos investigando esto. El plan de ejecución se agrega a la pregunta.
EventHorizon
Por lo que he leído, este es solo uno de esos planes triviales de ejecución que MSSQL usa para evitar leer montones e índices cuando el optimizador sabe que no hay filas que devolver
Craig Efrein
1
Vi un caso que se parecía mucho a esto. Resultó estar activando estadísticas de actualización (las estadísticas de actualización automática se activaron y el plan de mantenimiento se rompió).
Joshua

Respuestas:

18

Parece que incluso con una ... WHERE 0 = 1cláusula que todavía habrá un requisito para un ISbloqueo de intención compartida ( ) en la tabla. Probemos esto:

Comenzaré creando una tabla de prueba:

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

Ahora que tengo mi tabla de prueba, en una sesión (ventana de consulta) voy a ejecutar lo siguiente para poner un Xbloqueo exclusivo ( ) dbo.MyTestTable1:

use TestDb1;
go

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

Puedo verificar el bloqueo exclusivo mirando el sys.dm_tran_locksDMV. Luego, en otra sesión (nueva ventana de consulta) hago exactamente lo que hace su consulta:

use TestDb1;
go

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

A primera vista veo que no se está completando. Mirando sys.dm_exec_requests, veo exactamente por qué este es el caso:

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;

ingrese la descripción de la imagen aquí

Puedo ver aquí que mi ... WHERE 0 = 1consulta está esperando un ISbloqueo para este objeto (que object_id se traduce a dbo.MyTestTable1).

De ninguna manera estoy diciendo que la concurrencia es su problema, pero por lo que parece, está exhibiendo los síntomas. El ejemplo anterior es para demostrar que no está exento de bloquear y bloquear incluso con una WHEREcláusula que nunca devolverá datos.

Todo lo que podemos hacer es adivinar, por lo que lo que debe hacer cuando está "tomando mucho tiempo" es ver exactamente qué está haciendo esa solicitud que está tomando tanto tiempo. Si está esperando algo, entonces mira lo que está esperando.

Thomas Stringer
fuente
1

Dependiendo de cuán puntiagudos e hilos requieran sus consultas, su sistema podría simplemente poner en cola esa consulta. El recuento de trabajadores predeterminado (es decir, el número de subprocesos simultáneos del servidor SQL) para su configuración debe ser de aproximadamente 700.

Consulte sys.dm_os_schedulers y sys.dm_os_waiting_tasks para ver si eso podría ser un problema.

Sascha Rambeaud
fuente
Una buena sugerencia, pero el problema terminó siendo una cerradura tonta después de todo.
EventHorizon
No estaba realmente convencido, ya que 700 trabajadores es suficiente, pero fue fácil de verificar (y por lo tanto excluir)
Sascha Rambeaud