1

MySQL 5.0.75-0ubuntu10.2私はそのような固定テーブルレイアウトを持っています:

parentid を持つテーブル idを持つテーブルparentId を持つparent2テーブル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)

(PRIMARY) インデックスが使用されなくなった理由を説明できる人はいますか? 可能であれば、DB レイアウトを変更せずにこの問題を回避する方法はありますか?

ありがとう!

4

2 に答える 2

1

派生クエリで複数の列を引き出し始めると、オプティマイザーがダウンすると思います。これは、ユニオンでデータ型を変換する必要がある可能性があるためです (この場合ではなく、一般的に)。また、クエリが本質的に相関派生サブクエリになりたいという事実が原因である可能性もありますが、これは不可能です ( dev.mysql.comから):

JOIN 操作の ON 句内で使用されない限り、FR​​OM 句のサブクエリを相関サブクエリにすることはできません。

あなたがやろうとしていること(しかし有効ではありません)は次のとおりです。

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'.

2 つの左結合と IFNULL を好まない理由はありますか?

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

クエリ間の唯一の違いは、各テーブルに親がある場合、2 つの行を取得することです。それが必要な場合は、これもうまく機能し、結合は高速で、常にインデックスを利用します。

(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)
于 2009-12-16T09:33:42.340 に答える
0

私の最初の考えは、テーブルに「かなりの」数のレコードを挿入し、ANALYZETABLEを使用して統計を更新することです。4つのレコードを持つテーブルは、インデックスを経由するよりも、フルスキャンを使用すると常に読み取りが速くなります。さらに、USE INDEXを試して、インデックスの使用を強制し、プランがどのように変化するかを確認できます。

また、このドキュメントを読んで、関連するビットを確認することをお勧めします 。MYSQL::EXPLAINを使用したクエリの最適化

この記事は、MySQLに適切なインデックスを使用するように説得する7つの方法にも役立ち ます。

于 2009-10-22T08:59:29.513 に答える