Rất tiếc, tôi có thể thử viết truy vấn của bạn theo những dòng sau:
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
Đã di chuyển một số cột cho mục đích tổ chức. Điều này sẽ không ảnh hưởng lớn đến thời gian xử lý.
Tôi đã xóa tham chiếu đến phppos_suppliers
như:
- Bạn không sử dụng bất kỳ cột nào từ bảng
- Đó là
LEFT JOIN
, nghĩa là bạn không yêu cầu hàng tồn tại ở đó.
Tôi đã di chuyển GROUP BY
vào một truy vấn con mới, bởi vì phppos_sales_item_taxes
là bảng duy nhất có thể có các hàng trùng lặp cho các tiêu chí đã cho. Tôi đã bao gồm tham chiếu đến phppos_sales
bởi vì tôi không chắc liệu trình tối ưu hóa của MySQL (hoặc bất kỳ, thực sự) có đủ thông minh để đẩy citeria xuống hay không.
Phần chính của truy vấn đã được chuyển đến một truy vấn con đơn giản nên tôi không cần phải nhập công thức cho lineSubtotal
nhiều lần. Tôi đã sử dụng các công thức tương tự trong suốt, nhưng có các phiên bản đơn giản hóa có sẵn:
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
.... bạn có thể phải chạy những điều này bằng kế toán, vì chúng có xu hướng (dễ hiểu) về thứ tự hoạt động. Điều này có thể dẫn đến thời gian chạy nhanh hơn nhưng tôi nghi ngờ điều đó; chủ yếu đây là về việc đơn giản hóa các thuật ngữ để dễ đọc hơn.
Bạn đã không cung cấp bất kỳ bố cục bảng nào cho nửa còn lại của truy vấn, nhưng tôi cho rằng nó tương tự. Việc sửa đổi liên quan được để lại như một bài tập cho người đọc.
Các chiến lược giảm thiểu chung
Ngoài bất kỳ khả năng tăng tốc độ thay đổi truy vấn nào có thể có, có một số điều bạn có thể làm để khắc phục sự cố:
- Trong lớp ứng dụng của bạn, buộc truy vấn này (và có thể cả những truy vấn khác) phải trải qua một quy trình gửi công việc mà kết quả của nó có thể được truy xuất sau đó. Không thể chạy bản sao mới của truy vấn này cho đến khi bản sao trước đó hoàn thành. Tôi giả sử php có một thư viện hiện có cho việc này. Nói chung, chỉ cần điều chỉnh quá trình gửi có thể là tất cả những gì bạn cần.
- Dữ liệu đang được truy xuất dường như có thể lưu vào bộ nhớ đệm - lưu trữ mọi thứ trước
sale_date
được xử lý gần đây nhất và sau đó chỉ nhận được thông tin mới khi đang di chuyển (mặc dù quá trình chuyển đổi không thực sự khác biệt như vậy từ bản gốc - tuy nhiên, chỉ đơn giản là không thực hiện thêm các phép nối có thể hữu ích). - Không cho phép các truy vấn trong khoảng thời gian xử lý hiện tại. Điều này sẽ ngăn hệ thống cố gắng truy cập vào các hàng chưa được cam kết và có khả năng tránh xa các trang lập chỉ mục đang được sửa đổi. Loại thủ thuật này hoạt động hiệu quả nhất nếu bộ nhớ của bạn được bố trí để tận dụng lợi thế của I / O đồng thời.