私はテーブル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 |
+----+-------------+-------+------------+------+-----------------------------+-----------+---------+-------+--------+----------+-------------+
はあなたがそれを最適化することができますどのように任意のアイデアを持っていますか?
いくつかの詳細は:現在、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
ありがとうございます!あなたは多くの助けをしています。私は2つのカラム 'worker_id' +' last_processed_at'にインデックスを作成しました。クエリは10ミリ秒以下必要です。それは360倍高速です。 – yivo
@Animirだから、古いケースでは、MySQLは 'worker_id'にインデックスを使用し、次に' last_processed_at'をディスクから読み出して条件に使用します。 – yivo