Ich habe eine Reihe von Tabellen mit vielen hochpräzisen Daten, die von verschiedenen Geräten gesammelt wurden. Die Intervalle, in denen sie gesammelt wurden, variieren und wandern sogar über die Zeitreihen. Meine Benutzer möchten die Möglichkeit haben, einen Datumsbereich auszuwählen und einen Durchschnitt / min / max über diese Variablen mit einer bestimmten Häufigkeit zu erhalten. Dies ist der zweite Versuch, den ich unternommen habe, und er funktioniert, aber ich frage mich, ob es einen besseren / schnelleren Weg gibt, dies zu erreichen.
declare @start datetime
declare @end datetime
set @start = '3/1/2012'
set @end = '3/3/2012'
declare @interval int
set @interval = 300
declare @tpart table(
dt datetime
);
with CTE_TimeTable
as
(
select @start as [date]
union all
select dateadd(ss,@interval, [date])
from CTE_TimeTable
where DateAdd(ss,@interval, [date]) <= @end
)
insert into @tpart
select [date] from CTE_TimeTable
OPTION (MAXRECURSION 0);
select t.dt, avg(c.x1), min(c.x1), max(c.x2), avg(c.x2), min(c.x2), max(c.x2) from clean.data c ,
@tpart t
where
ABS(DateDIFF(ss, t.dt , c.Date) ) <= @interval /2
and
Date >= @start
and
Date <= @end
group by t.dt
Derzeit dauert die Ausführung dieser Abfrage über 32721 Zeilen für diesen Zeitraum von 3 Tagen ungefähr 43 Sekunden und gibt mir die 577 Zeilen, die ich erwarte, aber ich möchte dies schneller erhalten. Der große Erfolg kommt von der verschachtelten Schleife, um die innere Verbindung herzustellen.
quelle
clean.data
? Können Sie auch erklären, warum Sie Cross-Joining mit@tpart
?DATEDIFF
Aussage?ABS(DateDIFF(ss, t.dt , c.Date) )
? Sie könnten es indizieren. Macht die Operation für diec.Date
Spalte in der Spalte nach meinem Verständnis (was möglicherweise WAAAAY falsch sein kann)WHERE
den Index nicht unbrauchbar?WHERE
Klausel verwendet werden können.Antworten:
Ihre Verknüpfung zwischen den Tabellen ist in eine Funktion eingebettet, die es dem Optimierer wirklich schwer macht, etwas Kluges damit zu tun. Ich denke, es muss jede Zeile in einer Tabelle mit jeder anderen Zeile in der anderen Tabelle vergleichen.
Das Umschreiben Ihres Joins mit einer Bereichsprüfung sollte viel schneller erfolgen. Ich habe Ihrer Tabellenvariablen auch einen Primärschlüssel hinzugefügt, um eine Sortieroperation aus dem Abfrageplan zu entfernen, und stattdessen Ihre Tabellenvariable in eine temporäre Tabelle umgewandelt. Der Unterschied bei meinen Tests bestand darin, dass im Abfrageplan Parallelität verwendet wurde.
Hinweis: Diese Abfrage gibt nicht genau die gleichen Intervalle zurück wie Ihre Abfrage. Der Datumsbereich wird in gleich große Teile unterteilt, in denen Ihre Abfrage zu Beginn ein halbes Intervall und am Ende des Bereichs ein halbes Intervall hatte. Es ist natürlich möglich, die Abfrage so zu ändern, dass sie Ihrer Abfrage entspricht, wenn dies gewünscht wird.
Aktualisieren
Ich habe an einer Tabelle mit insgesamt
1036801
Zeilen und mit34560
im Intervall2012-03-01
bis getestet2012-03-03
. In meinen Tests dauert die ursprüngliche Abfrage 4,1 Sekunden. Die obige Abfrage dauert 0,1 Sekunden.Skript zum Generieren der Testdaten:
quelle
Die Antwort von Mikael Eriksson hat mich dazu inspiriert, meinen ursprünglichen Code etwas zu ändern. Das habe ich mir ausgedacht.
Die Tabellenvariable @tpart hat nun sowohl die Start- und Endzeit der Abfrage als auch den Mittelpunkt für die Gruppierung vorberechnet. Jetzt sieht meine Anfrage so aus:
Dies gab mir eine Abfragezeit von ca. 9 Sekunden. Nicht ganz so gut wie bei Mikael, aber viel besser als das, womit ich angefangen hatte und gut genug für meine Benutzer. Dies waren über ca. 80.000 Zeilen für einen einzelnen Tag, durchschnittlich fünf Minuten lang.
quelle