うーん、私はこれらの線に沿ってあなたのクエリを書いてみるかもしれません:
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
への参照を削除しました として:
- テーブルの列は使用しません
- これは
LEFT JOIN
、つまり、そこに行が存在する必要はありません。
GROUP BY
を移動しました phppos_sales_item_taxes
のため、新しいサブクエリに追加します 指定された基準に対して重複する行を持つ可能性がある唯一のテーブルです。 phppos_sales
への参照を含めました MySQLのオプティマイザ(または実際にはどれか)がシテリアを押し下げるのに十分賢いかどうかわからないからです。
クエリの主要部分がサブクエリに移動されたため、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
....ただし、これらは操作の順序について(当然のことながら)扱いにくい傾向があるため、アカウンティングによって実行する必要がある場合があります。このかもしれません 実行時間が速くなりますが、私はそれを疑っています。ほとんどの場合、これは用語をより読みやすいものに単純化することです。
クエリの残りの半分にテーブルレイアウトを指定していませんが、類似していると思います。関連する変更は、読者の演習として残されています。
一般的な緩和戦略
クエリを変更することでスピードアップする可能性があるだけでなく、問題を減らすためにできることがいくつかあります。
- アプリケーション層で、このクエリ(および場合によっては他のクエリ)に、後で結果を取得できるジョブ送信プロセスを強制的に実行させます。このクエリの新しいコピーは、前のクエリが完了するまで実行できません。 phpにはこのための既存のライブラリがあると思います。一般的に、提出を制限するだけで十分な場合があります。
- 取得するデータはキャッシュに適しているようです-最後に処理された
sale_date
の前にすべてを保存します 、そしてその場で新しい情報を取得するだけです(ただし、変換は実際にはそれほど違いはありません オリジナルから-ただし、単にそれ以上の結合を行わないことが役立つ場合があります。 - 現在の処理期間中のクエリを禁止します。これにより、システムがまだコミットされていない行にアクセスしようとするのを防ぎ、変更中のインデックスページから離れる可能性があります。この種のトリックは、同時I/Oを利用するようにストレージがレイアウトされている場合に最適に機能します。