Ich erinnere mich, dass ich an einer Stelle gelesen habe, dass es sich nicht wirklich lohnt, ein Feld mit geringer Kardinalität (eine geringe Anzahl unterschiedlicher Werte) zu indizieren. Ich gebe zu, ich weiß nicht genug darüber, wie Indizes funktionieren, um zu verstehen, warum das so ist.
Was ist, wenn ich eine Tabelle mit 100 Millionen Zeilen habe und Datensätze auswähle, bei denen ein Bitfeld 1 ist? Nehmen wir an, es gibt zu jedem Zeitpunkt nur eine Handvoll Datensätze, bei denen das Bitfeld 1 ist (im Gegensatz zu 0). Lohnt es sich, dieses Bitfeld zu indizieren oder nicht? Warum?
Natürlich kann ich es einfach testen und den Ausführungsplan überprüfen, und das werde ich tun, aber ich bin auch neugierig auf die Theorie dahinter. Wann ist Kardinalität wichtig und wann nicht?
quelle
Antworten:
Überlegen Sie, was ein Index in SQL ist - und Index ist wirklich ein Speicherblock, der auf andere Speicherblöcke zeigt (dh Zeiger auf Zeilen). Der Index ist in Seiten unterteilt, sodass Teile des Index je nach Verwendung aus dem Speicher geladen und entladen werden können.
Wenn Sie nach einer Reihe von Zeilen fragen, verwendet SQL den Index, um die Zeilen schneller zu finden als das Scannen von Tabellen (wobei jede Zeile betrachtet wird).
SQL verfügt über geclusterte und nicht geclusterte Indizes. Mein Verständnis von Clustered-Indizes ist, dass sie ähnliche Indexwerte auf derselben Seite gruppieren. Auf diese Weise kann SQL diese Zeilen von einer gruppierten Speicherseite zurückgeben, wenn Sie nach allen Zeilen fragen, die einem Indexwert entsprechen. Aus diesem Grund ist der Versuch, eine GUID-Spalte zu gruppieren, eine schlechte Idee. Sie versuchen nicht, zufällige Werte zu gruppieren.
Wenn Sie eine Ganzzahlspalte indizieren, enthält der SQL-Index eine Reihe von Zeilen für jeden Indexwert. Wenn Sie einen Bereich von 1 bis 10 haben, haben Sie 10 Indexzeiger. Je nachdem, wie viele Zeilen es gibt, kann dies unterschiedlich ausgelagert werden. Wenn Ihre Abfrage nach dem Index sucht, der mit "1" übereinstimmt, und dann, wo Name "Fred" enthält (vorausgesetzt, die Spalte "Name" ist nicht indiziert), erhält SQL sehr schnell den Satz von Zeilen, die mit "1" übereinstimmen, und die Tabelle durchsucht den Rest.
Was SQL also wirklich tut, ist zu versuchen, die Arbeitsmenge (Anzahl der Zeilen) zu reduzieren, über die es iterieren muss.
Wenn Sie ein Bitfeld (oder einen engen Bereich) indizieren, reduzieren Sie den Arbeitssatz nur um die Anzahl der Zeilen, die diesem Wert entsprechen. Wenn Sie eine kleine Anzahl übereinstimmender Zeilen haben, würde dies Ihren Arbeitssatz erheblich reduzieren. Bei einer großen Anzahl von Zeilen mit einer 50/50-Verteilung kann dies zu einem sehr geringen Leistungsgewinn führen, während der Index auf dem neuesten Stand gehalten wird.
Der Grund, warum jeder sagt, dass er testen soll, ist, dass SQL einen sehr cleveren und komplexen Optimierer enthält, der einen Index möglicherweise ignoriert, wenn er entscheidet, dass das Scannen von Tabellen schneller ist, eine Sortierung verwendet oder Speicherseiten organisiert, wie es ihm gefällt.
quelle
Ich bin gerade über eine andere auf diese Frage gestoßen. Angenommen, Ihre Aussage, dass nur eine Handvoll Datensätze den Wert 1 annehmen (und dass dies diejenigen sind, an denen Sie interessiert sind), könnte ein gefilterter Index eine gute Wahl sein. Etwas wie:
Dadurch wird ein wesentlich kleinerer Index erstellt, den der Optimierer verwenden kann, wenn dies ein Prädikat in Ihrer Abfrage ist.
quelle
yourBitColumn = @value
, kann der Optimierer nicht feststellen, ob der gefilterte Index verwendbar ist.100 Millionen Datensätze, bei denen nur wenige das Bitfeld auf 1 setzen? Ja, ich würde denken, dass das Indizieren des Bitfelds das Abfragen der Bit = 1-Datensätze definitiv beschleunigen würde. Sie sollten die logarithmische Suchzeit aus dem Index abrufen und dann nur die wenigen Seiten mit Bit = 1-Datensätzen berühren. Andernfalls müssten Sie alle Seiten der 100-Millionen-Datensatztabelle berühren.
Andererseits bin ich definitiv kein Datenbankexperte und könnte etwas Wichtiges vermissen.
quelle
Wenn Ihre Verteilung ziemlich bekannt und unausgeglichen ist, wie 99% der Zeilen Bit = 1 und 1% Bit = 0, wird bei einer WHERE-Klausel mit Bit = 1 etwa zur gleichen Zeit ein vollständiger Tabellenscan durchgeführt wie der Index-Scan. Wenn Sie eine schnelle Abfrage mit Bit = 0 haben möchten, ist der beste mir bekannte Weg, einen gefilterten Index zu erstellen und eine Klausel WHERE bit = 0 hinzuzufügen. Auf diese Weise speichert dieser Index nur die 1% -Zeile. Wenn Sie dann ein WHERE-Bit = 0 ausführen, kann der Abfrageoptimierer einfach diesen Index auswählen, und alle Zeilen daraus sind Bit = 0. Sie haben auch den Vorteil, dass nur sehr wenig Speicherplatz erforderlich ist, um einen vollständigen Index für das Bit zu vergleichen .
quelle
Obwohl ich nicht glaube, dass ich NUR eine Bitspalte selbst indizieren würde, ist es sehr üblich, Bitspalten als Teil eines zusammengesetzten Index einzuschließen.
Ein einfaches Beispiel wäre ein Index für ACTIVE, LASTNAME anstelle von nur Nachname, wenn Ihre Anwendung fast immer nach aktiven Kunden sucht.
quelle
Falls Sie es nicht gelesen haben, hat Jason Massie kürzlich einen Artikel geschrieben, in dem genau dieses Thema behandelt wurde.
http://statisticsio.com/Home/tabid/36/articleType/ArticleView/articleId/302/Never-Index-a-BIT.aspx
Bearbeiten: Neuer Artikelstandort - http://sqlserverpedia.com/blog/sql-server-bloggers/never-index-a-bit
Wayback-Maschine für zuvor "neuen" Artikel: http://web.archive.org/web/20120201122503/http://sqlserverpedia.com/blog/sql-server-bloggers/never-index-a-bit/
Der neue SQL Server Pedia-Speicherort ist Toadworld. In einem neuen Artikel von Kenneth Fisher wird dieses Thema behandelt:
http://www.toadworld.com/platforms/sql-server/b/weblog/archive/2014/02/17/dba-myths-an-index-on-a-bit-column-will-never-be- used.aspx
Wayback-Maschine: http://web.archive.org/web/20150508115802/http://www.toadworld.com/platforms/sql-server/b/weblog/archive/2014/02/17/dba-myths-an -index-on-a-bit-column-wird-nie-verwendet -.aspx
quelle
Natürlich lohnt es sich, besonders wenn Sie die Daten mit diesem Wert abrufen müssen. Es wäre ähnlich wie bei der Verwendung einer spärlichen Matrix anstelle einer normalen Matrix.
Mit SQL 2008 können Sie jetzt Partitionierungsfunktionen verwenden und die Daten filtern, die in einem Index enthalten sind. Der Nachteil früherer Versionen wäre, dass der Index für alle Daten erstellt wird. Dies kann jedoch optimiert werden, indem die interessanten Werte in einer separaten Dateigruppe gespeichert werden.
quelle
Wie andere gesagt haben, möchten Sie dies messen. Ich erinnere mich nicht, wo ich das gelesen habe, aber eine Spalte muss eine sehr hohe Kardinalität haben (ca. 95%), damit ein Index effektiv ist. Ihr bester Test hierfür wäre, den Index zu erstellen und die Ausführungspläne für die 0- und 1-Werte des BIT-Felds zu untersuchen. Wenn im Ausführungsplan eine Indexsuchoperation angezeigt wird, wissen Sie, dass Ihr Index verwendet wird.
Ihre beste Vorgehensweise wäre, die Tabelle SELECT * FROM mit einer einfachen Tabelle zu testen. WHERE BitField = 1; Fragen Sie die Funktionalität ab und bauen Sie sie langsam Schritt für Schritt aus, bis Sie eine realistische Abfrage für Ihre Anwendung haben. Überprüfen Sie den Ausführungsplan bei jedem Schritt, um sicherzustellen, dass die Indexsuche weiterhin verwendet wird. Zwar gibt es keine Garantie dafür, dass dieser Ausführungsplan in der Produktion verwendet wird, aber es besteht eine gute Chance, dass dies der Fall ist.
Einige Informationen finden Sie in den Foren von sql-server-performance.com und im Artikel, auf den verwiesen wird
quelle
"Ich erinnere mich, dass ich an einer Stelle gelesen habe, dass es sich nicht wirklich lohnt, ein Feld mit geringer Kardinalität (einer geringen Anzahl unterschiedlicher Werte) zu indizieren."
Dies liegt daran, dass SQL Server es fast immer effizienter findet, nur einen Tabellenscan durchzuführen, als den Index zu lesen. Im Grunde genommen wird Ihr Index niemals verwendet und es ist eine Verschwendung, ihn zu pflegen. Wie andere gesagt haben, könnte es in einem zusammengesetzten Index in Ordnung sein.
quelle
Wenn Sie die Abfrage nach Datensätzen beschleunigen möchten, bei denen der Bitfeldwert gleich '1' ist, können Sie eine indizierte Ansicht Ihrer Basistabelle versuchen, die nur Datensätze enthält, bei denen Ihr Bitfeld gleich '1' ist. Wenn in einer Enterprise Edition eine Abfrage eine indizierte Ansicht anstelle einer angegebenen Tabelle verwenden könnte, um die Abfrageleistung zu verbessern, wird die Ansicht verwendet. Theoretisch würde dies die Geschwindigkeit ausgewählter Abfragen erhöhen, die nur nach Datensätzen mit einem Bitfeldwert von '1' suchen.
http://www.microsoft.com/technet/prodtechnol/sql/2005/impprfiv.mspx
All dies setzt voraus, dass Sie Microsoft SQL Server 2005 Enterprise sind. Das gleiche könnte für 2008 gelten, ich bin mit dieser Version nicht vertraut.
quelle
Wenn Sie wissen möchten, ob ein Index die gewünschten Auswirkungen hat: Testen Sie und testen Sie erneut.
Im Allgemeinen möchten Sie keinen Index, der Ihre Tabelle aufgrund der Kosten für die Verwaltung eines Index nicht ausreichend einschränkt. (Kosten> Gewinn). Aber wenn der Index in Ihrem Fall die Tabelle halbiert, können Sie etwas gewinnen, aber es auf den Tisch legen. Es hängt alles von der genauen Größe / Struktur Ihrer Tabelle ab und davon, wie Sie sie verwenden (Anzahl der Lese- / Schreibvorgänge).
quelle
Nein, da dies zu einer sehr geringen Selektivität führt. Als Teil eines zusammengesetzten Index. durchaus aber erst nach anderen gleichheitsspalten.
quelle
Sie können in SQL Server 2000 kein Bitfeld indizieren, wie dies zu diesem Zeitpunkt in den Online-Büchern angegeben war:
Ja, wenn Sie nur eine Handvoll von Millionen Zeilen haben, hilft ein Index. Wenn Sie dies in diesem Fall tun möchten, müssen Sie die Spalte a erstellen
tinyint
.Hinweis : Mit Enterprise Manager können Sie keinen Index für eine Bitspalte erstellen. Wenn Sie möchten, können Sie dennoch manuell einen Index für eine Bitspalte erstellen:
SQL Server 2000 verwendet jedoch keinen solchen Index. Es wird eine Abfrage ausgeführt, bei der der Index ein perfekter Kandidat wäre, z.
SQL Server 2000 führt stattdessen einen Tabellenscan durch, als ob der Index nicht einmal vorhanden wäre. Wenn Sie die Spalte mit einer Tinyint SQL Server 2000 ändern wird tun versuchen , einen Index. Außerdem die folgende nicht abgedeckte Abfrage:
Es wird eine Indexsuche durchgeführt, gefolgt von einer Lesezeichensuche.
SQL Server 2005 unterstützt Indizes für Bitspalten nur eingeschränkt. Beispielsweise:
bewirkt eine Indexsuche durch den Deckungsindex. Aber der nicht abgedeckte Fall:
führt nicht zu einer Indexsuche, gefolgt von einer Lesezeichensuche, sondern führt einen Tabellenscan (oder einen Clustered-Index-Scan) durch, anstatt die Indexsuche gefolgt von einer Lesezeichensuche durchzuführen.
Verifiziert durch Experimente und direkte Beobachtung.
quelle
sehr späte Antwort ...
Ja, es kann laut SQL CAT-Team nützlich sein (aktualisiert, konsolidiert)
quelle
Ist das eine häufige Abfrage? Es mag sich lohnen, nach einer "Handvoll" Datensätzen zu suchen, aber in den anderen Zeilen hilft es Ihnen nicht viel. Gibt es andere Möglichkeiten, die Daten zu identifizieren?
quelle
Kardinalität ist ein Faktor, der andere ist, wie gut der Index Ihre Daten aufteilt. Wenn Sie ungefähr eine halbe und eine halbe Null haben, hilft es. (Angenommen, dieser Index ist ein besserer Weg als ein anderer Index). Wie oft fügen Sie jedoch ein und aktualisieren es? Das Hinzufügen von Indizes für die SELECT-Leistung beeinträchtigt auch die INSERT-, UPDATE- und DELETE-Leistung. Denken Sie also daran.
Ich würde sagen, wenn die Einsen bis Nullen (oder umgekehrt) nicht besser als 75% bis 25% sind, stören Sie sich nicht.
quelle
Messen Sie die Reaktionszeit vorher und nachher und prüfen Sie, ob es sich lohnt. Theoretisch sollte es die Leistung für Abfragen verbessern, die die indizierten Felder verwenden, aber es hängt wirklich von der Verteilung der wahren / falschen Werte und den anderen Feldern ab, die an den Abfragen beteiligt sind, um die Sie sich kümmern
quelle
Ian Boyd hat Recht, wenn er sagt, dass Sie dies nicht über Enterprise Manager für SQL 2000 tun können (siehe seinen Hinweis zum Erstellen über T-SQL).
quelle
Sie müssen hier klug sein, um abzufragen. Sie müssen den Ladewert in Ihrer Spalte kennen, wenn die Last von true in Ihrem System höher ist, und Sie möchten alle wahren Werte überprüfen. Schreiben Sie Ihre Abfrage, um nicht false zu überprüfen. Dies hilft sehr , es ist nur ein Trick.
quelle