Warum wird es benötigt?
Wenn Daten auf festplattenbasierten Speichergeräten gespeichert werden, werden sie als Datenblöcke gespeichert. Auf diese Blöcke wird in ihrer Gesamtheit zugegriffen, was sie zur atomaren Plattenzugriffsoperation macht. Plattenblöcke sind ähnlich wie verknüpfte Listen aufgebaut. Beide enthalten einen Datenabschnitt, einen Zeiger auf die Position des nächsten Knotens (oder Blocks), und beide müssen nicht zusammenhängend gespeichert werden.
Aufgrund der Tatsache, dass eine Anzahl von Datensätzen nur nach einem Feld sortiert werden kann, können wir angeben, dass für die Suche in einem nicht sortierten Feld eine lineare Suche erforderlich ist N/2
, für die (im Durchschnitt) Blockzugriffe erforderlich sind. Dabei N
ist die Anzahl der Blöcke angegeben Der Tisch überspannt. Wenn dieses Feld ein Nicht-Schlüsselfeld ist (dh keine eindeutigen Einträge enthält), muss der gesamte Tabellenbereich bei N
Blockzugriffen durchsucht werden .
Während bei einem sortierten Feld eine binäre Suche verwendet werden kann, die log2 N
Blockzugriffe hat. Da die Daten nach einem Nicht-Schlüsselfeld sortiert sind, muss der Rest der Tabelle nicht nach doppelten Werten durchsucht werden, sobald ein höherer Wert gefunden wurde. Somit ist die Leistungssteigerung erheblich.
Was ist Indizierung?
Durch die Indizierung können mehrere Datensätze nach mehreren Feldern sortiert werden. Durch das Erstellen eines Index für ein Feld in einer Tabelle wird eine andere Datenstruktur erstellt, die den Feldwert und einen Zeiger auf den Datensatz enthält, auf den er sich bezieht. Diese Indexstruktur wird dann sortiert, sodass binäre Suchen daran durchgeführt werden können.
Der Nachteil der Indizierung besteht darin, dass diese Indizes zusätzlichen Speicherplatz auf der Festplatte benötigen, da die Indizes mithilfe der MyISAM-Engine zusammen in einer Tabelle gespeichert werden. Diese Datei kann schnell die Größenbeschränkungen des zugrunde liegenden Dateisystems erreichen, wenn viele Felder in derselben Tabelle indiziert werden .
Wie funktioniert es?
Lassen Sie uns zunächst ein Beispiel für ein Datenbanktabellenschema skizzieren.
Feldname Datentyp Größe auf der Festplatte
id (Primärschlüssel) INT 4 Bytes ohne Vorzeichen
Vorname Char (50) 50 Bytes
lastName Char (50) 50 Bytes
emailAddress Char (100) 100 Bytes
Hinweis : char wurde anstelle von varchar verwendet, um eine genaue Größe des Festplattenwerts zu ermöglichen. Diese Beispieldatenbank enthält fünf Millionen Zeilen und ist nicht indiziert. Die Leistung mehrerer Abfragen wird nun analysiert. Hierbei handelt es sich um eine Abfrage unter Verwendung der ID (ein sortiertes Schlüsselfeld) und eine Abfrage unter Verwendung des Vornamens (ein nicht sortiertes unsortiertes Schlüsselfeld).
Beispiel 1 - sortierte vs unsortierte Felder
Ausgehend von unserer Beispieldatenbank mit r = 5,000,000
Datensätzen fester Größe mit einer Datensatzlänge von R = 204
Bytes werden diese mithilfe der MyISAM-Engine, die die Standardbytes für Blockgrößen verwendet, in einer Tabelle gespeichert B = 1,024
. Der Blockierungsfaktor der Tabelle wären bfr = (B/R) = 1024/204 = 5
Datensätze pro Plattenblock. Die Gesamtzahl der Blöcke, die zum Halten der Tabelle erforderlich sind, beträgt N = (r/bfr) = 5000000/5 = 1,000,000
Blöcke.
Eine lineare Suche im ID-Feld würde einen Durchschnitt von N/2 = 500,000
Blockzugriffen erfordern , um einen Wert zu finden, vorausgesetzt, das ID-Feld ist ein Schlüsselfeld. Da das ID-Feld aber auch sortiert ist, kann eine binäre Suche durchgeführt werden, die durchschnittlich log2 1000000 = 19.93 = 20
Blockzugriffe erfordert . Sofort können wir sehen, dass dies eine drastische Verbesserung ist.
Jetzt ist das Feld firstName weder sortiert noch ein Schlüsselfeld, sodass eine binäre Suche nicht möglich ist und die Werte nicht eindeutig sind. Daher muss die Tabelle bis zum Ende nach genauen N = 1,000,000
Blockzugriffen gesucht werden . Diese Situation soll durch die Indizierung korrigiert werden.
Da ein Indexdatensatz nur das indizierte Feld und einen Zeiger auf den ursprünglichen Datensatz enthält, liegt es nahe, dass er kleiner ist als der Mehrfelddatensatz, auf den er zeigt. Der Index selbst erfordert also weniger Plattenblöcke als die ursprüngliche Tabelle, weshalb weniger Blockzugriffe zum Durchlaufen erforderlich sind. Das Schema für einen Index für das Feld firstName ist unten aufgeführt.
Feldname Datentyp Größe auf der Festplatte
Vorname Char (50) 50 Bytes
(Datensatzzeiger) Spezielle 4 Bytes
Hinweis : Zeiger in MySQL sind je nach Größe der Tabelle 2, 3, 4 oder 5 Byte lang.
Beispiel 2 - Indizierung
Ausgehend von unserer Beispieldatenbank mit r = 5,000,000
Datensätzen mit einer Indexdatensatzlänge von R = 54
Bytes und unter Verwendung der Standardblockgröße B = 1,024
Bytes. Der Blockierungsfaktor des Index wären bfr = (B/R) = 1024/54 = 18
Datensätze pro Plattenblock. Die Gesamtzahl der Blöcke, die zum Halten des Index erforderlich sind, beträgt N = (r/bfr) = 5000000/18 = 277,778
Blöcke.
Jetzt kann eine Suche mit dem Feld firstName den Index verwenden, um die Leistung zu steigern. Dies ermöglicht eine binäre Suche des Index mit einem Durchschnitt von log2 277778 = 18.08 = 19
Blockzugriffen. Um die Adresse des tatsächlichen Datensatzes zu finden, für dessen Lesen ein weiterer Blockzugriff erforderlich ist, um die Gesamtzahl der 19 + 1 = 20
Blockzugriffe zu ermitteln, ist dies weit entfernt von den 1.000.000 Blockzugriffen, die erforderlich sind, um eine Übereinstimmung mit dem Vornamen in der nicht indizierten Tabelle zu finden.
Wann sollte es verwendet werden?
Angesichts der Tatsache, dass das Erstellen eines Index zusätzlichen Speicherplatz erfordert (277.778 zusätzliche Blöcke aus dem obigen Beispiel, eine Erhöhung um ~ 28%) und dass zu viele Indizes Probleme verursachen können, die sich aus den Größenbeschränkungen des Dateisystems ergeben, muss sorgfältig überlegt werden, um den richtigen auszuwählen zu indizierende Felder.
Da Indizes nur verwendet werden, um die Suche nach einem übereinstimmenden Feld in den Datensätzen zu beschleunigen, ist es naheliegend, dass Indizierungsfelder, die nur für die Ausgabe verwendet werden, lediglich eine Verschwendung von Speicherplatz und Verarbeitungszeit beim Einfügen oder Löschen darstellen sollte vermieden werden. Auch angesichts der Art einer binären Suche ist die Kardinalität oder Eindeutigkeit der Daten wichtig. Die Indizierung auf einem Feld mit einer Kardinalität von 2 würde die Daten in zwei Hälften teilen, während eine Kardinalität von 1.000 ungefähr 1.000 Datensätze zurückgeben würde. Bei einer so geringen Kardinalität wird die Effektivität auf eine lineare Sortierung reduziert, und der Abfrageoptimierer vermeidet die Verwendung des Index, wenn die Kardinalität weniger als 30% der Datensatznummer beträgt, wodurch der Index effektiv zu einer Platzverschwendung wird.