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 из таблицы 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 .
UNIQUE
ключей?