2017-03-01 7 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値を一度取得し、必要なtxTypesに一致するすべての行のスーパーセットを取得します。

次に、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)のインデックスが必要です。 2つのIN()述部があるので、WHERE節は索引の最初の列の索引のみを使用します。

WHERE句のインデックスを使用しないため、FIND_IN_SET()式は使用しないでください。

あなたはクエリに10個以上の用語があると言いました。だから私は、それらの言葉でいくつかの異なるタイプの表現があると予想しています。私は "次の言葉が別の何かのように見えたら..."と答えるつもりはない。サブクエリを1つのシングルパスクエリに解く方法を示しました。あなたの質問の他の言葉にそれを適用することはあなた次第です。ここで


は、私がテストしたデモです:各用語について

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

お知らせ1つのサブクエリ、それぞれが "タイプ=すべて" を行います。

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

はここにあなたのクエリのEXPLAINですそのテーブルアクセスとして。

は、ここに私のクエリのEXPLAINです:

+----+-------------+-------+------------+-------+---------------+---------------+---------+------+------+----------+------------------------------------+ 
| 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'節を削除してください。大部分の行がこれらの3つのタイプのものであっても、削除してください。次に、 'INDEX(clientOrderId)'を使って使い分けることができます。 –

+0

'clientOrderId'が一意の場合は、' PRIMARY KEY'にしてください。 –

関連する問題