2013-01-19 7 views
1

MySQL 문서에 따르면 가장 왼쪽 필드가 조건의 일부인 경우 복합 인덱스가 계속 사용됩니다. 그러나이 테이블은 기본 키와 올바르게 결합하지 않습니다. 그 다음에 사용되는 왼쪽 두 필드의 다른 색인을 추가해야했습니다.복합 인덱스가 MySQL에서 사용되지 않음

테이블 중 하나는 메모리이며 기본적으로 메모리는 그룹/주문에 사용할 수없는 해시 인덱스를 사용한다는 것을 알고 있습니다. 그러나 나는 메모리 테이블의 모든 행과 색인을 사용하지 않으므로 문제와 관련이 있다고 생각하지 않습니다.

무엇이 누락 되었습니까?

mysql> show create table pr_temp; 
| pr_temp | CREATE TEMPORARY TABLE `pr_temp` (
`player_id` int(10) unsigned NOT NULL, 
`insert_date` date NOT NULL, 
[...] 
PRIMARY KEY (`player_id`,`insert_date`) USING BTREE, 
KEY `insert_date` (`insert_date`) 
) ENGINE=MEMORY DEFAULT CHARSET=utf8 | 

mysql> show create table player_game_record; 
| player_tank_record | CREATE TABLE `player_game_record` (
`player_id` int(10) unsigned NOT NULL, 
`game_id` smallint(5) unsigned NOT NULL, 
`insert_date` date NOT NULL, 
[...] 
PRIMARY KEY (`player_id`,`insert_date`,`game_id`), 
KEY `insert_date` (`insert_date`), 
KEY `player_date` (`player_id`,`insert_date`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8 DATA DIRECTORY='...' INDEX DIRECTORY='...' | 

mysql> explain select pgr.* from player_game_record pgr inner join pr_temp on pgr.player_id = pr_temp.player_id and pgr.insert_date = pr_temp.date_prev;      
+----+-------------+---------+------+---------------------------------+-------------+---------+-------------------------------------------------------------------------+--------+-------+ 
| id | select_type | table | type | possible_keys     | key   | key_len | ref                  | rows  | Extra | 
+----+-------------+---------+------+---------------------------------+-------------+---------+-------------------------------------------------------------------------+--------+-------+ 
| 1 | SIMPLE  | pr_temp | ALL | PRIMARY       | NULL  | NULL | NULL                 | 174683 |  | 
| 1 | SIMPLE  | pgr  | ref | PRIMARY,insert_date,player_date | player_date | 7  | test_gamedb.pr_temp.player_id,test_gamedb.pr_temp.date_prev |  21 |  | 
+----+-------------+---------+------+---------------------------------+-------------+---------+-------------------------------------------------------------------------+--------+-------+ 
2 rows in set (0.00 sec) 

mysql> explain select pgr.* from player_game_record pgr force index (primary) inner join pr_temp on pgr.player_id = pr_temp.player_id and pgr.insert_date = pr_temp.date_prev; 
+----+-------------+---------+------+---------------+---------+---------+-------------------------------------------------------------------------+---------+-------+ 
| id | select_type | table | type | possible_keys | key  | key_len | ref                  | rows | Extra | 
+----+-------------+---------+------+---------------+---------+---------+-------------------------------------------------------------------------+---------+-------+ 
| 1 | SIMPLE  | pr_temp | ALL | PRIMARY  | NULL | NULL | NULL                 | 174683 |  | 
| 1 | SIMPLE  | pgr  | ref | PRIMARY  | PRIMARY | 7  | test_gamedb.pr_temp.player_id,test_gamedb.pr_temp.date_prev | 2873031 |  | 
+----+-------------+---------+------+---------------+---------+---------+-------------------------------------------------------------------------+---------+-------+ 
2 rows in set (0.00 sec) 

두 개의 왼쪽 열 (player_id, insert_date)이 사용되는 기본 키가 작동해야한다고 생각합니다. 그러나 기본적으로 player_date 인덱스를 사용합니다. 기본 인덱스를 사용하도록 강제하는 경우 두 인덱스가 아닌 한 필드 만 사용하는 것처럼 보입니다.

갱신 2 : MySQL의 버전 5.5.27 - 로그 갱신 3 : 는

mysql> show indexes in player_game_record; 
+--------------------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| Table    | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | 
+--------------------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| player_game_record |   0 | PRIMARY  |   1 | player_id | A   |  NULL |  NULL | NULL |  | BTREE  |   |    | 
| player_game_record |   0 | PRIMARY  |   2 | insert_date | A   |  NULL |  NULL | NULL |  | BTREE  |   |    | 
| player_game_record |   0 | PRIMARY  |   3 | game_id  | A   | 576276246 |  NULL | NULL |  | BTREE  |   |    | 
| player_game_record |   1 | insert_date |   1 | insert_date | A   |  33304 |  NULL | NULL |  | BTREE  |   |    | 
+--------------------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
4 rows in set (1.08 sec) 


mysql> select count(*) from player_game_record; 
+-----------+ 
| count(*) | 
+-----------+ 
| 576276246 | 
+-----------+ 
1 row in set (0.00 sec) 
+0

무엇을 의미 "기본 키에 제대로 참여하지 않을 것이다"는 무엇입니까? 결과가 잘못되었거나'EXPLAIN SELECT'가'pgr'에서 기본 키를 사용하지 않는다는 것을 의미합니까?기본 키만 사용할 수있을 때 의심스러운 잘못된 동작을 설명하기 위해 새 인덱스를 제거하고 또 다른'EXPLAIN SELECT '를 게시 할 수 있습니까? –

+0

나는 그것이 작동해야하는 인덱스를 사용하도록 강요한다면 분명히 explain (player_date 인덱스와 비교하여 볼 수있는 pgr 테이블의 행이 너무 많음)을 기반으로하지 않는다는 것을 의미합니다. 인덱스를 사용하지 않으며 쿼리가 너무 오래 걸립니다. player_date 인덱스를 제거하면 대신 insert_date가 선택되며, 인덱스를 생성하는 데 12 시간 이상이 소요되므로 제거하지 않을 것입니다. – Josh

답변

1

가 동의 (이것은 다른 테스트를 시도하면서 player_date 인덱스를 제거한 후입니다주의) 그 MEMORY 스토리지 엔진의 사용을위한 우리가 다른 테이블에 대해 말하고 있기 때문에 테이블 중 하나가 전혀 문제가되어서는 안됩니다.

또한 색인의 가장 왼쪽 접두어를 정확하게 사용하는 방법에 동의 할 수 있으며 기본 키를 다른 색인과 완전히 똑같이 사용할 수없는 이유를 생각할 수 없습니다. .

이것은 머리를 깎는 사람입니다. 생성 한 새 색인은 기본 키의 왼쪽과 같아야합니다. 그러면 같은 방식으로 작동하지 않는 이유는 무엇입니까? 나는 두 가지 생각을 가지고 있습니다. InnoDB를 사용하면서 MyISAM의 내부에 친숙하지는 않지만 동일한 권장 사항으로 안내합니다. (제쳐두고 MyISAM을 통해 InnoDB를 권하고 싶습니다.)

데이터를 삽입하기 시작했을 때 기본 키의 인덱스는 아마도 테이블에 있었고 새 인덱스는 추가되었지만 대부분의 데이터는 이미 그곳에. 이는 새 색인이 좋고 내부적으로 체계적으로 구성되어있는 반면 기본 키 색인은 데이터가로드 될 때 작성된 상태로 세분화되어있을 수 있음을 나타냅니다.

옵티마이 저가 표시하는 행 계수는 인덱스 통계를 기반으로하며 삽입 순서로 인해 기본 키가 부정확 할 수 있습니다.

조각화 이론은 기본 키를 인덱스로 쿼리하는 것이 왜 그렇게 빠르지 않은지 설명 할 수 있습니다. 인덱스 통계 이론은 왜 옵티마이 저가 다른 행 수인 을 가져 오는지 설명 할 수 있습니다. 왜 옵티마이 저가 인덱스를 사용하는 대신 전체 테이블 스캔을 선택했는지 설명 할 수 있습니다 (추측 일뿐입니다. 사용 가능한 설명이 없습니다).

이 두 가지 생각을 바탕으로 제안하는 것은 테이블에 OPTIMIZE TABLE을 실행 중입니다. 새 색인을 작성하는 데 12 시간이 걸리면 optimizing the table에 오래 걸릴 수도 있습니다.

아마 도움 : http://www.dbasquare.com/2012/07/09/data-fragmentation-problem-in-mysql-myisam/

+0

고마워, 나는 완전히 미치지 않다는 것을 알기 좋다. 올바르게 이해했다면 조각화로 인해 색인이 비효율적 일 수 있다고 생각하지만 모든 필드에서 동일한 색인을 문제없이 사용하고 있습니다. 저는 인덱스를 강제 할 때 오직 하나의 필드만을 사용한다는 것을 100 % 확신합니다. 나는 최근에 테이블을 수리했는데, 다시 빌드/최적화와 똑같은가? 다른 이유로 나는 인덱스 (player_id, game_id)를 필요로 할 수 있으므로 주문을 교환하고 완료했다고 할 수 있습니다.하지만 실제로 어떤 일이 일어나고 있는지 알고 싶습니다. – Josh

+0

MySQL 서버의 정식 버전 번호는 무엇입니까? 또한, 테이블을 복구하고 최적화/분석은 비슷하지만 완전히 동일하지는 않다고 말하면 ... MyISAM은 여러 수준의 "복구"기능을 제공합니다. InnoDB를 사용하지 않는 이유가 있습니까? –

+0

버전 5.5.27-log (원본에 추가). 나는 초기 테스트 동안 InnoDB를 사용하여 앞뒤로 갔다.하지만 디스크를 3 배 정도 사용했기 때문에 성장 속도를 알 수 없었다. 이것은 거의 전적으로 읽기 데이터베이스입니다 (하루에 일괄 업데이트, 나머지는 모두 읽음). 배치는 꽤 느립니다 (DB로 인한 것이 아닌 7-8 시간). InnoDB의 이점은이 경우에는 매력적이지 않습니다. – Josh