繁体   English   中英

如何优化这个 mysql 存储过程?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM