Подтвердить что ты не робот

Множественные и одиночные индексы

Мне немного стыдно спрашивать об этом, так как я много лет работаю с MySQL, но хорошо.

У меня есть таблица с двумя полями, a и b. Я буду запускать в нем следующие запросы:

  • SELECT * FROM ... WHERE A = 1;
  • SELECT * FROM ... WHERE B = 1;
  • SELECT * FROM ... WHERE A = 1 AND B = 1;

С точки зрения производительности по меньшей мере одна из следующих конфигураций индексов медленнее, по крайней мере, для одного запроса? Если да, пожалуйста, уточните.

  • ALTER TABLE ... ADD INDEX (a); ALTER TABLE ... ADD INDEX (b);
  • ALTER TABLE ... ADD INDEX (a, b);
  • ALTER TABLE ... ADD INDEX (a); ALTER TABLE ... ADD INDEX (b); ALTER TABLE ... ADD INDEX (a, b);

Спасибо (обратите внимание, что речь идет о не уникальных индексах)

4b9b3361

Ответ 1

Да, хотя бы один случай значительно медленнее. Если вы определяете только следующий индекс:

ALTER TABLE ... ADD INDEX (a, b);

... тогда запрос SELECT * FROM ... WHERE B = 1; не будет использовать этот индекс.

Когда вы создаете индекс с составным ключом, порядок столбцов ключа важен. Рекомендуется попытаться упорядочить столбцы в ключе, чтобы повысить избирательность, причем наиболее избирательные столбцы находятся в самой левой части ключа. Если вы этого не сделаете и поставьте неселективный столбец в качестве первой части ключа, вы рискуете вообще не использовать этот индекс. (Источник: Советы по оптимизации индекса Composite SQL Server)

Ответ 2

Очень маловероятно, что простое существование индекса замедляет запрос SELECT: он просто не будет использоваться.

В теории оптимизатор может неправильно выбрать более длинный индекс на (a, b), а не один на (a), чтобы обслуживать запрос, который ищет только a.

На практике я никогда не видел его: MySQL обычно делает противоположную ошибку, принимая более короткий индекс, когда существует более длинный.

Update:

В вашем случае для всех запросов будет достаточно одной из следующих конфигураций:

(a, b); (b)

или

(b, a); (a)

MySQL также может использовать два отдельных индекса с index_intersect, поэтому создание этих индексов

(a); (b)

также ускорит запрос с помощью a = 1 AND b = 1, хотя и в меньшей степени, чем любое из вышеперечисленных решений.

Вы также можете прочитать эту статью в своем блоге:

Обновление 2:

Кажется, я наконец понял ваш вопрос:)

ALTER TABLE ... ADD INDEX (a); ALTER TABLE ... ADD INDEX (b);

Отлично подходит для a = 1 и b = 1, достаточно хорош для a = 1 AND b = 1

ALTER TABLE ... ADD INDEX (a, b);

Отлично подходит для a = 1 AND b = 1, почти отлично подходит для a = 1, для b = 1

ALTER TABLE ... ADD INDEX (a); ALTER TABLE ... ADD INDEX (b); ALTER TABLE ... ADD INDEX (a, b);

Отлично подходит для всех трех запросов.

Ответ 3

SQL будет выбирать индекс, который наилучшим образом охватывает запрос. Индекс на A, B будет охватывать запрос как для случая 1, так и для 3, но не для 2 (поскольку столбец первичного индекса равен A)

Итак, чтобы охватить все три запроса, вам нужны два индекса:

ALTER TABLE ... ADD INDEX (a, b); ALTER TABLE ... ADD INDEX (b)

Ответ 4

Для примера у вас есть индексный набор №3, оптимальный. Mysql выберет одиночные индексы A и B для одного столбца, где предложения, и используйте составной индекс для предложения A и B where.