[英]How can I optimize this mysql stored proc?
我在 mysql 中有一个存储过程,它可以工作,但运行速度很慢,比如 120 秒。 我需要它比那更快。 我该如何优化呢?
CREATE DEFINER=`xxxx`@`%` PROCEDURE `sp_test`( IN merchantId int, IN startDate VARCHAR(50),IN endDate VARCHAR(50))
BEGIN
SELECT
inventory.sku AS 'SKU',
inventory.description AS 'Description',
inventory_category.name as 'Category',
inventory_sub_category.name as 'Sub Category',
IFNULL(tbl_ticket.price,0) AS 'Unit Price',
IFNULL(tbl_ticket.quantity_total,0) AS 'Total Issued',
IFNULL(ROUND(tbl_ticket.price,2),0) * IFNULL(tbl_ticket.quantity_total,0) AS 'Gross Amount',
IFNULL(tbl_ticket.promo_code_discount, 0 ) AS 'Total Discount',
ROUND((IFNULL(tbl_ticket.price,0) * IFNULL(tbl_ticket.quantity_total,0) ) - IFNULL(tbl_ticket.promo_code_discount, 0 ),2) AS 'Net Amount'
FROM inventory
LEFT JOIN inventory_category ON inventory.inventory_category_id = inventory_category.id
LEFT JOIN inventory_sub_category ON inventory.inventory_sub_category_id = inventory_sub_category.id
LEFT JOIN(
SELECT inventory.sku, inventory.price, channel.merchant_id, SUM(ticket.quantity_total) as 'quantity_total',
SUM(ticket.promo_code_discount) as 'promo_code_discount'
FROM inventory
JOIN v_transaction_items_details ON inventory.sku = v_transaction_items_details.item_name
JOIN ticket on ticket.id = v_transaction_items_details.ticket_id
JOIN transaction ON ticket.transaction_id = transaction.id
JOIN channel ON channel.sub_agent_id = ticket.reseller_id
WHERE CAST(transaction.time as DATE) BETWEEN startDate AND endDate
AND transaction.payment_status = 2
AND ticket.level = 1
AND ticket.type = 1
GROUP BY inventory.sku, inventory.price, channel.merchant_id) tbl_ticket on tbl_ticket.sku = inventory.sku
WHERE inventory.status = 1 AND (inventory.merchant_id = merchantId OR tbl_ticket.merchant_id = merchantId)
GROUP BY inventory.sku,inventory.description,inventory_category.name,inventory_sub_category.name;
END
我感谢任何可以帮助我的人。 如果我要使用缓存,那它是如何工作的?
解决此类性能问题的适当方法是直接使用 SP 中的查询。 从任何子查询开始,对其进行优化,然后找到顶级查询。 只有这样才能在 SP 本身上工作。
您有一个包含此 WHERE 子句的子查询。
WHERE CAST(transaction.time as DATE) BETWEEN startDate AND endDate
AND transaction.payment_status = 2
这有一个问题:它不能利用time
列上的任何索引。 尝试像这样重构它。
WHERE startDate <= transaction.time
AND transaction.time < endDate + INTERVAL 1 DAY
AND transaction.payment_status = 2
请注意日期/时间范围末尾的<
,而不是<=
。
然后在这两列上创建一个复合索引,将相等搜索列放在第一位,将范围搜索列放在第二位。 像这样。
ALTER TABLE transaction ADD INDEX status_time
(payment_status, time);
你没有告诉我们太多关于你的数据,所以这是一个猜测。 但形式的范围搜索
function(column) BETWEEN this AND that
通常是开始研究查询性能的好地方。 使用 function 来修改 WHERE 子句中的列值通常会破坏索引的使用。 阅读sargability 。
此外,在日期/时间值上使用 BETWEEN 通常是代码异味:暗示某些事情值得检查错误或混淆。
那些加入需要是LEFT
吗? 带有子查询的LEFT JOIN
是一个性能问题。
OR
也是如此。 切换到UNION
可能是解决方案。 (但是GROUP BY
增加了复杂性。)
transaction.time
的数据类型是什么? 如果是DATE
,那么CAST
是不必要的。 另一方面,如果startDate and endDate are
DATEs , then
DATETIME might work well. Let's see
might work well. Let's see
SHOW CREATE TABLE`。
同时,这些索引可能会有所帮助:
inventory: INDEX(status, merchant_id, inventory_category_id)
inventory: INDEX(sku, price)
channel: INDEX(sub_agent_id, merchant_id)
ticket: INDEX(level, type, id)
v_transaction_items_details: INDEX(item_name, ticket_id)
transaction: INDEX(time, payment_status, id)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.