SQL-запрос с подзапросами работает ужасно - PullRequest
1 голос
/ 24 ноября 2011

У меня есть довольно длинный запрос, который должен дать мне некоторую информацию об отгрузках, и он работает, но он работает ужасно плохо. Загрузка занимает около 4500 мс.

SELECT
    DATE(paid_at) AS day,
    COUNT(*) as order_count,
    (
      SELECT COUNT(*) FROM line_items
      WHERE order_id IN (SELECT id from orders WHERE DATE(paid_at) = day)
    ) as product_count,
    (
      SELECT COUNT(*) FROM orders
      WHERE shipping_method = 'colissimo'
      AND DATE(paid_at) = day
      AND state IN ('paid','shipped','completed')
    ) as orders_co,
    (
      SELECT COUNT(*) FROM orders
      WHERE shipping_method = 'colissimo'
      AND DATE(paid_at) = day
      AND state IN ('paid','shipped','completed')
      AND paid_amount < 70
    ) as co_less_70,
    (
      SELECT COUNT(*) FROM orders
      WHERE shipping_method = 'colissimo'
      AND DATE(paid_at) = day
      AND state IN ('paid','shipped','completed')
      AND paid_amount >= 70
    ) as co_plus_70,
    (
      SELECT COUNT(*) FROM orders
      WHERE shipping_method = 'mondial_relais'
      AND DATE(paid_at) = day
      AND state IN ('paid','shipped','completed')
    ) as orders_mr,
    (
      SELECT COUNT(*) FROM orders
      WHERE shipping_method = 'mondial_relais'
      AND DATE(paid_at) = day
      AND state IN ('paid','shipped','completed')
      AND paid_amount < 70
    ) as mr_less_70,
    (
      SELECT COUNT(*) FROM orders
      WHERE shipping_method = 'mondial_relais'
      AND DATE(paid_at) = day
      AND state IN ('paid','shipped','completed')
      AND paid_amount >= 70
    ) as mr_plus_70
    FROM orders
    WHERE MONTH(paid_at) = 11
    AND YEAR(paid_at) = 2011
    AND state IN ('paid','shipped','completed')
    GROUP BY day;

Есть идеи, что я могу делать неправильно или что я могу делать лучше? У меня есть другие запросы аналогичной длины, которые не требуют столько времени для загрузки, как эта. Я думал, что это будет быстрее, чем, например, иметь отдельный запрос для каждого дня (в моем программировании вместо SQL-запроса).

Ответы [ 2 ]

1 голос
/ 24 ноября 2011

Это потому, что вы используете подзапросы там, где они вам не нужны.

Как правило, когда у вас есть подзапрос в основном предложении SELECT, этот подзапрос будет запрашивать таблицы в нем один раз для каждой строки в основном предложении SELECT - так что если у вас есть 7 подзапросов и вы выбираете в диапазоне дат 30 дней вы фактически будете выполнять 210 отдельных подзапросов (плюс ваш основной запрос).

(Некоторые оптимизаторы запросов могут разрешать подзапросы в основном запросе при некоторых обстоятельствах, но, как правило, на это нельзя полагаться.)

В этом случае вам не нужен ни один из подзапросов orders, потому что все необходимые данные orders включены в основной запрос - так что вы можете переписать это как:

SELECT
    DATE(paid_at) AS day,
    COUNT(*) as order_count,
    (
      SELECT COUNT(*) FROM line_items
      WHERE order_id IN (SELECT id from orders WHERE DATE(paid_at) = day)
    ) as product_count,
    sum(case when shipping_method = 'colissimo' then 1 end) as orders_co,
    sum(case when shipping_method = 'colissimo' AND 
                  paid_amount < 70 then 1 end) as co_less_70,
    sum(case when shipping_method = 'colissimo' AND 
                  paid_amount >= 70 then 1 end) as co_plus_70,
    sum(case when shipping_method = 'mondial_relais' then 1 end) as orders_mr,
    sum(case when shipping_method = 'mondial_relais' AND 
                  paid_amount < 70 then 1 end) as mr_less_70,
    sum(case when shipping_method = 'mondial_relais' AND 
                  paid_amount >= 70 then 1 end) as mr_plus_70
    FROM orders
    WHERE MONTH(paid_at) = 11
    AND YEAR(paid_at) = 2011
    AND state IN ('paid','shipped','completed')
    GROUP BY day;
1 голос
/ 24 ноября 2011

Проблема в вашем запросе состоит в том, что сканирует одну и ту же таблицу снова и снова. Все сканы (выбираемые в вашем случае) таблицы ORDER могут быть преобразованы в несколько SUM + CASE или COUNT + CASE, как в SQL-запросе с подсчетом и оператором case .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...