私は数百万行のデータの可能性がある mysql テーブルを持っています - いくつかの極端なケースでは最大 100mil です。このデータを頻繁にクエリするアプリケーションを開発し、それを最適化するためにできる限りのことを行いました - データの非常に小さなサブセット (場所に関連付けられている) のみを検索しているため、ほとんどの場合、非常に迅速に動作します。 .
テーブル構造:
CREATE TABLE `prism_actions` (
`id` int(11) unsigned NOT NULL auto_increment,
`action_time` timestamp NOT NULL default CURRENT_TIMESTAMP,
`action_type` varchar(25) NOT NULL,
`player` varchar(16) NOT NULL,
`world` varchar(255) NOT NULL,
`x` int(11) NOT NULL,
`y` int(11) NOT NULL,
`z` int(11) NOT NULL,
`block_id` mediumint(5) unsigned NOT NULL,
`block_subid` mediumint(5) unsigned NOT NULL,
`data` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
KEY `x` (`x`),
KEY `action_type` (`action_type`),
KEY `player` (`player`),
KEY `block_id` (`block_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
WHERE ステートメントで最もよく使用するフィールドにいくつかの基本的なインデックスがあり、条件が 1 つだけのクエリで使用すると、非常に高速です。
これらのテストを実行しているテーブルの例には、2,200 万のレコードがあります。
例:
SELECT prism_actions.id FROM prism_actions WHERE prism_actions.action_type = 'block-break' LIMIT 1000;
1000 rows in set (0.00 sec)
SELECT prism_actions.id FROM prism_actions WHERE prism_actions.block_id = 2 LIMIT 1000;
1000 rows in set (0.01 sec)
私の問題は、クエリで使用する条件ごとに (ほとんどのクエリには通常複数の条件があります)、クエリにかなりの時間がかかることです。
SELECT prism_actions.id FROM prism_actions WHERE prism_actions.action_type = 'block-break' AND prism_actions.block_id = 2 LIMIT 1000;
1000 rows in set (0.79 sec)
完全なクエリでは .79 秒が許容されますが、それは条件の一部を使用しているだけです。
実際のクエリは次のようになります。
SELECT prism_actions.id FROM prism_actions WHERE prism_actions.action_type = 'block-break' AND prism_actions.player = 'viveleroi' AND prism_actions.block_id = 2 LIMIT 1000;
1000 rows in set (2.22 sec)
単一の条件では で実行し0.01
、2 では実行し、0.79
3 では2.2
長すぎる秒で実行しました。
インデックスをより適切に設計する方法を調査しますが、現在のデータベース スキーマとインデックスにほとんど満足しています。
しかし、そのように組み合わせて条件を速くするにはどうすればよいでしょうか?
アップデート
テーブルを外部キー形式に変換するのに時間を費やしました。player、action_type、world 列のデータは別のテーブルに移動され、それらの ID は元のテーブルに格納されました。データの移行に数時間かかりました。
ただし、以前に使用したのと同じクエリを再実行しています。速度が向上したものもあれば、ほとんど変化が見られないものもあります。
上記の 0.79 秒のクエリを変換したバージョンは、ほぼ同じ速度で実行されます。
SELECT prism_actions.id FROM prism_actions WHERE prism_actions.actiontype_id = 1 AND prism_actions.block_id = 2 LIMIT 1000;
1000 rows in set (0.73 sec)
block_id 列には、元のテーブル スキーマからのインデックスがまだあります。
条件として player_id を使用したクエリの実行が非常に遅かったため、列にインデックスを追加したところ、クエリが非常に高速になりました。
ただし、実際のユーザーからいくつかのクエリの例を取得し、このテーブル構造に合わせて更新した後、速度に変化は見られません.
SELECT prism_actions.id FROM prism_actions WHERE (prism_actions.actiontype_id = 2 OR prism_actions.actiontype_id = 1) AND (prism_actions.player_id = 1127) AND prism_actions.action_time >= '2013-02-22 07:47:54' LIMIT 1000;
以前は5.83 sec
、現在は5.29 sec
編集 - タイムスタンプのようです。上記のクエリからタイムスタンプ条件を除外すると、0.01 秒で結果が返されます。タイムスタンプのインデックスを追加しても何も起こりません - アイデアですか?
これまでのところ、私が実際に目にしているのは、特定の領域でのわずかな速度の向上と、重複した文字列を保存するためのファイル スペースのわずかな節約だけです。データを変換する時間の。
他の方法でインデックスを作成するなどの提案はありますか?