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 из таблицы employee в индекс, и мы хотим определить наименьшее число 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)
Как видите, фамилия Баба - самая частая. Теперь мы собираемся найти наиболее часто встречающиеся префиксы last_name , начиная с пятибуквенных префиксов.
+-----+--------+
| 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 .
Использование функций MD5 и SHA1 для генерации значений, которые должны быть проиндексированы, также не является хорошим подходом . Зачем? Прочтите это в посте Как правильно выбрать тип данных для первичного ключа в базе данных MySQL