2011-07-13 11 views
3

私は以下のような単純なMyISAMテーブルを用意しています(可読性のためにトリムされています - 実際はもっと幅があります。MySQL:COUNT(*)とGROUP BYを最適化する

CREATE TABLE IF NOT EXISTS `history` (
    `id` bigint(20) NOT NULL AUTO_INCREMENT, 
    `time` int(11) NOT NULL, 
    `event` int(11) NOT NULL, 
    `source` int(11) DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    KEY `event` (`event`), 
    KEY `time` (`time`), 
); 

現在のテーブルは約6,000,000行(現在およそ16万は、以下のクエリに一致そのうち)が含まれていますが、これは増加すると予想されます。特定のイベントIDが与えられ、ソースごとにグループ化されているので、特定の時間間隔中にそのIDを持つイベントがいくつ記録されたかを知りたいと思います。質問に対する答えは、「今日、イベントXはソースAに対して120回、ソースBに対して105回、ソースCに対して900回起こった」という行に沿ったものかもしれない。

私が製作したクエリはこのタスクを実行しますが、タイムスパンが「すべての時間」に設定されている場合には1分以上かかり、1週間後には30秒を超えて実行すると大変です。

これはリアルタイムでの使用ではないため、クエリには2〜2秒かかる場合もありますが、数分ではありません。クエリを説明することは明白な理由のために私をトラブル以下、与える:

id select_type  table type possible_keys key  key_len  ref  rows Extra 
1 SIMPLE   history ref  event,time  event 4   const 160399 Using where; Using temporary; Using filesort 

私は(そのような(イベント、時間)など)、様々なマルチカラム・インデックスを試してきたが、ない改善しました。これは、私が妥当な解決策ではないと想像することができないような一般的な使用例のようですが、私のグーグルリングは、私が既に持っているクエリのバージョンに沸騰しています。なぜパフォーマンスが非常に悪いのか)。

提案がありますか?

答えて

0

マルチカラムインデックスを試したと言います。列ごとに1つの単一列索引も試しましたか?

UPDATEは:また、GROUP BY句を超えるCOUNT(*)操作がグループ化されたカラムはまた、それにインデックスを持っている場合...もちろん、これは実際にあるNULL値の数に依存し、おそらくはるかに高速でありますその列には索引付けされていません。 eventについては

、MySQLはインデックスを分離した場合、私はマルチよりも優れたパフォーマンスを期待したい... timeため、RANGE SCANはそれほど速くないこれ、適用されるのに対し、非常に高速である、UNIQUE SCANを実行することができます - 列のもの。また

、多分あなたは、いくつかの期待値によって、あなたのテーブルを分割することによって何かを得ることができ/値の範囲:

ALTER TABLE `history` ADD INDEX `history_index` (`event` ASC, `time` ASC, `source` ASC); 

http://dev.mysql.com/doc/refman/5.5/en/partitioning-overview.html

+0

上のスキーマからわかるように、私が試した複数列の索引に加えて、イベントと時間の両方がそれぞれ別々に索引付けされています。 – pjohansson

+0

すみません、私はそれを逃しました。私は 'KEY'キーワードを使って' INDEX'を指定するその構文に慣れていませんでした... 'INDEX'を' source'に追加するのはどうですか? –

+0

phpmyadminのエクスポート機能を責めます - 私はそれに慣れていませんでした。 :)また、ソースのインデックス作成は、私のテストでは追加のメリットはありません。 – pjohansson

0

私はあなたがこのマルチカラムインデックスを試していますそれでも問題が解決しない場合は、次のクエリでインデックスを強制的に作成してください:

SELECT COUNT(*) AS count FROM history USE INDEX (history_index) 
WHERE event=2000 AND time >= 0 AND time < 1310563644 
GROUP BY source 
ORDER BY count DESC 
+0

その特定のインデックスは、私がマルチカラムインデックスを使っていたときに試したものです。索引の使用を強制しても、パフォーマンスには影響しないようです。 – pjohansson

+0

@pjohanssonこのクエリのEXPLAINを表示できますか? – Karolis

0

ソースがわかっているか、特定のソースの数を探したい場合は、次のようにしてみてください。

select count(source = 'A'またはNULL)をA、count(source = 'B'またはNULL)をBとして履歴から選択します。 を注文し、アプリケーションコードで注文することができます。また、イベントとソースを一緒に索引付けしてみてください。

これは、古いものより確実に速くなります。

+0

数多くの異なるソースがあり、同じクエリでそれらのすべてのデータが必要です。 – pjohansson

+0

番号を指定できますか?時間基準のみとイベント基準だけが一致します。私は、時間> 0および時間<1310563644の履歴から選択カウント(*)を意味し、イベント= 2000の履歴からカウント(*)を選択します。 – leftrright

+0

'%table%'のような結果を表示できますか? '%tmp%'のようなステータスを表示します。フラッシュステータスとクエリを実行した後。 – leftrright