¿Es posible forzar al optimizador a eliminar tablas irrelevantes en esta vista particionada?


22

Estoy probando diferentes arquitecturas para tablas grandes y una sugerencia que he visto es usar una vista particionada, mediante la cual una tabla grande se divide en una serie de tablas "particionadas" más pequeñas.

1 , 2 , 3 , 4

Al probar este enfoque, descubrí algo que no tiene mucho sentido para mí. Cuando filtro en la "columna de partición" en la vista de hechos, el optimizador solo busca en las tablas relevantes. Además, si filtro en esa columna en la tabla de dimensiones, el optimizador elimina las tablas innecesarias.

Sin embargo, si filtro en algún otro aspecto de la dimensión, el optimizador busca en el PK / CI de cada tabla base.

Aquí están las consultas en cuestión:

select 
    od.[Year], 
    AvgValue = avg(ObservationValue)
from dbo.v_Observation o 
join dbo.ObservationDates od
    on o.ObservationDateKey = od.DateKey
where o.ObservationDateKey >= 20000101
    and o.ObservationDateKey <= 20051231
group by od.[Year];

select 
    od.[Year], 
    AvgValue = avg(ObservationValue)
from dbo.v_Observation o 
join dbo.ObservationDates od
    on o.ObservationDateKey = od.DateKey
where od.DateKey >= 20000101
    and od.DateKey <= 20051231
group by od.[Year];

select 
    od.[Year], 
    AvgValue = avg(ObservationValue)
from dbo.v_Observation o 
join dbo.ObservationDates od
    on o.ObservationDateKey = od.DateKey
where od.[Year] >= 2000 and od.[Year] < 2006
group by od.[Year];

filtro de hechos en clave

filtro tenue en la llave

filtro tenue en el aspecto

Aquí hay un enlace a la sesión de SQL Sentry Plan Explorer.

Estoy trabajando en particionar la tabla más grande para ver si obtengo la eliminación de la partición para responder de manera similar.

Obtengo la eliminación de particiones para la consulta (simple) que filtra un aspecto de la dimensión.

Mientras tanto, aquí hay una copia de la base de datos de solo estadísticas:

https://gist.github.com/swasheck/9a22bf8a580995d3b2aa

El "viejo" estimador de cardinalidad obtiene un plan menos costoso, pero eso se debe a las estimaciones de cardinalidad más bajas en cada una de las búsquedas de índice (innecesarias).

Me gustaría saber si hay una manera de hacer que el optimizador use la columna clave al filtrar por otro aspecto de la dimensión para que pueda eliminar búsquedas en tablas irrelevantes.

Versión de SQL Server:

Microsoft SQL Server 2014 - 12.0.2000.8 (X64) 
    Feb 20 2014 20:04:26 
    Copyright (c) Microsoft Corporation
    Developer Edition (64-bit) on Windows NT 6.3 <X64> (Build 9600: ) (Hypervisor)

Solo para su información ... la última transmisión de estadísticas está dañadaCREATE STATISTICS [_WA_Sys_00000008_2FCF1A8A] ON [dbo].[Observation_2010]([StationStateCode]) WITH STATS_STREAM = 0x01000000010000000000000000000000D4531EDB00000000D5080000000000009508000000000000AF030000AF000000020000000000000008D000340000000007000000E65DE0007DA5000076F9780000000000867704000000000000000000ABAAAA3C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Kin Shah el

Parece que el script para la base de datos solo de estadísticas está truncado. Intenté hacer clic en "ver el archivo completo" y descargar el archivo zip, pero de cualquier manera no tengo estadísticas para la ObservationDatestabla. No estoy obteniendo el mismo plan que Paul, incluso con 4199, y creo que es por eso.
Geoff Patterson el

@GeoffPatterson funciona para mí. hiciste clic en el enlace al archivo sin formato? gist.githubusercontent.com/swasheck/9a22bf8a580995d3b2aa/raw/… sin embargo, como señaló Kin, el último flujo de estadísticas está dañado: /
swasheck

Hice clic en el enlace del archivo sin formato. El script funciona (excepto el problema que Kin notó), pero no contiene ninguna lógica para crear estadísticas ObservationDates. Sin UPDATE STATISTICS ObservationDates WITH ROWCOUNT = 10000embargo, terminé corriendo manualmente para obtener el plan que Paul demostró.
Geoff Patterson

impar. creando una nueva base de datos y ejecutando ese script, tengo objetos de estadísticas (bueno, son índices), ObservationDatesasí que no estoy seguro de qué está pasando con eso. Además, tampoco puedo obtener el plan Paul generado. Intentaré la actualización para ver.
swasheck el

Respuestas:


10

Habilite el indicador de seguimiento 4199.

También tuve que emitir:

UPDATE STATISTICS dbo.ObservationDates 
WITH ROWCOUNT = 73049;

para obtener los planes que se muestran a continuación. Faltaban estadísticas para esta tabla en la carga. La cifra 73.049 provino de la información de Cardinalidad de tabla en el archivo adjunto de Plan Explorer. Utilicé SQL Server 2014 SP1 CU4 (compilación 12.0.4436) con dos procesadores lógicos, memoria máxima configurada en 2048 MB y sin marcas de seguimiento aparte de 4199.

Luego, debe obtener un plan de ejecución que incluya la eliminación dinámica de particiones:

select 
    od.[Year], 
    AvgValue = avg(ObservationValue)
from dbo.v_Observation o 
join dbo.ObservationDates od
    on o.ObservationDateKey = od.DateKey
where 
    od.[Year] >= 2000 and od.[Year] < 2006
group by 
    od.[Year]
option (querytraceon 4199);

Fragmento del plan:

Fragmento de plan

Esto puede verse peor, pero los filtros son todos filtros de inicio . Un predicado de ejemplo es:

Propiedades de filtro

Por iteración del bucle, se prueba el predicado de inicio, y solo si devuelve verdadero se ejecuta la Búsqueda de índice agrupado debajo. Por lo tanto, eliminación de partición dinámica.

Esto quizás no muy tan eficiente como la eliminación estática, especialmente si el plan es paralelo.

Es posible que deba probar sugerencias como MAXDOP 1, FAST 1o FORCESEEKen la vista, para obtener el mismo plan. Las opciones de costos del optimizador con vistas particionadas (como las tablas particionadas) pueden ser complicadas.

El punto es que necesita un plan que cuente con filtros de inicio para eliminar la partición dinámica con vistas particionadas.


Consultas con USE PLANsugerencias incrustadas : (a través de gist.github.com):


1
Gran información, gracias Paul! Después de escribir mi respuesta, me preguntaba por qué no hay una forma en que SQL Server pueda hacer este tipo de eliminación. Resulta que sí, ¡simplemente no lo había visto antes!
Geoff Patterson el

6

Mi observación siempre ha sido que debe especificar el valor (o rango de valores) para la columna de partición explícitamente en la consulta para obtener la "eliminación de la tabla" en una vista particionada. Esto se basa en la experiencia con vistas particionadas en producción desde SQL Server 2000 hasta SQL Server 2014.

SQL Server no tiene el concepto de un operador de unión de bucle en el que el motor puede apuntar dinámicamente la búsqueda directamente a la tabla adecuada en el lado interno del bucle en función del valor de la fila en el lado externo del bucle. Sin embargo, como explica la respuesta de Paul , existe la posibilidad de un plan con filtros de inicio para omitir dinámicamente tablas irrelevantes en el lado interno del bucle en tiempo constante (en lugar de logarítmico al realizar la búsqueda).

Tenga en cuenta que para las tablas particionadas, sin embargo, este tipo de búsqueda (a una partición específica) es compatible.

Si está decidido a usar vistas particionadas, otra opción es dividir su consulta en múltiples consultas, como:

-- Gather than the min/max values for the partition column
DECLARE @minDateKey INT,
        @maxDateKey INT
SELECT @minDateKey = MIN(DateKey),
        @maxDateKey = MAX(DateKey)
FROM dbo.ObservationDates od
WHERE od.[Year] >= 2000 and od.[Year] < 2006

-- Since I have a stats-only copy of the database, simulate having run the query above
-- (You can comment this out since you have the actual data.)
SELECT @minDateKey = 20000101, @maxDateKey = 20051231

-- Adjust the query to use the min/max values of the partition column
-- rather than filtering on a different column in the dimension table
select 
    od.[Year], 
    AvgValue = avg(ObservationValue)
from dbo.v_Observation o 
join dbo.ObservationDates od
    on o.ObservationDateKey = od.DateKey
WHERE od.DateKey >= @minDateKey AND od.DateKey <= @maxDateKey
group by od.[Year]
-- Must use OPTION RECOMPILE; otherwise the plan will touch all tables because it
-- must do so in order to be valid for all values of the parameters!
OPTION (RECOMPILE)

Esto produce el siguiente plan. Ahora hay una consulta adicional que golpea la tabla de dimensiones, pero la consulta sobre la tabla de hechos (presumiblemente mucho más grande) está optimizada.

ingrese la descripción de la imagen aquí


¿Se lograría el mismo efecto si incorporara la primera consulta en la segunda sin recurrir a variables?
Andriy M

@AndriyM Si te entiendo correctamente, la respuesta es no, no se logrará el mismo efecto y el plan de consulta tocará todas las tablas en la vista particionada si intentas combinar las dos consultas. Si tuviera que ejecutar la primera consulta, luego pegue los valores 20000101y en 20051231lugar de las variables (o haga algo similar a través de dos consultas separadas en su aplicación), entonces sí, se lograría el mismo efecto sin usar las variables.
Geoff Patterson
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.