Mysql EXPLAIN 을 사용 하여 SQL 문 구 를 분석 하고 최적화(계속)
21708 단어 EXPLAIN
[다 표 공동 조회 최적화]
explain SELECT sql_no_cache pker.*,pk.* FROM ng_game_pk AS pk ,ng_game_pker AS pker where pker.pkid = pk.id and (pker.act_uid = 1 OR pker.def_uid = 1) AND pk.type <>4 GROUP BY pk.id limit 10;
+----+-------------+-------+--------+----------------------------------+---------+---------+--------------------+--------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+----------------------------------+---------+---------+--------------------+--------+----------------------------------------------+
| 1 | SIMPLE | pker | ALL | pkid,act_def | NULL | NULL | NULL | 177543 | Using where; Using temporary; Using filesort |
| 1 | SIMPLE | pk | eq_ref | PRIMARY,type,idx_type_status_uid | PRIMARY | 4 | pwgbk8.7.pker.pkid | 1 | Using where |
+----+-------------+-------+--------+----------------------------------+---------+---------+--------------------+--------+----------------------------------------------+
key:NULL,,,Extra:Using temporary,Using filesort 는 문장 이 느 립 니 다.type:모든 시계 스 캔,이보다 더 나 쁜 것 은 없습니다.
다음 변경 사항:
explain SELECT sql_no_cache pker.*,pk.* FROM ng_game_pk AS pk ,ng_game_pker AS pker where pker.pkid = pk.id and (pker.act_uid = 1 OR pker.def_uid = 1) AND pk.type <>4 GROUP BY pker.pkid limit 10;
+----+-------------+-------+--------+----------------------------------+---------+---------+--------------------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+----------------------------------+---------+---------+--------------------+------+-------------+
| 1 | SIMPLE | pker | index | pkid,act_def | pkid | 4 | NULL | 10 | Using where |
| 1 | SIMPLE | pk | eq_ref | PRIMARY,type,idx_type_status_uid | PRIMARY | 4 | pwgbk8.7.pker.pkid | 1 | Using where |
+----+-------------+-------+--------+----------------------------------+---------+---------+--------------------+------+-------------+
비교 하여 실행:
mysql> show profile for query 147;
+----------------------+----------+
| Status | Duration |
+----------------------+----------+
| Creating tmp table | 0.000372 |
| Copying to tmp table | 0.424248 |
| removing tmp table | 0.002125 |
+----------------------+----------+
여 기 는 다른 집행 을 소홀히 했다.임시 시계 로 복사 하 는 것 을 보 는 데 대부분의 시간 이 걸 렸 다.설명 이 필요 합 니 다.Copying to tmp table 은 메모리 에 복사 되 어 있 습 니 다.Copying to tmp table on disk 라면 메모리 공간 이 부족 하 다 는 것 을 의미 합 니 다.MySQL 은 디스크 에 임시 표를 쓸 것 입 니 다.이 크기 의 설정 은 tmp 참조table_size。
현재 두 번 째 SQL 을 분석 하면,자구 id 가 같 습 니 다.그러면 실행 순 서 는 위 에서 아래로,현재 pker 표를 조회 하고 색인 은 pkid 입 니 다.그러면 GROUP BY pker.pkid 가 위의 자구 에 작용 하고 rows 가 10 이 라면 limit 10 도 여기에 작용 한다 고 볼 수 있 습 니 다.
[색인 최적화,복합 색인]
mysql> select count(*) from ng_game_pk WHERE status = 0 AND type = 4 AND uid = 1;
+----------+
| count(*) |
+----------+
| 0 |
+----------+
1 row in set (13.03 sec)
mysql> explain select count(*) from ng_game_pk WHERE status = 0 AND type = 4 AND uid = 1;
+----+-------------+------------+------+---------------+------+---------+-------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+------+---------+-------+---------+-------------+
| 1 | SIMPLE | ng_game_pk | ref | type | type | 1 | const | 1729551 | Using where |
+----+-------------+------------+------+---------------+------+---------+-------+---------+-------------
이 문 구 는 색인 type 을 사 용 했 지만 type 의 수치 범위 가 매우 좁다(1,2,3,4)사실 이 색인 은 그다지 쓸모 가 없다.다음은 우리 가 복합 색인 을 만들어 서 효과 가 어떤 지,
mysql> alter table ng_game_pk add index idx_type_status_uid(type,status,uid);
Query OK, 5831851 rows affected (1 min 43.20 sec)
Records: 5831851 Duplicates: 0 Warnings: 0
mysql> explain select count(*) from ng_game_pk WHERE status = 0 AND type = 4 AND uid = 1;
+----+-------------+------------+------+--------------------------+---------------------+---------+-------------------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+--------------------------+---------------------+---------+-------------------+------+-------------+
| 1 | SIMPLE | ng_game_pk | ref | type,idx_type_status_uid | idx_type_status_uid | 6 | const,const,const | 1 | Using index |
+----+-------------+------------+------+--------------------------+---------------------+---------+-------------------+------+-------------+
1 row in set (0.11 sec)
mysql> select count(*) from ng_game_pk WHERE status = 0 AND type = 4 AND uid = 1;
+----------+
| count(*) |
+----------+
| 0 |
+----------+
1 row in set (0.00 sec)
효과 가 좋 은 것 같 습 니 다.SQL 을 조금 수정 하면,
mysql> select sql_no_cache count(*) from ng_game_pk WHERE type = 4 and status>0 AND uid = 1;
+----------+
| count(*) |
+----------+
| 2649 |
+----------+
1 row in set (0.40 sec)
성능 이 또 떨 어 졌 습 니 다.이것 은 B-Tree 알고리즘 때 문 입 니 다.저장 엔진 은 첫 번 째 조건 범위 오른쪽 에 있 는 열 을 최적화 할 수 없습니다.그러면(type,status,,)뒤의 색인 이 효력 을 잃 습 니 다.
그럼 조정 해 봐..
mysql> drop index idx_type_status_uid on ng_game_pk;
mysql> alter table ng_game_pk add index idx_type_uid_status (type,uid,status);
결국 성능 이 또 향상 되 었 다.
---------------------------EOF--------------------------------
참고:
#'고성능 MySql(제2판)'
#고성능 웹 사이트 구축
# http://www.cnitblog.com/aliyiyi08/archive/2008/09/09/48878.html
# http://www.perfgeeks.com/?p=460