Hmm, ik zou kunnen proberen om je vraag als volgt te schrijven:
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
Verschillende kolommen verplaatst voor organisatorische doeleinden. Dit zou geen groot effect moeten hebben op de verwerkingstijd.
Ik heb de verwijzing naar phppos_suppliers
verwijderd als:
- U gebruikt geen kolommen uit de tabel
- Het is een
LEFT JOIN
, wat betekent dat je geen rijen nodig hebt om daar te bestaan.
Ik heb de GROUP BY
. verplaatst in een nieuwe subquery, omdat phppos_sales_item_taxes
is de enige tabel die dubbele rijen kan hebben voor de opgegeven criteria. Ik heb de verwijzing naar phppos_sales
toegevoegd omdat ik niet zeker weet of MySQL's optimizer (of een andere, echt) slim genoeg is om citeria naar beneden te duwen.
Het grootste deel van de query is verplaatst naar een subquery, zodat ik de formule voor lineSubtotal
niet hoef te typen meerdere keren. Ik heb overal dezelfde formules gebruikt, maar er zijn vereenvoudigde versies beschikbaar:
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
.... misschien moet u deze echter boekhoudkundig uitvoeren, omdat ze (begrijpelijkerwijs) gevoelig zijn voor de volgorde van bewerkingen. Dit mag resulteren in een snellere runtime, maar ik betwijfel het; meestal gaat dit over vereenvoudiging van de termen tot iets leesbaars.
Je hebt geen tabellay-outs gegeven voor de andere helft van de query, maar ik neem aan dat het vergelijkbaar is. De gerelateerde wijziging wordt overgelaten als een oefening voor de lezer.
Algemene mitigatiestrategieën
Afgezien van de mogelijke versnelling van het wijzigen van de zoekopdracht, zijn er een aantal dingen die u kunt doen om het probleem te beperken:
- Dwing deze query (en mogelijk andere) in uw applicatielaag om een taakverzendingsproces te doorlopen waarvan de resultaten later kunnen worden opgehaald. Een nieuwe kopie van deze query kan pas worden uitgevoerd als de vorige is voltooid. Ik neem aan dat php hiervoor een bestaande bibliotheek heeft. Gewoon afknijpen van de inzending in het algemeen is misschien alles wat je nodig hebt.
- De gegevens die worden opgehaald lijken vatbaar voor caching - sla alles op vóór de meest recent verwerkte
sale_date
, en krijg dan alleen on-the-fly nieuwe informatie (hoewel de transformatie niet echt zo verschillend is van het origineel - het kan echter helpen om gewoon niet meer mee te doen). - Sta query's over de huidige verwerkingstijd niet toe. Dit zou moeten voorkomen dat het systeem toegang probeert te krijgen tot rijen die nog niet zijn vastgelegd, en mogelijk weg van indexpagina's die worden gewijzigd. Dit soort trucjes werkt het beste als je opslagruimte is ingericht om te profiteren van gelijktijdige I/O.