Estoy configurando un sistema de monitoreo para SQL Server usando Extended Events para encontrar consultas pesadas como 'comentarios de producción' para nuestros desarrolladores. Estoy usando los eventos sp_statement_completed
y sql_statement_completed
, con filtros de predicado en cpu_time, lecturas lógicas, etc. Esperaba agregar los resultados database_name
y query_hash
como se demostró en numerosos ejemplos en todo Internet, pero en los resultados veo que query_hash
es 0 para todas las declaraciones usando EXEC, como en la tabla a continuación (marca de tiempo y consulta abreviada para facilitar la lectura).
name timestamp query_hash plan_handle statement
sql_statement_completed 2016...6414 0 050056019600764... exec Shared.dbo.SyncFirm
sql_statement_completed 2016...9946 0 06003d00e01e730... exec spSetUserAuth @userid;
sql_statement_completed 2016...7184 0 0600e30028c9da0... exec spSetUserAuth @userid;
sp_statement_completed 2016...0409 9826...578 0600c00028e6aa0... SELECT obfuscated_columns FROM dbo.SomeTable
sp_statement_completed 2016...1448 8660...775 060084006d2d660... INSERT INTO dbo.SomeTable ( obfuscated_columns) EXEC(@sql)
sql_statement_completed 2016...7752 0 0600f9006c23f03... exec spSetUserAuth @userid;
sql_statement_completed 2016...1443 1304...641 06005a0008a9b11... select SUBQ.ontrackstatus, COUNT(SUBQ.ontrac
Todos los resultados tienen un valor plan_handle
y todos son diferentes, por lo que se están generando muchos planes. Otras declaraciones sin query_hash
(que he visto) incluyen ALTERAR ÍNDICE, PUNTO DE CONTROL, ACTUALIZAR ESTADÍSTICAS, TRANSACCIÓN DE COMPROMISO, RECIBIR SIGUIENTE DEL Cursor, algunas INSERTAS, SELECCIONAR @variable, SI (@variable = x).
¿Alguien sabe por qué el query_hash
es 0? Probablemente me estoy perdiendo el punto en algún lugar sobre el Analizador de consultas SQL y EXEC, pero no puedo encontrar ninguna pista que me señale en la dirección correcta. Si los resultados que estoy obteniendo son 'normales', entonces, ¿cómo agregar mejor los resultados? ¿La agrupación por declaración no incluiría literales, espacios en blanco, etc., que se eliminan al calcular query_hash?
EDITAR: como lo veo ahora, EXEC SomeStoredProcedure
inicia un procedimiento almacenado (obvio), y las declaraciones individuales en ese procedimiento almacenado terminan en la sesión de sp_statement_completed
eventos como eventos, y todos tienen un query_hash.
Entonces, para sp_statement_completed
(es decir, consultas 'reales'), puedo agregar en query_hash y database_name, y sql_statement_completed
sin query_hash (el EXEC SomeStoredProcedure), puedo usar el client_connection_id
para agrupar las declaraciones dentro de una ejecución específica de un procedimiento almacenado, para ver qué es lo más parte costosa del procedimiento.
fuente
query_hash
es 0, pero en cuanto a por qué lasexec spSetUserAuth @userid;
filas tienen diferentes identificadores de plan:The algorithms to match new SQL statements to existing, unused execution plans in the cache require that all object references be fully qualified.
( Fuente ). Si todas esas entradas fueranexec dbo.spSetUserAuth @userid;
, por ejemplo , podría obtener identificadores de plan idénticos para ellos.Respuestas:
Para explicar por qué se crea el hash:
Cuando enviamos una consulta al servidor, el proceso de algebrizer (sí, así se llama) crea un hash, como una firma codificada, de la consulta. El hash es un identificador único. Un identificador es único para cualquier consulta, incluido todo el texto que define la consulta, incluidos los espacios y los retornos de carro, el optimizador compara el hash con las consultas en la memoria caché. Si existe una consulta en la memoria caché que coincide con la consulta que ingresa al motor, se omite todo el costo del proceso de optimización y se reutiliza el plan de ejecución en la memoria caché del plan.
EXEC
inicia un procedimiento almacenado que puede tener su cambio de código, ya que SQL Server sabe que no necesita compararEXEC
para optimizarlo, SQL Server no crea un hash.fuente