Мой запрос выполняется медленно MySQL

#mysql

#mysql

Вопрос:

ВЫБЕРИТЕ (inv_total — isc_total) КАК прибыль ОТ (
ВЫБЕРИТЕ
SUM(inv.net_weight * inv.unit_price) КАК isc_total,
SUM(СЛУЧАЙ, КОГДА (i.».$ex_gst.»ex_gst = ‘YES’)
ЗАТЕМ (inv.net_weight * (СЛУЧАЙ, КОГДА (i.final = ‘Y’ И i.currency_id НЕ РАВНО NULL) ЗАТЕМ (ind.final_unit_price * cr.currency_value)
КОГДА (i.final = ‘Y’ И i.currency_id РАВНО NULL) ЗАТЕМ ind.final_unit_price
КОГДА (i.final<> ‘Y’ И i.currency_id НЕ РАВНО НУЛЮ) ЗАТЕМ (ind.unit_price * cr.currency_value)
КОГДА (i.final <> ‘Y’ И i.currency_id РАВНО НУЛЮ) ЗАТЕМ ind.unit_price ЕЩЕ ind.unit_price END ) * 1.06)
ЕЩЕ (inv.net_weight * (СЛУЧАЙ, КОГДА (i.final = ‘Y’ И i.currency_id НЕ РАВНО НУЛЮ), ЗАТЕМ (ind.final_unit_price * cr.currency_value)
, КОГДА (i.final = ‘Y’ И i.currency_id РАВНО НУЛЮ), ЗАТЕМ ind.final_unit_price,
КОГДА (i.final <> ‘Y’ И i.currency_id НЕ РАВЕН НУЛЮ), ЗАТЕМ (ind.unit_price * cr.currency_value)
, КОГДА (i.final <> ‘Y’ И i.currency_id РАВНО НУЛЮ), ЗАТЕМ ind.unit_price
ELSE ind.unit_price END )
) END
)КАК inv_total
ИЗ «.$prefix_qry.»inventory inv
ВНУТРЕННЕЕ СОЕДИНЕНИЕ «.$prefix_qry.»osc_detail osc_do НА osc_do.inventory_id = inv.inventory_id
ВНУТРЕННЕЕ СОЕДИНЕНИЕ продукта p НА inv.product_id = p.product_id
ЛЕВОЕ СОЕДИНЕНИЕ «.$prefix_qry.»iscisc НА inv.isc_batch_no = isc.isc_batch_no
ВНУТРЕННЕЕ СОЕДИНЕНИЕ поставщиков НА isc.supplier_id = s.supplier_id
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ПОСТАВЩИКОВ «.$prefix_qry.»счет i НА inv.osc_id = i.osc_id
ВНУТРЕННЕЕ СОЕДИНЕНИЕ «.$prefix_qry.»invoice_detail ind НА i.invoice_id = ind.invoice_id И ind.product_id = p.product_id
СЛЕВА ПРИСОЕДИНИТЕ currency cr К i.currency_id = cr.currency_id
, ГДЕ inv.osc_id !=»
И inv.inventory_type = ‘ПОДТВЕРДИТЬ’
И i.cancel_by РАВНО НУЛЮ
, А s.supplier_id = ‘».$supp_id.»‘
И МЕСЯЦ (i.date_of_delivery) = ‘».$month.»‘
И YEAR(i.date_of_delivery) = ‘».$ year .»‘) В КАЧЕСТВЕ

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

1. Спасибо, что поделились отчетом о состоянии. Ваш запрос выполняется медленно. Был ли вопрос ?

Ответ №1:

Чтобы позволить MySQL эффективно использовать сканирование диапазона в индексе с date_of_delivery в качестве ведущего столбца, предполагая, что $ year представляет действительный год, а $ month — значение от 1 до 12, затем измените это:

      AND MONTH(i.date_of_delivery) = '".$month."'
     AND YEAR(i.date_of_delivery) = '".$year ."'
  

К чему-то вроде этого:

      AND i.date_of_delivery >= STR_TO_DATE('".$year."-".$month."-01','%Y-%m-%d')
     AND i.date_of_delivery  < STR_TO_DATE('".$year."-".$month."-01','%Y-%m-%d') 
                                 INTERVAL 1 MONTH
  

«Внешность» LEFT JOIN to isc отрицается последующим внутренним соединением to s . То есть эквивалентный результат будет получен при замене LEFT JOIN на INNER JOIN .

Убедитесь, что подходящие индексы доступны и используются.

В выводе EXPLAIN будет показан план выполнения.

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


Учитывая, что запрос встроенного представления возвращает одну строку, накладные расходы производной таблицы незначительны.

Этот запрос должен вернуть результат, эквивалентный исходному встроенному представлению.

 SELECT SUM( inv.net_weight
          * inv.unit_price
       ) AS isc_total
     , SUM( inv.net_weight
          * IF(( i.".$ex_gst."ex_gst = 'YES' ), 1.06, 1.00)
          * IF(( i.final = 'Y' ), ind.final_unit_price, ind.unit_price)
          * IF(( i.final IS NULL OR i.currency_id IS NULL ), 1.00, cr.currency_value)
       ) AS inv_total
  FROM ".$prefix_qry."invoice i
  JOIN ".$prefix_qry."invoice_detail ind
    ON ind.invoice_id       = i.invoice_id
  JOIN ".$prefix_qry."inventory inv
    ON inv.product_id       = ind.product_id
   AND inv.inventory_type   = 'CONFIRM'
   AND inv.osc_id           = i.osc_id
   AND inv.osc_id          != ''
  JOIN ".$prefix_qry."osc_detail osc_do
    ON osc_do.inventory_id  = inv.inventory_id
  JOIN ".$prefix_qry."isc isc
    ON isc.supplier_id      = '".$supp_id."'
   AND isc.isc_batch_no     = inv.isc_batch_no
  JOIN supplier s
    ON s.supplier_id        = '".$supp_id."'
   AND s.supplier_id        = isc.supplier_id
  JOIN product p
    ON p.product_id         = inv.product_id
   AND p.product_id         = ind.product_id
  LEFT
  JOIN currency cr
    ON cr.currency_id       = i.currency_id
 WHERE i.cancel_by         IS NULL
   AND i.osc_id            != ''
   AND i.date_of_delivery  >= DATE_FROM_STR('".$year."-".$month."-01','%Y-%m-%d')
   AND i.date_of_delivery   < DATE_FROM_STR('".$year."-".$month."-01','%Y-%m-%d')
                                INTERVAL 1 MONTH
  

Сводка использования столбцов в списке ВЫБОРА

 -------- ---------------------------------------------------------------
i        final, currency_id, $[ex_gst]ex_gst
inv      net_weight,unit_price
cr       currency_value
  

Сводка использования столбцов в ПРЕДИКАТАХ

 -------- ---------------------------------------------------------------
i        osc_id, invoice_id, cancel_by, date_of_delivery
ind      invoice_id
inv      inventory_id, isc_batch_no, osc_id, inventory_type, product_id
isc      isc_batch_no, supplier_id
osc_do   inventory_id
p        product_id
s        supplier_id
cr       currency_id
  

Вероятно, эти таблицы меньше и уже имеют эти столбцы в качестве ПЕРВИЧНОГО КЛЮЧА

 ... ON p       (product_id)
... ON s       (supplier_id)
... ON cr      (currency_id)
  

Мы должны рассмотреть, необходимо ли включать таблицы product ( p ) и supplier ( s ) в запрос. Если столбцы, используемые (показанные выше) для p и s , являются ПЕРВИЧНЫМ КЛЮЧОМ или УНИКАЛЬНЫМ КЛЮЧОМ, и если применяются эти ограничения внешнего ключа:

  inv (product_id)  references p (product_id)
 ind (product_id)  references p (product_id)
 isc (supplier_id) references s (supplier_id)
  

тогда соединения с p и s не повлияют на результат. То есть эти таблицы могут быть удалены из запроса.

Первое сокращение при покрытии индексов, которое может помочь оптимизатору сгенерировать эффективный план выполнения…

 ... ON i       (date_of_delivery,cancel_by,osc_id,invoice_id,final,currency_id,[$ex_gst]ex_gst)
... ON ind     (invoice_id, product_id)
... ON inv     (inventory_id,inventory_type,isc_batch_no,osc_id,inventory_type,product_id,net_weight,unit_price)
... ON isc     (supplier_id,isc_batch_no)
... ON osc_do  (inventory_id)