2010-09-22 4 views
0

Я встречаюсь с странным поведением MySQL. Выполнение запроса (т. Е. Использование индексов, как показано в пояснении [QUERY]), и время, необходимое для выполнения, зависят от элементов предложения where.Почему запрос select влияет на выполнение запросов и производительность в MySQL?

Вот запрос, где возникает проблема:

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

ответ

2

Это ограничение 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)) 
+0

Звучит разумно. Но это не решение проблемы (мне пришлось бы иметь дело с огромным, избыточным избыточным набором результатов или с использованием сложного индекса). И, как ни странно, удаление DISTINCT не меняет выход EXPLAIN и не ускоряет запрос, как я только что проверил. – GredPapp

+0

Только что опробован: ваш запрос, похоже, дает те же результаты, что и мои, - и это намного быстрее! Благодаря!Думаю, мне нужно глубже погрузиться в SQL, чтобы использовать его соответствующим образом. – GredPapp

0

MySQL вернет данные из индекса, если это возможно, сохраняя загрузку всей строки. Таким образом, выбранные столбцы могут влиять на выбор индекса.

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