MySQL verbietet die Indizierung eines vollen Wertes von BLOB
, TEXT
und lange VARCHAR
Spalten, weil die Daten, die sie enthalten, riesig sein können und der DB-Index implizit groß sein wird, was bedeutet, dass der Index keinen Nutzen bringt.
MySQL verlangt, dass Sie die ersten N Zeichen definieren, die indiziert werden sollen, und der Trick besteht darin, eine Zahl N zu wählen, die lang genug ist, um gute Selektivität zu bieten, aber kurz genug, um Platz zu sparen. Das Präfix sollte lang genug sein, um den Index fast so nützlich zu machen, wie er wäre, wenn Sie die ganze Spalte indizieren würden.
Bevor wir fortfahren, sollten wir einige wichtige Begriffe definieren. Index-Selektivität ist das Verhältnis von die Gesamtzahl der eindeutigen indizierten Werte und die Gesamtzahl der Zeilen . Hier ist ein Beispiel für eine Testtabelle:
+-----+-----------+
| id | value |
+-----+-----------+
| 1 | abc |
| 2 | abd |
| 3 | adg |
+-----+-----------+
Wenn wir nur das erste Zeichen indizieren (N=1), dann sieht die Indextabelle wie die folgende Tabelle aus:
+---------------+-----------+
| indexedValue | rows |
+---------------+-----------+
| a | 1,2,3 |
+---------------+-----------+
In diesem Fall ist die Indexselektivität gleich IS=1/3 = 0,33.
Sehen wir uns nun an, was passiert, wenn wir die Anzahl der indizierten Zeichen auf zwei erhöhen (N=2).
+---------------+-----------+
| indexedValue | rows |
+---------------+-----------+
| ab | 1,2 |
| ad | 3 |
+---------------+-----------+
In diesem Szenario ist IS=2/3=0,66, was bedeutet, dass wir die Indexselektivität erhöht haben, aber wir haben auch die Größe des Index erhöht. Der Trick besteht darin, die minimale Anzahl N zu finden, die zu einer maximalen Indexselektivität .
Es gibt zwei Möglichkeiten, wie Sie Berechnungen für Ihre Datenbanktabelle durchführen können. Ich werde eine Demonstration über die dieser Datenbank-Dump .
Nehmen wir an, wir wollen eine Spalte hinzufügen letzter_name in Tabelle Mitarbeiter zum Index, und wir wollen die kleinste Zahl definieren N die die beste Indexselektivität ergibt.
Zunächst wollen wir die häufigsten Nachnamen ermitteln:
select count(*) as cnt, last_name
from employees
group by employees.last_name
order by cnt
+-----+-------------+
| cnt | last_name |
+-----+-------------+
| 226 | Baba |
| 223 | Coorg |
| 223 | Gelosh |
| 222 | Farris |
| 222 | Sudbeck |
| 221 | Adachi |
| 220 | Osgood |
| 218 | Neiman |
| 218 | Mandell |
| 218 | Masada |
| 217 | Boudaillier |
| 217 | Wendorf |
| 216 | Pettis |
| 216 | Solares |
| 216 | Mahnke |
+-----+-------------+
15 rows in set (0.64 sec)
Wie Sie sehen können, ist der Nachname Baba ist die häufigste. Jetzt werden wir die am häufigsten vorkommenden letzter_name Präfixe, beginnend mit Präfixen aus fünf Buchstaben.
+-----+--------+
| cnt | prefix |
+-----+--------+
| 794 | Schaa |
| 758 | Mande |
| 711 | Schwa |
| 562 | Angel |
| 561 | Gecse |
| 555 | Delgr |
| 550 | Berna |
| 547 | Peter |
| 543 | Cappe |
| 539 | Stran |
| 534 | Canna |
| 485 | Georg |
| 417 | Neima |
| 398 | Petti |
| 398 | Duclo |
+-----+--------+
15 rows in set (0.55 sec)
Es gibt viel mehr Vorkommen jedes Präfixes, was bedeutet, dass wir die Anzahl N erhöhen müssen, bis die Werte fast die gleichen sind wie im vorherigen Beispiel.
Hier die Ergebnisse für N=9
select count(*) as cnt, left(last_name,9) as prefix
from employees
group by prefix
order by cnt desc
limit 0,15;
+-----+-----------+
| cnt | prefix |
+-----+-----------+
| 336 | Schwartzb |
| 226 | Baba |
| 223 | Coorg |
| 223 | Gelosh |
| 222 | Sudbeck |
| 222 | Farris |
| 221 | Adachi |
| 220 | Osgood |
| 218 | Mandell |
| 218 | Neiman |
| 218 | Masada |
| 217 | Wendorf |
| 217 | Boudailli |
| 216 | Cummings |
| 216 | Pettis |
+-----+-----------+
Hier sind die Ergebnisse für N=10.
+-----+------------+
| cnt | prefix |
+-----+------------+
| 226 | Baba |
| 223 | Coorg |
| 223 | Gelosh |
| 222 | Sudbeck |
| 222 | Farris |
| 221 | Adachi |
| 220 | Osgood |
| 218 | Mandell |
| 218 | Neiman |
| 218 | Masada |
| 217 | Wendorf |
| 217 | Boudaillie |
| 216 | Cummings |
| 216 | Pettis |
| 216 | Solares |
+-----+------------+
15 rows in set (0.56 sec)
Das sind sehr gute Ergebnisse. Das bedeutet, dass wir einen Index für die Spalte last_name
mit Indizierung nur der ersten 10 Zeichen. In der Tabellendefinitionsspalte last_name
ist definiert als VARCHAR(16)
und das bedeutet, dass wir 6 Bytes (oder mehr, wenn der Nachname UTF8-Zeichen enthält) pro Eintrag eingespart haben. In dieser Tabelle gibt es 1637 eindeutige Werte, multipliziert mit 6 Bytes ergibt das etwa 9 KB, und stellen Sie sich vor, wie diese Zahl wachsen würde, wenn unsere Tabelle Millionen von Zeilen enthält.
Sie können andere Methoden zur Berechnung der Anzahl der N in meinem Beitrag Vorangestellte Indizes in MySQL .
10 Stimmen
Eine Tabelle kann nicht mehrere Primärschlüssel haben. Meinen Sie, dass sie einen zusammengesetzten Primärschlüssel hat (d.h. mehr als eine Spalte enthält) oder dass sie mehrere
UNIQUE
Schlüssel?1 Stimmen
In meinem Fall hatte ich aus irgendeinem Grund einen TEXT-Typ für eine E-Mail-Spalte anstelle von VARCHAR.
2 Stimmen
Verwenden Sie VARCHAR für eindeutige alphanumerische Angaben.