[英]Optimize MySQL Sub-Query
有沒有一種方法可以優化此查詢? 它看起來很多余:
SELECT
SUM((SELECT
IFNULL(SUM(trx.totalAmount), 0)
FROM trx
WHERE
FIND_IN_SET (trx.clientOrderId, "B6A8DB9568,6E7705B487,59C4D4234D,1D9CD4EF96,4C373E8CDE,E818BEE48F,6610555669,ECF388E288,32FD93075C,B03417425B,18FD77061A,1C39E4BD04,C92B970E55,0920F06DFA,EEFB4AAADA,FC2D9FF9AD") > 0
AND trx.txnType IN ('REFUND', 'VOID')
)) as refunds,
SUM((SELECT
IFNULL(SUM(trx.totalAmount), 0)
FROM trx
WHERE
FIND_IN_SET (trx.clientOrderId, "B6A8DB9568,6E7705B487,59C4D4234D,1D9CD4EF96,4C373E8CDE,E818BEE48F,6610555669,ECF388E288,32FD93075C,B03417425B,18FD77061A,1C39E4BD04,C92B970E55,0920F06DFA,EEFB4AAADA,FC2D9FF9AD") > 0
AND trx.txnType = 'SALE'
AND trx.billingCycleNumber != 1
)) AS lifetimeRevenue
請注意,這只是查詢的一部分,原始查詢中還有10多個查詢,因此確實需要知道是否可以對其進行優化。
謝謝大家
使用這樣的子查詢的問題是每個子查詢都必須掃描整個表。 同樣,使用FIND_IN_SET()的方式也會強制進行全表掃描,即使您有索引也是如此。 因此,您要進行12次完整的表格掃描。
這是根本不使用子查詢的解決方案。 它會在表中掃描一次匹配的clientOrderId值,以獲取與您需要的任何txType匹配的所有行的超集。
然后,如果txnType是某些類型之一,則totalAmount的每個和都是有條件的,否則對每行的totalAmount使用零,並且零對總和沒有任何貢獻,因此就像您跳過了不匹配txnType的行一樣。
SELECT
SUM(IF(trx.txnType IN ('REFUND', 'VOID'), trx.totalAmount, 0)) AS refunds,
SUM(IF(trx.txnType = 'SALE' AND trx.billingCycleNumber != 1, trx.totalAmount, 0)) AS lifetimeRevenue
FROM trx
WHERE trx.clientOrderId IN (
'B6A8DB9568', '6E7705B487', '59C4D4234D', '1D9CD4EF96',
'4C373E8CDE', 'E818BEE48F', '6610555669', 'ECF388E288',
'32FD93075C', 'B03417425B', '18FD77061A', '1C39E4BD04',
'C92B970E55', '0920F06DFA', 'EEFB4AAADA', 'FC2D9FF9AD')
AND trx.txnType IN ('REFUND', 'VOID', 'SALE');
您應該在此查詢的(clientOrderId)上有一個索引。 由於您有兩個IN()
謂詞,因此WHERE子句將僅對索引中的第一列使用索引。
不要使用FIND_IN_SET()表達式,因為它不會在WHERE子句中使用索引。
您說查詢中還有10個字詞。 因此,我預計在這些術語中會有一些不同類型的表達式。 我不會回答任何“但是如果下一個術語看起來有些不同……該怎么辦……”。 我已經向您展示了將子查詢分解為一個單遍查詢的方法。 您可以將其應用於查詢中的其他術語。
這是我測試過的一個演示:
create table trx (
clientOrderId char(10),
txnType enum('REFUND','VOID','SALE'),
totalAmount numeric(9,2),
billingCycleNumber int default 0,
key (clientOrderId)
);
+---------------+---------+-------------+--------------------+
| clientOrderId | txnType | totalAmount | billingCycleNumber |
+---------------+---------+-------------+--------------------+
| B6A8DB9568 | REFUND | 42.00 | 0 |
| 59C4D4234D | SALE | 84.00 | 0 |
+---------------+---------+-------------+--------------------+
這是您查詢的解釋:
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+
| 1 | PRIMARY | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No tables used |
| 3 | SUBQUERY | trx | NULL | ALL | NULL | NULL | NULL | NULL | 2 | 50.00 | Using where |
| 2 | SUBQUERY | trx | NULL | ALL | NULL | NULL | NULL | NULL | 2 | 50.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+
請注意,每個術語都有一個子查詢,每個子查詢都以“ type = All”作為其表訪問權限。
這是我的查詢的解釋:
+----+-------------+-------+------------+-------+---------------+---------------+---------+------+------+----------+------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+---------------+---------+------+------+----------+------------------------------------+
| 1 | SIMPLE | trx | NULL | range | clientOrderId | clientOrderId | 11 | NULL | 16 | 50.00 | Using index condition; Using where |
+----+-------------+-------+------------+-------+---------------+---------------+---------+------+------+----------+------------------------------------+
一個簡單的表訪問,使用索引。
給定示例數據,您的查詢和我的查詢的結果:
+---------+-----------------+
| refunds | lifetimeRevenue |
+---------+-----------------+
| 42.00 | 84.00 |
+---------+-----------------+
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.