Два индекса с одним столбцом против одного индекса с двумя столбцами в MySQL?


114

Я столкнулся со следующим, и я не уверен, что лучше всего.

Рассмотрим следующую таблицу (которая станет больше):

id PK | giver_id FK | recipient_id FK | Дата

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

SELECT...WHERE giver_id = x AND recipient_id = t.

Каждая такая комбинация будет уникальной в таблице.

Есть ли какая-то выгода от добавления индекса из двух столбцов к этим столбцам, или два отдельных индекса теоретически будут достаточными / одинаковыми?


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

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

Для экстраполяции на @ user1585784; Если комбинация двух столбцов уникальна, я думаю, что для них следует использовать уникальный ключ. На самом деле, если кто-то хочет обеспечить уникальность на уровне базы данных, уникальный ключ - это самый простой способ ...
Эрк

Ответы:


133

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

Если у вас есть индекс с двумя столбцами, запрос может быть быстрее (вы должны измерить). Индекс из двух столбцов также может использоваться как индекс из одного столбца, но только для столбца, указанного первым.

Иногда может быть полезно иметь индекс для (A, B) и другой индекс для (B). Это делает запросы, использующие один или оба столбца быстрыми, но, конечно, также использует больше дискового пространства.

При выборе индексов также необходимо учитывать влияние на вставку, удаление и обновление. Больше индексов = более медленные обновления.


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

33

Индекс покрытия, например:

ALTER TABLE your_table ADD INDEX (giver_id, recipient_id);

... будет означать, что индекс можно использовать, если упоминается запрос giver_idили комбинация giver_idи recipient_id. Имейте в виду, что критерий индекса основан на крайнем левом положении - запрос, относящийся только к recipient_id, не сможет использовать индекс покрытия в предоставленном мною утверждении.

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


10
MySQL can only use one index per SELECTэто больше не правда, было бы неплохо, если бы вы отредактировали свой ответ, чтобы он был обновлен.
Давор

Не могли бы вы объяснить, почему индекс покрытия не может быть использован recipient_id?
Иво Перейра

2
@IvoPereira Многоколоночные индексы в MySQL позволяют использовать все поля в индексе слева направо. Например, если у вас есть, INDEX (col1, col2, col3, col4)то индекс будет применяться для поиска с таким WHEREпредложением, как col1 = 'A'или col1 = 'A' AND col2 = 'B'или col1 = 'A' AND col2 ='B' AND col3 = 'C' AND col4 = 'D', но этот конкретный индекс не будет использоваться ни для чего подобного WHERE col2 = 'B'или WHERE col3 = 'C' AND col4 = 'D'потому что поля поиска не оставлены большей частью в определении индекса. Вам придется добавить дополнительные индексы для покрытия этих полей.
Slicktrick

"один индекс на SELECT" , это все еще верно для mariadb 10.1?
oldboy

1
@Anthony: Нет. См. Комментарий Давора выше.
капад

4

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

Еще одна вещь , чтобы рассмотреть, если вы можете устранить поле PK в этой таблице и определить первичный индекс ключа на giver_idи recipient_idполей. Вы сказали, что комбинация уникальна и, возможно, она сработает (учитывая множество других условий, на которые можете ответить только вы). Однако обычно я думаю, что добавленная сложность не стоит хлопот.


Спасибо, Марк, одна из клавиш действительно очень избирательна, так что все должно быть в порядке. Я решил оставить два (автоматических) индекса на месте и посмотреть, как они будут работать с течением времени. Я также подумал о комбинированном первичном ключе дающий: получатель, но, поскольку каждое поле также должно быть доступно для поиска индивидуально, это просто добавит накладные расходы php. Кроме того, новый ключ будет (более длинной) строкой вместо (более короткого) целого числа.
Том

2

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


не могли бы вы дать ссылку на некоторую документацию по этому поводу. Спасибо.
капад
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.