简体   繁体   English

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

[英]How can I optimize this mysql stored proc?

I have a stored procedure in mysql and it works but it's running so slow like 120 seconds.我在 mysql 中有一个存储过程,它可以工作,但运行速度很慢,比如 120 秒。 I need it to be faster than that.我需要它比那更快。 How can i optimize this?我该如何优化呢?

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

I appreciate anyone that could help me on this.我感谢任何可以帮助我的人。 If i were to use caching how does that work?如果我要使用缓存,那它是如何工作的?

The appropriate way to troubleshoot this kind of performance trouble is to work directly with the query in the SP.解决此类性能问题的适当方法是直接使用 SP 中的查询。 Start with any subqueries, optimize them, and work your way out to the top level query.从任何子查询开始,对其进行优化,然后找到顶级查询。 Only then work on the SP itself.只有这样才能在 SP 本身上工作。

You have a subquery containing this WHERE clause.您有一个包含此 WHERE 子句的子查询。

WHERE CAST(transaction.time as DATE) BETWEEN startDate AND endDate
AND transaction.payment_status = 2

This has a problem: it cannot exploit any index on the time column.这有一个问题:它不能利用time列上的任何索引。 Try refactoring it like so.尝试像这样重构它。

WHERE startDate <= transaction.time
  AND transaction.time < endDate + INTERVAL 1 DAY
  AND transaction.payment_status = 2

Notice the < , not <= , at the end of the date/time range.请注意日期/时间范围末尾的< ,而不是<=

Then create a compound index on those two columns, putting the equality-search column first and the range-search column second.然后在这两列上创建一个复合索引,将相等搜索列放在第一位,将范围搜索列放在第二位。 Like this.像这样。

ALTER TABLE transaction ADD INDEX status_time 
    (payment_status, time);

You didn't tell us much about your data, so this is a guess.你没有告诉我们太多关于你的数据,所以这是一个猜测。 But range searches of the form但形式的范围搜索

function(column) BETWEEN this AND that

are usually a good place to start working on query performance.通常是开始研究查询性能的好地方。 The use of a function to modify a column value in a WHERE clause often defeats the use of indexes.使用 function 来修改 WHERE 子句中的列值通常会破坏索引的使用。 Read about sargability .阅读sargability

Also, the use of BETWEEN on date/time values is often a code smell : a hint that something is worth checking for mistakes or confusion.此外,在日期/时间值上使用 BETWEEN 通常是代码异味:暗示某些事情值得检查错误或混淆。

Do those Joins need to be LEFT ?那些加入需要是LEFT吗? A LEFT JOIN with a subquery is a performance problem.带有子查询的LEFT JOIN是一个性能问题。

So is OR . OR也是如此。 Switching to a UNION may be the solution.切换到UNION可能是解决方案。 (But the GROUP BY adds complexity.) (但是GROUP BY增加了复杂性。)

What is the datatype of transaction.time ? transaction.time的数据类型是什么? If it is DATE , then the CAST is unnecessary.如果是DATE ,那么CAST是不必要的。 On the other hand, if startDate and endDate are DATEs , then DATETIME might work well. Let's see另一方面,如果startDate and endDate are DATEs , then DATETIME might work well. Let's see might work well. Let's see SHOW CREATE TABLE`. might work well. Let's see SHOW CREATE TABLE`。

Meanwhile, these indexes may help:同时,这些索引可能会有所帮助:

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