Home > database >  How can I optimize this mysql stored proc?
How can I optimize this mysql stored proc?

Time:09-09

I have a stored procedure in mysql and it works but it's running so slow like 120 seconds. 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?

CodePudding user response:

The appropriate way to troubleshoot this kind of performance trouble is to work directly with the query in the SP. Start with any subqueries, optimize them, and work your way out to the top level query. Only then work on the SP itself.

You have a subquery containing this WHERE clause.

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. 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. Read about 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.

CodePudding user response:

Do those Joins need to be LEFT? A LEFT JOIN with a subquery is a performance problem.

So is OR. Switching to a UNION may be the solution. (But the GROUP BY adds complexity.)

What is the datatype of transaction.time? If it is DATE, then the CAST is unnecessary. On the other hand, if startDate and endDate are DATEs, then DATETIMEmight work well. Let's seeSHOW 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)
  • Related