(я не согласен с индексами, рекомендованными в другом ответе.)
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
, он обычно работает следующим образом:
- Начните с таблицы с лучшими
WHERE
. Это было бы t2
. Таким образом, должен быть INDEX
, начинающийся с value
. - Затем переходите к другому столу. Единственный следующий выбор -
tt
из-за предложения ON
на этот раз. - После этого
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