2017-03-01 228 views
0

有沒有一種方法可以優化此查詢?它看起來多餘的:優化MySQL子查詢

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多那些原始查詢,以便真正需要知道它是否可以進行優化。

謝謝你們。

+0

不要使用'find_in_set'。使用'IN' – GurV

回答

0

像這樣使用子查詢的問題是每個子查詢都必須掃描整個表。即使你有索引,也使用FIND_IN_SET()來使用它的方式強制進行全表掃描。所以你正在做12個全表掃描。

這是一個根本不使用子查詢的解決方案。它掃描表匹配的clientOrderId值一次,以獲得匹配您需要的任何txType的所有行的超集。

然後totalAmount的每個總和是有條件的,如果txnType是某個類型的其中一個,否則對每個行的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 | 
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+ 

通知一個子查詢每學期,每個人做「類型=」作爲它的表訪問。

這裏的解釋我的查詢:

+----+-------------+-------+------------+-------+---------------+---------------+---------+------+------+----------+------------------------------------+ 
| 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 | 
+---------+-----------------+ 
+0

這與Danilo的答案相比如何? –

+0

如果Type只有這3個值,則刪除最後的AND條款。即使大部分行都屬於這三種類型,請將其移除。然後你可以使用'INDEX(clientOrderId)'來好用。 –

+0

如果'clientOrderId'是唯一的,則將其設爲'PRIMARY KEY'。 –