문제

~ 안에 MySQL 5.0.75-0ubuntu10.2 그런 고정 테이블 레이아웃이 있습니다.

테이블 parent ID 테이블로 parent2 ID 테이블로 children1 부모와 함께

CREATE TABLE  `Parent` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(200) default NULL,
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB
CREATE TABLE  `Parent2` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(200) default NULL,
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB
CREATE TABLE  `Children1` (
  `id` int(11) NOT NULL auto_increment,
  `parentId` int(11) NOT NULL,
  PRIMARY KEY  (`id`),
  KEY `parent` (`parentId`)
) ENGINE=InnoDB

아이들은 테이블 중 하나에 부모가 있습니다. Parent 또는 Parent2. 아이들을 데려 가야 할 때 다음과 같은 쿼리를 사용합니다.

select * from Children1 c 
inner join (
select id as parentId from Parent
union 
select id as parentId from Parent2
) p on p.parentId = c.parentId

설명 이 쿼리는 다음과 같습니다.

+----+--------------+------------+-------+---------------+---------+---------+------+------+-----------------------------------------------------+
| id | select_type  | table      | type  | possible_keys | key     | key_len | ref  | rows | Extra                                               |
+----+--------------+------------+-------+---------------+---------+---------+------+------+-----------------------------------------------------+
|  1 | PRIMARY      | NULL       | NULL  | NULL          | NULL    | NULL    | NULL | NULL | Impossible WHERE noticed after reading const tables | 
|  2 | DERIVED      | Parent     | index | NULL          | PRIMARY | 4       | NULL |    1 | Using index                                         | 
|  3 | UNION        | Parent2    | index | NULL          | PRIMARY | 4       | NULL |    1 | Using index                                         | 
| NULL | UNION RESULT | <union2,3> | ALL   | NULL          | NULL    | NULL    | NULL | NULL |                                                     | 
+----+--------------+------------+-------+---------------+---------+---------+------+------+-----------------------------------------------------+
4 rows in set (0.00 sec)

레이아웃이 주어지면 합리적입니다.

이제 문제 : 이전 쿼리는 부모 요소에서 열을 반환하지 않기 때문에 다소 쓸모가 없습니다. 현재 내부 쿼리에 더 많은 열을 추가하면 더 이상 색인이 사용되지 않습니다.

mysql> explain select * from Children1 c  inner join ( select id as parentId,name from Parent union  select id as parentId,name from Parent2 ) p on p.parentId = c.parentId;
+----+--------------+------------+------+---------------+------+---------+------+------+-----------------------------------------------------+
| id | select_type  | table      | type | possible_keys | key  | key_len | ref  | rows | Extra                                               |
+----+--------------+------------+------+---------------+------+---------+------+------+-----------------------------------------------------+
|  1 | PRIMARY      | NULL       | NULL | NULL          | NULL | NULL    | NULL | NULL | Impossible WHERE noticed after reading const tables | 
|  2 | DERIVED      | Parent     | ALL  | NULL          | NULL | NULL    | NULL |    1 |                                                     | 
|  3 | UNION        | Parent2    | ALL  | NULL          | NULL | NULL    | NULL |    1 |                                                     | 
| NULL | UNION RESULT | <union2,3> | ALL  | NULL          | NULL | NULL    | NULL | NULL |                                                     | 
+----+--------------+------------+------+---------------+------+---------+------+------+-----------------------------------------------------+
4 rows in set (0.00 sec)

누구든지 (1 차) 지수가 더 이상 사용되지 않는 이유를 설명 할 수 있습니까? DB 레이아웃을 변경하지 않고 가능하면이 문제에 대한 해결 방법이 있습니까?

감사!

도움이 되었습니까?

해결책

나는 Union에서 데이터 유형을 변환해야 할 가능성 때문에 파생 쿼리에서 여러 열을 꺼내기 시작하면 최적화가 떨어지는 것으로 생각합니다 (이 경우가 아니라 일반적으로). 또한 귀하의 쿼리가 본질적으로 상관 관계가있는 파생 하위 쿼리가되기를 원하기 때문일 수 있습니다. dev.mysql.com):

From Clause의 하위 쿼리는 조인 조작 조항 내에서 사용되지 않는 한 하위 쿼리가 될 수 없습니다.

당신이하려는 일 (그러나 유효하지는 않지만)은 다음과 같습니다.

select * from Children1 c 
inner join (
select id as parentId from Parent where Parent.id = c.parentId
union 
select id as parentId from Parent2 where Parent.id = c.parentId
) p 

Result: "Unknown column 'c.parentId' in 'where clause'.

두 개의 왼쪽 조인과 ifnulls를 선호하지 않는 이유가 있습니까?

select *, IFNULL(p1.name, p2.name) AS name from Children1 c
left join Parent p1 ON p1.id = c.parentId
left join Parent2 p2 ON p2.id = c.parentId

쿼리의 유일한 차이점은 각 테이블에 부모가 있으면 두 행을 얻을 수 있다는 것입니다. 그것이 당신이 원하는/필요한 것이라면, 이것은 또한 잘 작동하고 결합은 빠르며 항상 색인을 사용합니다.

(select * from Children1 c join Parent p1 ON p1.id = c.parentId)
union
(select * from Children1 c join Parent2 p2 ON p2.id = c.parentId)

다른 팁

첫 번째 생각은 테이블에 "상당한"레코드를 삽입하고 분석 테이블을 사용하여 통계를 업데이트하는 것입니다. 4 개의 레코드가있는 테이블은 항상 인덱스를 통해 전체 스캔을 사용하여 읽는 것이 더 빠릅니다! 또한 색인을 사용하여 색인의 사용을 강요하고 계획이 어떻게 변하는 지 살펴볼 수 있습니다.

또한이 문서를 읽고 어떤 비트가 관련이 있는지 확인할 것입니다.mysql :: 설명을 통해 쿼리 최적화

이 기사도 유용 할 수 있습니다MySQL이 올바른 색인을 사용하도록 설득하는 7 가지 방법

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top