Frage

In MySQL 5.0.75-0ubuntu10.2 habe ich bekam einen festen Tisch Layout wie folgt aus:

Tabelle parent mit einer ID Tabelle parent2 mit einem id Tabelle children1 mit einem parentId

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

Ein Kind hat einen Elternteil in eines des Tisches Parent oder Parent2. Wenn ich ein Kinder bekommen müssen verwende ich eine Abfrage wie folgt aus:

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

Erklären diese Abfrage ergibt:

+----+--------------+------------+-------+---------------+---------+---------+------+------+-----------------------------------------------------+
| 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)

, die das Layout gegeben sinnvoll ist.

Nun das Problem: Die vorherige Abfrage ist etwas nutzlos, da es keine Spalten aus den übergeordneten Elemente zurückgibt. Im Moment füge ich mehr Spalten der inneren Abfrage wird kein Index mehr verwendet werden:

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)

Kann mir jemand erklären, warum die (primäre) Indizes nicht mehr verwendet werden? Gibt es eine Abhilfe für dieses Problem, wenn möglich, ohne das DB-Layout ändern zu müssen?

Danke!

War es hilfreich?

Lösung

Ich denke, dass das Optimierungsprogramm nach unten fällt, wenn Sie wegen der Möglichkeit, mehr Spalten in der abgeleiteten Abfrage starten ziehen, dass es müßte Datentypen auf der Vereinigung konvertieren (in diesem Fall nicht, aber im Allgemeinen). Es kann auch aufgrund der Tatsache, dass Ihre Abfrage im Wesentlichen eine korrelierte abgeleitet subquery sein will, was nicht möglich ist (von dev.mysql.com ):

  

Unterabfragen in der FROM-Klausel kann nicht korrelierte Unterabfragen werden, es sei denn, in der ON-Klausel einer JOIN-Operation verwendet wird.

Was Sie versuchen zu tun (aber ist nicht gültig) ist:

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

Gibt es einen Grund, warum Sie nicht zwei linke bevorzugen Joins und 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

Der einzige Unterschied zwischen den Abfragen ist, dass in Ihnen sehen Sie zwei Zeilen, wenn ein Elternteil in jeder Tabelle ist. Wenn das, was Sie wollen / müssen, dann wird dies auch gut arbeiten und schnell verbindet und immer Nutzung der Indizes machen:

(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)

Andere Tipps

Mein erster Gedanke ist es, eine „erhebliche“ Anzahl der Datensätze in den Tabellen einfügen und die Statistiken zu aktualisieren verwenden ANALYZE TABLE. Eine Tabelle mit 4 Datensätze wird immer schneller sein eher mit einem Scan lesen dann über den Index gehen! Darüber hinaus können Sie USE INDEX versuchen, die Nutzung des Index zu erzwingen, und schauen, wie der Plan ändert.

Ich werde empfehlen, auch diese Dokumentation zu lesen und sehen, welche Bits relevant sind MYSQL :: Optimizing Abfragen mit EXPLAIN

Dieser Artikel kann auch nützlich sein 7 Möglichkeiten, davon zu überzeugen, MySQL den richtigen Index verwenden

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top