Mysql
 sql >> база данни >  >> RDS >> Mysql

скъпата заявка премахва сървъра на базата данни - търси начини за смекчаване

Хм, може да се опитам да напиша вашата заявка по следните редове:

SELECT Sale_Item.deleted, Sale_Item.deleted_by,
       Sale_Item.sale_time, Sale_Item.sale_date,
       Sale_Item.comment,
       Sale_Item.payment_type,
       Sale_Item.customer_id,
       Sale_Item.employee_id,
       Sale_Item.category,
       Sale_Item.sale_id, Sale_Item.item_id, NULL as item_kit_id, Sale_Item.line, 
       Sale_Item.supplier_id,
       Sale_Item.serialnumber, Sale_Item.description,
       Sale_Item.quantity_purchased, Sale_Item.item_cost_price, Sale_Item.item_unit_price,
       Sale_Item.discount_percent,
       Sale_Item.lineSubtotal,
       Sale_Item.lineSubtotal * COALESCE(Tax.non_cumulative, 0) + (Sale_Item.lineSubtotal * COALESCE(Tax.non_cumulative, 0) + Sale_Item.non_cumulative) * COALESCE(Tax.cumulative, 0) AS lineTax,
       Sale_Item.lineSubtotal + (Sale_Item.lineSubtotal * COALESCE(Tax.non_cumulative, 0) + (Sale_Item.lineSubtotal * COALESCE(Tax.non_cumulative, 0) + Sale_Item.non_cumulative) * COALESCE(Tax.cumulative, 0)) AS lineTotal,
       Sale_Item.lineSubtotal - (Sale_Item.item_cost_price * Sale_Item.quantity_purchased) AS profit

FROM (SELECT Sale.deleted, Sale.deleted_by,
             Sale.sale_time, DATE(Sale.sale_time) AS sale_date,
             Sale.comment,
             Sale.payment_type,
             Sale.customer_id,
             Sale.employee_id,
             Item.category,
             Sale_Item.sale_id, Sale_Item.item_id, NULL as item_kit_id, Sale_Item.line, 
             Sale_Item.supplier_id,
             Sale_Item.serialnumber, Sale_Item.description,
             Sale_Item.quantity_purchased, Sale_Item.item_cost_price, Sale_Item.item_unit_price,
             Sale_Item.discount_percent,
             (Sale_Item.item_unit_price * Sale_Item.quantity_purchased) - (Sale_Item.item_unit_price * Sale_Item.quantity_purchased * Sale_Item.discount_percent / 100) as lineSubtotal                 
      FROM phppos_sales_items Sale_Item
      JOIN phppos_sales Sale
        ON Sale.sale_id = Sale_Item.sale_id
           AND Sale.sale_time >= TIMESTAMP('2014-04-01')
           AND Sale.sale_time < TIMESTAMPADD(MONTH, 1, '2014-04-01')
           AND Sale.location_id = 1
           AND Sale.store_account_payment = 0) Sale_Item

LEFT JOIN (SELECT Tax.sale_id, Tax.item_id, Tax.line,
                  SUM(CASE WHEN Tax.cumulative = 1 THEN Tax.percent ELSE 0 END) as cumulative,
                  SUM(CASE WHEN Tax.cumulative <> 1 THEN Tax.percent ELSE 0 END) as non_cumulative
           FROM phppos_sales_item_taxes Tax
           JOIN phppos_sales Sale
             ON Sale.sale_id = Tax.sale_id
                AND Sale.sale_time >= TIMESTAMP('2014-04-01')
                AND Sale.sale_time < TIMESTAMPADD(MONTH, 1, '2014-04-01')
                AND Sale.location_id = 1
                AND Sale.store_account_payment = 0
           GROUP BY Tax.sale_id, Tax.item_id, Tax.line) Tax
       ON Tax.sale_id = Sale_Item.sale_id
          AND Tax.item_id = Sale_Item.sale_id
          AND Tax.line =Sale_Item.line 

Преместени няколко колони за организационни цели. Това не би трябвало да има голям ефект върху времето за обработка.

Премахнах препратката към phppos_suppliers като:

  1. Не използвате колони от таблицата
  2. Това е LEFT JOIN , което означава, че не изисквате редове да съществуват там.

Преместих GROUP BY в нова подзаявка, тъй като phppos_sales_item_taxes е единствената таблица, която може да има дублиращи се редове за дадените критерии. Включих препратката към phppos_sales защото не съм сигурен дали оптимизаторът на MySQL (или какъвто и да е, наистина) е достатъчно умен, за да изтласка citeria надолу.

Основната част от заявката е преместена в подзаявка просто, за да не се налага да въвеждам формулата за lineSubtotal много пъти. Използвах едни и същи формули навсякъде, но има налични опростени версии:

Sale_Item.item_unit_price * Sale_Item.quantity_purchased * (1 - (Sale_Item.discount_percent / 100)) as lineSubtotal  

Sale_Item.lineSubtotal * COALESCE(Tax.non_cumulative + Tax.cumulative + Tax.non_cumulative * Tax.cumulative, 0) as Tax

.... може да се наложи да ги стартирате чрез счетоводство, тъй като те са склонни да бъдат (разбираемо) докосни относно реда на операциите. Това може води до по-бързо изпълнение, но се съмнявам; най-вече става дума за опростяване на термините до нещо по-четливо.

Не сте предоставили никакви оформления на таблицата за другата половина на заявката, но предполагам, че е подобно. Свързаната модификация е оставена като упражнение за читателя.

Общи стратегии за смекчаване

Освен евентуално ускоряване на промяната на заявката, има редица неща, които можете да направите, за да намалите проблема:

  1. В слоя на приложението си принудете тази заявка (и евентуално други) да премине през процес на подаване на задание, чиито резултати могат да бъдат извлечени по-късно. Ново копие на тази заявка не може да бъде стартирано, докато предишното не завърши. Предполагам, че php има съществуваща библиотека за това. Като цяло може да се окаже всичко, от което се нуждаете.
  2. Извличаните данни изглежда подлежат на кеширане - съхранявайте всичко преди най-скоро обработената sale_date , а след това получавате нова информация само в движение (въпреки че трансформацията всъщност не е толкова различна от оригинала - обаче, просто да не правите повече свързвания може да помогне).
  3. Забранете заявките през текущия период от време за обработка. Това трябва да предпази системата от опити за достъп до редове, които все още не са заети, и потенциално далеч от индексни страници, които се променят. Този вид трик работи най-добре, ако хранилището ви е подредено така, че да се възползва от едновременния I/O.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Извличане на подниз на MySQL с помощта на разделител

  2. Автоматично попълване на държава и град от пощенски код и обратното

  3. MySQL подзаявката връща повече от един ред

  4. Как да конвертирате дата в .csv файл в SQL формат преди масово вмъкване

  5. Схема на база данни Laravel, чужда с нула