2017-09-27 3 views
0

지난 주에 나는 추가 데이터베이스 모니터링을 설치 했으므로 데이터베이스의 전체 30 %에 대해이 하나의 테이블 (현재 약 600 만 개의 행이 있음)에서 단일 쿼리에 소비되었음을 알게되었습니다.) :에서 mdl_grade_items_history를 최적화하십시오.

이 쿼리에 EXPLAIN 실행

이 조회가 실행될 때마다, 전체 테이블 스캔이 완료되었음을 나타냅니다 :

테스트 환경에서
delete FROM mdl_grade_items_history WHERE timemodified < ? 

, 나는 몇 가지 스키마 변경을 시도했다. A (매우 유사) SELECT 쿼리에 대한 EXPLAIN 확인

EXPLAIN DELETE FROM mdl_grade_items_history WHERE timemodified < '1490528405'; 
+----+-------------+-------------------------+------------+------+---------------+------+---------+------+--------+----------+-------------+ 
| id | select_type | table     | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra  | 
+----+-------------+-------------------------+------------+------+---------------+------+---------+------+--------+----------+-------------+ 
| 1 | DELETE  | mdl_grade_items_history | NULL  | ALL | NULL   | NULL | NULL | NULL | 140784 | 100.00 | Using where | 
+----+-------------+-------------------------+------------+------+---------------+------+---------+------+--------+----------+-------------+ 
1 row in set (0.00 sec) 

는 비슷한 상황을 보여줍니다. 그래서

CREATE INDEX `mdl_gradeitemhist_tim_ix` ON `mdl_grade_items_history` (`timemodified`); 
ALTER TABLE `mdl_grade_items_history` ADD INDEX `mdl_gradeitemhist_tim_ix` (`timemodified`); 

에서 (모두 CREATE INDEX를 통해 및 ALTER TABLE .. ADD INDEX) 하나를 추가하려고 테이블 정의를 확인

EXPLAIN SELECT id FROM mdl_grade_items_history WHERE timemodified < '1490528405'; 
+----+-------------+-------------------------+------------+------+---------------+------+---------+------+--------+----------+-------------+ 
| id | select_type | table     | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra  | 
+----+-------------+-------------------------+------------+------+---------------+------+---------+------+--------+----------+-------------+ 
| 1 | SIMPLE  | mdl_grade_items_history | NULL  | ALL | NULL   | NULL | NULL | NULL | 140784 | 33.33 | Using where | 
+----+-------------+-------------------------+------------+------+---------------+------+---------+------+--------+----------+-------------+ 
1 row in set, 1 warning (0.01 sec) 

, timemodified

SHOW INDEX FROM mdl_grade_items_history; 
+-------------------------+------------+-------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| Table     | Non_unique | Key_name    | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | 
+-------------------------+------------+-------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| mdl_grade_items_history |   0 | PRIMARY     |   1 | id   | A   |  140784 |  NULL | NULL |  | BTREE  |   |    | 
| mdl_grade_items_history |   1 | mdl_graditemhist_act_ix |   1 | action  | A   |   2 |  NULL | NULL |  | BTREE  |   |    | 
| mdl_grade_items_history |   1 | mdl_graditemhist_old_ix |   1 | oldid  | A   |  17170 |  NULL | NULL |  | BTREE  |   |    | 
| mdl_grade_items_history |   1 | mdl_graditemhist_cou_ix |   1 | courseid | A   |  1065 |  NULL | NULL | YES | BTREE  |   |    | 
| mdl_grade_items_history |   1 | mdl_graditemhist_cat_ix |   1 | categoryid | A   |  2300 |  NULL | NULL | YES | BTREE  |   |    | 
| mdl_grade_items_history |   1 | mdl_graditemhist_sca_ix |   1 | scaleid  | A   |   6 |  NULL | NULL | YES | BTREE  |   |    | 
| mdl_grade_items_history |   1 | mdl_graditemhist_out_ix |   1 | outcomeid | A   |   1 |  NULL | NULL | YES | BTREE  |   |    | 
| mdl_grade_items_history |   1 | mdl_graditemhist_log_ix |   1 | loggeduser | A   |   30 |  NULL | NULL | YES | BTREE  |   |    | 
+-------------------------+------------+-------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
8 rows in set (0.00 sec) 

에 인덱스가있을 것 같지 않습니다 두 인스턴스 모두에서 SELECT 쿼리가 영향을 받음 (type의 변경 참고)

EXPLAIN `SELECT` id FROM mdl_grade_items_history WHERE timemodified < '1490528405'; 
+----+-------------+-------------------------+------------+-------+--------------------------+--------------------------+---------+------+-------+----------+--------------------------+ 
| id | select_type | table     | partitions | type | possible_keys   | key      | key_len | ref | rows | filtered | Extra     | 
+----+-------------+-------------------------+------------+-------+--------------------------+--------------------------+---------+------+-------+----------+--------------------------+ 
| 1 | SIMPLE  | mdl_grade_items_history | NULL  | range | mdl_gradeitemhist_tim_ix | mdl_gradeitemhist_tim_ix | 9  | NULL | 70206 | 100.00 | Using where; Using index | 
+----+-------------+-------------------------+------------+-------+--------------------------+--------------------------+---------+------+-------+----------+--------------------------+ 
1 row in set, 1 warning (0.00 sec) 

그러나 DELETE 쿼리는 아닙니다.

EXPLAIN DELETE FROM mdl_grade_items_history WHERE timemodified < '1490528405'; 
+----+-------------+-------------------------+------------+------+--------------------------+------+---------+------+--------+----------+-------------+ 
| id | select_type | table     | partitions | type | possible_keys   | key | key_len | ref | rows | filtered | Extra  | 
+----+-------------+-------------------------+------------+------+--------------------------+------+---------+------+--------+----------+-------------+ 
| 1 | DELETE  | mdl_grade_items_history | NULL  | ALL | mdl_gradeitemhist_tim_ix | NULL | NULL | NULL | 140412 | 100.00 | Using where | 
+----+-------------+-------------------------+------------+------+--------------------------+------+---------+------+--------+----------+-------------+ 
1 row in set (0.00 sec) 

내가 잘못 했습니까? 그 밖의 무엇을 시도 할 수 있습니까?

+0

이 지수는 더욱 때문에 인덱스를 변경하는 원인이 삭제 아래로 삭제 느리게하지 않을까요? 대형 테이블과 다른 대형 테이블간에 외래 키 관계가 있습니까? 그 (것)들은 또한 큰 삭제를 또한 감속 할 수 있고 그 (것)들을 경우에 제거하고 그들을 재창조하기 위하여 일할지도 모르다는 것을 믿는다. 또는 루프를 사용하여 한 번에 여러 개의 레코드를 "일괄 처리"하여 삭제할 수 있습니까? – Nope

+0

@Fran 제 지식에는 외래 키가 없습니다. 일괄 적으로 DELETE로 쿼리를 변경하는 것은 확실히 테이블에 있습니다. –

답변

1
  • 낮은 카디널리티 색인 (action, scaleid, outcomeid)은 거의 사용되지 않습니다. 그들을 제거.
  • 많은 수의 단일 열 인덱스가있는 것이 빨간색 플래그입니다. "복합"지수의 장점과 이점에 대해 알아보십시오. (여기에 언급 된 선택/삭제와 관련이 없지만 다른 쿼리와 관련이있을 수 있음)
  • 인덱스가 추가로 업데이트되어야하므로 테이블의 여분의 인덱스가 INSERTsDELETEs으로 약간 느려집니다.
  • 인덱싱 된 열이 수정되면 추가 인덱스가 UPDATEs이됩니다.
  • CREATE INDEXALTER TABLE ADD INDEX은 동일한 작업을 수행합니다. 이제 중복 색인이 생겼을 것입니다.
  • EXPLAINs은 (1) SELECTDELETE이 다른 것을 수행하고 (2) EXPLAIN이별로 복잡하지 않기 때문에 다릅니다.
  • 많은 수의 행을 삭제하는 데 많은 노력이 필요합니다. 삭제 된 행은 ROLLBACK 일 때 중지됩니다. COMMIT 이후에만 행을 제거 할 수 있습니다. (autocommit=ON은 암시적인 COMMIT입니다.) 대형 삭제에

팁 :