2016-05-10 7 views
0

私は700万行近くのテーブルを持っています。ここにテーブルの構造はありますMySQLクエリの最適化

`CREATE TABLE `ERS_SALES_TRANSACTIONS` (
    `saleId` int(12) NOT NULL AUTO_INCREMENT, 
    `ERS_COMPANY_CODE` int(3) DEFAULT NULL, 
    `SALE_SECTION` varchar(128) DEFAULT NULL, 
    `SALE_DATE` date DEFAULT NULL, 
    `SALE_STOCKAGE_EXACT` int(4) DEFAULT NULL, 
    `SALE_NET_AMOUNT` decimal(11,2) DEFAULT NULL, 
    `SALE_ABSOLUTE_CDATE` date DEFAULT NULL, 
    PRIMARY KEY (`saleId`), 
    KEY `index_location` (`ERS_COMPANY_CODE`), 
    KEY `idx-erscode-salesec` (`SALE_SECTION`,`ERS_COMPANY_CODE`) USING BTREE, 
    KEY `idx-saledate-section` (`SALE_DATE`,`SALE_SECTION`) USING BTREE 
    KEY `idx_quick_sales_transactions` (`ERS_COMPANY_CODE`,`SALE_SECTION`,`SALE_DATE`,`SALE_STOCKAGE_EXACT`,`SALE_NET_AMOUNT`) 
) ENGINE=InnoDB; 

このクエリは実行に7秒以上かかる、これをスピードアップする方法はありますか?ここで

SELECT 
    A.SALE_SECTION, 
    SUM(IF(A.SALE_DATE BETWEEN '2016-01-16' AND '2016-04-30' 
      AND A.SALE_STOCKAGE_EXACT BETWEEN 0 AND 90, A.SALE_NET_AMOUNT, 0)) AS fs1_pd1_sale, 
    SUM(IF(A.SALE_DATE BETWEEN '2016-01-16' AND '2016-04-30' 
      AND A.SALE_STOCKAGE_EXACT BETWEEN 91 AND 180, A.SALE_NET_AMOUNT, 0)) AS fs2_pd1_sale, 
    SUM(IF(A.SALE_DATE BETWEEN '2016-01-16' AND '2016-04-30' 
      AND A.SALE_STOCKAGE_EXACT BETWEEN 181 AND 365, A.SALE_NET_AMOUNT, 0)) AS os1_pd1_sale, 
    SUM(IF(A.SALE_DATE BETWEEN '2016-01-16' AND '2016-04-30' 
      AND A.SALE_STOCKAGE_EXACT BETWEEN 366 AND 9999, A.SALE_NET_AMOUNT, 0)) AS os2_pd1_sale, 
    SUM(IF(A.SALE_DATE BETWEEN '2016-01-16' AND '2016-04-30', A.SALE_NET_AMOUNT, 0)) AS TOTAL_PD1_SALE, 
    SUM(IF(A.SALE_DATE BETWEEN '2016-04-01' AND '2016-04-30' 
      AND A.SALE_STOCKAGE_EXACT BETWEEN 0 AND 90, A.SALE_NET_AMOUNT, 0)) AS fs1_pd2_sale, 
    SUM(IF(A.SALE_DATE BETWEEN '2016-04-01' AND '2016-04-30' 
      AND A.SALE_STOCKAGE_EXACT BETWEEN 91 AND 180, A.SALE_NET_AMOUNT, 0)) AS fs2_pd2_sale, 
    SUM(IF(A.SALE_DATE BETWEEN '2016-04-01' AND '2016-04-30' 
      AND A.SALE_STOCKAGE_EXACT BETWEEN 181 AND 365, A.SALE_NET_AMOUNT, 0)) AS os1_pd2_sale, 
    SUM(IF(A.SALE_DATE BETWEEN '2016-04-01' AND '2016-04-30' 
      AND A.SALE_STOCKAGE_EXACT BETWEEN 366 AND 9999, A.SALE_NET_AMOUNT, 0)) AS os2_pd2_sale, 
    SUM(IF(A.SALE_DATE BETWEEN '2016-04-01' AND '2016-04-30', A.SALE_NET_AMOUNT, 0)) AS TOTAL_PD2_SALE, 
    SUM(IF(A.SALE_DATE BETWEEN '2016-05-01' AND '2016-05-31' 
      AND A.SALE_ABSOLUTE_CDATE BETWEEN '2016-03-01' AND '2016-05-31', A.SALE_NET_AMOUNT, 0)) AS fs1_achived_sale, 
    SUM(IF(A.SALE_DATE BETWEEN '2016-05-01' AND '2016-05-31' 
      AND A.SALE_ABSOLUTE_CDATE BETWEEN '2015-12-01' AND '2016-02-29', A.SALE_NET_AMOUNT, 0)) AS fs2_achived_sale, 
    SUM(IF(A.SALE_DATE BETWEEN '2016-05-01' AND '2016-05-31' 
      AND A.SALE_ABSOLUTE_CDATE BETWEEN '2015-06-01' AND '2015-11-30', A.SALE_NET_AMOUNT, 0)) AS os1_achived_sale, 
    SUM(IF(A.SALE_DATE BETWEEN '2016-05-01' AND '2016-05-31' 
      AND A.SALE_ABSOLUTE_CDATE BETWEEN '2006-12-26' AND '2015-05-31', A.SALE_NET_AMOUNT, 0)) AS os2_achived_sale, 
    SUM(IF(A.SALE_DATE BETWEEN '2016-05-01' AND '2016-05-31', A.SALE_NET_AMOUNT, 0)) AS Total_ACHIVED_SALE 
    FROM ERS_SALES_TRANSACTIONS A WHERE A.ERS_COMPANY_CODE = 48 GROUP BY A.SALE_SECTION 

は、複合インデックスを追加した後、クエリ

{ 
"data": 
[ 
    { 
     "id": 1, 
     "select_type": "SIMPLE", 
     "table": "A", 
     "type": "ref", 
     "possible_keys": "index_location,idx-erscode-salesec,idx-saledate-section", 
     "key": "index_location", 
     "key_len": "5", 
     "ref": "const", 
     "rows": 1411944, 
     "Extra": "Using where; Using temporary; Using filesort" 
    } 
] 
} 

を説明します、時間は4.03秒に減少しました。ここでは」計画

{ 
"data": 
[ 
    { 
     "id": 1, 
     "select_type": "SIMPLE", 
     "table": "A", 
     "type": "ref", 
     "possible_keys": "index_location,idx-erscode-salesec,idx-saledate-section,idx_quick_sales_transactions", 
     "key_len": "5", 
     "key": "idx_quick_sales_transactions", 
     "ref": "const", 
     "rows": 1306058, 
     "Extra": "Using where" 
    } 
] 

}

+0

代わりに、これらすべてのSUM(IF(...、試してみてください)自己結合を試してください – JimmyB

+0

キー 'index_location'はERS_COMPANY_CODEのインデックスです – sam

答えて

1

私はここでジミーBと同意しません。あなたの質問は私の意見では完璧に見えます。

会社48のレコード数に応じて、テーブル全体を順番に読み取るか(たとえば、すべてのテーブルレコードの50%)、ERS_COMPANY_CODEのインデックスを使用する必要があります、例えば、すべてのレコードのわずか1%)。

DBMSがERS_COMPANY_CODEで索引を使用することを決定したので、後者が該当します。

合成インデックスを作成することで、クエリの速度をさらに向上させることができます。少なくとも(ERS_COMPANY_CODE , SALE_SECTION)にすると、GROUP BYが速くなります。さらにすべてのフィールドを追加すると、インデックスからすべてのデータを集めることができ、テーブル自体にアクセスする必要はありません。

CREATE INDEX idx_quick_sales_transactions ON ERS_SALES_TRANSACTIONS 
    (ERS_COMPANY_CODE, SALE_SECTION, SALE_DATE, SALE_STOCKAGE_EXACT, SALE_NET_AMOUNT); 
+0

複合インデックスのカラム順を調べるにはどうすればいいですか? – sam

+0

私はいつも 'WHERE'句2の1.カラムの順番でカラムを使います。 'GROUP BY'句のカラム3. HAVING句のカラム3. SELECT句のカラム4.データの取得には第一の優先度があり、第二の集約と結果の最後の表示 –

+0

注意してください。助けてくれてありがとう – sam

0
SELECT 
    sales.SALE_SECTION, 
    SUM(fs1_pd1.SALE_NET_AMOUNT) AS fs1_pd1_sale, 
    SUM(fs2_pd1.SALE_NET_AMOUNT) AS fs2_pd1_sale, 
... 
FROM ERS_SALES_TRANSACTIONS sales 

LEFT OUTER JOIN ERS_SALES_TRANSACTIONS fs1_pd1 ON sales.ERS_COMPANY_CODE = fs1_pd1.ERS_COMPANY_CODE AND sales.SALE_SECTION = fs1_pd1.SALE_SECTION 
    AND fs1_pd1.SALE_DATE BETWEEN '2016-01-16' AND '2016-04-30' 
    AND fs1_pd1.SALE_STOCKAGE_EXACT BETWEEN 0 AND 90 

LEFT OUTER JOIN ERS_SALES_TRANSACTIONS fs2_pd1 ON sales.ERS_COMPANY_CODE = fs2_pd1.ERS_COMPANY_CODE AND sales.SALE_SECTION = fs2_pd1.SALE_SECTION 
    AND fs2_pd1.SALE_DATE BETWEEN '2016-01-16' AND '2016-04-30' 
    AND fs2_pd1.SALE_STOCKAGE_EXACT BETWEEN 91 AND 180 
... 
    WHERE sales.ERS_COMPANY_CODE = 48 
    GROUP BY sales.SALE_SECTION 

この方法では、オプティマイザはクエリのために複数の索引を使用することができます。

しかし、複合インデックス@Thorsten Kettnerが推奨するのは、はるかに少ない複雑さで同じ効果を実現できることをお勧めします。

+0

申し訳ありませんが、このクエリはクエリ時間カバーインデックスを追加する前と後でテストしました – sam

2

これをスピードアップする方法があるかどうかわかりません。しかし、あなたはインデックスを使ってみることができます。 ERS_SALES_TRANSACTIONS(ERS_COMPANY_CODE, SALE_SECTION, SALE_DATE, SALE_NET_AMOUNT)にお勧めします。

これはクエリのカバーインデックスであり、クエリに使用されるすべての列がインデックスにあるため、データベースエンジンは元のデータページにアクセスする必要はありません。

ただし、パフォーマンスは依然として特定の会社コードと一致する行の数によって異なります。特に、集計に使用されるファイルソートのパフォーマンス。

+0

さて、複合インデックスを追加した後、クエリの時間は4.03秒に短縮されましたが、まだまだです。 – sam

+0

'ERS_COMPANY_CODE'と' SALE_SECTION'ごとに1行のテーブルがありますか? –

+0

company_codeは複数のsale_sectionを持つことができます – sam