2012-04-13 13 views
0

私はAmazon RDSでMySQLデータベースを持つアプリケーションを使っています。質問内のテーブルは、次のような設定されている:MySQLテーブルインデックスの最適化

CREATE TABLE `log` (
    `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, 
    `timestamp` datetime NOT NULL, 
    `username` varchar(45) NOT NULL, 
    .. snip some varchar and int fields .. 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 

このシステムは、しばらくの間、ベータ版になっていると、すでにデータセットは非常に巨大で、クエリがかなり遅くなるし始めています。

SELECT COUNT(*) FROM log --> 16307224 (takes 105 seconds to complete) 

この表はかなりのみ意味、一般的に完了するために、周りの100-180秒を取って1000のと6000行の間に何かを与えるこの

SELECT timestamp, username, [a few more] FROM log 
WHERE timestamp BETWEEN '2012-03-30 08:00:00' AND '2012-03-30 16:00:00' 
AND username='XX' 

のようなクエリオフつのレポートを構築するために使用されますWebアプリケーションはタイムアウトして空のレポートを残します(私もタイムアウトを調べますが、この問題は根本的な原因です)。

私はデータベースにはあまりよくありませんが、ここで私を殺しているのは私の推測です。私が考えているのは、おそらく何とかタイムスタンプをインデックスとして使用すべきだということです。タイムスタンプはユーザー名に沿って一意性を提供する必要があります(私はidフィールドを何も使用しません)。

私はすべての耳に最適化のための提案を誰もがある場合。

UPDATE:

表は今SELECT文の次

CREATE TABLE `log` (
    `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, 
    `timestamp` datetime NOT NULL, 
    `username` varchar(45) NOT NULL, 
    .. snip .. 
    `task_id` int(10) unsigned DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    KEY `index_un_ts` (`timestamp`,`username`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 

EXPLAINに変更されるようになり、タイムスタンプ列とユーザーIDで、次の

id => 1 
select_type => SIMPLE 
table => log 
type => range 
possible_keys => index_un_ts 
key => index_un_ts 
key_len => 55 
ref => 
rows => 52258 
Extra => Using where; Using index 
+0

MyISAMに切り替えることができます。たとえば、毎日cronでデータを集計し、別のレポート表に保管します。 –

答えて

1

まあインデックスを返します。役に立ったEXPLAINステートメントの出力を読み取ることができる必要があります。

のMySQLに移動し、次の操作を行います。

EXPLAIN SELECT timestamp, username, [a few more] FROM log 
WHERE timestamp BETWEEN '2012-03-30 08:00:00' AND '2012-03-30 16:00:00' 
AND username='XX' 

このショーあなたは、MySQLがクエリを実行するために使用する計画。キーと呼ばれる列があります。これは、クエリでMySQLが使用しているインデックスを示します。私はあなたがそこにすべてが表示されると思う。これは、MySQLがあなたのwhere節に対してあらゆる行にマッチする上から下までテーブルをスキャンしていることを意味する。タイムスタンプとユーザーIDの列に索引を作成します。再度EXPLAINステートメントを実行してください。作成した索引は、キー列に表示されます。

MySQLがインデックスを使用する場合、クエリはかなり速くなるはずです。オーバーインデックスにならないように覚えておいてください。インデックスにより、挿入、更新、削除が遅くなります。テーブルに新しい行を挿入し、テーブルに3つのインデックスがある場合、新しい行は3つの異なるインデックスに3つの値を書き込む必要があります。だから二重の剣です。

+0

ああ、ちょうどcreate indexステートメントが実行されるので、そこに座っているとパニックにならないようにしてください。 entiresテーブルをスキャンして値を取得し、新しいインデックス構造に挿入する必要があります。インデックスはディスクに格納されたBツリーまたはRツリーで、テーブルと同期して保持されます。 – Namphibian

+0

テーブルをopenarkキットで変更してください。 –

+1

説明はALLで戻ってきます。タイムスタンプ用とユーザー名用の2つのインデックス、またはそれらの複合インデックスを作成することをお勧めしますか? – danneth