2016-05-24 7 views
0

私はこれらのテーブルをMySQLに持っています。MySQLでのSQLの改善

CREATE TABLE `tableA` (
    `id_a` int(11) NOT NULL, 
    `itemCode` varchar(50) NOT NULL, 
    `qtyOrdered` decimal(15,4) DEFAULT NULL, 
      : 
    PRIMARY KEY (`id_a`), 
    KEY `INDEX_A1` (`itemCode`) 
) ENGINE=InnoDB 

CREATE TABLE `tableB` (
    `id_b` int(11) NOT NULL AUTO_INCREMENT, 
    `qtyDelivered` decimal(15,4) NOT NULL, 
    `id_a` int(11) DEFAULT NULL, 
    `opType` int(11) NOT NULL, -- '0' delivered to customer, '1' returned from customer 
        : 
    PRIMARY KEY (`id_b`), 
    KEY `INDEX_B1` (`id_a`) 
    KEY `INDEX_B2` (`opType`) 
) ENGINE=InnoDB 

tableA我々は、顧客からの注文を受けどのように多くの量を示し、tableBは、私たちが注文ごとに顧客に納入どのように多くの量を示しています。

itemCodeに配送可能な数量を数えるSQLを作成します。 SQLは次のとおりです。このSQLは機能しますが、遅いです。

SELECT T1.itemCode, 
     SUM(IFNULL(T1.qtyOrdered,'0')-IFNULL(T2.qtyDelivered,'0')+IFNULL(T3.qtyReturned,'0')) as qty 
FROM tableA AS T1 
LEFT JOIN (SELECT id_a,SUM(qtyDelivered) as qtyDelivered FROM tableB WHERE opType = '0' GROUP BY id_a) 
    AS T2 on T1.id_a = T2.id_a 
LEFT JOIN (SELECT id_a,SUM(qtyDelivered) as qtyReturned FROM tableB WHERE opType = '1' GROUP BY id_a) 
    AS T3 on T1.id_a = T3.id_a 
WHERE T1.itemCode = '?' 
GROUP BY T1.itemCode 

私は、このSQLにexplainを試みたが、結果は以下の通りです。

+----+-------------+------------+------+----------------+----------+---------+-------+-------+----------------------------------------------+ 
| id | select_type | table  | type | possible_keys | key  | key_len | ref | rows | Extra          | 
+----+-------------+------------+------+----------------+----------+---------+-------+-------+----------------------------------------------+ 
| 1 | PRIMARY  | T1   | ref | INDEX_A1  | INDEX_A1 | 152  | const |  1 | Using where         | 
| 1 | PRIMARY  | <derived2> | ALL | NULL   | NULL  | NULL | NULL | 21211 |            | 
| 1 | PRIMARY  | <derived3> | ALL | NULL   | NULL  | NULL | NULL | 10 |            | 
| 3 | DERIVED  | tableB  | ref | INDEX_B2  | INDEX_B2 | 4  |  | 96 | Using where; Using temporary; Using filesort | 
| 2 | DERIVED  | tableB  | ref | INDEX_B2  | INDEX_B2 | 4  |  | 55614 | Using where; Using temporary; Using filesort | 
+----+-------------+-------------------+----------------+----------+---------+-------+-------+----------------------------------------------+ 

私はクエリを改善したいと思います。どうやってやるの?

答えて

1

まず、テーブルBにopTypeのintがありますが、文字列と '0'と '1'を比較しています。数字0と1のままにしておきます。事前集計を最適化するには、個々の列インデックスを持つべきではなく、コンポジット(この場合はカバーインデックス)を使用します。 INDEXテーブルB ON(OpType、ID_A、QtyDelivered)を1つのインデックスとして使用します。グループを最適化するためにWHERE、ID_Aを最適化するOpType、生データページに行くことなくインデックス内の集約に対してQtyDelivered。

2つのタイプを探しているので、1つのパス結果のいずれかのために、それらを1つのサブクエリテストにロールアップすることができます。次に、あなたのtableAの結果に参加してください。

SELECT 
     T1.itemCode, 
     SUM(IFNULL(T1.qtyOrdered, 0) 
     - IFNULL(T2.qtyDelivered, 0) 
     + IFNULL(T2.qtyReturned, 0)) as qty 
    FROM 
     tableA AS T1 
     LEFT JOIN (SELECT 
          id_a, 
          SUM(IF(opType=0,qtyDelivered, 0)) as qtyDelivered, 
          SUM(IF(opType=1,qtyDelivered, 0)) as qtyReturned 
         FROM 
          tableB 
         WHERE 
          opType IN (0, 1) 
         GROUP BY 
          id_a) AS T2 
      on T1.id_a = T2.id_a 
    WHERE 
     T1.itemCode = '?' 
    GROUP BY 
     T1.itemCode 

、あなたのテーブルのサイズに応じて、あなたはより良いあなただけがexpectinているアイテムコードのそれらを得るように、テーブルAに、あなたの内側のテーブルにJOINをやっているかもしれません。あなたが50kのアイテムを持っていて、修飾アイテム= 120アイテムしか探していない場合、内側のクエリーは50kに基づいてまだ適格です。その場合、過度の攻撃になります。私は `WHERE OPTYPE IN(のいずれかのポイントが0ないと思うこの場合、私は(ItemCode、ID_A)によって、テーブルAのインデックスを示唆していると

  LEFT JOIN (SELECT 
          b.id_a, 
          SUM(IF(b.opType = 0, b.qtyDelivered, 0)) as qtyDelivered, 
          SUM(IF(b.opType = 1, b.qtyDelivered, 0)) as qtyReturned 
         FROM 
          (select distinct id_a 
           from tableA 
           where itemCode = '?') pqA 
           JOIN tableB b 
           on PQA.id_A = b.id_a 
           AND b.opType IN (0, 1) 
         GROUP BY 
          id_a) AS T2 

My Query against your SQLFiddle

+0

に内側のクエリを調整します、1) 'これは唯一の2つの値です。 – Barmar

+0

返信ありがとうございます。しかし、サブクエリを使用すると、クエリが遅くなります。私はサブクエリを排除したい。サブ問合せなしで同じことをすることはできますか? –

+0

@ N.F。、どのサブクエリ。最初のサンプルでも2つのサブクエリが表示されています。 2番目のサンプルは、データ、アイテムの量に基づいており、アイテムに関わらずすべてを照会し、そのアイテムに再び参加しました。配送/返品の可能な複製を削除するには、少なくとも1つのサブクエリが必要です。 – DRapp