2016-07-19 10 views
0

Ich optimiere meine Abfragen und finde etwas, was ich nicht verstehen kann.Unterabfrage mehr Zeilen als nötig verarbeiten

ich die folgende Abfrage verwenden eine Reihe von Kategorien zu wählen, so dass sie mit einem Aliasnamen aus einer Tabelle mit alter und neue Aliase für Kategorien kombinieren:

SELECT `c`.`id` AS `category.id`, 
    (SELECT `alias` 
    FROM `aliases` 
    WHERE category_id = c.id 
    AND `old` = 0 
    AND `lang_id` = 1 
    ORDER BY `id` DESC 
    LIMIT 1) AS `category.alias` 
FROM (`categories` AS c) 
WHERE `c`.`status` = 1 AND `c`.`parent_id` = '11'; 

Es gibt nur 2 Kategorien mit einem Wert von 11 für parent_id, so sollte es 2 Kategorien aus der Alias-Tabelle nachschlagen.

enter image description here

Dennoch, wenn ich EXPLAIN verwenden sie sagt, es 48 Zeilen zu verarbeiten hat. Die Alias-Tabelle enthält ebenfalls 1 Eintrag pro Kategorie (in diesem Fall kann es mehr sein). Alles ist indiziert und wenn ich es richtig verstehe, sollte es sofort den richtigen Alias ​​finden.

enter image description here

Jetzt ist hier die seltsame Sache. Wenn ich die Aliase nicht nach Kategorien aus den Bedingungen, sondern manuell nach den Kategorie-IDs vergleiche, die die Abfrage zurückgibt, verarbeitet sie nur eine Zeile, wie mit dem Index beabsichtigt.

Also ersetze ich WHERE category_id = c.id durch WHERE category_id IN (37, 43) und die Abfrage wird schneller:

enter image description here

Das einzige, was ich denken kann, ist, dass die Unterabfrage nicht über die Ergebnisse der Abfrage ausgeführt wird, aber vor einigen Filtern erledigt. Jede Art von Erklärung oder Hilfe ist willkommen!

Edit: alberne mich, die WHERE IN funktioniert nicht, da es keine eindeutige Auswahl macht. Die Frage steht immer noch!

erstellen Tabellenschema

CREATE TABLE `aliases` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `lang_id` int(2) unsigned NOT NULL DEFAULT '1', 
    `alias` varchar(255) DEFAULT NULL, 
    `product_id` int(10) unsigned DEFAULT NULL, 
    `category_id` int(10) unsigned DEFAULT NULL, 
    `brand_id` int(10) unsigned DEFAULT NULL, 
    `page_id` int(10) unsigned DEFAULT NULL, 
    `campaign_id` int(10) unsigned DEFAULT NULL, 
    `old` tinyint(1) unsigned DEFAULT '0', 
    PRIMARY KEY (`id`), 
    KEY `product_id` (`product_id`), 
    KEY `category_id` (`category_id`), 
    KEY `page_id` (`page_id`), 
    KEY `alias_product_id` (`product_id`,`alias`), 
    KEY `alias_category_id` (`category_id`,`alias`), 
    KEY `alias_page_id` (`page_id`,`alias`), 
    KEY `alias_brand_id` (`brand_id`,`alias`), 
    KEY `alias_product_id_old` (`alias`,`product_id`,`old`), 
    KEY `alias_category_id_old` (`alias`,`category_id`,`old`), 
    KEY `alias_brand_id_old` (`alias`,`brand_id`,`old`), 
    KEY `alias_page_id_old` (`alias`,`page_id`,`old`), 
    KEY `lang_brand_old` (`lang_id`,`brand_id`,`old`), 
    KEY `id_category_id_lang_id_old` (`lang_id`,`old`,`id`,`category_id`) 
) ENGINE=InnoDB AUTO_INCREMENT=112392 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT; 
+0

Eh? Das Schema stimmt nicht mit dem 'SELECT' überein - wo sind' status' und 'parent_id'? –

+0

'status' und' parent_id' stammen aus der Haupttabelle ('categories'), nicht die Unterabfrage (beachten Sie den' c' Alias) – Tumtum

Antwort

1
SELECT ... 
    WHERE x=1 AND y=2 
    ORDER BY id DESC 
    LIMIT 1 

wird in einem von mehreren Wegen durchgeführt werden.

Da Sie haben uns nicht die Indizes angezeigt Sie haben (SHOW CREATE TABLE), werde ich einige wahrscheinlich Fälle abdecken ...

  • INDEX(x, y, id) - Dies kann die letzte Zeile für diesen Zustand finden, tut sie dies nicht müssen mehr als eine Zeile sehen.
  • Ein anderer Index, oder kein Index: Scan DESCending von der letzten id Überprüfung jeder Zeile für x=1 AND y=2, stoppt, wenn (wenn) eine solche Zeile gefunden wird.
  • Ein anderer Index oder kein Index: Scannen Sie die gesamte Tabelle und überprüfen Sie jede Zeile auf x=1 AND y=2; sammle sie in eine temporäre Tabelle; Sortieren nach id; Liefern Sie eine Reihe.

Einige der EXPLAIN Hinweise:

  • Verwendung, wo - nicht viel filesort
  • Verwendung nicht sagen - es eine Art hat, offenbar für die ORDER BY. (Es wurde möglicherweise vollständig im RAM ausgeführt; ignorieren Sie "Datei".)
  • Index-Bedingung verwenden (nicht "Using Index") - dies zeigt eine interne Optimierung, in der es die WHERE-Klausel effizienter als früher überprüfen kann in älteren Versionen.

nicht Vertrauen in den "Zeilen" in EXPLAIN. Oft sind sie einigermaßen korrekt, aber manchmal sind sie um Größenordnungen ausgeschaltet. Hier ist ein besserer Weg, um zu sehen, „wie viel Arbeit“ in einem ziemlich schnellen Abfrage getan:

FLUSH STATUS; 
SELECT ...; 
SHOW SESSION STATUS LIKE 'Handler%'; 

Mit dem CREATE TABLE, ich kann haben Vorschläge, wie den Index zu verbessern.

+0

Danke für die zusätzlichen Informationen. Sehr interessant! Es ist sehr schwer für mich, das Ergebnis der Sitzungsstatusabfrage zu verstehen. – Tumtum

+0

Ich habe das Schema CREATE hinzugefügt. Merkwürdig ist, dass es auf meiner lokalen Maschine eine bessere Indizierung basierend auf den Schlüsseln verwendet. – Tumtum

+0

Einfache Interpretation von 'STATUS':" einige große Zahlen = langsam; alle kleinen Zahlen = schnell " –

Verwandte Themen