2010-09-04 3 views
1

У меня есть этот запрос ниже. Существует четыре основных таблицы: tblOrder, tblItems, tblOrder_archive, tblItem_archive. Заказы и элементы перемещаются в заархивированные версии таблиц через несколько месяцев, чтобы не замедлять выполнение основных табличных запросов. (продажи и оборот ДЕЙСТВИТЕЛЬНО ВЫСОКИЙ). Поэтому, чтобы получить данные о продажах, я выбираю то, что мне нужно, из каждого набора таблиц (архив и не архивный). Объедините их .. сделайте группу по объединению .. затем выполните некоторую математику по результату.Нужна помощь в оптимизации сложного запроса MySQL

Проблема в том, что с любым значительным количеством строк (временной интервал заказа) .. для выполнения запроса потребуется столько времени, сколько времени истечет. Я добавил все ключи, о которых я могу думать, и все еще работает очень медленно.

Есть ли еще больше, чтобы сделать это быстрее? Могу ли я написать его по-другому? Могу ли я использовать разные индексы?

или должен ли я написать сценарий, который сначала получает данные из каждой таблицы, а затем выполняет ли математика в скрипте php их комбинирование?

Спасибо за помощь.

SELECT 
    description_invoice 
, supplier 
, type 
, sum(quantity) AS num_sold 
, sum(quantity*wholesale) AS wholesale_price 
, sum(quantity*price) AS retail_price 
, sum(quantity*price) - sum(quantity*wholesale) AS profit 
FROM (
    SELECT 
     tblOrder.* 
    , tblItem.description_invoice 
    , tblItem.type 
    , tblItem.product_number 
    , tblItem.quantity 
    , tblItem.wholesale 
    , tblItem.price 
    , tblItem.supplier 
    FROM tblOrder USE KEY (finalized), tblItem 
    WHERE 
     tblItem.order_id = tblOrder.order_id 
    AND 
     finalized=1 
    AND 
     wholesale <> 0 
    AND (order_time >= 1251788400 AND order_time <= 1283669999) 

    UNION 

    SELECT 
     tblOrder_archive.* 
    , tblItem_archive.description_invoice 
    , tblItem_archive.type 
    , tblItem_archive.product_number 
    , tblItem_archive.quantity 
    , tblItem_archive.wholesale 
    , tblItem_archive.price 
    , tblItem_archive.supplier 
    FROM tblOrder_archive USE KEY (finalized), tblItem_archive 
    WHERE 
     tblItem_archive.order_id=tblOrder_archive.order_id 
    AND 
     finalized=1 
    AND 
     wholesale <> 0 
    AND (order_time >= 1251788400 AND order_time <= 1283669999) 
) AS main_table 
GROUP BY 
    description_invoice 
, supplier,type 
ORDER BY profit DESC; 
+0

Вы можете показать нам, какие индексы (ключи) вы создали? –

ответ

2
  • Создание индексов в столбцах, которые вы используете в ИНЕКЕ.
  • Удалить указатель на индекс: USE KEY (finalized). Если он вообще что-то делает, он, вероятно, просто сделает его медленнее, заставив MySQL выбрать этот ключ вместо потенциально лучшего ключа.
  • Добавьте LIMIT, чтобы избежать слишком большого количества строк. Используйте пейджинг, если вы хотите увидеть больше строк.
  • Используйте UNION ALL вместо UNION. Это будет быстрее, потому что он не проверяет наличие дубликатов, и вы, вероятно, не хотите удалять дубликаты здесь, так как это повлияет на общее количество.

Заказов и товары перемещаются к архивированным версиям таблиц после нескольких месяцев как не замедлять основные таблицы запросов.

Возможно, это плохая идея. Вместо этого вы должны правильно индексировать свои данные, чтобы при добавлении дополнительных данных запросы не становились значительно медленнее. Или, альтернативно, вы можете посмотреть partitioning the table.

+0

И проверьте EXPLAIN. Это хороший способ увидеть, как запрос фактически обрабатывается за кулисами. Он также может дать вам представление о том, где его можно улучшить. – CaseySoftware

1

Я переписал ваш запрос как:

SELECT COALESCE(x.description_invoice, y.description_invoice) AS description_invoice, 
      COALESCE(x.supplier, y.supplier) AS supplier, 
      COALESCE(x.type, y.type) AS type, 
      COALESCE(SUM(x.quantity), 0) + COALESCE(SUM(y.quantity), 0) as num_sold, 
      COALESCE(SUM(x.quantity * x.wholesale), 0) + COALESCE(SUM(y.quantity * y.wholesale), 0) AS wholesale_price, 
      COALESCE(SUM(x.quantity * x.price), 0) + COALESCE(SUM(y.quantity * y.price), 0) AS retail_price, 
      COALESCE(SUM(x.quantity * x.price), 0) - COALESCE(SUM(x.quantity * x.wholesale), 0) + COALESCE(SUM(y.quantity * y.price), 0) - COALESCE(SUM(y.quantity * y.wholesale), 0) as profit 
    FROM (SELECT o.order_id 
      FROM TBLORDER o 
      WHERE o.finalized = 1 
       AND o.order_time BETWEEN 1251788400 
            AND 1283669999 
      UNION ALL 
      SELECT oa.order_id 
      FROM TBLORDER_ARCHIVE oa 
      WHERE oa.finalized = 1 
      AND oa.order_time BETWEEN 1251788400 
            AND 1283669999) a 
LEFT JOIN TBLITEM x ON x.order_id = a.order_id 
        AND x.wholesale != 0 
LEFT JOIN TBLITEM_ARCHIVE y ON y.order_id = a.order_id 
          AND y.wholesale != 0 
GROUP BY description_invoice, supplier, type 
ORDER BY profit DESC 
  • Ваш запрос был UNION, но я бы ожидать не нужно дублировать удаление из таблицы архива, поэтому я изменил его на UNION ALL - что быстрее , потому что он не удаляет дубликаты
  • Для чего вы предоставили, у вас были SELECT ORDERS.* и SELECT ORDER_ARCHIVE.*, но никогда не использовали ни один из столбцов.
  • Все функции агрегации (SUM) находились в таблице TBLITEM, что было необязательно в пределах производной таблицы/встроенного представления.
  • Я опустил USE KEY(finalized); вы можете повторно добавить его, если хотите, но я бы сравнил с ним и без него - я предлагаю запустить ANALYZE TABLE occaissionally по обеим таблицам до запуска запроса, чтобы оптимизатор имел относительно свежую статистику.
  • Я не вижу большого значения в индексе в столбце finalized, но я не знаю ваших данных или использования - просто этот запрос. Но на основе этого запроса, я бы индекс:

    1. Order_ID
    2. order_time
    3. доработан

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

+0

Это не учитывает таблицу tblItem_archive. Должно быть соединение между ним и tblOrder_archive .. с функциями агрегации по обоим запросам перед соединением. – danjfoley

+0

@danjfoley: см. Обновление –

0

я переписал его следующим образом на основе вашей помощи, и добавил рекомендуемый индекс покрытия для обоих tblOrder и tblOrder архив и вещи кажутся намного быстрее. Но все же мне интересно, есть ли что-то еще в том, как вы его написали. Но мне нужно будет использовать tblItem_archive, также связанный с tblOrder_archive.

SELECT 
    description_invoice 
, supplier 
, type 
, sum(quantity) AS num_sold 
, sum(quantity*wholesale) AS wholesale_price 
, sum(quantity*price) AS retail_price 
, sum(quantity*price) - sum(quantity*wholesale) AS profit 
FROM (
    SELECT 
     tblOrder.order_id 
    , tblItem.description_invoice 
    , tblItem.type 
    , tblItem.product_number 
    , tblItem.quantity 
    , tblItem.wholesale 
    , tblItem.price 
    , tblItem.supplier 
    FROM tblOrder, tblItem 
    WHERE 
     tblItem.order_id = tblOrder.order_id 
    AND 
     finalized=1 
    AND 
     wholesale <> 0 
    AND (order_time >= 1251788400 AND order_time <= 1283669999) 

    UNION ALL 

    SELECT 
     tblOrder_archive.order_id 
    , tblItem_archive.description_invoice 
    , tblItem_archive.type 
    , tblItem_archive.product_number 
    , tblItem_archive.quantity 
    , tblItem_archive.wholesale 
    , tblItem_archive.price 
    , tblItem_archive.supplier 
    FROM tblOrder_archive, tblItem_archive 
    WHERE 
     tblItem_archive.order_id=tblOrder_archive.order_id 
    AND 
     finalized=1 
    AND 
     wholesale <> 0 
    AND (order_time >= 1251788400 AND order_time <= 1283669999) 
) AS main_table 
GROUP BY 
    description_invoice 
, supplier,type 
ORDER BY profit DESC; 
Смежные вопросы