Surviving the Night

El blog de Pablo Doval sobre .NET, SQL, WinDbg...

Tell Me Where To Go: Estudio de Consultas AdHoc en SQL Server

Uno de mis temas favoritos a la hora de dar charlas de rendimiento de SQL Server es el estudio de la cache de planes de ejecución y la presencia de consultas AdHoc. Puedo pasarme horas hablando sobre ello, y contando batallitas… muy a pesar de los pobres asistentes que deben acabar hasta las narices de las consultas AdHoc, de mí, y de mi santa madre :)

Pero no nos engañemos, si me apasiona tanto este tema es porque se trata de un aspecto muy importante de la salud del servidor y de las aplicaciones que le atacan. Y, además, resulta muy fácil comprobar si estamos sufriendo algún problema relacionado con la presencia masiva de consultas AdHoc en el sistema.

Lo curioso es que, a pesar de lo mucho que me gusta y lo importante que es el tema, no le he hecho justicia con artículos en este blog. Y con esto no quiero decir que no haya escrito acerca de ello; aquí podéis encontrar una breve descripción del ciclo de vida de las consultas en SQL Server, y aquí podéis leer sobre la opción de optimización para cargas de trabajo AdHoc en SQL Server 2008.

Sin embargo, creo que nunca he explicado como procedo a estudiar el estado de salud de la cache de planes de ejecución y procedimientos almacenados, así que espero redimirme un poquito con esta entrada.

NOTA: En esta entrada no voy a explicar el qué son las consultas AdHoc, ni el por qué pueden resultar perniciosas desde el punto de vista del rendimiento. Para esta explicación os recomiendo revisar los dos enlaces que os he puesto un poco más arriba. En esta ocasión solo me centraré en el proceso de estudio de estas consultas.

Vistazo General

Una de las maneras más rápidas y cómodas de comprobar si tenemos una elevada presencia de consultas AdHoc en el sistema es mediante los informes del SQL Server Management Studio (SSMS).

Aunque parezca mentira, voy a dedicar un par de párrafos y capturas de pantalla a detallar como localizar estos informes. Con el paso de los años y las charlas es ido aprendiendo que, curiosamente, estos informes son tan potentes como desconocidos. Lo más habitual es que más de la mitad de los asistentes a mis sesiones desconozcan la existencia de los mismos, por lo que aprovecho para presentarlos a quienes aún no los conozcáis.

Dentro de la interfaz del SSMS, y más concretamente, en el menú pop-up (el del botón derecho del ratón) de todos los nodos del Object Explorer, tenemos una opción llamada Reports.

image

Esta opción es contextual: vamos a tener informes a nivel de instancia, a nivel de base de datos, de usuarios, etc. Evidentemente, hay ciertos tipos de nodos que no tienen ningún informe predefinido, pero siempre podríamos crearnos informes personalizados incluso para los nodos vacíos; son simples ficheros RDLC.

Si bien en esta caso solo vamos a trabajar con un informe concreto, os recomiendo encarecidamente que os deis una vuelta por los informes que vienen predefinidos (Standard Reports), y especialmente por los definidos sobre el nodo de instancia y los definidos sobre los nodos de bases de datos específicas.

En esta caso concreto, nos interesa un informe llamado Server Dashboard, que se encuentra a nivel de instancia. Por tanto, para llegar a él, pinchamos con el botón derecho sobre el nodo de la instancia. Ahí vámos a Reports –> Standard Reports –> Server Dashboard.

NOTA: Esto habituado a trabajar con la versión del producto en inglés, por lo que me vais a perdonar que los pantallazos estén en este idioma, y que no realice las traducciones pertinentes.

image

Como su propio nombre indica, este informe nos muestra un vistazo general del servidor, con la configuración del mismo, versiones del producto, detalles de actividad, etc. Y, cómo no, también nos deja ver un par de gráficas de tarta que alegran el informe con su vivos colores :P

Estas gráficas muestran el porcentaje de utilización de CPU y de E/S por parte de cada una de las bases de datos del sistema, algo bastante útil para detectar si alguna de las bases de datos está monopolizando los recursos del sistema.

A continuación os muestro, a modo de ejemplo, un pantallazo del informe en mi máquina local:

image

Si os fijáis, las tareas que más CPU están empleando en mi entorno no son relacionadas con ninguna de las bases de datos presentes (msdb, PerfDW, ReportServer y db_ProcedimientosAdministrativos), sino con tareas AdHoc.

Como podéis ver, un rápido vistazo a este informe nos muestra que podríamos estar experimentando un problema de consultas AdHoc en el sistema, ya que el consumo de CPU de las consultas AdHoc muy es elevado. ¿Quiere esto decir que si en la gráfica no aparece un gran consumo de CPU o E/S por consultas AdHoc, estamos libres del problema?

… pues va a ser que no :)

Cierto es… aunque tengamos muy poca presencia de consultas AdHoc en el diagrama, es posible que las consultas de este tipo sean un problema en nuestro sistema. Desde aquí, haciendo un pequeño esfuerzo, puedo escuchar vuestras voces de incredulidad en la distancia:

- ¡¿Cómo es posible?! (…se oyen las voces desde más alla del Manzanares…)
- Das ist Unglaublich!! (…algun avezado lector desde la puerta de Brandemburgo…)
- Cómo ye, ¡ho! (…estremecedores palabras que oigo entre Mieres y La Moreda…)

¡Muy fácil! Puede ser que el sistema tenga miles de consultas AdHoc, muy livianas, cuya ejecución no es costosa ni en CPU ni en E/S, pero sin embargo genera presión por recompilación, etc.

Entrando en Detalle

Vale, ya sabemos que puede ser necesario investigar un poco más ¿Cómo podemos hacerlo? Yo recomiendo empezar por comparar el ratio entre consultas AdHoc y consultas No AdHoc. A continuación os pongo un ejemplo capturado de un cliente en el que he estado recientemente:

SELECT
   COUNT(*)
FROM sys.dm_exec_cached_plans
WHERE objtype LIKE 'Adhoc'

En el caso concreto de este servidor, esta consulta ha devuelto 15636 planes adhoc. ¡No es precisamente un número pequeño de planes de ejecución en la cache! Vamos a ver ahora cuantos planes de ejecución no adhoc hay en la cache:

SELECT
   COUNT(*)
FROM sys.dm_exec_cached_plans
WHERE objtype NOT LIKE 'Adhoc'

La consulta anterior nos indica que hay 706 planes de ejecución de consultas no AdHoc. Evidentemente, el ratio entre unas y otras es extremadamente preocupante, y signo evidente de que el sistema está generando constantemente consultas AdHoc.

NOTA: Es difícil dar reglas a seguir en estos casos, pero generalmente puedo decir que si detecto que más del 30% de las consultas de la cache son de tipo AdHoc, considero que hay un problema que investigar respecto a la generación y parametrización de las consultas.

El siguiente paso sería detectar la memoria empleada en planes reutilizados, y en planes no reutilizados, y catalogarlos apropiadamente. En este caso yo utilizo un script, basado en el excelente trabajo de Davide Mauri, que me viene de perlas en estos casos:

WITH Planes AS
(
    SELECT
        Reutilizado = CASE
                        WHEN usecounts > 1 THEN 'Plan Reutilizado (Mb)'
                        ELSE 'Plan No Reutilizado (Mb)'
                      END,
        size_in_bytes AS [Tamaño (Mb)],
        cacheobjtype AS TipoObjetoCache,
        objtype AS Tipo
    FROM
        sys.dm_exec_cached_plans
),
Agregado AS
(
    SELECT
        Reutilizado,
        Tipo,
        TipoObjetoCache,
        [Tamaño (Mb)] = SUM([Tamaño (Mb)] / 1024. / 1024.)
    FROM
        Planes
    GROUP BY
        Reutilizado,
        TipoObjetoCache,
        Tipo
),
Pivote AS
(
    SELECT *
    FROM
        Agregado a
        PIVOT
        ( SUM([Tamaño (Mb)]) FOR Reutilizado IN ([Plan Reutilizado (Mb)], [Plan No Reutilizado (Mb)]) ) p
)
SELECT
    Tipo,
    TipoObjetoCache,
    [Tamaño Reutilizado (Mb)] = SUM([Plan Reutilizado (Mb)]),
    [Tamaño No Reutilizado (Mb)] = SUM([Plan No Reutilizado (Mb)])
FROM
    Pivote
GROUP BY
    Tipo,
    TipoObjetoCache
    WITH ROLLUP
HAVING
    (Tipo IS NULL AND TipoObjetoCache IS NULL ) OR
    (Tipo IS NOT NULL AND TipoObjetoCache IS NOT NULL )

Volviendo al caso de mi cliente, la ejecución de esta consulta devolvió los siguientes resultados:

image

Como podéis comprobar, en este caso el tamaño no reutilizado es casi similar al listado para los planes reutilizados, lo cual es otro indicativo claro de que hay un gran problema de no reutilización de planes de ejecución debido a consultas AdHoc mal parametrizadas.

Después de comprobar que realmente estamos sufriendo el problema ¿cual sería mi siguiente paso? Pues el más divertido de todos… ¡buscar al culpable! ;)

Para ello, buscaría las consultas que aparecen en la cache, de tipo AdHoc, y cruzaría la vista con la funcion sys.dm_exec_sql_text para poder sacar el texto de la SQL a partir del handle:

SELECT
   refcounts,
   size_in_bytes,
   cacheobjtype,
   text
FROM
   sys.dm_exec_cached_plans
   CROSS APPLY sys.dm_exec_sql_text(plan_handle)
WHERE objtype LIKE 'Adhoc'

Os muestro una salida parcial para que veais el problema (sin mostrar toda la consulta y revelar parte del modelo de datos de mi cliente, evidentmente):

image

Como se puede ver, las consultas son iguales, variando exclusivamente en los parámetros; el hecho de que sigan recompilandose y no se reutilicen es significativo, y un potencial problema de rendimiento (como ya se comentó en los otros posts).

¡Ya tenemos nuestros culpables! ¡¡Yeah!!

Resumiendo

A modo de resumen, yo abordaría el estudio del siguiente modo:

  1. Revisión del informe Server Dashboard para buscar presencia de consultas AdHoc
  2. Consulta sobre sys.dm_exec_cached_plans para ver el ratio AdHoc/No AdHoc
  3. Consulta para ver la memoria fugada en planes no reutilizados
  4. Si procede, revisar las consultas problematicas.

Fácil, sencillo y para toda la familia :)

Después de ver esta información, tendremos una buena idea de si estamos siendo víctimas de algún tipo de problema derivado de la presencia masiva de consultas AdHoc en nuestro sistema. Si fuera así, habrá que comprobar la presencia de consultas dinámicas sin preparar, consultas sin parametrizar desde el cliente, etc.

Espero que os haya resultado interesante la entrada, y os animo a que probéis en vuestros servidores SQL Server: ¡seguro que más de uno de vosotros se lleva una sorpresa!

Rock Tip:

Los últimos rock tips, si bien han sido temazos, se han alejado un poco de mi corazoncito hardrockero ochentero, así que es buen momento de retomarlo. Y para ocasiones especiales, nada mejor que los grandísimos glam-metaleros noruegos Wig Wam.

Representantes de su país en el festival de Eurovisión de 2005, con el temazo ‘In My Dreams’, en esta ocasión nos quedamos con su balada ‘Tell Me Where To Go’ para acompañar este post.

A todo esto, apuntaros esta fecha en vuestros calendarios: 18 de Septiembre de 2010. Ese será el día que los chicos de WigWam nos visitarán en Madrid por primera vez, en la sala Ritmo y Compás ¡No creí que mis ojos fueran a ver esto! Ya solo queda ver por estas tierras a Steel Panther y seré un hombre plenamente feliz :)

Posted: 27/7/2010 17:39 por Pablo Alvarez | con 6 comment(s) |
Archivado en: ,
Comparte este post:

Comentarios

Juan Irigoyen ha opinado:

Excelente Pablo, estoy chequeando mis BD, y la mayoría hacen uso intensivo de consultas adhoc, desgraciadamente en los programas comerciales tan solo podemos forzar a que el servidor las intente optimizar.

Por cierto disfrute mucho de tu charla.

Un saludo.

# July 28, 2010 12:09 PM

Pablo Alvarez ha opinado:

Gracias Juan!

A ver si volvemos a coincidir en algun evento pronto... quizá el de Anuar (*guiño*, *guiño*)

Precisamente ahora mismo estoy en un cliente tratando de cambiar su código dinámico para que las consultas se parametricen correctamente; tengo un único procedimiento almacenado que ahora mismo tiene unos 14000 planes en la cache!

...por estas cosas adoro mi trabajo! :)

En el caso de que tu código sea mayoritariamente de terceros, prueba con la optimizacion para consutlas AdHoc o a forzar la autoparametrización y cuentanos que tal te fue!

un abrazo!

# July 28, 2010 12:31 PM

Pepof ha opinado:

Un artículo magnífico. ¡Muchas gracias!.

# July 28, 2010 6:24 PM

Pablo Alvarez ha opinado:

¡¡Gracias a ti, Pepof, por leerlo!!

# July 28, 2010 9:38 PM

pregunton cojonero ha opinado:

un post de cómo generar un volcado programáticamente en c# estaría muy bien !!!

# August 26, 2010 2:41 PM

Surviving the Night ha opinado:

Me alegra comprobar que, al parecer, el pequeño reto que nos traemos Unai y yo está provocando cierto

# November 22, 2011 8:23 PM