2017-11-05 16 views
0

私はテーブルpostsと6.5M +レコードを持っています。各投稿は固定長のnameで表されます。私はMySQL Community 5.7、約10K-20KのIOPSと1GBのメモリを持つSSDディスク、key-buffer-sizeを512Mに設定しています(ほとんどの場合、私はデフォルトのMySQL設定でドライブします)。私は限られたリソースしか持っていないので、MyISAMをストレージエンジンとして選択しました。私のベンチマークではMyISAMの方が速いことがわかりました。また、私はそれを更新することができるので、あまりデータを気にしません。日時範囲で選択してください。

だから、ここに私スキームの情報です:

+------------+--------+------------+ 
| TABLE_NAME | ENGINE | row_format | 
+------------+--------+------------+ 
| posts  | MyISAM | Fixed  | 
+------------+--------+------------+ 

+---------------------+---------------------+------+-----+---------+----------------+ 
| Field    | Type    | Null | Key | Default | Extra   | 
+---------------------+---------------------+------+-----+---------+----------------+ 
| id     | int(11) unsigned | NO | PRI | NULL | auto_increment | 
| name    | char(30)   | NO | UNI | NULL |    | 
| worker_id   | tinyint(4) unsigned | NO | MUL | NULL |    | 
| processing_priority | tinyint(4) unsigned | NO | MUL | 0  |    | 
| last_processed_at | datetime   | YES | MUL | NULL |    | 
| scraped_at   | datetime   | NO | MUL | NULL |    | 
+---------------------+---------------------+------+-----+---------+----------------+ 

+-------+------------+---------------------+--------------+---------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| Table | Non_unique | Key_name   | Seq_in_index | Column_name   | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | 
+-------+------------+---------------------+--------------+---------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| posts |   0 | PRIMARY    |   1 | id     | A   |  6579588 |  NULL | NULL |  | BTREE  |   |    | 
| posts |   0 | name    |   1 | name    | A   |  6579588 |  NULL | NULL |  | BTREE  |   |    | 
| posts |   1 | last_processed_at |   1 | last_processed_at | A   |  6579588 |  NULL | NULL | YES | BTREE  |   |    | 
| posts |   1 | processing_priority |   1 | processing_priority | A   |   3 |  NULL | NULL |  | BTREE  |   |    | 
| posts |   1 | worker_id   |   1 | worker_id   | A   |   50 |  NULL | NULL |  | BTREE  |   |    | 
| posts |   1 | scraped_at   |   1 | scraped_at   | A   |  234985 |  NULL | NULL |  | BTREE  |   |    | 
+-------+------------+---------------------+--------------+---------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 

は、私が実行したクエリ:

SELECT COUNT(*) FROM `posts` WHERE `posts`.`worker_id` = 1 AND (last_processed_at >= '2017-11-04 22:20:27.203761') 

MySQLは、このクエリを実行する3676.4msを必要とします。

クエリは次のように説明し

+----+-------------+-------+------------+------+-----------------------------+-----------+---------+-------+--------+----------+-------------+ 
| id | select_type | table | partitions | type | possible_keys    | key  | key_len | ref | rows | filtered | Extra  | 
+----+-------------+-------+------------+------+-----------------------------+-----------+---------+-------+--------+----------+-------------+ 
| 1 | SIMPLE  | posts | NULL  | ref | last_processed_at,worker_id | worker_id | 1  | const | 232621 | 37.45 | Using where | 
+----+-------------+-------+------------+------+-----------------------------+-----------+---------+-------+--------+----------+-------------+ 

はあなたがそれを最適化することができますどのように任意のアイデアを持っていますか?

答えて

3

worker_idキーの代わりに、worker_idlast_processed_atの組み合わせキーを作成できます。

+1

いくつかの詳細は:現在、MySQLはテーブルの 'posts'上の' 'last_processed_at'とworker_id'の一つだけ使用しています。 indexを使用して 'worker_id'によってすべての行を取得し、これらの行をすべて調べて' last_processed_at'を1つずつ比較します。時間がかかる。結合インデックス 'worker_id' +' last_processed_at'を作成した場合、MySQLは結合インデックスの2番目の部分を 'last_processed_at'と' worker_id'でフィルタリングするため、ずっと速くなります。 Docs [MySQL 5.7複数列インデックス](https://dev.mysql.com/doc/refman/5.7/en/multiple-column-indexes.html)を参照してください – Animir

+0

ありがとうございます!あなたは多くの助けをしています。私は2つのカラム 'worker_id' +' last_processed_at'にインデックスを作成しました。クエリは10ミリ秒以下必要です。それは360倍高速です。 – yivo

+0

@Animirだから、古いケースでは、MySQLは 'worker_id'にインデックスを使用し、次に' last_processed_at'をディスクから読み出して条件に使用します。 – yivo

0

あなたはスペースのために窮屈されている場合は、次の可変長namesため

  • CHAR(30)は、おそらくそれは、必要に応じてASCIIまたはLATIN1、または3 として大きな場合は必要以上に50%より大きく、あなたの.MYDファイルを作りますutf8の場合。
  • すべての列に盲目的にインデックスを作成しないでください。それは.MYIファイル内のスペースを無駄にします。特に、INDEX(processing_priority)はおそらく使用されません。

SHOW CREATE TABLEと、スペースの設定をさらに批判するクエリのいくつかを見てみましょう。

1GBのRAMと512MBの場合は、key_bufferが本当に悪いです。まず、key_bufferはインデックスブロック(それぞれ1KB)をキャッシュするためだけです。第二に、OSにはデータをキャッシュする余地が必要です。第三に、コードやその他のデータのためのスペースが必要です。 key_buffer_size = 50M以下を推奨します。

(あなたの実際の質問については、@Turoが優れた答えを示しています)しかし、現在は冗長なINDEX(worker_id)を削除しましたか? (これは70メガバイト程度保存されます。)

よりインデックス作成に:http://mysql.rjweb.org/doc.php/index_cookbook_mysql

関連する問題