Работает ли составной ИНДЕКС для ОБЪЕДИНЕНИЯ (МНОГО-МНОГО)? - PullRequest
0 голосов
/ 04 февраля 2020

tt - таблица сопоставления. tt структура

table_1 | таблица_2 | table_3

   SELECT t1.foo1, t2.foo2, t3.foo3 FROM tt 
        JOIN table1 t1 ON tt.table_1 = t1.id
        JOIN table2 t2 ON tt.table_2 = t2.id
        JOIN table3 t3 ON tt.table_3 = t3.id
    WHERE t2.value = 'test'

Имеет ли индекс смысл и будет работать для tt? Составной индекс: ix_table_1__table_2__table_3(table1, table2, table_3)

Если да - почему, если нет - почему?

Ответы [ 3 ]

2 голосов
/ 04 февраля 2020

(я не согласен с индексами, рекомендованными в другом ответе.)

SELECT * FROM tt 
    JOIN table1 t1 ON tt.table_1 = t1.id
    JOIN table2 t2 ON tt.table_2 = t2.id
    JOIN table3 t3 ON tt.table_3 = t3.id
WHERE t2.value = 'test'

Когда оптимизатор выбирает, как выполнить JOIN, он обычно работает следующим образом:

  1. Начните с таблицы с лучшими WHERE. Это было бы t2. Таким образом, должен быть INDEX , начинающийся с value.
  2. Затем переходите к другому столу. Единственный следующий выбор - tt из-за предложения ON на этот раз.
  3. После этого t1 и t3, в любом порядке.

Теперь для индексы, перечисленные в указанном выше порядке:

t2:  INDEX(value)
tt:  INDEX(table_2)

t1 и t3 доступны через их id. Итак, если вы соблюдаете соглашение, согласно которому id является ПК, то PRIMARY KEY(id) уже существует.

Теперь давайте переключимся на новую версию запроса:

SELECT t1.foo1, t2.foo2, t3.foo3 FROM tt  ...

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

t2:  INDEX(value, id, foo2)
tt:  INDEX(table_2, table_3, table_1)  -- table_2 must be first

Две вещи, на которые следует обратить внимание при рассмотрении индекса "покрытия":

  • При достижении таблицы через PRIMARY KEY нет никакого преимущества в создании «покрывающего» индекса. PK «кластеризован» с данными, следовательно, фактически «покрывает».
  • Не имеет смысла иметь слишком много столбцов в индексе. Вы запрашиваете все (*) столбцы.

Подробнее о создании оптимальных индексов: http://mysql.rjweb.org/doc.php/index_cookbook_mysql

Увы, EXPLAIN показывает, что является сделано с тем, что доступно; не следует добавлять индексы и другие советы.

Ваши таблицы не похожи на традиционные многие: многие таблицы. См. Это для конкретных c советов по этому типу таблицы: http://mysql.rjweb.org/doc.php/index_cookbook_mysql#many_to_many_mapping_table

1 голос
/ 04 февраля 2020

Если три поля всегда вместе, то составной имеет смысл.

, но в вашем случае вам также понадобится один единственный для t2.value

1 голос
/ 04 февраля 2020

Для этого запроса:

SELECT * FROM tt 
    JOIN table1 t1 ON tt.table_1 = t1.id
    JOIN table2 t2 ON tt.table_2 = t2.id
    JOIN table3 t3 ON tt.table_3 = t3.id
WHERE t2.value = 'test'

Да, индекс на tt(table_1, table_2, table_3) может быть полезным.

Вам также нужны индексы для следующих столбцов:

t1(id)
t2(id, value)
t3(id)

Как прокомментировал spencer7593, вы также можете попробовать t2(value, id) вместо t2(id, value). Если id является первичным ключом в том виде, как он выглядит, первый должен быть гораздо более эффективным, поскольку его можно использовать для предварительной фильтрации записей в предложении where и эффективного ограничения количества строк, к которым нужно присоединиться.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...