2013-11-15 3 views
4

У меня проблема с MySQL Query, и я не могу ее оптимизировать.MySQl Query: Join and Group By, slow performance

SELECT 
    p.id, 
    p.name, 
    p.sku, 
    p.type 
FROM 
    xm_products p 
    LEFT JOIN xm_store_product sp ON p.id = sp.product_id 
    LEFT JOIN xm_store s ON sp.store_id = s.id 
WHERE 
    s.id = 1 
ORDER BY 
    p.type, 
    p.name asc 
LIMIT 
    20 OFFSET 0 

Этот запрос очень медленно: Querytime 2.532s

Если удалить Order By пункта, запрос очень быстро: 0.0001s

Поясните показать следующую информацию:

+----+-------------+-------+--------+-------------------------------------------+----------------------+---------+---------------------------------------+--------+----------------------------------------------+ 
| id | select_type | table | type | possible_keys        | key     | key_len | ref         | rows | Extra          | 
+----+-------------+-------+--------+-------------------------------------------+----------------------+---------+---------------------------------------+--------+----------------------------------------------+ 
| 1 | SIMPLE  | s  | const | PRIMARY         | PRIMARY    | 4  | const         |  1 | Using index; Using temporary; Using filesort | 
| 1 | SIMPLE  | sp | ref | IDX_CA42254AB092A811,IDX_CA42254A4584665A | IDX_CA42254AB092A811 | 5  | const         | 102157 | Using where         | 
| 1 | SIMPLE  | p  | eq_ref | PRIMARY         | PRIMARY    | 4  | model.sp.product_id     |  1 |            | 
+----+-------------+-------+--------+-------------------------------------------+----------------------+---------+---------------------------------------+--------+----------------------------------------------+ 
3 rows in set 

у меня есть 3 таблицы:

  • xm_product с первичным ключом ID
  • xm_store с первичным ключом ID
  • xm_store_product с индексом на store_id и PRODUCT_ID

Я попытался добавить индекс p.name и p.type, а также комбинированный индекс (р .name, p.type), но это не помогло.

Как я могу оптимизировать производительность этого запроса?

EDIT:

Я взял меня 2 часа, чтобы создать sqlfidle. Но здесь есть некоторые данные. http://sqlfiddle.com/#!2/2bf8d/1

Проблема заключается в том, что «Group By» вызывает «Использование индекса, использование временного файла с использованием filesort».

Как я могу исправить свой пример?

EDIT 2:

De xm_products таблица имеет около 200'000 записей. Xm_store_products около 400 000. Запрос предназначен для пейджера, предел до 20% на страницу.

+1

Привет, можете ли вы создать sqlfiddle (sqlfiddle.com) для вашей схемы с образцами? – Damodaran

+0

Вы запустили объяснение с индексами на p.name и p.type? – jah

+0

Сколько записей нужно сортировать? –

ответ

1

Я положу его в качестве ответа после положительной обратной связи :)

То есть (заметно) разница в производительности делает много смысла.

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

Возможно, с комбинированным индексом в вашем заказе-за-предложением и представлением о том, что вы можете получить производительность.

+0

LIMIT 20 существует, потому что запрос предназначен для пейджера. Я не думаю, что это влияет на производительность. – Brainski

+0

Нет, это не так. Но без заказа, LIMIT _has_ влияет на производительность, положительный, поэтому эта версия намного быстрее. – oerkelens

+0

Хорошо, теперь я понимаю. Это означает, что я должен искать проблему в другом месте. – Brainski

0

Ваша проблема заключается в том, что оптимизатор MySQL основан на затратах.

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

Вы сортировать по таблице product (p.type, p.name asc), но эта таблица обращается последним в плане объяснения, поэтому MySQL необходимо создать временную таблицу «Использование временного» для хранения результатов .. и поскольку результаты не отсортированы правильно, дополнительная быстродействующая сортировка «требуется использовать filesort».

Вы можете проверить с STRAIGHT_JOIN поэтому оптимизатор MySQL будет «обойти», обратите внимание, это может дать отрицательные результаты работы, если s.id = 1 не существует в таблице ...

SELECT 
    STRAIGHT_JOIN 
    p.id, 
    p.name, 
    p.sku, 
    p.type 
FROM 
    xm_products p 
    LEFT JOIN xm_store_product sp ON p.id = sp.product_id 
    LEFT JOIN xm_store s ON sp.store_id = s.id 
WHERE 
    s.id = 1 
ORDER BY 
    p.type, 
    p.name asc 
LIMIT 
    20 OFFSET 0 

Примечание может быть лучшие варианты, если вы также используете вывод инструкции create table, см. MySQL slow query using filesort ... Если s.id всегда 1 запись, вы можете использовать примечание о методе производной таблицы, вам может понадобиться добавить новый указатель