2009-11-11 5 views
18

Meine Tabelle (SQL Server 2008) hat 1 Million + Datensätze, wenn ich Datensätze nach Datetime bestellen, dauert es 1 Sekunde, aber wenn ich nach ID (int) bestellen, es dauert nur etwa 0,1 Sekunden.SQL Server 2008: Bestellung von Datetime ist zu langsam

Gibt es eine Möglichkeit, die Effizienz zu verbessern? (Ich habe bereits die Datetime-Spalte zum Index hinzugefügt)

+0

Welche 'RDBMS' verwenden Sie? – Quassnoi

+0

Ich verwende SQL Server 2008 – silent

+7

ist diese Datetime-Spalte in einem separaten Index für sich? Sie sagen "hinzugefügt .. zum Index" ....wenn die Datetime-Spalte z.B. Spaltennr. 3 in einem zusammengesetzten Index, das überhaupt nicht helfen wird, wenn man versucht, durch diese datetime Spalte allein zu bestellen ........ –

Antwort

23

Bestellung von id verwendet wahrscheinlich einen Clustered-Index-Scan bei der Bestellung von datetime verwendet entweder Sortierung oder Index-Lookup.

Beide Methoden sind langsamer als ein Clustered-Index-Scan.

Wenn Ihre Tabelle von id geclustert wird, bedeutet es im Grunde, dass es bereits sortiert ist. Die Datensätze sind in einem B+Tree enthalten, der eine verknüpfte Liste aufweist, die die Seiten in der Reihenfolge id verknüpft. Die Engine sollte nur die verkettete Liste durchqueren, um die von id bestellten Datensätze zu erhalten.

Wenn die id s in sequentieller Reihenfolge eingefügt wurden, bedeutet dies, dass die physische Reihenfolge der Zeilen der logischen Reihenfolge entspricht und der Clustered-Index-Scan noch schneller ist.

Wenn Sie Ihre Aufzeichnungen von datetime bestellt werden, gibt es zwei Möglichkeiten:

  • alle Datensätze aus der Tabelle nehmen und sie sortieren. Langsamkeit ist offensichtlich.
  • Verwenden Sie den Index auf datetime. Der Index wird in einem separaten Bereich der Festplatte gespeichert. Dies bedeutet, dass die Engine in einer verschachtelten Schleife zwischen den Indexseiten und den Tabellenseiten wechseln muss. Es ist auch langsamer.

die Bestellung zu verbessern, können Sie einen separaten abdeckenden Index auf datetime erstellen:

CREATE INDEX ix_mytable_datetime ON mytable (datetime) INCLUDE (field1, field2, …) 

und beinhalten alle Spalten, die Sie in Ihrer Abfrage in diesem Index verwenden.

Dieser Index ist wie eine Schattenkopie Ihrer Tabelle, aber mit Daten in anderer Reihenfolge sortiert.

Dies wird es ermöglichen, die Schlüssel-Lookups loszuwerden (da der Index alle Daten enthält), die die Bestellung von datetime so schnell machen wie die auf id.

Update:

Ein frischer Blog-Beitrag zu diesem Problem:

+0

Gibt es dafür einen effizienten Weg? – silent

+0

Ich glaube, die Datenbank wird es in diesem Format sowieso gespeichert haben (und likey vergleicht es auch auf diese Weise). Ich dachte anfangs auch an das Gleiche, aber ich glaube nicht, dass es die Antwort sein sollte. – Jrud

+1

+1 Um für die Datetime-Sortierung zu optimieren, erstellen Sie datetime den Clustered-Index und den ID-Index einen Nonclustered-Primärschlüssel. – Andomar

0

vielleicht, wenn Sie speichern Datatime als int, aber es würde einige Zeit dauern, jedes Mal, wenn Sie konvertieren Daten speichern oder abrufen (gemeinsame Technik verwendet, um Mitarbeiter wie IP-Adresse zu speichern und haben eine schnellere Suche Zeiten)

sollten Sie in Ihrem Server überprüfen, wie es speichert Datum, b/c es Ihr Server speichert es bereits als int oder bigint .. es wird Verändere nichts....

2

Fügen Sie die Datum Zeit zu einem neuen Index hinzu und fügen Sie es der ID hinzu, wird Ihnen immer noch nicht viel helfen.

0

Wenn Ihr DateTime-Feld viele verschiedene Werte enthält und diese Werte sich selten ändern, definieren Sie einen Clustered-Index für das DateTime-Feld. Dadurch werden die tatsächlichen Daten nach dem DateTime-Wert sortiert. Informationen zur Verwendung von Clustered-Indizes finden Sie unter http://msdn.microsoft.com/en-us/library/aa933131(SQL.80).aspx.

Dies führt jedoch zu einer langsameren Suche nach int, da sie auf die Verwendung eines nicht gruppierten Indexes verweisen.

1

Könnte es sein, dass es einen Index für Ihre int-Spalte gibt, aber nicht für Ihre datetime-Spalte? Sehen Sie sich den Ausführungsplan an.

+0

+1 guter Punkt - überprüfen Sie den Ausführungsplan! Wird der Index überhaupt verwendet? –

0

Haben Sie das DateTime-Feld zum "the" -Index oder zu einem exklusiven Index hinzugefügt? Filtern Sie Ihre Auswahl nach einem anderen Feld und der DateTime oder nur dieser?

Sie müssen einen Index mit allen Feldern haben, die Sie filtern und vorzugsweise in der gleichen Reihenfolge, um die Leistung zu optimieren.

+0

Ich hatte es zu einem vorhandenen Index hinzugefügt, ich habe gerade versucht, einen neuen Index zu erstellen, es wird relativ schneller (0,5 Sekunden), aber immer noch langsamer als eine int-Spalte. – silent

+0

Es ist wichtig, einen guten Index zu erstellen, um die Felder in den Anweisungen "WHERE" und "ORDER BY" (und "GROUP BY", falls vorhanden) zu betrachten. Es sollte die gleichen Felder und in der gleichen Reihenfolge sein. Wenn Sie nicht alle Spalten in der Tabelle benötigen, nehmen Sie SELECT nur mit den gewünschten Feldern vor. Löschen Sie dann den Cache und die Statistik und versuchen Sie die Ergebnisse. Denken Sie auch, dass es schwierig ist, mit der gleichen Geschwindigkeit des gruppierten Index in Tabellen mit vielen Daten auszuwählen. Dies ist der Grund, sorgfältig auszuwählen, welcher der gruppierte sein soll. –

6

die ORDER BY, den Motor zu ehren hat zwei Alternativen:

  • die Zeilen scannen einen Index verwenden, die die Reihenfolge

Erste Möglichkeit schnell die Reihen

  • Art angefordert bietet, die zweite ist langsam. Das Problem besteht darin, dass der Index sein muss, um Index zu verwenden. Dies bedeutet, dass es alle Spalten in der SELECT-Projektionsliste und alle Spalten enthält, die in WHERE-Klauseln (mindestens) verwendet werden. Wenn der Index nicht überdeckt, müsste die Engine den gruppierten Index (dh die "Tabelle") für jede Zeile nachschlagen, um die Werte der benötigten Spalten zu erhalten. Dieses konstante Nachschlagen von Werten ist teuer, und es gibt einen Wendepunkt, wenn die Engine (zu Recht) entscheidet, dass es effizienter ist, den Clustered-Index einfach zu scannen und das Ergebnis zu sortieren, wodurch Ihr nicht gruppierter Index ignoriert wird. Einzelheiten finden Sie unter The Tipping Point Query Answers.

    Betrachten Sie die folgenden drei Abfragen:

    SELECT dateColumn FROM table ORDER BY dateColumn 
    SELECT * FROM table ORDER BY dateColumn 
    SELECT someColumn FROM table ORDER BY dateColumn 
    

    Die erste wird einen nicht gruppierten Index auf dateColumn verwendet werden werden. Aber die zweite wird keinen Index für dateColumn verwenden, wird wahrscheinlich einen Scan wählen und stattdessen für 1M Zeilen sortieren. Auf der anderen Seite kann die dritte Abfrage von einem Index auf Table(dateColumn) INCLUDE (someColumn) profitieren.

    Dieses Thema wird auf MSDN ausführlich behandelt, siehe Index Design Basics, General Index Design Guidelines, Nonclustered Index Design Guidelines oder How To: Optimize SQL Indexes.

    Letztendlich ist die wichtigste Wahl Ihres Tabellendesigns der Clustered-Index, den Sie verwenden. Fast immer bleibt der Primärschlüssel (normalerweise eine automatisch inkrementierte ID) als Clustered-Index übrig, eine Entscheidung, die nur bestimmten OLTP-Ladevorgängen zugute kommt.

    Und schließlich, eine ziemlich offensichtliche Frage: Warum in der Welt würden Sie 1 Million Reihen bestellen? Sie können sie möglicherweise nicht anzeigen, oder? Wenn Sie ein wenig mehr über Ihren Anwendungsfall erklären, können wir eine bessere Antwort für Sie finden.

  • +0

    Danke Remus, ich möchte nicht 1 Million + Datensätze auf einmal anzeigen, ich benutze row_number() Methode für Paging, aber ich fand, wenn ich versuche, eine große Nummer, wie Seite 50000 (20 Rec/Seite), wird die Abfrage sehr langsam, aber wenn ich die Ordnungsmethode zu ID ändere, wird es fast 10 mal schneller. – silent

    +1

    Ich dachte, das muss Row_number Paginierung sein. Ist es LINQ, zufällig? Am besten geben Sie die Abfrage wie folgt aus: Wählen Sie die IDs der gewünschten Seite aus (siehe die 20 IDs auf Seite 17) und rufen Sie dann die Details dieser 20 Datensätze ab. Dies * kann * in T-SQL und auch in LINQ ausgedrückt werden und kann schnell genug sein. Sie veröffentlichen das betreffende Schema und die Abfragen besser. –