Consejos para diagnosticar una consulta lenta "a veces"

20

Tengo un procedimiento almacenado que devuelve los resultados de una vista indexada a través de un índice de cobertura. Por lo general, funciona rápido (~ 10 ms), a veces puede durar hasta 8 segundos.

Aquí hay un ejemplo de ejecución aleatoria (nota: esta no es lenta, pero el texto de la consulta es el mismo aparte del valor pasado):

declare @p2 dbo.IdentityType
insert into @p2 values(5710955)
insert into @p2 values(5710896)
insert into @p2 values(5710678)
insert into @p2 values(5710871)
insert into @p2 values(5711103)
insert into @p2 values(6215197)
insert into @p2 values(5710780)

exec ListingSearch_ByLocationAndStatus @statusType=1,@locationIds=@p2

Aquí está el SPROC:

ALTER PROCEDURE [dbo].[ListingSearch_ByLocationAndStatus]
    @LocationIds IdentityType READONLY,
    @StatusType TINYINT
AS
BEGIN
    SET NOCOUNT ON;

    SELECT      -- lots of fields
    FROM        [dbo].[ListingSearchView][a] WITH (NOEXPAND)
    INNER JOIN  @LocationIds [b] ON [a].[LocationId] = [b].[Id]
    WHERE       [a].[StatusType] = @statusType
    OPTION (RECOMPILE);

(nota: agregué la OPTION (RECOMPILE)pista recientemente después de algunos consejos, pero no ha ayudado.

Aquí está el índice de cobertura (nota: la vista también tiene un índice agrupado ListingId, que es único)

CREATE NONCLUSTERED INDEX [IX_ListingSearchView_ForAPI] ON [dbo].[ListingSearchView]
(
    [LocationId] ASC,
    [StatusType] ASC
)
INCLUDE ( -- all the fields in the query) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
GO

Puse un rastreador de perfil, con estadísticas de showplan XML.

Aquí hay uno lento (6 segundos) y el plan relevante: ingrese la descripción de la imagen aquí

Se ve exactamente como esperaba, y es el mismo plan cuando la consulta es rápida.

Aquí está el acercamiento a la parte costosa del plan, si eso ayuda: ingrese la descripción de la imagen aquí

Aquí está el esquema completo de las tablas de vista / respaldo, si eso ayuda: https://pastebin.com/wh1sRcbQ

Notas:

  • Los índices han sido desfragmentados, las estadísticas actualizadas.
  • Originalmente, la consulta estaba en línea con la vista, pero me mudé a SPROC para tratar de ayudar a estabilizar. No ha ayudado
  • Agregar WITH OPTION (RECOMPILE);sugerencia (no funcionó, ¿no puede ser el rastreo de parámetros?)
  • Otras consultas en el sistema también a veces se ejecutan lentamente, y tampoco tienen problemas obvios en su plan.
  • Podría estar bloqueando? No estoy seguro de cómo confirmar.

¿Alguna idea de lo que podría probar a continuación?

Gracias

RPM1984
fuente
1
Los comentarios no son para discusión extendida; Esta conversación se ha movido al chat . Todos: Por favor, utilicen ese servicio para seguir discutiendo esta pregunta.
Paul White dice GoFundMonica
dado que el enlace no funciona. la consulta de proceso es sencilla, hay una gran diferencia entre el número real y estimado de filas, lo cual es un área de preocupación. Creo que el problema radica en la consulta de vista. Creo que no hay datos suficientes. Debería estar cerca
KumarHarsh
¿Has intentado ejecutar WhoIsActive (por Adam Machanic) mientras se ejecuta la consulta? whoisactive.com Incluye información sobre las tareas de espera, que deberían guiarlo en la dirección correcta.
MJH
¿Has eliminado algo externo a la base de datos que causa esto? ¿Quizás alguna otra aplicación que causa IO síncrono al almacenamiento compartido con la base de datos?
Johan

Respuestas:

2

Realmente no creo que usarlo OPTION (RECOMPILE)sea ​​una forma efectiva de eliminar la posibilidad de olfatear parámetros.

El rastreo de parámetros ocurre cuando SQL está confundido acerca de una consulta en particular y piensa que es nuevo porque ve nuevos parámetros. Es lento porque lleva tiempo adicional generar un nuevo plan de ejecución.

Todo lo que hace esa opción es forzar a SQL a producir un nuevo plan cada vez que es más o menos lo mismo. En cambio, es posible que desee considerar agregar parámetros predeterminados utilizando esta sugerencia:

OPTION(OPTIMIZE FOR(@LocationIds='xx',@StatusType='xx'))

Al elegir los parámetros por defecto, asegúrese de utilizar un conjunto estadísticamente representativo.
Eso obligará a usar el mismo plan cada vez y eliminará la posibilidad de olfatear parámetros. Una vez que haga eso, y determine que no ayudó, entonces probablemente sea seguro descartar la inhalación de parámetros como una posibilidad.

Shooter McGavin
fuente
1

Quizás intente forzar el orden, por lo que probablemente siempre comience con la tabla más pequeña (variable). Sin embargo, eso es complicado con las vistas ...

    SELECT  -- lots of fields
    FROM    @LocationIds [b] WITH (NOEXPAND)
            INNER JOIN  [dbo].[ListingSearchView][a] WITH (NOEXPAND) 
                ON [a].[LocationId] = [b].[Id]
    WHERE   [a].[StatusType] = @statusType
    OPTION (FORCE ORDER);

o puede forzar una unión en bucle si generalmente es así como desea unir la variable de tabla a la vista, lo que también forzará el orden ...

    SELECT  -- lots of fields
    FROM    @LocationIds [b] WITH (NOEXPAND)
            INNER LOOP JOIN  [dbo].[ListingSearchView][a] WITH (NOEXPAND) 
                ON [a].[LocationId] = [b].[Id]
    WHERE   [a].[StatusType] = @statusType
    --leaving this here so you don't get an annoying warning 
    OPTION (FORCE ORDER);
Jeremy Giaco
fuente
0

Escriba el nombre del procedimiento Store en el Editor de consultas, luego seleccione el proceso Store. nombre y luego seleccione Visualizar plan de ejecución estimada o haga clic (Ctrl + L). debajo de la imagen de esto.

Imagen del plan de ejecución estimado de visualización

luego, Planes de ejecución se muestra justo al lado de la pestaña Mensajes en la parte inferior del Editor de consultas. luego, en las líneas de color verde, muestre los detalles del índice que faltan y haga clic derecho sobre eso. Luego Nueva consulta abierta en una nueva pestaña y luego crear el ÍNDICE entonces su consulta se ejecuta rápidamente.

Así que utilicé este método para diagnosticar la consulta que trabaja lentamente. y también hay tantas consultas o métodos que puedes usar.

Plan de ejecucion con detalles

rks_dotnet
fuente
-1

Si cree que el problema está en el bloqueo, le sugeriré que use un nivel de aislamiento de transacción optimizado.

REFERENCIA: https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/sql/snapshot-isolation-in-sql-server

Si el problema no está en el bloqueo de lectura / escritura, puede intentar agregar índices en su vista (la mejor opción de índices depende de la selectividad de sus datos)

CREATE NONCLUSTERED INDEX IX_ListingSearchView (LocationID, StatusType) INCLUDE (other columns...)
Artashes Khachatryan
fuente
1
El índice que sugiere ya existe IX_ListingSearchView_ForAPI(vea el script en la pregunta).
Paul White dice GoFundMonica
1
Hola, gracias por tu respuesta. Sin embargo, como dije en mi pregunta, quiero saber cuál es el problema antes de aplicar una solución. De lo contrario, podría pasar por alto el verdadero problema. Mi pregunta es sobre encontrar el problema primero, luego la solución correcta.
RPM1984
¿Puede obtener esa consulta lenta en su entorno local? Si la misma consulta a veces se ejecuta lenta y otras veces, puede depender de los parámetros de entrada. ¿Puede proporcionar el número de lecturas lógicas y el número total de filas devueltas por su consulta lenta?
Artashes Khachatryan
@ArtashesKhachatryan sí, a veces también funciona lento en local. He actualizado la pregunta con un plan de ejecución. Me pregunto si está relacionado con las consultas lentas que devuelven más filas que la rápida, como has dicho.
RPM1984