2017-06-26 10 views
1

私は、結果をタイムリーに返すようにデータセットを間引くクエリを取得することに重大な問題があります。私はこのテーブルのインデックスの下にペーストしました(速度を向上させるのに十分だろうと思っていました)。そして、クエリのロジックも貼り付けました。MYSQLランク付けモードのクエリを最適化する

内部クエリで「ORDER BY」を削除していたことが1つありましたが、実際にはそのタイミングが改善されず、不要ないくつかの不要な列が削除されました。それを「十分に速く」することはできませんでした。

SELECT unix_date, price FROM 
(SELECT @row := @row +1 as row_num, unix_date, price 
FROM (SELECT @row:=0, unix_date, price FROM 
price_data WHERE created_date >= '2017-03-26 00:00:00' AND created_date 
<= '2017-06-26 23:59:59' AND currency= 'USD' ORDER BY unix_date DESC) 
AS p) AS d 
WHERE MOD(row_num, 288) = 1; 

このクエリの全体のポイントはただごとにしか第二百八十八(またはX)のデータ点を返すに結果価格データポイントのセット(Unixタイムスタンプ、価格)が、薄いそれを返すようにしようとしています。このテーブルは現在のところ正直にはかなり小さいです(合計行:198109)ので、なぜクエリが戻ってくるのに時間がかかりそうなのか分かりません。ここで

は現在、テーブルのインデックスです:

CREATE TABLE `price_data` (
    `created_date` datetime NOT NULL, 
    `unix_date` int(11) NOT NULL, 
    `currency` varchar(255) NOT NULL DEFAULT '', 
    `price` decimal(10,6) DEFAULT NULL, 
    PRIMARY KEY (`unix_date`,`currency`), 
    KEY `created_date` (`created_date`), 
    KEY `price` (`price`) 
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1 | 

だろう、このクエリの速度を向上させる方法上の任意のアドバイス:私が作成したテーブルを追加した提案パー

| Table    | Non_unique | Key_name  | Seq_in_index | 
Column_name | Collation | Cardinality | Sub_part | Packed | Null | 
Index_type | Comment | Index_comment | 
+--------------------+------------+--------------+--------------+------ 
--------+-----------+-------------+----------+--------+------+--------- 
---+---------+---------------+ 
| price_data |   0 | PRIMARY  |   1 | 
unix_date | A   |  200002 |  NULL | NULL |  | 
BTREE  |   |    | 
| price_data |   0 | PRIMARY  |   2 | 
currency  | A   |  200002 |  NULL | NULL |  | 
BTREE  |   |    | 
| price_data |   1 | created_date |   1 | 
created_date | A   |  200002 |  NULL | NULL |  | 
BTREE  |   |    | 
| price_data |   1 | price  |   1 | price   
| A   |  200002 |  NULL | NULL | YES | BTREE  |   
|    | 
+--------------------+------------+--------------+--------------+------ 
--------+-----------+-------------+----------+--------+------+--------- 
---+---------+-- 

大いに感謝します。

EDIT:問題は、このクエリの最終WHEREの行に沿ったものである可能性があります。実際には、以前の内部クエリから派生したrow_numの「偽の列」に対して情報を評価しています。それ自体のインデックス?だから、WHEREがそれを評価しているときに、通常のインデックスされたカラムの何かの速度でそうしていないのでしょうか?

+0

ここでのボトルネックのように思えるのは、並べ替えの「インデックス」として使用される@row varを追加することだけです。私はこれをインデックスとして追加し、それに基づいてソートすることなくこれを達成できる別の方法を知っている人がいるかどうかはわかりませんが、問題を引き起こしている行ごとにこれを追加しなければならないという気がします。 – parchambeau

+0

'SHOW CREATE TABLE price_data'を実行して出力を貼り付けることで、表を読みやすくすることができます。なぜ多くの人がこのコマンドを知りませんか、その代わりにMySQLテーブルの不完全な、または判読不能な記述を投稿する理由はわかりません。 –

+1

提案を賞賛する@BillKarwin、私は今編集しました。 – parchambeau

答えて

2

主キーを通貨unix_dateに変更します。通貨の等価条件とunix_dateの範囲条件があるので、最初に等価条件を指定して列を配置する必要があります。次に、unix_dateの範囲条件とORDER BYの両方で主キーの順序を使用する必要があります。

create_dateではなく、unix_dateに条件を適用して、主キーインデックスを使用するようにします。

派生テーブルのサブクエリを使用する必要がありますが、2つのネストされたサブクエリを使用する必要はありません。

SELECT row_num, unix_date, price 
FROM (
    SELECT @row := @row + 1 AS row_num, unix_date, price 
    FROM (SELECT @row := 0) AS _init 
    CROSS JOIN price_data 
    WHERE currency = 'USD' 
    AND unix_date BETWEEN UNIX_TIMESTAMP('2017-03-26 00:00:00') 
         AND UNIX_TIMESTAMP('2017-06-26 23:59:59') 
    ORDER BY unix_timestamp DESC 
) AS t 
WHERE MOD(row_num, 288) = 1 

インデックスの使用状況を分析するには、use EXPLAINをご確認ください。

あなたは私のプレゼンテーションHow to Design Indexes, Really、およびビデオをまた好むかもしれない:https://www.youtube.com/watch?v=ELR7-RdU9XU

のMySQL 8.0では、ウィンドウ関数持っているので、いつかその次の年のためになるはずです。

+0

本当に助けてくれてありがとう!私はこれを今実行し、違いを比較するつもりです。適切なインデックスの使用方法について私の理解に欠けていることは間違いないので、あなたのビデオも見ていきます。関数をウィンドウ処理することによって、Postgresのようなものは "PARTITION"などの意味を持ちますか? – parchambeau

+0

はい、MySQLのウィンドウ機能を開発しているエンジニアのプレゼンテーションは、https://www.slideshare.net/DagHWanvik/sql-window-functions-for-mysqlを参照してください。それでもまだ利用できませんが、彼はそれに取り組んでいます。 –