나는 테이블이 posts
이고 6.5M + 레코드입니다. 각 게시물은 고정 길이 name
을 사용하여 표시됩니다. MySQL 커뮤니티 5.7, SSD 디스크 (약 10K-20K IOPS 및 1GB 메모리, key-buffer-size
)를 512M으로 설정합니다 (BTW는 대부분 기본 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' 중 하나만 사용합니다. 그것은 인덱스를 사용하여'worker_id'에 의해 모든 행을 얻은 다음'last_processed_at'를 하나씩 비교하기 위해 모든 행을 거칩니다. 시간이 걸린다. 결합 된 인덱스'worker_id' +'last_processed_at'를 생성하면, MySQL은 결합 된 인덱스의 두 번째 부분을'last_processed_at'뿐만 아니라'worker_id'에 의해 필터링하기 위해 훨씬 더 빨라질 것입니다. Docs [MySQL 5.7 다중 컬럼 색인] (https://dev.mysql.com/doc/refman/5.7/en/multiple-column-indexes.html)을 참조하십시오. – Animir
감사합니다! 너는 많은 도움이된다. 나는'worker_id' +'last_processed_at' 두개의 컬럼에 인덱스를 생성했습니다. 이제 쿼리는 10ms를 넘지 않아도됩니다.360 배 빠릅니다. – yivo
@Animir 그래서 기본적으로 오래된 케이스에서 MySQL은'worker_id'에 인덱스를 사용하고 디스크에서'last_processed_at'를 읽어서 조건에서 사용합니다. 맞습니까? – yivo