MySQL Забороняє індексації повної вартості BLOB
, TEXT
і довгі VARCHAR
стовпці , так як дані , які вони містять , може бути величезними, і неявно індекс DB будуть великими, не означають нічого не поможе індексу.
MySQL вимагає, щоб ви визначили перші N символів для індексації, а хитрість полягає у виборі числа N, яке досить довге, щоб дати гарну вибірковість, але досить коротке, щоб заощадити місце. Префікс повинен бути досить довгим, щоб зробити індекс майже таким же корисним, як це було б, якби ви індексували весь стовпець.
Перш ніж піти далі, давайте визначимося з деякими важливими термінами. Селективність індексу - це відношення загальної різної індексованої величини та загальної кількості рядків . Ось один приклад для тестової таблиці:
+-----+-----------+
| id | value |
+-----+-----------+
| 1 | abc |
| 2 | abd |
| 3 | adg |
+-----+-----------+
Якщо ми індексуємо лише перший символ (N = 1), то таблиця індексів буде мати вигляд наступної таблиці:
+---------------+-----------+
| indexedValue | rows |
+---------------+-----------+
| a | 1,2,3 |
+---------------+-----------+
У цьому випадку вибірковість індексу дорівнює IS = 1/3 = 0,33.
Давайте тепер подивимося, що буде, якщо збільшити кількість індексованих символів до двох (N = 2).
+---------------+-----------+
| indexedValue | rows |
+---------------+-----------+
| ab | 1,2 |
| ad | 3 |
+---------------+-----------+
У цьому сценарії IS = 2/3 = 0,66, це означає, що ми збільшили вибірковість індексу, але також збільшили розмір індексу. Трюк - знайти мінімальне число N, що призведе до максимальної вибірковості індексу .
Існує два підходи, за допомогою яких можна обчислити таблицю бази даних. Я продемонструю цей дамп на базі даних .
Скажімо, ми хочемо додати ім'я стовпця last_name до працівників таблиці до індексу, і ми хочемо визначити найменше число N, яке створить найкращу вибірковість індексу.
Спершу визначимо найчастіші прізвища:
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)
Як бачите, прізвище Баба є найчастішим. Тепер ми будемо знаходити префікси прізвища, що найчастіше зустрічаються , починаючи з п'ятибуквених префіксів.
+-----+--------+
| 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)
Кожен префікс набагато більше, а це означає, що нам потрібно збільшити число N, поки значення майже не будуть такими ж, як у попередньому прикладі.
Ось результати для 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 |
+-----+-----------+
Ось результати для 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)
Це дуже хороші результати. Це означає, що ми можемо робити індекс на стовпчику last_name
з індексуванням лише перших 10 символів. У таблиці визначення стовпця last_name
визначається як VARCHAR(16)
, і це означає, що ми зберегли 6 байтів (або більше, якщо в прізвищі є символи UTF8) на запис. У цій таблиці 1637 різних значень, помножених на 6 байт, це приблизно 9 КБ, і уявіть, як зростало б це число, якщо наша таблиця містить мільйон рядків.
Ви можете прочитати інші способи обчислення кількості N у моєму пост Префіксні індекси в MySQL .
UNIQUE
ключів?