2010-05-22 10 views
12

Ich bin völlig auf diesem einen ratlos. Aus irgendeinem Grund, wenn ich diese Abfrage nach DESC sortiere, ist es super schnell, aber wenn es nach ASC sortiert wird, ist es extrem langsam.MySQL ORDER BY DESC ist schnell, aber ASC ist sehr langsam

Dieser Vorgang dauert ca. 150 Millisekunden:

SELECT posts.id 
FROM posts USE INDEX (published) 
WHERE posts.feed_id IN (4953,622,1,1852,4952,76,623,624,10) 
ORDER BY posts.published DESC 
LIMIT 0, 50; 

Dieser Vorgang dauert ca. 32 Sekunden:

SELECT posts.id 
FROM posts USE INDEX (published) 
WHERE posts.feed_id IN (4953,622,1,1852,4952,76,623,624,10) 
ORDER BY posts.published ASC 
LIMIT 0, 50; 

Die EXPLAIN ist die gleiche für beide Abfragen.

id select_type table type possible_keys key key_len ref rows Extra 
1 SIMPLE posts index NULL published 5 NULL 50 Using where 

Ich habe es auf "USE INDEX (veröffentlicht)" gefunden. Wenn ich das herausnehme, ist es die gleiche Leistung in beiden Richtungen. Aber das EXPLAIN zeigt, dass die Abfrage insgesamt weniger effizient ist.

id select_type table type possible_keys key key_len ref rows Extra 
1 SIMPLE posts range feed_id feed_id 4 \N 759 Using where; Using filesort 

Und hier ist der Tisch.

CREATE TABLE `posts` (
    `id` int(20) NOT NULL AUTO_INCREMENT, 
    `feed_id` int(11) NOT NULL, 
    `post_url` varchar(255) NOT NULL, 
    `title` varchar(255) NOT NULL, 
    `content` blob, 
    `author` varchar(255) DEFAULT NULL, 
    `published` int(12) DEFAULT NULL, 
    `updated` datetime NOT NULL, 
    `created` datetime NOT NULL, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `post_url` (`post_url`,`feed_id`), 
    KEY `feed_id` (`feed_id`), 
    KEY `published` (`published`) 
) ENGINE=InnoDB AUTO_INCREMENT=196530 DEFAULT CHARSET=latin1; 

Gibt es eine Lösung dafür? Vielen Dank!

Antwort

5

Ihr Index ab, so sortiert wird, wenn Sie für aufsteigend fragen braucht es viel mehr Arbeit zu tun, es in dieser Reihenfolge

zurück zu bringen
+0

Danke für die Erklärung. Gibt es eine Lösung dafür? Ich denke über die Verwendung von 2 verschiedenen Abfragen, diese für DESC und eine andere für ASC. – Pepper

+0

Wenn Sie MySQL 5+ verwenden, sollten Sie in der Lage sein, mehrere Indizes zu definieren. –

+4

Von http://dev.mysql.com/doc/refman/5.5/de/create-index.html: Eine index_col_name-Spezifikation kann mit ASC oder DESC enden. Diese Schlüsselwörter sind für zukünftige Erweiterungen zum Angeben des aufsteigenden oder absteigenden Indexwertspeichers zulässig. Derzeit werden sie analysiert, aber ignoriert. Indexwerte werden immer in aufsteigender Reihenfolge gespeichert. Also, wie kann ich einen Index erstellen, der desc sortiert ist? – a1ex07

0

Wie wäre es blätterte die Bedingung WO?

SELECT posts.id 
FROM posts USE INDEX (published) 
WHERE posts.feed_id IN (10,624,623,76,4952,1852,622,4953) 
ORDER BY posts.published DESC; 
+1

Ich verstehe nicht, können Sie klären oder ein Beispiel geben? – Pepper

+0

SELECT posts.id FROM Beiträge USE INDEX (published) WHERE posts.feed_id IN (10,624,623,76,4952,1852,622,4953) ORDER BY posts.published DESC; gut ... post.created sollte genau die gleiche Sortierung haben – user184365

0

Sie möchten einen Index über (feed_id, veröffentlicht) hinzuzufügen:

ALTER TABLE posts ADD INDEX (feed_id, published) 

Das wird machen diese Abfrage ausführen, am besten, und Sie werden nicht einen bestimmten Index mit USE INDEX zwingen müssen .

+0

Dies ist, was ich vorher hatte, aber auf einer Tabelle von 500000+ Einträge war es langsam. Das Erzwingen des oben veröffentlichten Indexes ist etwa 3x schneller, wenn er von DESC bestellt wird, und 10x langsamer, wenn er von ASC bestellt wird. – Pepper

+0

Sie haben diesen exakten Index ausprobiert? In dieser Reihenfolge? Definieren Sie "langsam". 500.000+ Zeilen sind für MySQL wirklich keine große Sache (es sei denn, Ihr Server ist alt), und mit einem Index über diese beiden Felder sollte diese Abfrage ungeachtet der Sortierrichtung vollständig indexiert sein. Dass "Using filesort" in Ihrem one explain-Plan Ihnen einen Tipp geben sollte - es gibt keinen Grund, der bei der Optimierung einfacher Ein-Tabellen-Abfragen wie dieser passieren sollte. Auch was ist "veröffentlicht"? Gibt es einen guten Grund, dass es ein Int (12) ist? –

+0

Ich denke mit "langsam" meine ich langsamer als was ich mit DESC sortiere. Es macht einen Typ: range, trifft 4000 statt 50 Zeilen und benutzt filesort. – Pepper

1

Ich würde nicht vorschlagen, dass Sie einen anderen Index auf dem Tisch erstellen; Jedes Mal, wenn eine Zeile eingefügt oder gelöscht wird, muss jeder Index in der Tabelle aktualisiert werden, was die Abfragen INSERT verlangsamt.

Der Index ist definitiv, was es verlangsamt. Vielleicht könnten Sie IGNORE versuchen es -ing:

SELECT posts.id 
FROM posts IGNORE INDEX (published) 
WHERE posts.feed_id IN (4953,622,1,1852,4952,76,623,624,10) 
ORDER BY posts.published ASC 
LIMIT 0, 50; 

Oder da das Feld bereits KEY ed, können Sie Folgendes versuchen:

SELECT posts.id 
FROM posts USE KEY (published) 
WHERE posts.feed_id IN (4953,622,1,1852,4952,76,623,624,10) 
ORDER BY posts.published ASC 
LIMIT 0, 50; 
+0

Danke, USE KEY und USE INDEX scheinen das gleiche Ergebnis zu haben. Und die Verwendung von USE INDEX führt nicht zu demselben Ergebnis wie IGNORE INDEX. – Pepper

3

Sie Ihre Daten zuerst gesetzt bekommen konnte, und dann bestellen es.

So etwas wie

SELECT posts.id FROM (
SELECT posts.id 
FROM posts USE INDEX (published) 
WHERE posts.feed_id IN (4953,622,1,1852,4952,76,623,624,10) 
LIMIT 0, 50 
) 
order by postS.id ASC; 

Es sollte zuerst den Index verwenden, um alle Datensätze zu finden, die Ihre „where“ Anweisung erfüllen, und das wird sie bestellen. Aber die Reihenfolge würde in einem kleineren Satz durchgeführt werden. Probieren Sie es aus und erzählen Sie es uns.

Mit freundlichen Grüßen.

+0

Danke, ich versuche es mal. – Pepper

+1

Kurz notiert, die obige Unterabfrage benötigt einen Alias, um zu funktionieren. – Pepper

Verwandte Themen