Ist es möglich, das Optimierungsprogramm zu zwingen, irrelevante Tabellen in dieser partitionierten Ansicht zu entfernen?


22

Ich teste verschiedene Architekturen für große Tabellen und ein Vorschlag, den ich gesehen habe, ist die Verwendung einer partitionierten Ansicht, bei der eine große Tabelle in eine Reihe kleinerer, "partitionierter" Tabellen aufgeteilt wird.

1 , 2 , 3 , 4

Beim Testen dieses Ansatzes habe ich etwas entdeckt, das für mich keinen Sinn ergibt. Wenn ich in der Faktensicht nach "Partitionierungsspalte" filtere, sucht der Optimierer nur in den relevanten Tabellen. Wenn ich in der Dimensionstabelle nach dieser Spalte filtere, entfernt das Optimierungsprogramm darüber hinaus unnötige Tabellen.

Wenn ich jedoch nach einem anderen Aspekt der Dimension filtere, sucht der Optimierer nach dem PK / CI jeder Basistabelle.

Hier sind die fraglichen Fragen:

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];

Tatsachenfilter auf Schlüssel

Dimmfilter auf Taste

Filter auf Aspekt dimmen

Hier ist ein Link zur SQL Sentry Plan Explorer-Sitzung.

Ich arbeite daran, die größere Tabelle tatsächlich zu partitionieren, um festzustellen, ob die Partitionseliminierung auf ähnliche Weise reagiert.

Für die (einfache) Abfrage, die nach einem Aspekt der Dimension filtert, wird die Partition entfernt.

In der Zwischenzeit ist hier eine Nur-Statistiken-Kopie der Datenbank:

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

Der "alte" Kardinalitätsschätzer bekommt einen günstigeren Plan, aber das liegt an den niedrigeren Kardinalitätsschätzungen für jeden der (unnötigen) Index-Suchvorgänge.

Ich möchte wissen, ob es eine Möglichkeit gibt, das Optimierungsprogramm dazu zu bringen, die Schlüsselspalte beim Filtern nach einem anderen Aspekt der Dimension zu verwenden, damit Suchvorgänge für irrelevante Tabellen vermieden werden.

SQL Server Version:

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)

Nur zu Ihrer Information ... der letzte Status-Stream ist beschädigtCREATE STATISTICS [_WA_Sys_00000008_2FCF1A8A] ON [dbo].[Observation_2010]([StationStateCode]) WITH STATS_STREAM = 0x01000000010000000000000000000000D4531EDB00000000D5080000000000009508000000000000AF030000AF000000020000000000000008D000340000000007000000E65DE0007DA5000076F9780000000000867704000000000000000000ABAAAA3C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Kin Shah

Es sieht so aus, als ob das Skript für die reine Statistikdatenbank abgeschnitten ist. Ich habe versucht, auf "Vollständige Datei anzeigen" zu klicken und die ZIP-Datei herunterzuladen, aber in beiden Fällen liegen keine Statistiken für die ObservationDatesTabelle vor. Ich bekomme nicht den gleichen Plan wie Paul, auch mit 4199, und ich denke, das ist der Grund.
Geoff Patterson

@GeoffPatterson es funktioniert bei mir. Haben Sie auf den Link zur Rohdatei geklickt? gist.githubusercontent.com/swasheck/9a22bf8a580995d3b2aa/raw/… Wie Kin jedoch bemerkte, ist der letzte Statistik-Stream beschädigt: /
swasheck

Ich habe auf den Link für die Rohdatei geklickt. Das Skript funktioniert (mit Ausnahme des angegebenen Problems Kin), enthält jedoch keine Logik zum Erstellen von Statistiken ObservationDates. Am Ende lief ich UPDATE STATISTICS ObservationDates WITH ROWCOUNT = 10000manuell, um den Plan zu erhalten, den Paul demonstrierte.
Geoff Patterson

ungerade. Erstellen einer neuen Datenbank und Ausführen dieses Skripts Ich habe Statistikobjekte (nun ObservationDatesja , sie sind Indizes), daher bin ich mir nicht sicher, was damit los ist. Ich bin auch nicht in der Lage, den Plan zu generieren, den Paul erstellt hat. Ich werde versuchen, das Update zu sehen.
Swasheck

Antworten:


10

Aktivieren Sie das Trace-Flag 4199.

Ich musste auch folgendes ausstellen:

UPDATE STATISTICS dbo.ObservationDates 
WITH ROWCOUNT = 73049;

um die unten gezeigten Pläne zu erhalten. Statistiken für diese Tabelle fehlten im Upload. Die Zahl 73.049 stammt aus den Informationen zur Tabellenkardinalität im Plan-Explorer-Anhang. Ich habe SQL Server 2014 SP1 CU4 (Build 12.0.4436) mit zwei logischen Prozessoren, maximalem Speicher auf 2048 MB und keinen Ablaufverfolgungsflags außer 4199 verwendet.

Sie sollten dann einen Ausführungsplan erhalten, der die dynamische Eliminierung von Partitionen beinhaltet:

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);

Planfragment:

Fragment planen

Dies könnte schlechter aussehen, aber die Filter sind alle Start-up - Filter. Ein Beispiel-Prädikat ist:

Filtereigenschaften

Pro Iteration der Schleife wird das Start-Prädikat getestet, und nur wenn es true zurückgibt, wird der darunter liegende Clustered-Index-Suchlauf ausgeführt. Daher dynamische Partitionsbeseitigung.

Dies ist möglicherweise nicht ganz so effizient wie die statische Beseitigung, insbesondere wenn der Plan parallel ist.

Unter Umständen müssen Sie Hinweise , wie versuchen MAXDOP 1, FAST 1oder FORCESEEKauf der Ansicht , den gleichen Plan zu erhalten. Optimierer-Kalkulationsoptionen mit partitionierten Ansichten (wie partitionierten Tabellen) können schwierig sein.

Der Punkt ist, dass Sie einen Plan benötigen, der Startfilter enthält, um eine dynamische Partitionsbeseitigung mit partitionierten Ansichten zu erreichen.


Abfragen mit eingebetteten USE PLANHinweisen: (über gist.github.com):


1
Tolle Infos, danke Paul! Ich habe mich gefragt, nachdem ich meine Antwort geschrieben habe, warum SQL Server diese Art der Beseitigung nicht durchführen kann. Es stellte sich heraus, dass ich es einfach noch nie gesehen hatte!
Geoff Patterson

6

Meine Beobachtung war immer, dass Sie den Wert (oder Wertebereich) für die Partitionsspalte explizit in der Abfrage angeben müssen, um "Tabelleneliminierung" in einer partitionierten Ansicht zu erhalten. Dies basiert auf Erfahrungen mit partitionierten Ansichten in der Produktion von SQL Server 2000 bis SQL Server 2014.

In SQL Server gibt es kein Konzept für einen Schleifenverknüpfungsoperator, bei dem das Modul die Suche dynamisch direkt auf die richtige Tabelle auf der Innenseite der Schleife ausrichten kann, basierend auf dem Wert der Zeile auf der Außenseite der Schleife. Wie Pauls Antwort erklärt , gibt es jedoch die Möglichkeit, einen Plan mit Startfiltern zu erstellen, um irrelevante Tabellen auf der Innenseite der Schleife in konstanter Zeit dynamisch zu überspringen (im Gegensatz zur logarithmischen Ausführung der Suche).

Beachten Sie, dass für partitionierte Tabellen diese Art der Suche (für eine bestimmte Partition) unterstützt wird.

Wenn Sie nur partitionierte Ansichten verwenden möchten, können Sie Ihre Abfrage auch in mehrere Abfragen aufteilen, z.

-- 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)

Dies ergibt den folgenden Plan. Es gibt jetzt eine zusätzliche Abfrage, die auf die Dimensionstabelle trifft, aber die Abfrage über die (vermutlich viel größere) Faktentabelle ist optimiert.

Bildbeschreibung hier eingeben


Würde derselbe Effekt erzielt, wenn Sie die erste Abfrage ohne Rückgriff auf Variablen in die zweite Abfrage integrieren würden?
Andriy M

@AndriyM Wenn ich Sie richtig verstehe, lautet die Antwort "Nein". Der gleiche Effekt wird nicht erzielt, und der Abfrageplan berührt alle Tabellen in der partitionierten Ansicht, wenn Sie versuchen, die beiden Abfragen zu kombinieren. Wenn Sie die erste Abfrage ausführen, dann die Werte einfügen 20000101und 20051231anstelle der Variablen (oder über zwei separate Abfragen in Ihrer Anwendung etwas Ähnliches tun), dann wird derselbe Effekt erzielt, ohne die Variablen zu verwenden.
Geoff Patterson
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.