Я встречаю странное поведение MySQL. Выполнение запроса (т.е. Использование индексов, как показано в пояснении [QUERY]), и время, необходимое для выполнения, зависят от элементов предложения where.
Вот запрос, в котором возникает проблема:
select distinct
e1.idx, el1.idx, r1.fk_cat, r2.fk_cat
from ent e1, ent_leng el1, rel_c r1, _tax_c t1, rel_c r2, _tax_c t2
where el1.fk_ent=e1.idx
and r1.fk_ent=e1.idx and ((r1.fk_cat=43) or (r1.fk_cat=t1.fk_cat1 and t1.fk_cat2=43))
and r2.fk_ent=e1.idx and ((r2.fk_cat=10) or (r2.fk_cat=t2.fk_cat1 and t2.fk_cat2=10))
Соответствующий вывод объяснения:
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra
+----+-------------+-------+--------+-------------------------+---------+---------+---------------+-------+------------------------------------
| 1 | SIMPLE | el1 | index | fk_ent | fk_ent | 4 | NULL | 15002 | Using index; Using temporary
| 1 | SIMPLE | e1 | eq_ref | PRIMARY | PRIMARY | 4 | DB.el1.fk_ent | 1 | Using index
| 1 | SIMPLE | r1 | ref | fk_ent,fk_cat,fks | fks | 4 | DB.e1.idx | 1 | Using where; Using index
| 1 | SIMPLE | r2 | ref | fk_ent,fk_cat,fks | fks | 4 | DB.el1.fk_ent | 1 | Using index
| 1 | SIMPLE | t1 | index | fk_cat1,fk_cat2,fk_cats | fk_cats | 8 | NULL | 69 | Using where; Using index; Distinct;
| | | | | | | | | | Using join buffer
| 1 | SIMPLE | t2 | index | fk_cat1,fk_cat2,fk_cats | fk_cats | 8 | NULL | 69 | Using where; Using index; Distinct;
| Using join buffer
Как вы видите, индекс с одним столбцом имеет то же имя, что и столбец, которому он принадлежит. Я также добавил некоторые бесполезные индексы вместе с используемыми, просто чтобы проверить, не изменили ли они выполнение (чего у них нет).
Выполнение занимает ~ 4,5 секунды.
Когда я добавляю столбец entl1.name в часть выбора (ничего больше не изменил), индекс fk_ent в el1 больше не может быть использован:
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra
+----+-------------+-------+--------+-------------------------+---------+---------+---------------+-------+------------------------------------
| 1 | SIMPLE | el1 | ALL | fk_ent | NULL | NULL | NULL | 15002 | Using temporary
Выполнение теперь занимает ~ 8.5 секунд.
Я всегда думал, что выбранная часть запроса не влияет на использование индексов движком и не влияет на производительность таким образом.
Оставить атрибут не является решением, и есть еще больше атрибутов, которые я должен выбрать. Хуже того, запрос в используемой форме даже немного сложнее, и проблема с производительностью является большой проблемой.
Итак, мои вопросы: 1) В чем причина этого странного поведения? 2) Как я могу решить проблему с производительностью?
Спасибо за вашу помощь! GRED
Это ограничение DISTINCT. Вы можете думать об этом как о другом запрете WHERE. Когда вы меняете список выбора, вы действительно меняете предложение WHERE для ограничения DISTINCT, и теперь оптимизатор решает, что он все равно должен выполнять сканирование таблицы, поэтому он может также не использовать ваш индекс.
EDIT:
Не уверен, что это помогает, но если я правильно понимаю ваши данные, я думаю, вы можете избавиться от ограничения DISTINCT следующим образом:
select
e1.idx, el1.idx, r1.fk_cat, r2.fk_cat
from ent e1
Inner Join ent_leng el1 ON el1.fk_ent=e1.idx
Inner Join rel_c r1 ON r1.fk_ent=e1.idx
Inner Join rel_c r2 ON r2.fk_ent=e1.idx
where
((r1.fk_cat=43) or Exists(Select 1 From _tax_c t1 Where r1.fk_cat=t1.fk_cat1 and t1.fk_cat2=43))
and
((r2.fk_cat=10) or Exists(Select 1 From _tax_c t2 Where r2.fk_cat=t2.fk_cat1 and t2.fk_cat2=10))
MySQL будет возвращать данные из индекса, если это возможно, сохраняя всю загруженную строку. Таким образом, выбранные столбцы могут влиять на выбор индекса.
Имея это в виду, гораздо эффективнее добавить все необходимые столбцы в индекс, особенно в случае выбора только небольшого подмножества столбцов.