Wie schnell DISTINCT-Daten aus einem Datums- / Uhrzeitfeld, SQL Server, ausgewählt werden

7

Ich frage mich, ob es eine gute Abfrage zur Auswahl bestimmter Daten (Ignorieren von Zeiten) aus einer Tabelle mit einem Datum / Uhrzeit-Feld in SQL Server gibt.

Mein Problem ist nicht, dass der Server dies tatsächlich tut (ich habe diese Frage bereits, und wir hatten bereits etwas ähnliches mit DISTINCT). Das Problem ist, ob es einen Trick gibt, um es schneller zu erledigen. Mit den Daten, die wir verwenden, gibt unsere aktuelle Abfrage ~ 80 eindeutige Tage zurück, für die ~ 40.000 Datenzeilen vorhanden sind (nach dem Filtern einer anderen indizierten Spalte), gibt es einen Index für die Datumsspalte, und die Abfrage schafft es immer 5+ Sekunden. Was zu langsam ist.

Das Ändern der Datenbankstruktur ist möglicherweise eine Option, aber eine weniger wünschenswerte.

    
ruquay 20.08.2009, 16:32
quelle

10 Antworten

6

Jede Option, die eine CAST- oder TRUNCATE- oder DATEPART-Manipulation im datetime-Feld beinhaltet, hat das gleiche Problem: Die Abfrage muss die gesamte Ergebnismenge (die 40k) scannen, um die eindeutigen Daten zu finden. Die Leistung kann geringfügig zwischen verschiedenen Implementierungen variieren.

Was Sie wirklich brauchen, ist ein Index, der die Antwort blitzartig erzeugt. Sie können entweder eine persistente berechnete Spalte mit und einen Index haben (erfordert Änderungen der Tabellenstruktur) oder eine indizierte Sicht ( erfordert Enterprise Edition für QO, um den Index zu berücksichtigen (out-of-the-box).

Konstante berechnete Spalte:

%Vor%

Indizierte Sicht:

%Vor%

Aktualisieren

Um den Scan vollständig zu eliminieren, könnte man eine ausgeführte indexierte GROUP BY-Ansicht verwenden, wie folgt:

%Vor%

Die Abfrage select distinct date_only from foo verwendet stattdessen diese indizierte Sicht. Ist immer noch ein Scan technisch, aber auf einem bereits "eindeutigen" Index, so werden nur die benötigten Datensätze gescannt. Es ist ein Hack, ich denke, ich würde es nicht für Live-Produktion empfehlen.

AFAIK SQL Server ist nicht in der Lage, einen echten Index mit Überspringwiederholungen zu scannen, d. suche nach oben, suche dann größer als oben, suche dann sukzessive größer als zuletzt.

    
Remus Rusanu 20.08.2009, 17:03
quelle
9

Ich habe Folgendes verwendet:

%Vor%

Dadurch wird die Zeit vom Datum entfernt, indem sie in eine float konvertiert und der "Zeit" -Teil abgeschnitten wird, der die Dezimalzahl von float ist.

Sieht etwas klobig aus, funktioniert aber gut in einem großen Datensatz (~ 100.000 Zeilen), den ich den ganzen Tag lang verwende.

    
Scott Vercuski 20.08.2009 16:34
quelle
5

Das funktioniert für mich:

%Vor%     
s atkins 10.10.2011 12:21
quelle
3

Der einfachste Weg besteht darin, eine berechnete Spalte nur für den Datumsbereich hinzuzufügen und darauf auszuwählen. Sie können dies in einer Ansicht tun, wenn Sie die Tabelle nicht ändern möchten.

    
Joel Coehoorn 20.08.2009 16:35
quelle
3

Ich bin mir nicht sicher, warum Ihre bestehende Abfrage für 40.000 Zeilen mehr als 5 Sekunden dauern würde.

Ich habe gerade die folgende Abfrage gegen eine Tabelle mit 100.000 Zeilen versucht und sie ist in weniger als 0.1 s zurückgekehrt.

%Vor%

(Beachten Sie, dass diese Abfrage wahrscheinlich keine Indizes für die Datumsspalte nutzen kann, aber sie sollte relativ schnell sein, wenn Sie davon ausgehen, dass Sie sie nicht Dutzende Male pro Sekunde ausführen.)

>     
LukeH 20.08.2009 17:15
quelle
2

Aktualisierung:

Die Lösung wird unten auf Effizienz in einer 2M -Tabelle getestet und nimmt nur 40 ms .

Plain DISTINCT für eine indizierte berechnete Spalte hat 9 seconds übernommen.

Sehen Sie diesen Eintrag in meinem Blog für Leistungsdetails:

Leider kann SQL Server 's Optimierer weder die% s SKIP SCAN von% noch die MySQL von INDEX FOR GROUP-BY verwenden.

Es dauert immer Stream Aggregate , das dauert lange.

Sie können eine Liste möglicher Daten mit einem rekursiven CTE erstellen und mit Ihrer Tabelle verknüpfen:

%Vor%

Dies ist effizienter als Stream Aggregate

    
Quassnoi 20.08.2009 16:42
quelle
1

Ich habe das benutzt

%Vor%     
JendaZ. 23.02.2011 18:10
quelle
0

Was ist Ihr Prädikat für diese andere gefilterte Spalte? Haben Sie versucht, ob Sie von einem Index für diese andere gefilterte Spalte, gefolgt vom Datum / Uhrzeit-Feld, eine Verbesserung erhalten?

Ich rate hauptsächlich hier, aber 5 Sekunden, um eine Menge von vielleicht 100000 Reihen auf 40000 zu filtern und dann eine Art zu machen (was vermutlich so vor sich geht), scheint mir keine unangemessene Zeit zu sein. Warum sagst du, es ist zu langsam? Weil es nicht den Erwartungen entspricht?

    
Erwin Smout 20.08.2009 16:46
quelle
0

Konvertieren Sie einfach das Datum: dateadd(dd,0, datediff(dd,0,[Some_Column]))

    
JeffO 20.08.2009 17:20
quelle
0

Wenn Sie die Schritt-Extraktion oder Neuformatierung des Datums vermeiden wollen - was vermutlich die Hauptursache für die Verzögerung ist (durch Erzwingen eines vollständigen Tabellen-Scans) - haben Sie keine andere Wahl, als das Datum nur als Teil der Datetime zu speichern, was leider eine Änderung der Datenbankstruktur erfordert.

Wenn Sie SQL Server 2005 oder höher verwenden, ist ein persistentes berechnetes Feld der richtige Weg

%Vor%     
Cruachan 20.08.2009 16:44
quelle

Tags und Links