[英]mysql query performance improve
我在以下查詢中有性能問題:
SELECT t.local_branch_revenue, t.total_payment,
(SELECT SUM(IF(cpo.real_account_type = 'HQ', 0, cpo.payment_amount)) AS cpo_payment_amount
FROM customer_payment_options cpo
WHERE tran_id=t.id
AND cpo.payment_type != 'WALLET' AND cpo.payment_type != 'REWARD_CREDIT'
GROUP BY cpo.tran_id)
as cpo_payment_amount,
b.ben_firstname, b.ben_lastname
FROM transaction t
LEFT JOIN beneficiary b
ON b.id=t.ben_id
WHERE t.local_branch_id='31'
AND DATE(t.date_added) < '2016-04-07'
AND source_country_id='40'
AND t.transaction_status != 'CANCELLED'
說明
+----+--------------------+-------+--------+----------------------------------------+----------------------------------------+---------+-----------------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------------+-------+--------+----------------------------------------+----------------------------------------+---------+-----------------+------+-------------+
| 1 | PRIMARY | t | ref | local_branch_id,source_country_id | local_branch_id | 5 | const | 2 | Using where |
+----+--------------------+-------+--------+----------------------------------------+----------------------------------------+---------+-----------------+------+-------------+
| 1 | PRIMARY | b | eq_ref | PRIMARY | PRIMARY | 8 | mtesdb.t.ben_id | 1 | |
+----+--------------------+-------+--------+----------------------------------------+----------------------------------------+---------+-----------------+------+-------------+
| 2 | DEPENDENT SUBQUERY | cpo | ref | tran_id_payment_type_real_account_type | tran_id_payment_type_real_account_type | 9 | mtesdb.t.id | 1 | Using where |
+----+--------------------+-------+--------+----------------------------------------+----------------------------------------+---------+-----------------+------+-------------+
如您所見,它正在使用可能鍵的索引。 但是查詢仍然需要大約13秒。
我也有transaction
表的索引: (ben_id, company_id, source_country_id, date_added, tran_owner)
。 但是,它甚至不在可能的鍵部分。
讓我知道您是否需要table
架構。
我在這里想念什么?
依賴的子查詢在MySQL中的性能不佳...查詢計划程序無法將其有效地轉換為JOINed子查詢。 (它們在Oracle和SQL Server中還可以,但是誰有錢呢?)因此,對您而言,一個好的選擇是重構查詢以消除依賴的子查詢。
這是您的子查詢。 讓我們將其重構為一個獨立的子查詢。 我們將擺脫WHERE tran_id=t.id
然后將其移至ON
子句。
SELECT tran_id,
SUM(IF(real_account_type = 'HQ',
0,
payment_amount)) AS cpo_payment_amount
FROM customer_payment_options
WHERE payment_type != 'WALLET'
AND payment_type != 'REWARD_CREDIT'
GROUP BY tran_id
請注意,您可以按以下方式簡化此操作-您的IF()
子句排除real_account_type = 'HQ'
。 您可以改為在WHERE
子句中執行此操作。
SELECT tran_id,
SUM(payment_amount) AS cpo_payment_amount
FROM customer_payment_options
WHERE payment_type != 'WALLET'
AND payment_type != 'REWARD_CREDIT'
AND real_account_type != 'HQ'
GROUP BY tran_id
(tran_id, payment_type, real_account_type, payment_amount)
上的復合索引可以幫助此子查詢更快地運行。 但是,這三個!=
子句的存在保證了完整的索引掃描。 無法隨機訪問這些索引。
這將生成一個虛擬表,每個tran_id
包含一行, tran_id
包含所需的總和。
接下來,我們需要將其加入您的主要查詢中。
SELECT t.local_branch_revenue,
t.total_payment,
IFNULL(cposum.cpo_payment_amount,0) cpo_payment_amount,
b.ben_firstname, b.ben_lastname
FROM transaction t
LEFT JOIN beneficiary b ON b.id=t.ben_id
LEFT JOIN (
SELECT tran_id,
SUM(payment_amount) AS cpo_payment_amount
FROM customer_payment_options
WHERE payment_type != 'WALLET'
AND payment_type != 'REWARD_CREDIT'
AND real_account_type != 'HQ'
GROUP BY tran_id
) cposum ON t.id = cposum.tran_id
WHERE t.local_branch_id='31'
AND DATE(t.date_added) < '2016-04-07'
AND source_country_id='40'
AND t.transaction_status != 'CANCELLED'
您是否看到我們如何將依賴的摘要子查詢更改為其自己的虛擬表? 這樣,查詢計划者就可以只運行一次該查詢,而不是對主查詢中的每一行運行一次。 這很有幫助。
對於缺少任何對應的customer_payment_options
行的transaction
行, IFNULL()
您提供cpo_payment_amount的數字值,而不是NULL。
transaction
表上的復合索引(local_branch_id, source_country_id, date_added)
將有助於此查詢; 查詢引擎可以隨機訪問local_branch_id
和source_country_id
值,然后對date_added
值進行范圍掃描。
您如何學會自己做到這一點? http://use-the-index-luke.com/是一個好的開始。
WHERE t.local_branch_id='31'
AND DATE(t.date_added) < '2016-04-07'
AND source_country_id='40'
將該日期測試更改為t.date_added < '2016-04-07'
! 否則,以下索引建議將不起作用。
source_country_id
在哪個表中? 如果在t
,則需要INDEX(local_branch_id, source_country_id, date_added)
。 如果不在t
, INDEX(local_branch_id, date_added)
。
如果您需要進一步討論,請提供SHOW CREATE TABLE
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.