4

急速に成長しているテーブルが速度を上げていくという問題に直面しています (現在 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をキーとして使用しているのか疑問に思っていますか?

ただし、特にパーティションと適切なハッシュに関して、さらに多くのアイデアとアドバイスを探しています。

4

4 に答える 4

2

まず、SELECT を次のように変更します。

SELECT x1,y1,x2,y2,s,c,r,m FROM canvas
WHERE 
  x1 BETWEEN 0 AND 400 AND y1 BETWEEN 0 AND 400 OR
  x2 BETWEEN 0 AND 400 AND y2 BETWEEN 0 AND 400
ORDER BY id desc

また、その式に必ずインデックスを付けてください。

CREATE INDEX canvas400 ON canvas(
  x1 BETWEEN 0 AND 400 AND y1 BETWEEN 0 AND 400 OR
  x2 BETWEEN 0 AND 400 AND y2 BETWEEN 0 AND 400
)
于 2011-05-18T23:09:31.930 に答える
1

MySQL はクエリごとにテーブルごとに 1 つのインデックスのみを使用することに注意してください。SELECT クエリは、同じクエリで両方のインデックスを使用することはできません。どちらか一方を使用します。それぞれが適切なインデックスを使用できるように、2 つの SELECT クエリを一緒に UNION する方が効率的であることに気付くかもしれません。

SELECT x1,y1,x2,y2,s,c,r,m FROM canvas
WHERE 
 x1 >= 0
 AND x1 <= 400
 AND y1 >= 0
 AND y1 <= 400
UNION
SELECT x1,y1,x2,y2,s,c,r,m FROM canvas
WHERE
 x2 >= 0
 AND x2 <= 400
 AND y2 >= 0
 AND y2 <= 400
;

または、提案された他の返信のいずれかのように BETWEEN を使用できます。

SELECT x1,y1,x2,y2,s,c,r,m FROM canvas
WHERE x1 BETWEEN 0 AND 400 AND y1 BETWEEN 0 AND 400
UNION
SELECT x1,y1,x2,y2,s,c,r,m FROM canvas
WHERE x2 BETWEEN 0 AND 400 AND y2 BETWEEN 0 AND 400
;

UNION を使用してからしばらく経っているので、ORDER BY 句をどこに置くかわかりませんが、それを試すことができます。

言及された他の回答の 1 つとして、EXPLAIN を使用して、クエリを満たすために MySQL が考慮しなければならない行数を確認します。

RTREE インデックスも検討する価値があるかもしれませんが、私自身はそれらで遊んだことはありません。

于 2011-08-03T17:09:31.530 に答える
1
  1. サーバーが現在使用しているメモリの量は?
  2. これはサーバー上の唯一のデータベース/テーブルですか?
  3. MyISAM のみを使用していますか?

行を更新しない限り、MyISAM は問題なく使用できます。MyISAM テーブルの行を更新すると、MySQL はテーブル全体をロックし、UPDATE が完了するまで SELECT と INSERTS の実行をブロックします。UPDATE は SELECT よりも優先されるため、多数の UPDATE を実行している場合、SELECT はすべてが完了するまで待ってから行を返します。

それでも問題ない場合は、サーバー構成に移動してください。my.cnf ファイルはどのようなものですか? このファイルを最適化して、インデックスに使用できるメモリの量を最大化する必要があります。これらの SELECT の速度が低下している場合は、テーブル インデックスがメモリに収まっていないことが原因です。MySQL がテーブル インデックスをメモリに収めることができない場合、ディスクにアクセスしてテーブル スキャンを実行し、データを取得する必要があります。これによりパフォーマンスが低下します。

編集 2011 年 5 月 18 日午後 9 時 30 分 EST

my.cnf を確認したところ、MyISAM の最適化がまったく行われていないことがわかりました。あなたの出発点はkey_buffer_size変数になります。この変数は、経験則として、システムで使用可能なメモリの合計の 25% から 50% の間のどこかに設定されます。お使いのシステムには 8 GB のメモリが利用可能であるため、最低でも 3 GB 程度が出発点と言えます。ただし、システム上の他の変数を制御できることがわかっている場合は、必要な量を見積もり、必要に応じて最適化することができます。

あなたがすべきことは/var/lib/mysql、すべてのデータファイルが置かれている mysql データディレクトリ (通常は ) に cd することです。インデックス データの量をすばやく確認する方法は次のとおりです。

 sudo du -hc `find . -type f -name "*.MYI"

このコマンドは、すべての MyISAM インデックス ファイルのサイズを調べて、それらの合計サイズを教えてくれます。十分なメモリがある場合key_buffer_sizeは、my.cnf をすべての MYI ファイルの合計サイズよりも大きくしたいと考えています。これにより、MyISAM インデックスがメモリ内にあることが保証されるため、MySQL はインデックス データのためにディスクにアクセスする必要がなくなります。

key_buffer_size簡単なメモ、ウィリーニリーを増やさないでください。これは、メモリを必要とする MySQL の 1 つの領域にすぎません。メモリ使用量のバランスをとる必要がある他の可動部分があります。MySQL 接続はメモリを消費し、さまざまなテーブル エンジンはインデックスにさまざまなメモリ プールを使用し、MySQL はさまざまな目的で他のビットのメモリを使用します。設定がkey_buffer_size大きすぎるためにメモリが不足すると、サーバーがページングを開始したり (仮想メモリを使用すると、パフォーマンスがさらに低下します)、さらに悪いことにクラッシュする可能性があります。不明な場合は小さい値から始めて、メモリ使用量を確認し、パフォーマンスに満足でき、サーバーがクラッシュしなくなるまで値を増やしてください。

于 2011-05-18T23:21:52.747 に答える
0

どのような速度が得られますか? データをRedisに移動することを検討する必要があるリレーショナルなものは必要ないため、マシンで +100k の挿入または読み取り/秒を簡単に実行できるはずです。

于 2011-05-19T00:17:51.427 に答える