Mysql
 sql >> Baza danych >  >> RDS >> Mysql

kosztowne zapytanie powoduje wyłączenie serwera bazy danych — szukanie sposobów na złagodzenie tego problemu

Hmm, mógłbym spróbować napisać Twoje zapytanie w następujący sposób:

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 

Przeniesiono kilka kolumn w celach organizacyjnych. Nie powinno to mieć dużego wpływu na czas przetwarzania.

Usunąłem odniesienie do phppos_suppliers jako:

  1. Nie używasz żadnych kolumn z tabeli
  2. To LEFT JOIN , co oznacza, że ​​nie musisz tam istnieć wierszy.

Przeniosłem GROUP BY do nowego podzapytania, ponieważ phppos_sales_item_taxes jest jedyną tabelą, która może mieć zduplikowane wiersze dla podanych kryteriów. Dołączyłem odniesienie do phppos_sales ponieważ nie jestem pewien, czy optymalizator MySQL (lub jakikolwiek inny, naprawdę) jest wystarczająco sprytny, aby obniżyć kryteria.

Główna część zapytania została przeniesiona do podzapytania, aby nie trzeba było wpisywać formuły dla lineSubtotal wiele razy. Używałem tych samych formuł w całym tekście, ale dostępne są uproszczone wersje:

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

.... być może będziesz musiał prowadzić je przez księgowość, ponieważ są one (co zrozumiałe) drażliwe w kwestii kolejności operacji. To może skutkuje szybszym czasem działania, ale wątpię w to; głównie chodzi o uproszczenie terminów do czegoś bardziej czytelnego.

Nie podałeś żadnych układów tabel dla drugiej połowy zapytania, ale przypuszczam, że jest podobnie. Powiązana modyfikacja jest pozostawiona jako ćwiczenie dla czytelnika.

Ogólne strategie łagodzenia skutków

Oprócz potencjalnego przyspieszenia zmiany zapytania, jest kilka rzeczy, które możesz zrobić, aby ograniczyć ten problem:

  1. W warstwie aplikacji wymuś przejście tego zapytania (i ewentualnie innych) przez proces przesyłania zadania, którego wyniki można później pobrać. Nie można uruchomić nowej kopii tego zapytania, dopóki poprzednie nie zostanie zakończone. Zakładam, że php ma do tego istniejącą bibliotekę. Po prostu ogólne ograniczenie przesyłania może być wszystkim, czego potrzebujesz.
  2. Pobierane dane wydają się podlegać buforowaniu — przechowuj wszystko przed ostatnią przetworzoną sale_date , a następnie otrzymuj tylko nowe informacje w locie (chociaż transformacja nie jest tak naprawdę tak różna z oryginału - jednak po prostu nie robienie więcej łączeń może pomóc).
  3. Nie zezwalaj na zapytania w bieżącym okresie przetwarzania. Powinno to uniemożliwić systemowi dostęp do wierszy, które nie zostały jeszcze zatwierdzone, i potencjalnie z dala od modyfikowanych stron indeksu. Ten rodzaj triku działa najlepiej, jeśli twoja pamięć masowa jest skonfigurowana tak, aby wykorzystać współbieżne operacje we/wy.



  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 -- Ostatnie 30 dni

  2. usuń nazwę z e-maila w mysql bez php czy to możliwe?

  3. Połącz się ze zdalnym serwerem MySQL za pomocą SSL z PHP

  4. MySQL UNIX_TIMESTAMP dla PostgreSQL

  5. Błąd sql:Konwersja typu danych varchar na typ danych data/godzina skutkowała wartością spoza zakresu