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.
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.
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.
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.
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.)
>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:
SQL Server
: effiziente DISTINCT
für Daten 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:
Dies ist effizienter als Stream Aggregate
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?
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%Tags und Links sql-server datetime distinct