Как увеличить скорость запроса MySQL с дополнительным условием?

#php #mysql #sql #performance #query-performance

#php #mysql #sql #Производительность #запрос-производительность

Вопрос:

Я пытаюсь ускорить следующий запрос, поскольку его выполнение занимает довольно много времени: сейчас это «всего» около 1,5 секунд, но он, безусловно, будет медленнее с увеличением количества строк (что в 10 раз увеличится в течение следующего периода).

В принципе, я хочу показать все строки из таблицы orders для пользователя, и в каждой строке отображается общая сумма заказа (которая является СУММОЙ таблицы orders_products).

 SELECT 
orders.order_number,
orders.order_date, 
companies.company_name,
COALESCE(SUM(orders_products.product_price * orders_products.product_quantity),0) AS order_value 
FROM orders 
LEFT JOIN companies ON companies.id = orders.company_id
LEFT JOIN orders_products ON orders_products.order_id = orders.id
LEFT JOIN users ON users.id = orders.user_id 
WHERE orders.user_id = '$user_id'
AND companies.user_id = '$user_id'
GROUP BY orders.id ORDER BY orders.order_date DESC, orders.order_number DESC
  

Я попытался добавить другое условие AND orders_products.user_id = '$user_id' . Скорость запроса была примерно в 12 раз быстрее (да!), Но проблема в том, что не во всех заказах есть продукты. В этом случае заказы без продуктов в них не возвращаются.

Как мне изменить свой запрос так, чтобы, несмотря на то, что в заказе нет продуктов, он все равно возвращался (с общим значением заказа 0), одновременно ускоряя запрос?

Заранее спасибо за вашу помощь!

Комментарии:

1. Просто для проверки: вы установили правильные индексы? Я предполагаю, что у вас есть.

2. Я не установил никаких индексов. Я слышал о них, но понятия не имею, как их установить… Поможет ли это ускорить подобные запросы?

3. Да, индексы — это СПОСОБ ускорить процесс.

4. Не связано, но есть некоторые вещи, которые я нахожу странными. Для чего вы присоединяетесь к таблице users ? Почему вы пытаетесь внешне присоединиться к таблице companies? Почему у компании есть идентификатор пользователя ?

5. @Thorsten, я присоединяюсь к таблице users, потому что мне также нужно выбрать некоторые детали для пользователя. Теперь я вижу, что я оставил этот оператор select из своего кода. Приношу свои извинения за путаницу. Я присоединяюсь к таблице companies, потому что хочу получить все заказы и присоединиться к компаниям, чтобы показать название компании в строке заказа. Должен ли я использовать другое соединение? Имена users / user_id могут немного сбивать с толку, но вкратце: у меня есть пользователи, и эти пользователи могут добавлять компании. И, в свою очередь, эти компании могут добавлять заказы. Итак, я хочу знать, какой пользователь добавил какую компанию.

Ответ №1:

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

 SELECT o.order_number, o.order_date,  c.company_name,
      (SELECT COALESCE(SUM(op.product_price * op.product_quantity), 0)
       FROM orders_products op
       WHERE op.order_id = o.id
      ) AS order_value 
FROM orders o LEFT JOIN
     companies c
     ON c.id = o.company_id AND c.user_id = o.user_id
WHERE o.user_id = '$user_id'
ORDER BY o.order_date DESC, o.order_number DESC
  

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

Тогда для производительности вам нужны следующие индексы:

  • orders(user_id, order_date desc, order_number_desc, company_id)
  • companies(id, company_id, company_name)
  • orders_products(order_id, product_price, product_quantity)

Комментарии:

1. Привет, Гордон Линофф, спасибо за ваш ответ. Я протестировал коррелированный подзапрос, но, к сожалению, он не ускоряет запрос. Старый запрос: 1,1285 секунды Новый запрос: 1,0912 секунды По сравнению с другим запросом с дополнительным предложением AND: 0,0368 секунды Любым способом добавьте дополнительное предложение AND, но все равно верните все строки orders, даже если в заказе нет продуктов?

2. @Nicholas . . . Вы бы добавили условие в ON предложение или подзапрос. Я добавил индексы, которые должны улучшить производительность. Конечно, если у одного пользователя десятки тысяч заказов, запрос займет время.

3. Я добавил условие в подзапрос следующим образом: (SELECT COALESCE(SUM(ROUND(orders_products.product_price, 2) * orders_products.product_quantity), 0) FROM orders_products WHERE orders_products.order_id = orders.id AND orders_products.user_id = '$user_id') AS order_value . Запрос выполняется, но не быстрее (1.4106 секунды). Может быть, это просто нельзя ускорить таким образом, только с помощью индексов?

4. @Nicholas . , , Вы пробовали рекомендуемые индексы?

5. Я опубликовал свой ответ непосредственно перед тем, как увидел ваш обновленный ответ. Теперь я добавил индексы, и они работают как шарм: 0,0273 секунды! Большое вам спасибо за вашу помощь!