2011-01-09 7 views
3

Я полный новичок с индексами MySQL. У меня есть несколько таблиц MyISAM в MySQL 5.0x, имеющих кодировки utf8 и сопоставления с 100k + записями. Первичные ключи обычно целые. Многие столбцы на каждой таблице могут иметь повторяющиеся значения.Индексы MySQL: как они работают?

Мне нужно быстро подсчитать, суммировать, усреднять или иным образом выполнять пользовательские вычисления по любому числу полей в каждой таблице или присоединяться к любому числу других.

Я нашел эту страницу, дающую обзор использования индекса MySQL: http://dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html, но я все еще не уверен, что использую индексы правильно. Просто, когда я думаю, что сделал идеальный индекс из коллекции полей, которые я хочу рассчитать, я получаю ошибку «индекс должен быть меньше 1000 байтов».

Может ли кто-нибудь объяснить, как наиболее эффективно создавать и использовать индексы для ускорения запросов?

Предостережение: модернизация Mysql в этом случае невозможна. Использование Navicat Light для администрирования db, но это приложение не требуется.

+0

только поместить индекс в поля, которые вы хотели бы искать, в условии where, а не те, которые вы хотите суммировать или усреднить. – dqhendricks

+0

@dqhendricks: это впечатление, которое я получаю от страницы документа MySQL, связанной выше. Но у меня часто будет более одного поля в 'WHERE', и часто более одного поля, добавленного в индекс, вызывает эту ошибку. –

+0

Если у вас слишком много полей, вы можете неправильно структурировать свои таблицы, например, добавив кучу полей для атрибутов, вместо того, чтобы иметь отдельную таблицу атрибутов, которую вы связываете с основной таблицей, используя внешние ключи и запросы JOIN. – dqhendricks

ответ

8

Когда вы создаете индекс в столбце или столбцах в таблице 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 like:

ALTER TABLE mytable ADD KEY (column_a, column_b); 

В базе данных будет создано aforementi oned B-дерево, которое будет иметь четыре клавиши в ней, один для каждой строки:

hello-2 
hello-3 
how-4 
foo-5 

При выполнении поиска, который ссылается на column_a столбце, или ссылаются на column_a И column_b столбцов, база данных будет иметь чтобы использовать этот индекс для сужения набора записей, который он должен исследовать. Скажем, у вас есть вопрос, как:

SELECT ... FROM mytable WHERE column_a = 'hello'; 

Несмотря на приведенный выше запрос не указывает значение для column_b колонны, он все еще может воспользоваться нашим индексом, глядя на все лады, которые начинаются с «привет». По той же причине, если у вас есть запрос типа:

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. Предположим, что он работает DID; вы будете создавать следующие ключи:

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 в декларация выше. Однако, вообще говоря, если вы используете длинные ключи, возможно, что-то не так с вашим дизайном таблицы.

Помните, что индексы с одним столбцом часто обеспечивают большую полезность, чем индексы с несколькими столбцами. Вы хотите использовать многоколоночный индекс, когда часто собираетесь/всегда используете его, указав все необходимые критерии в своих запросах. Кроме того, как отмечали другие, НЕ индексируйте каждый столбец таблицы, поскольку каждый индекс добавляет накладные расходы на хранение в вашу базу данных.Вы хотите ограничить свои индексы столбцами, которые часто используются в запросах, и если вам кажется, что вам нужно слишком много, вы, вероятно, должны подумать о том, чтобы разбить ваши таблицы на более логические компоненты.

+0

Спасибо за отличное объяснение. Что вы думаете о решении _prefix indexes_, данное @ bill-karvin здесь ?: http://stackoverflow.com/a/8747703/569439 Как вы думаете, такие индексы будут работать? – rineez

1

Индексы, как правило, не подходят для пользовательских вычислений, когда пользователь может создавать свои собственные запросы. Как правило, вы выбираете индексы для соответствия конкретным запросам, которые вы собираетесь запускать, используя EXPLAIN, чтобы узнать, используется ли этот индекс.

В случае, если вы абсолютно не знаете, какие запросы могут быть выполнены, как правило, лучше всего создать один индекс на столбец - и не один индекс, охватывающий все столбцы.

Если у вас есть хорошее представление о том, какие запросы могут выполняться часто, вы можете создать дополнительный индекс для этих конкретных запросов. Вы также можете добавить индексы позже, если ваши пользователи жалуются, что определенные типы запросов выполняются слишком медленно.

Кроме того, индексы обычно не так полезны для вычисления счетчиков, сумм и средних значений, так как для этих типов вычислений требуется просмотр каждой строки.

+0

", используя EXPLAIN, чтобы узнать, используется ли индекс." Благодарю. Я обязательно проверю это. Но по ожидаемым запросам, как вы думаете, я должен лучше всего составлять индексы? Обычно я предполагаю, какие поля ссылаются на 'WHERE', но я не знаю, почему я запутался или как избежать ограничения байта. Часто это мешает мне добавлять в индекс больше одного поля. –

1

Похоже, вы пытаетесь поместить слишком много полей в свой индекс. Предел - это, вероятно, количество байтов, которое требуется для кодирования всех полей.

Этот индекс используется для поиска записей, поэтому вы хотите выбрать поля, которые вы «ГДЕ». Выбирая между этими полями, вы хотите выбрать те, которые быстрее сократят результаты.

В качестве примера, фильтр для мужчин и женщин, как правило, не поможет, потому что вы собираетесь экономить около 50% времени. Однако фильтр по состоянию может быть полезен, потому что вы разделитесь на многие другие категории. Однако, если почти все в базе данных находятся в одном состоянии, это не сработает.

+0

«Предел - это, вероятно, количество байтов, которое требуется для кодирования всех полей». Что ты имеешь в виду? Кодирование имен полей, всех уникальных значений столбца или ...? –

+1

@ bob-the-destroyer: значения. то есть 4 байта для целого числа, 11 для текстового поля с 11 символами и т. д. –

+0

Если вы используете этот предел, у вас слишком много полей в вашем индексе. –

1

Помните, что индексы предназначены для сортировки и поиска строк.

Сообщение об ошибке, которое вы получили, похоже на то, что речь идет о префиксном префиксе 1000 байтов для индексов таблицы MyISAM. Из http://dev.mysql.com/doc/refman/5.0/en/create-index.html:

The statement shown here creates an index using the first 10 characters of the name column:

CREATE INDEX part_of_name ON customer (name(10)); If names in the column usually differ in the first 10 characters, this index should not be much slower than an index created from the entire name column. Also, using column prefixes for indexes can make the index file much smaller, which could save a lot of disk space and might also speed up INSERT operations.

Prefix support and lengths of prefixes (where supported) are storage engine dependent. For example, a prefix can be up to 1000 bytes long for MyISAM tables, and 767 bytes for InnoDB tables.

Может быть, вы можете попробовать полнотекстовый индекс для проблемных столбцов.

+0

ntag: В итоге я назвал каждый индекс «a», «b», «c» и т. Д., Который все еще вызывал эту ошибку размера. Вот почему моя путаница в отношении размера индекса здесь. –

Смежные вопросы