急速に成長しているテーブルが速度を上げていくという問題に直面しています (現在 400 万行、1 日 30 万回の挿入)。近い将来にウェブサイトがダウンする前に、セットアップを改善し、箱から最後のビットを絞り出すために、ここでいくつかのアイデアやアドバイスを得られることを願っています.
セットアップ:
Intel i7 720
8GB RAM
2x750GB SATA RAID 0
CentOS
MySQL 5.5.10
Node.js + node-lib_mysql-client
テーブル定義:
CREATE TABLE IF NOT EXISTS `canvas` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`x1` int(11) NOT NULL,
`y1` int(11) NOT NULL,
`x2` int(11) NOT NULL,
`y2` int(11) NOT NULL,
`c` int(4) unsigned NOT NULL,
`s` int(3) unsigned NOT NULL,
`m` bigint(20) unsigned NOT NULL,
`r` varchar(32) NOT NULL,
PRIMARY KEY (`id`,`x1`,`y1`) KEY_BLOCK_SIZE=1024,
KEY `x1` (`x1`,`y1`) KEY_BLOCK_SIZE=1024,
KEY `x2` (`x2`,`y2`) KEY_BLOCK_SIZE=1024
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT KEY_BLOCK_SIZE=4
/*!50100 PARTITION BY HASH ( (
(
x1 MOD 10000
)
) + y1 MOD 10000)
PARTITIONS 10 */ AUTO_INCREMENT=13168904 ;
クエリ:
SELECT x1,y1,x2,y2,s,c,r,m FROM canvas
WHERE 1 AND ((
x1 >= 0
AND x1 <= 400
AND y1 >= 0
AND y1 <= 400
) OR (
x2 >= 0
AND x2 <= 400
AND y2 >= 0
AND y2 <= 400
) )
ORDER BY id desc
x1、y1、x2、および y2 の値がクエリごとに変化するという事実を除いて、これが私が実行している唯一のクエリです。これは 2D キャンバスで、各行はキャンバス上の線を表します。1 つのフィールドに選択される最大範囲が 1200 (ピクセル) を超えることはないことを知っておくことも重要だと思います。数週間前、MySQL 5.5.10 にアップグレードし、パーティションの使用を開始しました。'x1 % 10000' hashw は、パーティションのトピックに入る最初の無意識のアプローチです。これで SELECT の速度はかなり向上しましたが、まだ最適化の余地があると確信しています。
ああ、あなたが尋ねる前に... 私は MyISAM テーブルを使用しているという事実を認識しています。私の友人は innoDB を提案しましたが、すでに試してみた結果、テーブルが 2 倍大きくなり、SELECT のパフォーマンスが大幅に低下しました。派手なトランザクションなどは必要ありません...必要なのは、可能な限り最高のSELECTパフォーマンスとINSERTでのまともなパフォーマンスだけです。
何を変えますか?どうにかしてインデックスを微調整できますか? 私のパーティション設定はまったく意味がありますか? おそらくパーティションファイルの数を増やす必要がありますか?
すべての提案は大歓迎です...私は友人とメモリテーブルへのローカルレプリケーションについても話しましたが、テーブルサイズがRAMを超えてスワッピングボックスがかなり醜いものになるまでは時間の問題だと確信しています見る。
私の問題について考えるときは、それが急速かつ予測できないほど大きくなっていることに留意してください。何らかの理由でどこかで話題になった場合、1 日あたり 100 万件以上の INSERTS が表示されると予想しています。
読んで考えて下さりありがとうございます。:)
編集: 要求された EXPLAIN 結果
select_type table type possible_keys key key_len ref rows Extra
SIMPLE canvas index_merge x1,x2 x1,x2 8,8 NULL 133532 Using sort_union(x1,x2); Using where; Using fileso...
EDIT2: 要求された my.cnf
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
user=mysql
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
innodb_buffer_pool_size = 1G
sort_buffer_size = 4M
read_buffer_size = 1M
read_rnd_buffer_size = 16M
innodb_file_format = Barracuda
query_cache_type = 1
query_cache_size = 100M
# http://dev.mysql.com/doc/refman/5.5/en/performance-schema.html
;performance_schema
[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
innoDB の値は、私の innoDB の試行用です...もう必要ないと思います。このサーバーは他に 4 つの Web サイトも実行していますが、それらはかなり小さく、言及する価値はありません。とにかく、このプロジェクトをすぐに専用のボックスに移動します。あなたのアイデアは急進的かもしれません - 私は実験を気にしません.
EDIT3 - インデックス付きのベンチマーク
わかりました...さまざまなインデックスでいくつかのベンチマークを作成しましたが、これまでのところ結果はかなり良好です。このベンチマークでは、2000x2000 ピクセルのボックス内のすべての行を選択しました。
SELECT SQL_NO_CACHE x1,y1,x2,y2,s,c FROM canvas_test WHERE 1 AND (( x1 BETWEEN -6728 AND -4328 AND y1 BETWEEN -6040 AND -4440 ) OR ( x2 BETWEEN -6728 AND -4328 AND y2 BETWEEN -6040 AND -4440 ) ) ORDER BY id asc
上記のテーブル/インデックス定義を使用すると、平均クエリ時間は1740ms でした。
次に、主キーを除くすべてのインデックスを削除しました-> 1900ms
x1 のインデックスを 1 つ追加 -> 1800ms
y1 に 1 つのインデックスを追加 -> 1700ms
x2 のインデックスを 1 つ追加 -> 1500ms
y2 のインデックスを 1 つ追加 -> 900ms!
これまでのところ、これは非常に驚くべきことです...何らかの理由で、x1/y1とx2/y2の結合インデックスを作成することは何とか理にかなっていると思っていましたが、実際には間違っていたようです。
EXPLAIN は次のように返します。
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE canvas_test index_merge x1,y1,x2,y2 y1,y2 4,4 NULL 263998 Using sort_union(y1,y2); Using where; Using fileso..
なぜ4つすべてではなくy1/y2をキーとして使用しているのか疑問に思っていますか?
ただし、特にパーティションと適切なハッシュに関して、さらに多くのアイデアとアドバイスを探しています。