Frage

Ich bin ein seltsames Verhalten von MySQL zu stoßen. Query-Ausführung (das heißt die Verwendung von Indizes, wie erklären [QUERY] gezeigt) zur Ausführung und Zeitaufwand sind abhängig von den Elementen der where-Klausel.

Hier ist eine Abfrage, wo das Problem auftritt:

select distinct
e1.idx, el1.idx, r1.fk_cat, r2.fk_cat
from ent e1, ent_leng el1, rel_c r1, _tax_c t1, rel_c r2, _tax_c t2
where el1.fk_ent=e1.idx
and r1.fk_ent=e1.idx and ((r1.fk_cat=43) or (r1.fk_cat=t1.fk_cat1 and t1.fk_cat2=43))
and r2.fk_ent=e1.idx and ((r2.fk_cat=10) or (r2.fk_cat=t2.fk_cat1 and t2.fk_cat2=10))

Der entsprechende Ausgang erklären ist:

| id | select_type | table | type   | possible_keys           | key     | key_len | ref           | rows  | Extra                       
+----+-------------+-------+--------+-------------------------+---------+---------+---------------+-------+------------------------------------
|  1 | SIMPLE      | el1   | index  | fk_ent                  | fk_ent  | 4       | NULL          | 15002 | Using index; Using temporary
|  1 | SIMPLE      | e1    | eq_ref | PRIMARY                 | PRIMARY | 4       | DB.el1.fk_ent |     1 | Using index
|  1 | SIMPLE      | r1    | ref    | fk_ent,fk_cat,fks       | fks     | 4       | DB.e1.idx     |     1 | Using where; Using index
|  1 | SIMPLE      | r2    | ref    | fk_ent,fk_cat,fks       | fks     | 4       | DB.el1.fk_ent |     1 | Using index
|  1 | SIMPLE      | t1    | index  | fk_cat1,fk_cat2,fk_cats | fk_cats | 8       | NULL          |    69 | Using where; Using index; Distinct; 
|    |             |       |        |                         |         |         |               |       | Using join buffer
|  1 | SIMPLE      | t2    | index  | fk_cat1,fk_cat2,fk_cats | fk_cats | 8       | NULL          |    69 | Using where; Using index; Distinct;  
                                                                                                          | Using join buffer

Wie Sie ein Ein-Spalten-Index die gleichen Namen wie der Spalt sehen sie gehört hat. Ich habe auch einige nutzlose Indizes zusammen mit den benutzten hinzugefügt, nur um zu sehen, ob sie die Ausführung ändern (was sie nicht tun).

Die Ausführung dauert ~ 4,5 Sekunden.

Wenn ich die Spalte entl1.name den Auswahlteil (sonst nichts geändert) hinzuzufügen, der Index fk_ent in el1 kann nicht mehr verwendet werden:

| id | select_type | table | type   | possible_keys           | key     | key_len | ref           | rows  | Extra                       
+----+-------------+-------+--------+-------------------------+---------+---------+---------------+-------+------------------------------------
|  1 | SIMPLE      | el1   | ALL    | fk_ent                  |  NULL   | NULL    | NULL          | 15002 | Using temporary

Die Ausführung jetzt dauert ~ 8,5 Sekunden.

Ich habe immer gedacht, dass die ausgewählten Teil einer Abfrage nicht die Verwendung von Indizes durch den Motor nicht beeinflusst und wirkt sich nicht auf die Leistung in einer solchen Art und Weise.

Das Weglassen das Attribut ist keine Lösung, und es gibt noch mehr Attribute, die ich wählen müssen. Noch schlimmer ist, ist die Abfrage in der verwendeten Form noch ein wenig komplexe, und das macht das Leistungsproblem ein großes Problem.

Also meine Fragen sind: 1) Was ist der Grund für dieses seltsame Verhalten? 2) Wie kann ich die Leistung Problem lösen?

Vielen Dank für Ihre Hilfe! Gred

War es hilfreich?

Lösung

Es ist die DISTINCT Einschränkung. Sie können als eine andere WHERE Einschränkung daran denken. Wenn Sie auf die Auswahlliste ändern, werden Sie wirklich die WHERE-Klausel für die DISTINCT Einschränkung zu ändern, und jetzt entscheidet der Optimierer, dass es eine Table-Scan sowieso zu tun hat, so kann es auch nicht Ihren Index verwenden.

EDIT:

Nicht sicher, ob das hilft, aber wenn ich die Daten richtig zu verstehen, ich glaube, Sie loszuwerden, die DISTINCT Einschränkung wie folgt zu erreichen:

select
e1.idx, el1.idx, r1.fk_cat, r2.fk_cat
from ent e1
  Inner Join ent_leng el1 ON el1.fk_ent=e1.idx
  Inner Join rel_c r1 ON r1.fk_ent=e1.idx
  Inner Join rel_c r2 ON r2.fk_ent=e1.idx
where 
 ((r1.fk_cat=43) or Exists(Select 1 From _tax_c t1 Where r1.fk_cat=t1.fk_cat1 and t1.fk_cat2=43)) 
 and 
 ((r2.fk_cat=10) or Exists(Select 1 From _tax_c t2 Where r2.fk_cat=t2.fk_cat1 and t2.fk_cat2=10))

Andere Tipps

MySQL Daten zurück aus einem Index, wenn möglich, aus der gesamten Zeile Speicher geladen werden. Auf diese Weise können die ausgewählten Spalten die Indexauswahl beeinflussen.

In diesem Sinne, kann es viel effizienter, alle erforderlichen Spalten in einen Index hinzufügen, vor allem im Fall von nur eine kleine Teilmenge von Spalten auswählen.

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