Когда вы создаете индекс для столбца или столбцов в таблице MySQL, база данных создает структуру данных, называемую B-деревом (при условии, что вы используете настройку индекса по умолчанию), для которой ключ каждой записи является конкатенацией значения в индексированных столбцах.
Например, предположим, у вас есть таблица, которая определяется как:
CREATE TABLE mytable (
id int unsigned auto_increment,
column_a char(32) not null default '',
column_b int unsigned not null default 0,
column_c varchar(512),
column_d varchar(512),
PRIMARY KEY (id)
) ENGINE=MyISAM;
Тогда давайте приведем некоторые данные:
INSERT INTO mytable VALUES (1, 'hello', 2, null, null);
INSERT INTO mytable VALUES (2, 'hello', 3, 'hi', 'there');
INSERT INTO mytable VALUES (3, 'how', 4, 'are', 'you?');
INSERT INTO mytable VALUES (4, 'foo', 5, '', 'bar');
Теперь предположим, что вы решили добавить ключ к column_a
и column_b
, например:
ALTER TABLE mytable ADD KEY (column_a, column_b);
База данных собирается создать вышеупомянутое B-дерево, в котором будет четыре ключа, по одному для каждой строки:
hello-2
hello-3
how-4
foo-5
Когда вы выполняете поиск по столбцу column_a
или по столбцам column_a
AND column_b
, база данных сможет использовать этот индекс для сужения набора записей, который необходимо проверить. Допустим, у вас есть запрос вроде:
SELECT ... FROM mytable WHERE column_a = 'hello';
Несмотря на то, что в приведенном выше запросе не указано значение для столбца column_b
, он все равно может воспользоваться нашим индексом, ища все ключи, которые начинаются с «hello». По той же причине, если у вас был запрос вроде:
SELECT ... FROM mytable WHERE column_b = '2';
Этот запрос НЕ сможет использовать наш индекс, потому что ему придется анализировать сами ключи индекса, чтобы попытаться определить, какое из двух значений ключей соответствует '2', что ужасно неэффективно.
Теперь давайте обратимся к вашему первоначальному вопросу максимальной длины. Предположим, мы пытаемся создать индекс, охватывающий все четыре столбца без PK в этой таблице:
ALTER TABLE mytable ADD KEY (column_a, column_b, column_c, column_d);
Вы получите ошибку:
ERROR 1071 (42000): Specified key was too long; max key length is 1000 bytes
В этом случае наши длины столбцов равны 32, 10, 512 и 512, что в ситуации «один байт на символ» равно 1066, что превышает предел 1000. Предположим, что он работает; вы будете создавать следующие ключи:
hello-2-
hello-3-hi-there
how-4-are-you?
foo-5--bar
Теперь предположим, что у вас были значения в column_c
и column_d
, которые были очень длинными - 512 символов каждое. Даже в базовом однобайтовом наборе символов ваши ключи теперь будут иметь длину более 1000 байт, на что жалуется MySQL. Это становится еще хуже с многобайтовыми наборами символов, где, казалось бы, «маленькие» столбцы могут по-прежнему нажимать клавиши выше предела.
Если вы ДОЛЖНЫ использовать большой составной ключ, одним из решений является использование таблиц InnoDB, а не таблиц MyISAM по умолчанию, которые поддерживают большую длину ключа (3500 байт) - вы можете сделать это, поменяв ENGINE=InnoDB
вместо ENGINE=MyISAM
в объявлении выше. Однако, вообще говоря, если вы используете длинные ключи, возможно, что-то не так с вашим дизайном стола.
Помните, что индексы с одним столбцом часто предоставляют больше полезности, чем индексы с несколькими столбцами. Вы хотите использовать многостолбцовый индекс, когда будете часто / всегда использовать его, указав все необходимые критерии в своих запросах. Кроме того, как уже упоминали другие, НЕ индексируйте каждый столбец таблицы, поскольку каждый индекс добавляет дополнительные ресурсы хранения в вашу базу данных. Вы хотите ограничить свои индексы столбцами, которые часто используются запросами, и если вам кажется, что вам нужно слишком много, вам, вероятно, следует подумать о разбиении ваших таблиц на более логичные компоненты.