簡體   English   中英

優化MySQL子查詢

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM