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)
Це дуже хороші результати. Це означає, що ми можемо робити покажчик на прізвище стовпця, індексуючи лише перші 10 символів. У таблиці визначення стовпця прізвище last_name визначається як VARCHAR(16)
, і це означає, що ми зберегли 6 байтів (або більше, якщо в прізвищі є символи UTF8). У цій таблиці 1637 різних значень, помножених на 6 байт, це приблизно 9 КБ, і уявіть, як зростало б це число, якщо наша таблиця містить мільйон рядків.
Ви можете прочитати інші способи обчислення кількості N у моєму пост Префіксні індекси в MySQL .
Використання функцій MD5 та SHA1 для генерування значень, які слід індексувати, також не є гарним підходом . Чому? Прочитайте його у публікації Як правильно вибрати тип даних для первинного ключа в базі даних MySQL