Составной индекс требуется для ускорения объединенного запроса? - PullRequest
6 голосов
/ 12 января 2010

Коллега попросил меня объяснить, как индексы (индексы?) Повышают производительность; Я пытался это сделать, но запутался.
Я использовал модель ниже для объяснения (база данных ошибок / диагностики). Он состоит из трех таблиц:

  • Список бизнес-систем, таблица «Система», содержащая их названия
  • Список различных типов трассировок, таблица «TraceTypes», определяющая, какие виды сообщений об ошибках могут регистрироваться
  • Актуальные сообщения трассировки с внешними ключами из таблиц System и TraceTypes

Я использовал MySQL для демонстрации, однако я не помню типы таблиц, которые я использовал. Я думаю, что это был InnoDB.

 System                                TraceTypes
-----------------------------         ------------------------------------------
| ID          | Name        |         | ID    | Code   | Description           |
-----------------------------         ------------------------------------------
| 1           | billing     |         | 1     | Info   | Informational mesage  |
| 2           | hr          |         | 2     | Warning| Warning only          |
-----------------------------         | 3     | Error  | Failure               |
           |                          ------------------------------------------
           |                ------------|
 Traces    |                |            
 --------------------------------------------------
 | ID | System_ID | TraceTypes_ID | Message       |
 --------------------------------------------------
 | 1  |  1        |  1            | Job starting  |
 | 2  |  1        |  3            | System.nullr..|
 --------------------------------------------------

Сначала я добавил несколько записей во все таблицы и продемонстрировал, что приведенный ниже запрос выполняется за 0,005 секунды:

select count(*) from Traces 
  inner join System on Traces.System_ID = System.ID
  inner join TraceTypes on Traces.TraceTypes_ID = TraceTypes.ID
where 
  System.Name='billing' and TraceTypes.Code = 'Info'

Затем я сгенерировал больше данных (пока нет индексов)

  • «Система» содержит около 100 записей
  • "TraceTypes" содержит около 50 записей
  • «Следы» содержали ~ 10 миллионов записей.

Теперь предыдущий запрос занял 8-10 секунд.

Я создал индексы для столбца Traces.System_ID и столбца Traces.TraceTypes_ID. Теперь этот запрос выполняется за миллисекунды:

select count(*) from Traces where System_id=1 and TraceTypes_ID=1;

Это было также быстро:

select count(*) from Traces 
  inner join System on Traces.System_ID = System.ID
where System.Name='billing' and TraceTypes_ID=1;

, но предыдущий запрос, объединяющий все три таблицы, все еще занимал 8-10 секунд.

Только при создании составного индекса (столбцы System_ID и TraceTypes_ID включены в индекс) скорость снижалась до миллисекунд.

Основное утверждение, которому меня учили ранее, это «все столбцы, которые вы используете для объединения, должны быть проиндексированы».
Однако в моем сценарии у меня были индексы как System_ID, так и TraceTypes_ID, однако MySQL их не использовал. Вопрос - почему? Мои ставки - соотношение количества предметов 100: 10 000 000: 50 делает индексы из одного столбца слишком большими для использования. Но так ли это?

Ответы [ 3 ]

2 голосов
/ 13 января 2010

Во-первых, правильный и самый простой способ проанализировать медленный оператор SQL - это выполнить EXPLAIN. Узнайте, как оптимизатор выбрал свой план, и подумайте, почему и как его улучшить. Я бы посоветовал изучить результаты EXPLAIN только с двумя отдельными индексами, чтобы увидеть, как mysql выполняет вашу инструкцию.

Я не очень знаком с MySQL, но, похоже, в MySQL 4 есть ограничение на использование только одного индекса на таблицу, участвующую в запросе. Кажется, есть улучшения в этом, так как MySQL 5 ( index merge ), но я не уверен, применимо ли это к вашему случаю. Опять же, EXPLAIN должна сказать вам правду.

Даже при использовании 2 индексов на таблицу (MySQL 5) использование 2 отдельных индексов, как правило, медленнее, чем составного индекса. Использование 2 отдельных индексов требует шага слияния индекса по сравнению с одним проходом использования составного индекса.

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

1 голос
/ 12 января 2010

Не размер индексов, а их селективность определяет, будет ли их использовать оптимизатор.

0 голосов
/ 12 января 2010

Я предполагаю, что он будет использовать индекс, а затем использовать традиционный поиск, чтобы перейти к другому индексу и затем отфильтровать. Пожалуйста, проверьте план выполнения. Короче говоря, вы можете проходить по двум индексам во вложенном цикле. Согласно моему пониманию. Мы должны попытаться создать составной индекс для столбца, который находится в фильтре или в соединении, а затем мы должны использовать предложение Include для столбцов, которые находятся в select. Я никогда не работал в MySql, поэтому мое понимание основано на SQL Server 2005.

...