Индексы БД использовать для нескольких комбинаций запросов одного и того же набора столбцов? - PullRequest
5 голосов
/ 22 октября 2011

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

Этот маркированный список представляет три различных условия запроса, обычно выполняемых для моей таблицы:

  • ГДЕ race_type =? И recordable_type =? И активный =?
  • ГДЕ race_type =? И recordable_id =? И recordable_type =? И активный =?
  • ГДЕ user_id =? И тип гонки =? И recordable_id =? И recordable_type =? И активный =?

Примечание: user_id (int), race_type (varchar), recordable_id (int), recordable_type (varchar), активный (логический)

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

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

Ответы [ 6 ]

8 голосов
/ 17 ноября 2011

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

Это не меняет того факта, что вам следует пытаться иметь определенный индекс для определенного предложения where.Если несколько индексов WHERE можно объединить в один, вы освободите некоторое пространство и циклы ЦП.

Начнем с определения индекса для каждого WHERE:

index1 (race_type, recordable_type, active)
index2 (race_type, recordable_id, recordable_type, active)
index3 (user_id, race_type, recordable_id, recordable_type, active)

InВ общем, вы можете оптимизировать свой заказ, увеличив количество элементов.Количество элементов - это число возможных значений, которые столбец будет иметь в вашем наборе данных .В вашем примере active является логическим значением.(Обратите внимание, что тот факт, что boolean может иметь только два значения, на самом деле не важен. Это может быть int , если вы знаете, что оно будет иметь только два значения: 0 и 1 ).

Низкая мощность вашего поля active означает, что с помощью одного поиска мы можем исключить половину возможных записей (конечно, в зависимости от вашего набора данных).После этого шага ваш первый индекс будет выглядеть так:

index1 (active, race_type, recordable_type)

Помимо кардинальности, вам следует обратить внимание на любую логическую иерархию между полями.Не зная точно, что означают эти имена, я полагаю, что некоторые типы рас будут иметь свои записываемые .- Это не исключает возможности использования записываемого материала с более чем одним типом расы, но вы должны выбрать ордер, и это кажется более логичным.- Таким образом, мы будем использовать порядок race_type, recordable_type.

Теперь давайте взглянем на второй индекс.Вы ввели recordable_id здесь.Не зная вашего набора данных, я могу с уверенностью предположить, что количество элементов recordable_id будет больше, чем значение recordable_type.Другими словами, будет больше идентификаторов, чем типов.Также я подозреваю иерархию между типом и идентификатором (пахнет как один ко многим).Итак, давайте поместим его после типа:

index2 (active, race_type, recordable_type, recordable_id)

Теперь пришло время обратить внимание на другой важный аспект.Индексы имеют свою стоимость на вашем жестком диске (в основном бесплатную) и циклы ЦП, когда изменяет вашей БД.Подмножество любого индекса можно использовать, начиная слева направо.index2 по существу содержит index1, как и index1 + recordable_id, так что вы можете просто избавиться от него и в итоге получить один.

Вдоль user_id.В качестве поля идентификатора он предлагает большую мощность (много возможных значений), но учтите, что не является правилом , что «чем больше мощность, тем позже будет заполнено поле».Мы скорее использовали кардинальность в качестве маяка, чтобы помочь определить иерархические отношения между полями.(И размеры индекса сокращения).

Указывает ли user_id на отдельного участника, данные которого мы рассматриваем (много-много возможностей)?Или клиент загрузил данные (очень мало возможностей)?Сложно сказать.Вы можете просто добавить его к нашему существующему index2, и в итоге вы получите один индекс, который можно использовать во всех трех секриариях:

search_index (active, race_type, recordable_type, recordable_id, user_id)

... или он может стоить иметь второй индекс дляthis scanario ...

Ваш вопрос особенный, поскольку в предложении where вы используете только =.Есть много других соображений, если у вас было что-то вроде AND (race_type = 1 OR race_type=8) Не говоря уже о > или <.Также, если вы используете ORDER BY, это может быть учтено в используемых вами индексах.

3 голосов
/ 16 ноября 2011

Первый шаг - использовать EXPLAIN в запросах, которые вы рассматриваете для оптимизации. MySQL объяснение вернет важную информацию о том, какие индексы будут использоваться для выполнения запроса, и поможет вам оптимизировать ваши запросы.

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

Вам также следует рассмотреть возможность изменения столбцов varchar на идентификаторы, ссылающиеся на таблицы поиска. Это добавит некоторую дополнительную схему в вашу базу данных, но вы получите следующие преимущества:

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

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

2 голосов
/ 16 ноября 2011

imho

alter table your_table
add index ( race_type, recordable_type, active, user_id, recordable_id);
// watch-out the max length allowed for an index

общие найденные столбцы race_type, recordable_type, active,
, и я думаю, что при построении индекса все 5 столбцов будут соответствовать всем шаблонам поиска.

пожалуйста, дайте мне знать, если предложение не работает

1 голос
/ 17 ноября 2011

Mysql использует самые левые индексы, это означает, что, если индекс сложный (содержит более одного столбца), запрос переходит по индексу слева направо в списке столбцов индекса, если есть void (запрос where или оператор join не имеет чем дальнейшие столбцы индекса не будут использоваться)

быстрый совет, для полей с несколькими возможными значениями вы можете написать запрос, что он перекрывает все возможные значения, что означает, что еще можно использовать больше столбцов индекса (например, где (active = 0 или active = 1) и ...)

1 голос
/ 17 ноября 2011

В вашем случае правильный индекс равен user_id + race_type + recordable_id + recordable_type + active в любом порядке. Это было просто. Вы спрашивали об общем подходе? Вот оно.

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

Все столбцы, используемые в where, order и group by, должны иметь индексы. Mysql использует двоичные деревья для индексации. Это означает, что индексы могут использоваться частично слева направо без пробелов. Например. у нас есть составной индекс над (а, б). Итак: WHERE a = 1 AND b = 1 - использует полный индекс, WHERE a = 1 - использует половину индекса - двоичные индексы дерева могут использоваться частично слева, WHERE b = 1 - использует полный просмотр (индекс не может быть использован), WHERE (a = 0 OR a = 1) AND b = 1 - использует полный просмотр (mysql не поддерживает несколько поисковых веток).

Некоторые запросы вообще не могут использовать индексы. Например. запросы с оператором «ИЛИ» (двоичные индексы дерева являются последующими). Или col LIKE "% ...%" - двоичные индексы можно использовать только частично слева.

Алгоритм применения правильных индексов: получите все уникальные имена столбцов, которые вы используете в "ГДЕ". Возьмите все уникальные имена столбцов из порядка и группы по тому, как они отображаются в запросе, и добавьте их в поля из "ГДЕ" (добавьте справа). Чем минимизировать индексы, чтобы они все еще могли использоваться mysql.

В ваших запросах нет заказов, но заказам также нужны индексы. Поэтому я сделал ваш пример немного сложнее:

  • ГДЕ race_type =? И recordable_type =? И активный =? ЗАКАЗАТЬ по типу расы
  • ГДЕ race_type =? И recordable_id =? И recordable_type =? И активный =? ЗАКАЗАТЬ по дате DESC,
  • ГДЕ user_id =? И тип гонки =? И recordable_id =? И recordable_type =? И активный =? ЗАКАЗАТЬ по дате ASC

    1. Индексы из "ГДЕ": "тип_расы + тип_записи + активный", "тип_расы + тип записи_идентификатора + тип_записи + активный" и "идентификатор_пользователя + тип_расхода + запись._ид + тип_записи + активный".

    2. Добавление индексов из сортов:

      • тип_расы + тип записи + активный + тип_расы
      • тип_расы + идентификатор_записи + тип_записи + активная + дата
      • user_id + race_type + recordable_id + recordable_type + active + date
    3. Сократить индексы:

      • recordable_type + active + race_type (используется как для "WHERE", так и для "ORDER")
      • recordable_type + active + race_type + recordble_id + date (транспонировал два столбца, но оставил «date» в конце для сортировки)
      • без изменений (мы не можем переместить «user_id» после «date» и попытаться включить предыдущий индекс в этот)

Видите, индекс № 1 включен в индекс № 2, поэтому выбросьте индекс № 1. Наконец, у нас есть два индекса:

  • recordable_type + active + race_type + recordble_id + date
  • user_id + race_type + recordable_id + recordable_type + active + date

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

0 голосов
/ 17 ноября 2011

У вас есть следующие поля в условиях WHERE: user_id, race_type, recordable_id, recordable_type и active.Некоторые из них могут повторять указанное в условии.

Я заказал их следующим образом:

* WHERE race_type = ? AND recordable_type = ? AND active = ?
* WHERE race_type = ? AND recordable_type = ? AND active = ? AND recordable_id = ?
* WHERE race_type = ? AND recordable_type = ? AND active = ? AND recordable_id = ? AND user_id = ?

Это позволяет нам создать один составной индекс:

ALTER TABLE table_name
  ADD INDEX IX_table_name (race_type, recordable_type, active, recordable_id, user_id);

Если таблица имеет другие индексы или первичный ключ, добавьте предложение USE INDEX для использования именованного индекса:

SELECT * FROM table_name USE INDEX IX_table_name
WHERE
  race_type = ? AND recordable_type = ? AND active = ? AND recordable_id = ? AND user_id = ?
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...