Hmm, jag kan försöka skriva din fråga på följande sätt:
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
Flyttade flera kolumner i organisatoriska syften. Detta bör inte ha någon större effekt på handläggningstiden.
Jag tog bort referensen till phppos_suppliers
som:
- Du använder inga kolumner från tabellen
- Det är en
LEFT JOIN
, vilket betyder att du inte kräver att rader finns där.
Jag flyttade GROUP BY
till en ny underfråga, eftersom phppos_sales_item_taxes
är den enda tabellen som kan ha dubbletter av rader för de givna kriterierna. Jag inkluderade referensen till phppos_sales
eftersom jag inte är säker på om MySQL:s optimerare (eller någon, verkligen) är smart nog att trycka ner citeria.
Huvuddelen av frågan har flyttats till en underfråga helt enkelt så att jag inte skulle behöva skriva formeln för lineSubtotal
flera gånger. Jag har använt samma formler genomgående, men det finns förenklade versioner tillgängliga:
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
.... du kanske måste köra dessa genom bokföring, eftersom de tenderar att vara (förståeligt nog) känsliga för ordningsföljden. Detta kan resultera i en snabbare körtid men jag tvivlar på det; mest handlar det om att förenkla termerna till något mer läsbart.
Du angav inga tabelllayouter för den andra hälften av frågan, men jag antar att den är liknande. Den relaterade modifieringen lämnas som en övning för läsaren.
Allmänna begränsningsstrategier
Utöver eventuella snabbare förändringar av frågan, finns det ett antal saker du kan göra för att minska problemet:
- Tvinga den här frågan (och eventuellt andra) i ditt ansökningslager att gå igenom en process för inlämning av jobb vars resultat kan hämtas senare. En ny kopia av den här frågan kan inte köras förrän den föregående är klar. Jag antar att php har ett befintligt bibliotek för detta. Att bara strypa inlämning i allmänhet kan vara allt du behöver.
- Datan som hämtas verkar vara tillgänglig för cachning - lagra allt före det senast bearbetade
sale_date
, och sedan bara få ny information i farten (även om transformationen egentligen inte är så annorlunda från originalet - dock kan det hjälpa att helt enkelt inte göra fler joins). - Tillåt inte frågor under den aktuella bearbetningstiden. Detta bör hindra systemet från att försöka få åtkomst till rader som inte har registrerats ännu, och eventuellt borta från indexsidor under modifiering. Den här typen av knep fungerar bäst om din lagring är utformad för att dra fördel av samtidiga I/O.