amark
@amark
rush less, feel more

Можно ли оптимизировать этот запрос?

Есть запрос к базе, который собирает информацию для отображения статистики по заказам.

Структура БД

В запросе используются таблицы:
  • order – заказы:
    • status – признак оплаты (3 – "оплачен", для оплачиваемых заказов, 2 – "принят", для неоплачиваемых заказов),
    • payment_type – тип оплаты (card/cash – картой/наличкой; omc, dmc, free – "неоплачиваемый")

  • order_services – услуги в заказах ("слепок" с кодом, ценой и названием услуги),
  • lpu_services – перечень услуг (фактический прайс-лист),
  • lpu_service_categories – категории услуг.


5d470b1d82975785726800.png


Можно ли как-то оптимизировать этот запрос ?

SELECT
            os.order_id,
            
            count(os.id) total_count,
            
            SUM(IF((o.`payment_type`='cash' or o.`payment_type`='card'), os.price, 0)) paid_revenue,
            SUM(IF((o.`payment_type`='dmc'), os.price, 0)) dmc_revenue,
                            
            SUM(IF(o.`payment_type`='cash', 1, 0)) cash_count,
            SUM(IF(o.`payment_type`='card', 1, 0)) card_count,
            SUM(IF(o.`payment_type`='omc', 1, 0)) oms_count,
            SUM(IF(o.`payment_type`='free', 1, 0)) free_count,
            SUM(IF(o.`payment_type`='dmc', 1, 0)) dmc_count,
            
            SUM(lsc.id=1) usg_count,
		SUM(IF(lsc.id=1 AND o.`payment_type`='omc', 1, 0)) usg_oms_count,
                SUM(IF(lsc.id=1 AND (o.`payment_type`='omc'), os.price, 0)) usg_oms_revenue,
                
                SUM(IF(lsc.id=1 AND o.`payment_type`='dmc', 1, 0)) usg_dms_count,
                SUM(IF(lsc.id=1 AND (o.`payment_type`='dmc'), os.price, 0)) usg_dms_revenue,
                
                SUM(IF(lsc.id=1 AND o.`payment_type`='free', 1, 0)) usg_free_count,
                
                SUM(IF(lsc.id=1 AND (o.`payment_type`='cash' OR o.`payment_type`='card'), 1, 0)) usg_paid_count,
                SUM(IF(lsc.id=1 AND (o.`payment_type`='cash' OR o.`payment_type`='card'), os.price, 0)) usg_paid_revenue,
                
            SUM(lsc.id=2) md_count,
            	SUM(IF(lsc.id=2 AND o.`payment_type`='omc', 1, 0)) md_oms_count,
                SUM(IF(lsc.id=2 and o.`payment_type`='omc', 2.16, 0)) md_oms_revenue, 
                
                SUM(IF(lsc.id=2 AND o.`payment_type`='dmc', 1, 0)) md_dms_count,
                SUM(IF(lsc.id=2 AND (o.`payment_type`='dmc'), os.price, 0)) md_dms_revenue,
                
                SUM(IF(lsc.id=2 AND o.`payment_type`='free', 1, 0)) md_free_count,
                
                SUM(IF(lsc.id=2 AND (o.`payment_type`='cash' OR o.`payment_type`='card'), 1, 0)) md_paid_count,
                SUM(IF(lsc.id=2 AND (o.`payment_type`='cash' OR o.`payment_type`='card'), os.price, 0)) md_paid_revenue,
                
            SUM(lsc.id=7) fizio_count,
            	SUM(IF(lsc.id=7 AND o.`payment_type`='omc', 1, 0)) fizio_oms_count,
                SUM(IF(lsc.id=7 AND (o.`payment_type`='omc'), os.price, 0)) fizio_oms_revenue,
                
                SUM(IF(lsc.id=7 AND o.`payment_type`='dmc', 1, 0)) fizio_dms_count,
                SUM(IF(lsc.id=7 AND (o.`payment_type`='dmc'), os.price, 0)) fizio_dms_revenue,
                
                SUM(IF(lsc.id=7 AND o.`payment_type`='free', 1, 0)) fizio_free_count,
                
                SUM(IF(lsc.id=7 AND (o.`payment_type`='cash' OR o.`payment_type`='card'), 1, 0)) fizio_paid_count,
                SUM(IF(lsc.id=7 AND (o.`payment_type`='cash' OR o.`payment_type`='card'), os.price, 0)) fizio_paid_revenue,

            SUM(lsc.id=8) massage_count,
            	SUM(IF(lsc.id=8 AND o.`payment_type`='omc', 1, 0)) massage_oms_count,
                SUM(IF(lsc.id=8 AND (o.`payment_type`='omc'), os.price, 0)) massage_oms_revenue,
                
                SUM(IF(lsc.id=8 AND o.`payment_type`='dmc', 1, 0)) massage_dms_count,
                SUM(IF(lsc.id=8 AND (o.`payment_type`='dmc'), os.price, 0)) massage_dms_revenue,
                
                SUM(IF(lsc.id=8 AND o.`payment_type`='free', 1, 0)) massage_free_count,
                
                SUM(IF(lsc.id=8 AND (o.`payment_type`='cash' OR o.`payment_type`='card'), 1, 0)) massage_paid_count,
                SUM(IF(lsc.id=8 AND (o.`payment_type`='cash' OR o.`payment_type`='card'), os.price, 0)) massage_paid_revenue,
                
            SUM(lsc.id=9) medproc_count,
            	SUM(IF(lsc.id=9 AND o.`payment_type`='omc', 1, 0)) medproc_oms_count,
                SUM(IF(lsc.id=9 AND (o.`payment_type`='omc'), os.price, 0)) medproc_oms_revenue,
                
                SUM(IF(lsc.id=9 AND o.`payment_type`='dmc', 1, 0)) medproc_dms_count,
                SUM(IF(lsc.id=9 AND (o.`payment_type`='dmc'), os.price, 0)) medproc_dms_revenue,
                
                SUM(IF(lsc.id=9 AND o.`payment_type`='free', 1, 0)) medproc_free_count,
                
                SUM(IF(lsc.id=9 AND (o.`payment_type`='cash' OR o.`payment_type`='card'), 1, 0)) medproc_paid_count,
                SUM(IF(lsc.id=9 AND (o.`payment_type`='cash' OR o.`payment_type`='card'), os.price, 0)) medproc_paid_revenue,
                
            SUM(lsc.id=10) fd_count,
            	SUM(IF(lsc.id=10 AND o.`payment_type`='omc', 1, 0)) fd_oms_count,
                SUM(IF(lsc.id=10 AND (o.`payment_type`='omc'), os.price, 0)) fd_oms_revenue,
                
                SUM(IF(lsc.id=10 AND o.`payment_type`='dmc', 1, 0)) fd_dms_count,
                SUM(IF(lsc.id=10 AND (o.`payment_type`='dmc'), os.price, 0)) fd_dms_revenue,
                
                SUM(IF(lsc.id=10 AND o.`payment_type`='free', 1, 0)) fd_free_count,
                
                SUM(IF(lsc.id=10 AND (o.`payment_type`='cash' OR o.`payment_type`='card'), 1, 0)) fd_paid_count,
                SUM(IF(lsc.id=10 AND (o.`payment_type`='cash' OR o.`payment_type`='card'), os.price, 0)) fd_paid_revenue
    
        FROM order_services os, lpu_services ls, lpu_service_categories lsc, `order` o
        WHERE 
        o.id=os.order_id AND os.service_id=ls.id AND ls.service_category_id=lsc.id
        AND (
            	((o.`payment_type`='cash' or o.`payment_type`='card') and o.`status`=3) 
            	OR (o.`payment_type`='omc' AND o.`status`=2)
                OR (o.`payment_type`='dmc' AND o.`status`=2)
                OR (o.`payment_type`='free' AND o.`status`=2)
            )
        GROUP BY order_id  
        ORDER BY `os`.`order_id` ASC


UPD1.: Вопрос, скорее всего, касается синтаксиса. Такое ощущение, что можно сгруппировать параметры в select'е, т.к. много кусков повторяются. Но как это сделать пока не могу придумать.
  • Вопрос задан
  • 80 просмотров
Пригласить эксперта
Ответы на вопрос 1
HemulGM
@HemulGM
Delphi Developer, сис. админ
Можно, наверное. Попробуй получить план выполнения запроса и посмотреть, где полные выборки и можно ли их избежать, если они выполняются несколько раз. Также, использовать индексацию.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы