Estoy luchando por minimizar el costo de la operación de clasificación en un plan de consulta con la advertencia Operator used
tempdbto spill data during execution with spill level 2
He encontrado varias publicaciones relacionadas con los datos de derrames durante la ejecución con el nivel de derrame 1 , pero no el nivel 2. El nivel 1 parece ser causado por estadísticas desactualizadas , ¿qué pasa con el nivel 2? No pude encontrar nada relacionado con level 2
.
Este artículo me pareció muy interesante en relación con las advertencias de clasificación:
Nunca ignore una advertencia de clasificación en SQL Server
Mi servidor SQL?
Microsoft SQL Server 2014 (SP2) (KB3171021) - 12.0.5000.0 (X64) 17 de junio de 2016 19:14:09 Copyright (c) Microsoft Corporation Enterprise Edition (64 bits) en Windows NT 6.3 (Build 9600:) (Hypervisor)
Mi hardware
ejecutando la consulta a continuación para encontrar el hardware:
- Información de hardware de SQL Server 2012
SELECT cpu_count AS [Logical CPU Count], hyperthread_ratio AS [Hyperthread Ratio],
cpu_count/hyperthread_ratio AS [Physical CPU Count],
physical_memory_kb/1024 AS [Physical Memory (MB)], affinity_type_desc,
virtual_machine_type_desc, sqlserver_start_time
FROM sys.dm_os_sys_info WITH (NOLOCK) OPTION (RECOMPILE);
memoria asignada actualmente
SELECT
(physical_memory_in_use_kb/1024) AS Memory_usedby_Sqlserver_MB,
(locked_page_allocations_kb/1024) AS Locked_pages_used_Sqlserver_MB,
(total_virtual_address_space_kb/1024) AS Total_VAS_in_MB,
process_physical_memory_low,
process_virtual_memory_low
FROM sys.dm_os_process_memory;
Cuando ejecuto mi consulta con un año de alcance, no recibo ninguna advertencia, según la imagen a continuación:
Pero cuando lo ejecuto solo durante 1 día, recibo esta advertencia on the sort operator
:
Esta es la consulta:
DECLARE @FromDate SMALLDATETIME = '19-OCT-2016 11:00'
DECLARE @ToDate SMALLDATETIME = '20-OCT-2016 12:00'
SELECT DISTINCT
a.strAccountCode ,
a.strAddressLine6 ,
a.strPostalCode ,
CASE WHEN a.strCountryCode IN ('91','92') THEN 'GB-Int'
ELSE a.strCountryCode
END AS [strCountryCode]
FROM Bocss2.dbo.tblBAccountParticipant AS ap
INNER JOIN Bocss2.dbo.tblBAccountParticipantAddress AS apa ON ap.lngParticipantID = apa.lngParticipantID
AND apa.sintAddressTypeID = 2
INNER JOIN Bocss2.dbo.tblBAccountHolder AS ah ON ap.lngParticipantID = ah.lngParticipantID
INNER JOIN Bocss2.dbo.tblBAddress AS a ON apa.lngAddressID = a.lngAddressID
AND a.blnIsCurrent = 1
INNER JOIN Bocss2.dbo.tblBOrder AS o ON ap.lngParticipantID = o.lngAccountParticipantID
AND o.sdtmOrdCreated >= @FromDate
AND o.sdtmOrdCreated < @ToDate
OPTION(RECOMPILE)
el plan de consulta usando pastetheplan
Preguntas: 1) en el plan de consulta veo esto:
StatementOptmEarlyAbortReason="GoodEnoughPlanFound" CardinalityEstimationModelVersion="70"
¿Por qué 70? Estoy usando el servidor sql 2014
2) ¿cómo me deshago de ese operador de clasificación (si es posible)?
3) He visto que la expectativa de vida de la página es bastante baja, además de agregar más memoria a este servidor, ¿hay algo más que pueda ver para ver si puedo evitar esta advertencia?
salud
Actualización después de la respuesta de Shanky y Paul White
Verifiqué mis estadísticas de acuerdo con el siguiente script, y parecen todas correctas y actualizadas.
Estos son todos los índices y tablas utilizados en esta consulta.
DBCC SHOW_STATISTICS ('dbo.tblBAddress','IDXF_tblBAddress_lngAddressID__INC')
GO
DBCC SHOW_STATISTICS ('dbo.tblBOrder','IX_tblBOrder_sdtmOrdCreated_INCL')
GO
DBCC SHOW_STATISTICS ('dbo.tblBAccountHolder','PK_tblAccountHolder')
GO
DBCC SHOW_STATISTICS ('dbo.tblBAccountParticipant','PK_tblBAccountParticipants')
GO
DBCC SHOW_STATISTICS ('dbo.tblBAccountParticipantAddress','IDXF_tblBAccountParticipantAddress_lngParticipantID')
GO
esto es lo que me devolvieron:
Este es un resultado parcial, pero los he vuelto a visitar a todos.
Para la actualización de estadísticas actualmente tengo Ola Hallengren
the Index Optimize Job - programado para ejecutarse una vez a la semana - domingos
EXECUTE [dbo].[IndexOptimize]
@Databases = 'USER_DATABASES,-%Archive',
@Indexes = 'ALL_INDEXES' ,
@FragmentationLow = NULL,
@FragmentationMedium = NULL,
@FragmentationHigh = NULL,
@PageCountLevel=1000,
@StatisticsSample =100
,@UpdateStatistics = 'Index',
@OnlyModifiedStatistics = 'Y',
@TimeLimit=10800,
@LogToTable = 'Y'
Aunque las estadísticas parecían estar actualizadas Después de ejecutar el siguiente script, no recibí más advertencias sobre el operador de clasificación.
UPDATE STATISTICS [Bocss2].[dbo].[tblBOrder] WITH FULLSCAN
--1 hour 04 min 14 sec
UPDATE STATISTICS [Bocss2].[dbo].tblBAddress WITH FULLSCAN
-- 45 min 29 sec
UPDATE STATISTICS [Bocss2].[dbo].tblBAccountHolder WITH FULLSCAN
-- 26 SEC
UPDATE STATISTICS [Bocss2].[dbo].tblBAccountParticipant WITH FULLSCAN
-- 4 min
UPDATE STATISTICS [Bocss2].[dbo].tblBAccountParticipantAddress WITH FULLSCAN
-- 7 min 3 sec
fuente
Respuestas:
Según este viejo documento de MS, el número en el derrame de Tempdb significa cuántos pases se requieren sobre los datos para ordenarlos. Entonces, el Derrame 1 significa que tiene que pasar 1 vez para ordenar los datos y 2 significa que tiene que pasar 2 veces.
Citando del blog:
Esto se debe a que el nivel de compatibilidad de la base de datos en la imagen NO es 120 (lo que significa el nivel de compatibilidad de la base de datos 2014) ya que no es 120, la consulta se procesará utilizando el antiguo modelo de estimación de cardinalidad (CE) que se conoce como
CardinalityEstimationModelVersion="70"
. Estoy seguro de que sabe que desde SQL Server 2014 tenemos un nuevo CE.El comando distinto que está utilizando está causando la operación de clasificación. Los datos que se están ordenando no caben en la memoria, por lo que se derraman a tempdb y, cuando esto sucede, se da una advertencia de clasificación con un signo de exclamación amarillo en el plan de ejecución. Las advertencias de clasificación no siempre son un problema.
Puede ver en el plan de ejecución que el número estimado de filas a ordenar es 1, pero se encuentran 16,353 en tiempo de ejecución. La cantidad de memoria reservada para la ordenación se basa en el tamaño esperado (estimado) de la entrada y no puede crecer durante la ejecución (en este caso).
La pequeña concesión de memoria para la consulta (1632 KB) también se reparte entre los operadores consumidores de memoria que se ejecutan simultáneamente (clasificación y uniones de bucle 'optimizadas' ). En su plan, eso significa que 33.33% (544KB) está disponible para la clasificación mientras lee filas (fracción de memoria de entrada). Esto no es suficiente memoria para ordenar las 16.353 filas, por lo que se derrama a tempdb . Un derrame de un solo nivel no es suficiente para completar la clasificación, por lo que se necesita un segundo nivel de derrame (consulte la referencia al final para obtener más detalles sobre los niveles de derrame).
Ordenar propiedades como se ve en el Explorador de planes de SQL Sentry
La actualización de las estadísticas probablemente ayudará con el problema de la estimación de la cardinalidad. Puede estar experimentando el problema de la clave ascendente, especialmente en la mesa
tblBOrder
. Una simple selección de esa tabla con las fechas literales de su pregunta probablemente estimará una fila en este momento.PLE es indicación de la cantidad de actividad de E / S, ¿ha aumentado? Entonces, ¿esto sucede a menudo o solo cuando ejecuta cierta consulta o ha ocurrido esto hoy? Evite la reacción instintiva, primero debemos asegurarnos de que realmente se enfrenta a una presión de memoria o alguna consulta maliciosa que genera demasiada E / S está causando esto. De todos modos, ya tiene 97 G de memoria asignada a SQL Server.
Para obtener más información sobre los niveles de derrame y el problema clave ascendente, consulte:
fuente