2012-01-18 6 views
0

Следующий запрос:Очень медленный SQL запрос на выборку

SELECT 
    `so`.*, 
    IF(
    ISNULL(`ips`.`border`), 
    `io`.`cdborder`, 
    `ips`.`border` 
) AS order_status, 
    IF(
    ISNULL(`ips`.`status`), 
    `io`.`cdstatus`, 
    `ips`.`status` 
) AS order_state, 
    `io`.*, 
    IF(
    ISNULL(`ips`.`sale`), 
    `iol`.`regelstatus`, 
    `ips`.`sale` 
) AS order_line_status 
FROM 
    `sales_order` AS `so` 
    INNER JOIN `sales_flat_order_item` AS `soi` 
    ON soi.order_id = so.entity_id 
    LEFT JOIN `import`.`import_orders` AS `io` 
    ON so.atorder_id = io.cdorder 
    AND so.cdadmin = io.cdadmin 
    AND (error_msg IS NULL 
     OR error_msg = "") 
    LEFT JOIN `import`.`import_orderlines` AS `iol` 
    ON iol.cdorder = so.atorder_id 
    AND iol.cdadmin = so.cdadmin 
    LEFT JOIN `import`.`import_purchase_sales` AS `ips` 
    ON so.atorder_id = ips.order 
WHERE (soi.sku IS NULL) 
    OR (
    soi.sku = iol.cdproduct 
    AND (
     soi.atorder_line = iol.nrordrgl 
    ) 
    AND (
     iol.atg != soi.qty_shipped 
     OR iol.at != soi.qty_invoiced 
     OR iol.atb != soi.qty_ordered 
    ) 
) 
GROUP BY `so`.`atorder_id`, 
    `so`.`cdadmin` 
ORDER BY `io`.`modification_date_order` ASC 
LIMIT 200 

Принимает 4 минуты для выполнения! Как это может быть? Объяснить показывает следующее:

id  select_type  table  type   possible_keys   key   key_len  ref           rows  Extra 
1  SIMPLE   so  index  PRIMARY    order_id 32   NULL          127828 Using temporary; Using filesort 
1  SIMPLE   io  eq_ref  PRIMARY,error_msg  PRIMARY  261   livetest3.so.order_id,livetest3.so.cdadmin 1  
1  SIMPLE   soi  ref   IDX_ORDER    IDX_ORDER 4   livetest3.so.entity_id      2    
1  SIMPLE   iol  ref   cdorder    cdorder  258   livetest3.so.order_id      6  Using where 
1  SIMPLE   ips  ref   sale_order   sale_order 32   livetest3.so.order_id      3 

Я попробовал несколько профилировщика инструментов запроса, но никто не показал мне подробную информацию о том, какие части запроса настолько медленно ...

«так» таблица содержит только 130k строк. .. Даже с кучей левых объединений это не должно быть так медленно ... Любые идеи?

+0

Вы можете добавить фильтр на столе заказов на продажу? Может быть, вам нужны только заказы с определенного периода времени? –

ответ

1

EXPLAIN предоставил вам всю необходимую информацию. Часть Using temporary; Using filesort - это медленная часть.

+0

Как это исправить? –

+0

Я не уверен, вызывает ли это ваше предложение WHERE или GROUP. Попробуйте удалить один из них и проверьте скорость запроса. – Chronial

+0

это ГДЕ ... удаление его бросает мой запрос на 0.003s –

1

Похоже, что основной ключ order_id, но ваш запрос не может его использовать. Если вы создаете индекс на sku, ваш запрос должен работать быстрее.

Обратите внимание, что есть место для большего улучшения, но я бы начал с создания индекса на sku и снова запустил запрос, чтобы посмотреть, как он работает сейчас.

+0

Я пробовал делать это ... у этого стола было 500 000 записей ... он добавил 25 минут, чтобы добавить индекс:/ –

+0

И за 25 ~ 30 минут его мощность была увеличена только до 25 000 .... так для добавления этого индекса может потребоваться 10 часов. –

+1

Возможно, было бы быстрее создать вторую таблицу с тем же индексом структуры + и добавить записи из первой во вторую таблицу. Но у меня создается впечатление, что с вами что-то не так с сервером mysql (медленная машина или плохая конфигурация) – Chronial

1

Запрос должен извлекать все 127828 записей из таблицы «so», помещать их во временную таблицу, а затем выполнять все IF для каждой записи, а затем сортировать после полей, сгруппированных по. В зависимости от скорости машины, ее загрузки и особенно объема доступной памяти это время выполнения не является нереалистичным.

+0

Как я могу оптимизировать этот запрос? –

+0

Трудно сказать. Как правило, мне нравится анализировать, что заставляет вас писать запрос так, как вы это делали. Наличие структуры базы данных помогает. Знание того, что вы можете изменить структуру базы данных, добавить индексы или изменить порядок сортировки, также помогает. Знание того, можно ли разделить отчет, может помочь. Иногда быстрее выбирать одну часть в качестве временной таблицы, а затем присоединяться и выбирать вторую часть, используя эту таблицу. Оптимизация проще для более коротких, менее «раздутых» запросов. – 0xCAFEBABE

+0

ну это, конечно, не группировка, равно как и инструкции IF ... удаление инструкции WHERE будет уменьшаться по времени выполнения запроса до 0.003s –

1

Не зная точно, что ВЫ ХОТИТЕ из данных, ваш запрос имеет экземпляр «soi.sku IS NULL», который будет означать LEFT JOIN для этого псевдонима. У вас было нормальное соединение, указывающее на то, что ВСЕГДА хотели, чтобы запись соответствовала «soi». Вы имели в виду взять это в LEFT JOIN вместо этого? Если вы ВСЕГДА хотите «soi», то я бы удалил часть запроса «soi.sku IS NULL OR».

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

Table       Index 
Sales_Order     (atorder_id, ccadmin) 
import.import_orderlines  (cdorder, cdadmin) 
import.import_orders   (cdorder, cdadmin) 
import.import_purchase_sales (order) 

Тогда изменение

SELECT ... 

в

SELECT STRAIGHT_JOIN ... 
Смежные вопросы