2011-04-23 3 views
0

이 쿼리MySQL 전문가 : 왜 2 개의 쿼리가 서로 다른 '설명'인덱스 사용 결과를 제공합니까?

explain 
SELECT `Lineitem`.`id`, `Donation`.`id`, `Donation`.`order_line_id` 
    FROM `order_line` AS `Lineitem` 
     LEFT JOIN `donations` AS `Donation` 
     ON (`Donation`.`order_line_id` = `Lineitem`.`id`) 
WHERE `Lineitem`.`session_id` = '1' 

올바르게 EXPLAIN이에 도시 Donation.order_line_idLineitem.id 인덱스를 사용하여 출력 :

 
id select_type  table  type possible_keys key    key_len  ref   rows Extra 
1 SIMPLE   Lineitem ref  session_id  session_id  97   const  1  Using where; Using index 
1 SIMPLE   Donation ref  order_line_id order_line_id 4   Lineitem.id 2  Using index

그러나, 단순히 다른 필드를 포함하고이 질의 :

explain 
SELECT `Lineitem`.`id`, `Donation`.`id`, `Donation`.`npo_id`, 
     `Donation`.`order_line_id` 
    FROM `order_line` AS `Lineitem` 
     LEFT JOIN `donations` AS `Donation` 
     ON (`Donation`.`order_line_id` = `Lineitem`.`id`) 
WHERE `Lineitem`.`session_id` = '1' 

Donation 테이블에서 인덱스를 사용하지 않음을 보여줍니다.

 
id select_type  table  type possible_keys key    key_len  ref  rows Extra 
1 SIMPLE   Lineitem ref  session_id  session_id  97   const 1  Using where; Using index 
1 SIMPLE   Donation ALL  order_line_id NULL   NULL  NULL 3

표의 모든 _id 필드의 색인이 생성되지만이 필드를 선택한 필드 목록에 추가하면 색인이 삭제되는 이유를 알 수 없습니다.

CREATE TABLE `donations` (
`id` int(10) unsigned NOT NULL auto_increment, 
`npo_id` int(10) unsigned NOT NULL, 
`order_line_detail_id` int(10) unsigned NOT NULL default '0', 
`order_line_id` int(10) unsigned NOT NULL default '0', 
`created` datetime default NULL, 
`modified` datetime default NULL, 
PRIMARY KEY (`id`), 
KEY `npo_id` (`npo_id`), 
KEY `order_line_id` (`order_line_id`), 
KEY `order_line_detail_id` (`order_line_detail_id`) 
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8 

CREATE TABLE `order_line` (
`id` bigint(20) unsigned NOT NULL auto_increment, 
`order_id` bigint(20) NOT NULL, 
`npo_id` bigint(20) NOT NULL default '0', 
`session_id` varchar(32) collate utf8_unicode_ci default NULL, 
`created` datetime default NULL, 
PRIMARY KEY (`id`), 
KEY `order_id` (`order_id`), 
KEY `npo_id` (`npo_id`), 
KEY `session_id` (`session_id`) 
) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8 

가 나는 또한 일부는 기수에 대한 책을 읽은했고, 모두 Donations.npo_idDonations.order_line_id는 2의 카디널리티는 희망이 무엇인가를 알 수있을 것 같습니다 :

제임스 C의 요청에 따라, 여기에 테이블 정의는 유능한?

USE INDEX이 문제를 해결할 수 있다고 생각하지만, 약간 까다로울 수있는 ORM을 사용하고 있는데 왜 JOIN이 구체적으로 이름을 지정할 때 올바른 색인을 얻지 못하는지 이해하지 못합니다. 인덱싱 된 필드?!?

양해 해 주셔서 감사합니다.

답변

3

첫 번째 설명 끝에 "인덱스 사용"이 있습니다. 즉, 행 은 인덱스를보고 행 데이터를 가져 오거나 분석하지 않아도 쿼리 결과를 반환 할 수있었습니다.

두 번째 쿼리에서 인덱싱되지 않을 가능성이있는 행을 추가합니다. 이것은 MySQL이 테이블의 데이터를 봐야한다는 것을 의미한다. 왜 옵티마이 저가 테이블 스캔을 선택했는지 모르겠지만 테이블이 상당히 작 으면 개별 행의 세부 사항을 선택하는 것보다 모든 것을 읽는 것이 더 쉽다는 생각이들 것입니다.

편집 : 난 단지 조인 사용 인덱스의 모든 훨씬 더 일을 개선하게됩니다 다음 인덱스를 추가 생각 :

ALTER TABLE order_line ADD INDEX(session_id, id); 
ALTER TABLE donations ADD INDEX(order_line_id, npo_id, id) 

를이 다음 session_id 및 반환을 사용하여 행을 찾기 위해 order_line을 허용합니다 id 또한 donationsorder_line_id에 결합시킨 다음 다른 두 열을 반환 할 수 있습니다.

auto_increment 값을 보면 거기에 많은 데이터가 없다고 가정 할 수 있습니다. 테이블에있는 데이터의 양이 쿼리 계획에 영향을 미치고 테스트 데이터에 일부 샘플 데이터를 넣어 두는 것이 좋습니다. 좀 더 자세한 내용은이 블로그 포스트에서 좀 더 살펴 보도록하겠습니다. http://webmonkeyuk.wordpress.com/2010/09/27/what-makes-a-good-mysql-index-part-2-cardinality/

+0

실제로 이것은 100 % 올바르지 않을 수 있습니다. 당신은 테이블에 대한'SHOW CREATE TABLE'을 추가 할 수 있습니까? 그리고 전체'EXPLAIN' 출력을 주시겠습니까? –

+0

이유를 이해할 수는 없지만 두 번째 인덱스를 추가하면됩니다.이 3 개의 ID는 모두 색인 생성되었습니다. 왜 order_line_id 색인이 무시되는 경우 이러한 ID로 구성된 색인을 생성합니까? – iopener

+0

I think * 옵티마이 저가 단일 인덱스 사용에 이점이 없다고 판단했기 때문에 이러한 상황이 발생했습니다. 나는 테이블의 크기가 커짐에 따라 이것을 계속 지켜 볼 것입니다. 감사! – iopener

관련 문제