Amazon RDS で 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)
このテーブルは、ほとんどの場合、このようなクエリから 1 つのレポートを作成するためにのみ使用されます
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'
これは通常、完了するまでに約100〜180秒かかる1000〜6000行の何かを提供します。これは、Webアプリケーションがタイムアウトして空のレポートを残すことが多いことを意味します(タイムアウトも調べますが、この質問はルート向けです原因)。
私はデータベースがあまり得意ではありませんが、ここで私を殺しているのは BETWEEN だと思います。私が考えているのは、おそらく何らかの形でタイムスタンプをインデックスとして使用する必要があるということです。タイムスタンプとユーザー名を組み合わせることで、一意性が維持されるはずです (私は id フィールドを何にも使用しません)。
最適化のための提案を持っている人がいれば、私はすべて耳にします。
アップデート:
テーブルは次のように変更されました
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
SELECT
ステートメントの次を返します
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