3

私はテーブルを持っています:

CREATE TABLE `p` (  
`id` bigint(20) unsigned NOT NULL,  
`rtime` datetime NOT NULL,  
`d` int(10) NOT NULL,  
`n` int(10) NOT NULL,  
PRIMARY KEY (`rtime`,`id`,`d`) USING BTREE  
) ENGINE=MyISAM DEFAULT CHARSET=latin1;  

そして私は質問があります:

select id, d, sum(n) from p where  rtime between '2012-08-25' and date(now()) group by id, d;

私は小さなテーブル(2レコード)でこのクエリについてexplainを実行していますが、PKを使用することを通知します。

id  | select_type  | table | type   | possible_keys key  | key     | key_len | ref  | rows | Extra
1   | SIMPLE       | p     | range  | PRIMARY            | PRIMARY | 8       | NULL | 1    | Using where; Using temporary; Using filesort

しかし、同じテーブルで同じクエリを使用すると、今回は巨大な(3億5000万レコード)だけですが、すべてのレコードを調べてキーを無視することを好みます

id  | select_type  | table  | type | possible_keys  | key  | key_len | ref  | rows      | Extra
1   | SIMPLE       | p      | ALL  | PRIMARY        | NULL | NULL    | NULL | 355465280 | Using where; Using temporary; Using filesort

明らかに、これは非常に遅いです..誰かが助けることができますか?

編集:この単純なクエリにもかなりの時間がかかります:

select count(*) from propagation_delay where  rtime > '2012-08-28';
4

4 に答える 4

1

2 番目のクエリでは、日付範囲が非常に多くの行を返すため、MySQL はインデックスを使用しないことにしました。nインデックスに含まれていないため、これを行いました。非カバー インデックスは依然としてルックアップであり、多数のルックアップを実行すると、テーブルをスキャンするよりも遅くなります。

インデックスを利用するには、選択した行の数を減らすか、nインデックスに含めて完全な「カバー」インデックスにする必要があります。

于 2012-08-28T13:29:54.463 に答える
1

あなたの質問:

...WHERE rtime between '2012-08-25' and date(now()) group by id, d;

rtime を採用し、id と d でグループ化します。少なくとも、 で索引付けする必要がありますrtime。この順序で索引付けを試みることもrtime, id, d, nできますが、そうすると、索引には表とほぼ同じデータが含まれることがわかります。

おそらく、オプティマイザはいくつかの計算を行い、インデックスを使用する価値がないと結論付けます。

インデックスはそのままにしておきrtimeます。本当の決め手は、一致するレコードWHEREの数です。数が少ない場合は、インデックスを読み取ってテーブルを飛び回ると便利です。それらが複数ある場合は、テーブル全体を順次スキャンして、前後の読み取りを節約する方がよいでしょう。

クエリは、これらの 3 億 5000 万から大きな塊を取得しています - 私は数百万と言うでしょう

インデックスから 5 億件のレコードをすばやく抽出し、その 5 億件のレコードを復元するためにメイン テーブルを往復する累積コストは、メイン テーブルを開くコストよりも高くなる可能性があります。 、途中でグループ化と合計を行う 3 億 5000 万のレコードすべてを調べます。

このようなシナリオで、常に(またはほとんど) に対して集計クエリを実行しrtime、かつテーブルが累積 (履歴) テーブルであり、かつ各カップル(id, d)が 1 日あたり数スコアのエントリを参照する場合は、日付別集計セカンダリ テーブルの作成を検討できます。つまり、(たとえば) 真夜中にクエリを実行し、

INSERT INTO aggregate_table
    SELECT DATE(@yesterday) AS rtime, id, d, sum(n) AS n
    FROM main_table WHERE DATE(rtime) = @yesterday GROUP BY id, d;

のデータには、その日の合計を保持するaggregate_tableカップルごとに 1 つのエントリしかありません。テーブルはそれに比例して小さくなり、クエリが高速になります。これは、比較的少数のテーブルがあり、それぞれが毎日メイン テーブルに多数の行を生成することを前提としています。(id, d)n(id, d)

カップルごとに 1 分間に 1 回のログ記録を行うと、集約によって 3 桁以上高速化されるはずです (逆に、膨大な数の異なるセンサーを 1 日に 2 回取得している場合、そのメリットは無視できます)。

于 2012-08-28T12:57:11.800 に答える
0

Index Hint Syntaxを使用して、MySQL に特定のインデックスを使用させることができます。

于 2012-08-28T15:27:01.950 に答える
-1

少しの経験で、エンジンを MyISAM から InnoDB に変更してみてください。MyISAM には、多くの録音やその他のバグに関するいくつかの問題があり、InnoDB は改善されています。また、MySQL 5.5 以降のデフォルト エンジンは InnoDB です: http://dev.mysql.com/doc/refman/5.5/en/innodb-default-se.html

于 2012-08-28T12:57:02.923 に答える