2017-11-05 1 views
0

나는 테이블이 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 | 
+----+-------------+-------+------------+------+-----------------------------+-----------+---------+-------+--------+----------+-------------+ 

당신이 그것을 최적화 할 수있는 방법 어떤 아이디어가 있습니까?

답변

3

worker_id 키를 대체하여 worker_idlast_processed_at의 조합 키를 만들 수 있습니다. 당신이 공간 비좁은 경우

+1

일부 세부 사항 : 현재, 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

+0

감사합니다! 너는 많은 도움이된다. 나는'worker_id' +'last_processed_at' 두개의 컬럼에 인덱스를 생성했습니다. 이제 쿼리는 10ms를 넘지 않아도됩니다.360 배 빠릅니다. – yivo

+0

@Animir 그래서 기본적으로 오래된 케이스에서 MySQL은'worker_id'에 인덱스를 사용하고 디스크에서'last_processed_at'를 읽어서 조건에서 사용합니다. 맞습니까? – yivo

0

:

  • CHAR(30) 변수 길이는 names 가능성이 당신의 .MYD 파일의 50 %가 ASCII 또는 latin1에 경우 필요 이상 큰, 또는 필요에 따라 3 로 큰한다 if utf8.
  • 모든 열을 맹목적으로 색인하지 마십시오. .MYI 파일의 공간을 낭비합니다. 특히 INDEX(processing_priority)은 절대로 사용되지 않습니다.

SHOW CREATE TABLE 및 공간에 대한 설정을 자세히 검토하기위한 몇 가지 쿼리를 보겠습니다.

RAM이 1GB이고 512MB가 key_buffer 인 것은 정말 나쁩니다. 첫째, key_buffer는 인덱스 블록 (각각 1KB)을 캐싱하기위한 것입니다. 둘째, 운영 체제가 수행하는 데이터 캐싱 공간이 필요합니다. 셋째, 코드 및 기타 데이터를위한 공간이 필요합니다. key_buffer_size = 50M 이상을 권장하지 않습니다.

(실제 질문에 대해서는 @Turo가 탁월한 답을 제공합니다.)하지만 지금 중복 된 INDEX(worker_id)을 제거 했습니까? (즉 70메가바이트에 대해 저장됩니다.)

더 많은 인덱스 생성에 : http://mysql.rjweb.org/doc.php/index_cookbook_mysql