¿Cómo puedo eliminar un plan de ejecución incorrecto de Azure SQL Database?

12

DBCC FREEPROCCACHEno funciona en Azure SQL DB. ¿De qué otra manera puedo forzar un plan para que salga del caché de una manera que no perjudique a un sistema de producción (es decir, no puedo simplemente alterar las tablas de todas formas)? Esto es específicamente para SQL creado por Entity Framework, por lo que estos no son procesos almacenados autogestionados, es efectivamente SQL dinámico.

(La fuente era índices malos -> estadísticas malas, etc. Eso está todo arreglado, pero un mal plan no desaparecerá).

ACTUALIZACIÓN: Seleccioné la solución de @ mrdenny cuando llegó allí primero. Sin embargo, estoy usando con éxito el script de @Aaron Bertrand para realizar el trabajo. ¡Gracias a todos por la ayuda!

Jaxidian
fuente
¿Se puede hacer una sp_recompile en Azure?
mrdenny
Si. ¿En qué lo ejecutaría exactamente? No tenemos procesos almacenados. Esto es dinámico SQL se ejecutó sp_executesql.
Jaxidian
2
Puede ejecutarlo sobre la mesa y eso debería eliminar los planes que usan esa tabla. (Si esto funciona, lo responderé)
Mrdenny
1
Acabo de probar esto en una mesa y aparentemente bloquea la mesa en una transacción mientras se procesa. Lo probé en una tabla de 10 columnas con solo 24 registros y me llevó más de un minuto terminar. Durante este tiempo, no pude consultar la tabla. ¡No puedo ejecutar algo así en nuestras mesas reales en Producción!
Jaxidian
1
Maldición, eso es un fastidio. Parece que tendrá que hacer un cambio de esquema como agregar una columna anulable y luego soltarla. Eso también borrará el caché y debería ser rápido. Las pruebas lo dirán con seguridad.
mrdenny

Respuestas:

12

Azure SQL ahora admite directamente esto

Azure SQL Database admite directamente la eliminación de la caché de proceso de la base de datos del usuario actual sin ningún tipo de piratería:

ALTER DATABASE SCOPED CONFIGURATION CLEAR PROCEDURE_CACHE;

Información Adicional

El siguiente script (de Shannon Gowen ) se puede usar para ver el proceso paso a paso:

-- run this script against a user database, not master
-- count number of plans currently in cache
select count(*) from sys.dm_exec_cached_plans;

-- Executing this statement will clear the procedure cache in the current database, which means that all queries will have to recompile.
ALTER DATABASE SCOPED CONFIGURATION CLEAR PROCEDURE_CACHE;

-- count number of plans in cache now, after they were cleared from cache
select count(*) from sys.dm_exec_cached_plans;

-- list available plans
select * from sys.dm_exec_cached_plans;
Todd Menier
fuente
Todavía no lo he intentado, pero si de hecho es funcional, esta es probablemente la "mejor" respuesta a principios de 2017. Gracias por esto, ¡no tenía idea de que estaba allí! :-)
Jaxidian
He intentado esto (en un Premium DB) y funcionó.
Remi Lemarchand
He marcado esto como una "Respuesta aceptada" actualizada, pero todavía no lo he probado. Estoy basando esto directamente en los comentarios de Todd y Remi. ¡Gracias a todos!
Jaxidian
¡Solo para volver a visitarlo, he usado esto y funcionó bien para mí! Estoy agregando algunos guiones adicionales a la respuesta de Todd aquí para enriquecerlo, pero su publicación dio en el clavo.
Jaxidian
Esto no parece funcionar para mí, solo se ejecuta, pero las listas aún están llenas. Estoy en SQL Azure. ¿Qué puede estar mal?
Dirk Boer
12

No hay una forma explícita de hacer esto hoy, pero ese no es un escenario permanente (el comando DBCC todavía no es compatible, pero se lee en el Almacén de consultas ). Incluso cuando el golpe de cambio de esquema es aceptable, puede que no sea lo que desea, porque invalidará todos los planes relacionados con el objeto subyacente, no solo el malo.

No busco crédito para esto, pero construir SQL dinámico para realizar la misma operación en varias tablas es bastante fácil:

DECLARE @sql NVARCHAR(MAX) = N'';

SELECT @sql += N'ALTER TABLE '
  + QUOTENAME(SCHEMA_NAME([schema_id])) 
  + '.' + QUOTENAME(name) + ' ADD fake_column INT NULL;
  ALTER TABLE ' 
  + QUOTENAME(SCHEMA_NAME([schema_id]))
  + '.' + QUOTENAME(name) + ' DROP COLUMN fake_column;'
FROM sys.tables
--WHERE name IN, LIKE, etc.

PRINT @sql;

-- if the command > 8K, you can see the second chunk e.g.

PRINT SUBSTRING(@sql, 8001, 8000);

--EXEC sys.sp_executesql @sql;

(Escribí un consejo sobre este problema de "longitud de SQL dinámico" ...)

Aaron Bertrand
fuente
En mi caso, eliminarlos todos es mucho mejor que dejar a los malos allí. Gracias por el aviso. Sé que no puedes decirme las características, pero ¿puedes decirme cuándo ya no estarás restringido para hablar sobre cosas de las que no puedes hablar? ;-)
Jaxidian
Eso también está clasificado, lo siento. :-)
Aaron Bertrand
No estoy seguro de lo que quieres decir con el enlace. Lo que quise decir es que su nvarchar(max)variable alcanza un límite después de 4000 caracteres, 8000 caracteres si lo cambio a varchar(max). Ejecutando ese script exacto. Tenemos ~ 450 mesas, por lo que acertamos fácilmente (~ 30/60 tablas). varchar(max)es una sintaxis válida, es idéntica varchar(8000)y nvarchar(max)idéntica a nvarchar(4000).
Jaxidian
3
Bueno, sí, cuando PRINTel comando, solo muestra 8000 bytes. Esa es una limitación del PRINTcomando, no Azure. Si ejecuta el comando, funcionará incluso si no puede inspeccionar visualmente todo.
Aaron Bertrand
... doh, lo siento, creo que tienes razón! ¡Gracias por corregirme! Eso es lo que sucede cuando tu esposa esperaba que te fueras hace 25 minutos ... ;-) ¡Este script funciona perfectamente para mí!
Jaxidian
6

Agregue una columna anulable a la tabla y luego suelte la columna. Eso obligará a SQL a vaciar el caché para ese objeto.

En cuanto a hacer todas las tablas, un cursor debería hacer el truco. Simplemente use un nombre de columna que nunca existirá en ninguna tabla como 'zzzzzz_go_away' o algo así.

mrdenny
fuente
4

Azure SQL Database actualmente no es compatible DBCC FREEPROCCACHE, por lo que no puede eliminar manualmente un plan de ejecución del caché. Sin embargo, si realiza cambios en una tabla o vista a la que hace referencia la consulta ( ALTER TABLE/ ALTER VIEW), el plan se eliminará de la memoria caché. ( Referencia )

Kin Shah
fuente
Ya sabía todo lo que publicaste aquí. Este no es un procedimiento almacenado ni una vista, por lo que no puedo modificar uno de esos. ¿Cómo podría modificar mis tablas de manera insignificante, bajo carga y sin causar ningún tiempo de inactividad o bloqueo de la tabla, para activar esto?
Jaxidian
1
Posiblemente puede agregar una columna ficticia y luego soltarla. Esto eliminará el plan del caché. ¿Qué tan grande es la mesa?
Kin Shah
Esa terminó siendo la solución, según lo recomendado por @mrdenny. ¡¡Gracias por la ayuda!! :-)
Jaxidian
1
Gracias ... Solo unos segundos en poco tiempo ... Estaba respondiendo alguna otra publicación en stackexchange ...
Kin Shah
1

Para borrar todo el plan de ejecución, use esto:

    SET NOCOUNT ON

DECLARE @lcl_name VARCHAR(100)
DECLARE @addcolumnSql nVARCHAR(MAX)
DECLARE @dropcolumnSql nVARCHAR(MAX)

DECLARE cur_name CURSOR FOR
SELECT name
FROM sysobjects
WHERE type = 'U'
OPEN cur_name
FETCH NEXT FROM cur_name INTO @lcl_name
WHILE @@Fetch_status = 0
BEGIN
set @addcolumnSql = 'alter table [' + @lcl_name + '] add temp_col_to_clear_exec_plan bit'
EXEcute sp_executesql @addcolumnSql
print @addcolumnSql
set @dropcolumnSql = 'alter table [' + @lcl_name + '] drop column temp_col_to_clear_exec_plan'
EXEcute sp_executesql @dropcolumnSql
print @dropcolumnSql
--  EXEC (@lcl_name )
FETCH NEXT FROM cur_name INTO @lcl_name
END
CLOSE cur_name
DEALLOCATE cur_name
SET NOCOUNT OFF

Si modifica una tabla o una vista que hace referencia a ella, el plan de ejecución se borra.

Un poco más explicado aquí http://christianarg.wordpress.com/2013/08/22/remove-execution-plans-from-the-procedure-cache-in-sql-azure/

cristiano
fuente