2010-02-03 11 views
9

Cuando estoy probando una consulta, generalmente coloco las siguientes líneas delante de lo que estoy probando para asegurarme de que empiezo desde la misma línea base cada vez que ejecuto una consulta.Caché de cebado o calentamiento en SQL Server

CHECKPOINT 
GO 
DBCC FREEPROCCACHE 
GO 
DBCC DROPCLEANBUFFERS 
GO 
EXEC sp_MyProc 12345 

En el procedimiento almacenado que estaba corriendo hoy me di cuenta de que cuando me encontré con estas líneas que tomó Aproximadamente 18 minutos cada vez. Cuando dejé estas líneas solo tardé 3. Al ver la drástica diferencia causada por tener un caché borrado frente a un caché preparado, decidí agregar lo siguiente para ver si podía preparar el caché manualmente antes de ejecutar mi proceso y ver qué hacía eso. actuación.

CHECKPOINT 
GO 
DBCC FREEPROCCACHE 
GO 
DBCC DROPCLEANBUFFERS 
GO 
SELECT top 1 '1' from Table1 
EXEC sp_MyProc 12345 

Como puede haber adivinado sp_MyProc utiliza Table1 un poco. Me sorprendió descubrir que al hacer esto, mi tiempo de ejecución se redujo a aproximadamente 6 minutos constantemente. Aunque mejora el rendimiento, parece un poco hackish, y tengo curiosidad de saber si hay algo integrado en SQL Server que logre esto.

  • está haciendo esto para mejorar el rendimiento de las consultas no escuchadas de ?
  • ¿Estoy incluso en lo cierto al suponer que la mejora en el tiempo que vi fue el resultado de un caché "imprimado"?

Si mi comprensión del almacenamiento en caché es un poco apagado, siéntase libre de compartir cualquier enlace o información que considere útil.

ACTUALIZACIÓN: Bueno, me da vergüenza decir que traté de reproducir este comportamiento hoy, pero no pude. Hablé con algunas personas en mi trabajo y parece que algunas de las cosas que estaban haciendo en el DB ayer pueden haber hecho parecer que mi selección antes del proceso mejoraba el rendimiento cuando en realidad no era así. Todavía estaría interesado en saber si alguien sabe si es posible "preparar" el caché.

+0

+1 Buena pregunta, aunque me sorprende que la selección pre TOP 1 haya hecho alguna diferencia, ya que no habría pensado que realmente habría cargado datos relevantes en el caché que sp_MyProc necesita. – AdaTheDev

+0

He estado jugando con esto y no puedo reproducir el comportamiento. La única diferencia entre todo lo que he intentado es el número de lecturas de lectura anticipada realizadas (cuando no borra los búferes limpios), pero los tiempos son consistentemente los mismos. Mi tabla de muestra tiene 4.000,000 filas. ¿Podría ser algo relacionado con los índices? Mi tabla de muestra tiene varios índices (tanto exclusivos como exclusivos), así como una clave principal agrupada. – adrianbanks

Respuesta

3

Proporcionar una "respuesta" con el fin de tratar de trabajar a través de este ya que esto es algo que estoy particularmente interesado en.

me encontré con this artículo de MSDN sobre la forma de ver lo que está en la caché de SQL Server. hay una consulta hay que le mostrará el número de páginas de datos se almacenan en caché por objeto - que he pellizcado que acaba de incluir el nombre del índice de la siguiente manera:

SELECT count(*) AS cached_pages_count, obj.name, index_id, i.name AS IndexName 
FROM sys.dm_os_buffer_descriptors AS bd 
    INNER JOIN 
    (
     SELECT object_id, object_name(object_id) AS name 
      ,index_id ,allocation_unit_id 
     FROM sys.allocation_units AS au 
      INNER JOIN sys.partitions AS p 
       ON au.container_id = p.hobt_id 
        AND (au.type = 1 OR au.type = 3) 
     UNION ALL 
     SELECT object_id, object_name(object_id) AS name 
      ,index_id, allocation_unit_id 
     FROM sys.allocation_units AS au 
      INNER JOIN sys.partitions AS p 
       ON au.container_id = p.partition_id 
        AND au.type = 2 
    ) AS obj 
     ON bd.allocation_unit_id = obj.allocation_unit_id 
    LEFT JOIN sysindexes i ON obj.object_id = i.id AND obj.index_id = i.indid 
WHERE database_id = db_id() 
GROUP BY obj.name, index_id, i.name 
ORDER BY cached_pages_count DESC; 

Si intenta los siguientes pasos, debe ser capaz de ver qué está pasando con respecto al almacenamiento en caché. Hacer estas dentro de su base de datos (a diferencia de, por ejemplo principal):

1) puesto de control + borrar la caché abajo
2) ejecutar la consulta arriba y usted debe conseguir probablemente obtendrá 1 registro devuelto (por sysobjvalues), pero nada de Tabla 1
3) ahora ejecute la instrucción SELECT TOP 1 '1' FROM MyTable
4) Vuelva a ejecutar la consulta anterior y ver lo que aparece en los resultados ahora - probablemente verá registro (s) de MiTabla mostrando las páginas en caché - tomar nota de ese número

Esto debería darle una indicación en cuanto al nivel de caché de datos que está sucediendo para ese SELECT inicial.Si repite el proceso otra vez pero en lugar de la sentencia SELECT TOP, ejecute su sproc y luego vea cuánto termina en la caché cuando se ejecuta, tal vez la comparación de estos resultados indique la cantidad relativa de caché que está realizando el SELECCIONE TOP 1 en comparación con la llamada sproc - y esa cantidad relativa podría indicar la mejora del rendimiento.

Esto es mucho "pensar en voz alta" cosas. No hubiera pensado que el TOP 1 realmente hubiera preparado el caché de forma significativa para la llamada sproc, ¡pero es por eso que estoy interesado en esta pregunta!

Al principio pensé que se trataba más de otros factores (por ejemplo, la carga del servidor/disco). Puede alternar entre los 2 escenarios para 3 o 4 iteraciones, una después de la otra, para verificar si el enfoque SELECCIONAR ARRIBA es de hecho consistentemente mejor (ayuda a minimizar el riesgo de que sea una falla única)

Espero que esto ayude/haga rodar la pelota.

Actualización:
Ahora se sabe que no es el SELECT TOP que ha cebado la caché, una buena manera de cebar la caché es como dijeron AdrianBanks. ¡Al menos ahora puedes explicar lo inesperado/confuso que es la diferencia de rendimiento! Mantenga la secuencia de comandos anterior en su biblioteca, es útil para verificar el estado de la memoria caché.

+0

Parece que pude haber estado equivocado al asumir que mis ganancias de rendimiento se debían a la selección. Echa un vistazo a la actualización de mi publicación. Gran post sin embargo. ¡Muy informativo! –

2

Su actualización de su pregunta coincide con lo que esperaría que sucediera. No veo cómo ejecutar la consulta SELECT 1... podría tener un beneficio de rendimiento real en la consulta siguiente.

Según tengo entendido, SQL Server carga las páginas de datos (que contienen datos de tabla o datos de índice) en la memoria cuando las necesita al ejecutar consultas. Estos se guardan en la memoria a menos que se eliminen explícitamente (usando DBCC DROPCLEANBUFFERS - es decir, elimine cualquier búfer (página almacenada en memoria caché) en la memoria que no se haya alterado desde que se cargó) o hay presión de memoria (poca memoria libre en la máquina o un máximo memoria establecida en SQL Server). Debido a este comportamiento, puede ser beneficioso calentar una base de datos de SQL Server para su uso. Cuando posteriormente ejecuta una consulta, es posible que los datos necesarios para recopilar los resultados de la consulta ya estén en la memoria. Si es así, la consulta se ejecutará más rápido, ya que incurrirá en menos IO.

El problema viene, sin embargo, en saber qué precaché y, por lo tanto, qué consultas ejecutar. Puede ejecutar un rastreo SQL en una actividad típica y luego reproducirlo en datos de precaché que se utilizan con frecuencia. Sin embargo, sin dejar que SQL Server contenga una gran cantidad de memoria asignada, siempre tendrá que leer algunas cosas desde el disco (a menos que tenga una pequeña base de datos). Como nunca sabrá qué se almacena en la memoria caché y qué no, confiar en este comportamiento para el rendimiento parece incorrecto.

Concentraría mis esfuerzos en hacer las consultas más eficientes, leyendo menos datos o usando índices cuando sea posible. Eso también le dará beneficios generales, así como un mejor rendimiento de los comienzos en frío.

0

Una forma de cebar la caché de SQL Server para los datos completos de tabla (o subconjuntos de los mismos) es ejecutar: SELECT SUM(CAST(BINARY_CHECKSUM(*) AS BIGINT)) FROM my_table

Esto hace que todas las columnas de una tabla para ser leído desde el disco, pero devuelve un resultado pequeño que puede ser incrementalmente calculado por SQL. El optimizador de SQL no lo hará si intenta utilizar COUNT o consultas similares para preparar el caché, ya que pueden responderse cargando solo páginas de índice.

Ajuste las columnas y agregue declaraciones de cláusula WHERE para almacenar en caché índices o subconjuntos de tablas como desee.

Cuestiones relacionadas