MySQL bestellen vor vor gruppieren nach


243

Es gibt viele ähnliche Fragen, die hier zu finden sind, aber ich denke nicht, dass jemand die Frage angemessen beantwortet.

Ich werde mit der derzeit beliebtesten Frage fortfahren und ihr Beispiel verwenden, wenn das in Ordnung ist.

In diesem Fall besteht die Aufgabe darin, den neuesten Beitrag für jeden Autor in der Datenbank abzurufen.

Die Beispielabfrage führt zu unbrauchbaren Ergebnissen, da nicht immer der letzte Beitrag zurückgegeben wird.

SELECT wp_posts.* FROM wp_posts
    WHERE wp_posts.post_status='publish'
    AND wp_posts.post_type='post'
    GROUP BY wp_posts.post_author           
    ORDER BY wp_posts.post_date DESC

Die aktuell akzeptierte Antwort lautet

SELECT
    wp_posts.*
FROM wp_posts
WHERE
    wp_posts.post_status='publish'
    AND wp_posts.post_type='post'
GROUP BY wp_posts.post_author
HAVING wp_posts.post_date = MAX(wp_posts.post_date) <- ONLY THE LAST POST FOR EACH AUTHOR
ORDER BY wp_posts.post_date DESC

Leider ist diese Antwort schlicht und einfach falsch und führt in vielen Fällen zu weniger stabilen Ergebnissen als die ursprüngliche Abfrage.

Meine beste Lösung besteht darin, eine Unterabfrage des Formulars zu verwenden

SELECT wp_posts.* FROM 
(
    SELECT * 
    FROM wp_posts
    ORDER BY wp_posts.post_date DESC
) AS wp_posts
WHERE wp_posts.post_status='publish'
AND wp_posts.post_type='post'
GROUP BY wp_posts.post_author 

Meine Frage ist dann einfach: Gibt es überhaupt eine Möglichkeit, Zeilen vor dem Gruppieren zu ordnen, ohne auf eine Unterabfrage zurückzugreifen?

Bearbeiten : Diese Frage war eine Fortsetzung einer anderen Frage und die Besonderheiten meiner Situation unterscheiden sich geringfügig. Sie können (und sollten) davon ausgehen, dass es auch eine wp_posts.id gibt, die eine eindeutige Kennung für diesen bestimmten Beitrag darstellt.


2
Wie Sie in den Kommentaren zu den gegebenen Antworten erwähnt haben, ist es möglicherweise möglich, dass einige Beiträge denselben Zeitstempel haben. Wenn ja, geben Sie bitte ein Beispiel mit Daten und dem erwarteten Ergebnis. Und bitte beschreiben Sie, warum Sie dieses Ergebnis erwarten. post_authorund post_datesind nicht genug, um eine eindeutige Zeile zu erhalten, daher muss es mehr geben, um eine eindeutige Zeile propost_author
Sir Rufo

@ SirRufo Du hast recht, ich habe eine Bearbeitung für dich hinzugefügt.
Rob Forrest

There are plenty of similar questions to be found on here but I don't think that any answer the question adequately.Dafür sind Kopfgelder da.
Leichtigkeitsrennen im Orbit

@LightnessRacesinOrbit, wenn die aktuelle Frage bereits eine akzeptierte Antwort hat, die meiner Meinung nach falsch ist, was würden Sie vorschlagen?
Rob Forrest

1
Sie fragen sich, warum Sie eine Antwort akzeptiert haben, die eine Unterabfrage verwendet - wenn Ihre Frage eindeutig lautet ... "" Gibt es überhaupt eine Möglichkeit, Zeilen vor dem Gruppieren zu bestellen, ohne auf eine Unterabfrage zurückzugreifen? "???
TV-C-15

Antworten:


373

Die Verwendung von ORDER BYin einer Unterabfrage ist nicht die beste Lösung für dieses Problem.

Die beste Lösung, um den max(post_date)Autor zu ermitteln, besteht darin, eine Unterabfrage zu verwenden, um das maximale Datum zurückzugeben, und diese dann sowohl am post_authorals auch am maximalen Datum mit Ihrer Tabelle zu verknüpfen .

Die Lösung sollte sein:

SELECT p1.* 
FROM wp_posts p1
INNER JOIN
(
    SELECT max(post_date) MaxPostDate, post_author
    FROM wp_posts
    WHERE post_status='publish'
       AND post_type='post'
    GROUP BY post_author
) p2
  ON p1.post_author = p2.post_author
  AND p1.post_date = p2.MaxPostDate
WHERE p1.post_status='publish'
  AND p1.post_type='post'
order by p1.post_date desc

Wenn Sie folgende Beispieldaten haben:

CREATE TABLE wp_posts
    (`id` int, `title` varchar(6), `post_date` datetime, `post_author` varchar(3))
;

INSERT INTO wp_posts
    (`id`, `title`, `post_date`, `post_author`)
VALUES
    (1, 'Title1', '2013-01-01 00:00:00', 'Jim'),
    (2, 'Title2', '2013-02-01 00:00:00', 'Jim')
;

Die Unterabfrage gibt das maximale Datum und den Autor von zurück:

MaxPostDate | Author
2/1/2013    | Jim

Da Sie dies dann wieder mit der Tabelle verknüpfen, geben Sie für beide Werte die vollständigen Details dieses Beitrags zurück.

Siehe SQL Fiddle mit Demo .

Um meine Kommentare zur Verwendung einer Unterabfrage zur genauen Rückgabe dieser Daten zu erweitern.

MySQL zwingt Sie nicht zu GROUP BYjeder Spalte, die Sie in die SELECTListe aufnehmen. Wenn Sie also nur GROUP BYeine Spalte verwenden, aber insgesamt 10 Spalten zurückgeben, gibt es keine Garantie dafür, dass die anderen Spaltenwerte, die zu den post_authorzurückgegebenen gehören , zurückgegeben werden. Wenn sich die Spalte nicht in GROUP BYMySQL befindet, wird ausgewählt, welcher Wert zurückgegeben werden soll.

Durch die Verwendung der Unterabfrage mit der Aggregatfunktion wird sichergestellt, dass jedes Mal der richtige Autor und Beitrag zurückgegeben wird.

ORDER BYNebenbei bemerkt, während MySQL die Verwendung von a in einer Unterabfrage und die Anwendung von a GROUP BYauf nicht jede Spalte in der SELECTListe ermöglicht, ist dieses Verhalten in anderen Datenbanken, einschließlich SQL Server, nicht zulässig.


4
Ich sehe, was Sie dort getan haben, aber das gibt einfach das Datum zurück, an dem der letzte Beitrag verfasst wurde, nicht die gesamte Zeile für den letzten Beitrag.
Rob Forrest

1
@RobForrest das macht der Join. Sie geben das letzte Post-Datum in der Unterabfrage nach Autor zurück und verbinden sich dann mit Ihrem wp_postsin beiden Spalten, um die vollständige Zeile zu erhalten.
Taryn

7
@RobForrest Wenn Sie GROUP BYzum einen nur auf eine Spalte anwenden , gibt es keine Garantie dafür, dass die Werte in den anderen Spalten konsistent korrekt sind. Leider lässt MySQL diese Art von SELECT / GROUPing zu, was bei anderen Produkten nicht der Fall ist. ORDER BYZweitens ist die Syntax der Verwendung von a in einer Unterabfrage, während sie in MySQL zulässig ist, in anderen Datenbankprodukten, einschließlich SQL Server, nicht zulässig. Sie sollten eine Lösung verwenden, die bei jeder Ausführung das richtige Ergebnis zurückgibt.
Taryn

2
Für die Skalierung ist die Verbindung INDEX(post_author, post_date)wichtig.
Rick James

1
@ jtcotton63 Stimmt, aber wenn Sie post_idIhre innere Abfrage eingeben, sollten Sie sich technisch auch danach gruppieren, was Ihre Ergebnisse höchstwahrscheinlich verzerren würde.
Taryn

20

Ihre Lösung verwendet eine Erweiterung der GROUP BY- Klausel, mit der Sie nach bestimmten Feldern gruppieren können (in diesem Fall nur post_author):

GROUP BY wp_posts.post_author

und wählen Sie nicht aggregierte Spalten aus:

SELECT wp_posts.*

die nicht in der group by-Klausel aufgeführt sind oder die nicht in einer Aggregatfunktion (MIN, MAX, COUNT usw.) verwendet werden.

Richtige Verwendung der Erweiterung der GROUP BY-Klausel

Dies ist nützlich, wenn alle Werte nicht aggregierter Spalten für jede Zeile gleich sind.

Angenommen, Sie haben einen Tisch GardensFlowers( namedes Gartens, der im Garten flowerwächst):

INSERT INTO GardensFlowers VALUES
('Central Park',       'Magnolia'),
('Hyde Park',          'Tulip'),
('Gardens By The Bay', 'Peony'),
('Gardens By The Bay', 'Cherry Blossom');

und Sie möchten alle Blumen extrahieren, die in einem Garten wachsen, in dem mehrere Blumen wachsen. Dann müssen Sie eine Unterabfrage verwenden, zum Beispiel könnten Sie diese verwenden:

SELECT GardensFlowers.*
FROM   GardensFlowers
WHERE  name IN (SELECT   name
                FROM     GardensFlowers
                GROUP BY name
                HAVING   COUNT(DISTINCT flower)>1);

Wenn Sie stattdessen alle Blumen extrahieren müssen, die die einzigen Blumen im Garder sind, können Sie einfach die HAVING-Bedingung in ändern HAVING COUNT(DISTINCT flower)=1, aber MySql ermöglicht Ihnen auch Folgendes:

SELECT   GardensFlowers.*
FROM     GardensFlowers
GROUP BY name
HAVING   COUNT(DISTINCT flower)=1;

Keine Unterabfrage, kein Standard-SQL, aber einfacher.

Falsche Verwendung der Erweiterung der GROUP BY-Klausel

Aber was passiert, wenn Sie nicht aggregierte Spalten auswählen, die nicht für jede Zeile gleich sind? Welchen Wert wählt MySql für diese Spalte?

Es sieht so aus, als würde MySQL immer den ERSTEN Wert auswählen, auf den es stößt.

Um sicherzustellen, dass der erste Wert, auf den er trifft, genau der gewünschte Wert ist, müssen Sie a GROUP BYauf eine geordnete Abfrage anwenden , daher muss eine Unterabfrage verwendet werden. Sie können es nicht anders machen.

Unter der Annahme, dass MySql immer die erste Zeile auswählt, auf die es trifft, sortieren Sie die Zeilen vor der GROUP BY korrekt. Wenn Sie die Dokumentation jedoch sorgfältig lesen, werden Sie leider feststellen, dass diese Annahme nicht zutrifft.

Bei der Auswahl nicht aggregierter Spalten, die nicht immer gleich sind, kann MySql einen beliebigen Wert auswählen, sodass der resultierende Wert, der tatsächlich angezeigt wird, unbestimmt ist .

Ich sehe, dass dieser Trick, um den ersten Wert einer nicht aggregierten Spalte zu erhalten, häufig verwendet wird und normalerweise / fast immer funktioniert. Ich verwende ihn manchmal auch (auf eigenes Risiko). Da dies jedoch nicht dokumentiert ist, können Sie sich nicht auf dieses Verhalten verlassen.

Dieser Link (danke ypercube!) Der GROUP BY-Trick wurde weg optimiert. Er zeigt eine Situation, in der dieselbe Abfrage unterschiedliche Ergebnisse zwischen MySql und MariaDB zurückgibt, wahrscheinlich aufgrund einer anderen Optimierungs-Engine.

Wenn dieser Trick funktioniert, ist es nur eine Frage des Glücks.

Die akzeptierte Antwort auf die andere Frage erscheint mir falsch:

HAVING wp_posts.post_date = MAX(wp_posts.post_date)

wp_posts.post_dateist eine nicht aggregierte Spalte, und ihr Wert wird offiziell unbestimmt sein, aber es wird wahrscheinlich die erste sein, die post_dateangetroffen wird. Da der GROUP BY-Trick jedoch auf eine ungeordnete Tabelle angewendet wird, ist nicht sicher, welche zuerst post_dateangetroffen wird.

Es werden wahrscheinlich Beiträge zurückgegeben, die die einzigen Beiträge eines einzelnen Autors sind, aber selbst dies ist nicht immer sicher.

Eine mögliche Lösung

Ich denke, dass dies eine mögliche Lösung sein könnte:

SELECT wp_posts.*
FROM   wp_posts
WHERE  id IN (
  SELECT max(id)
  FROM wp_posts
  WHERE (post_author, post_date) = (
    SELECT   post_author, max(post_date)
    FROM     wp_posts
    WHERE    wp_posts.post_status='publish'
             AND wp_posts.post_type='post'
    GROUP BY post_author
  ) AND wp_posts.post_status='publish'
    AND wp_posts.post_type='post'
  GROUP BY post_author
)

Bei der inneren Abfrage gebe ich das maximale Post-Datum für jeden Autor zurück. Ich berücksichtige dann die Tatsache, dass derselbe Autor theoretisch zwei Beiträge gleichzeitig haben könnte, sodass ich nur die maximale ID erhalte. Und dann gebe ich alle Zeilen zurück, die diese maximalen IDs haben. Es könnte schneller mit Joins anstelle der IN-Klausel gemacht werden.

(Wenn Sie sicher sind, dass dies IDnur zunimmt und dies ID1 > ID2auch bedeutet, post_date1 > post_date2könnte die Abfrage viel einfacher gestaltet werden, aber ich bin mir nicht sicher, ob dies der Fall ist.)


Das extension to GROUP Byist eine interessante Lektüre, danke dafür.
Rob Forrest

2
Ein Beispiel, wo es fehlschlägt: GROUP BY Trick wurde weg optimiert
ypercubeᵀᴹ

Nicht aggregierte Spalten in ausgewählten Ausdrücken mit GROUP BY funktionieren standardmäßig nicht mehr mit MySQL 5.7: stackoverflow.com/questions/34115174/… . Welches IMHO ist viel sicherer und zwingt einige Leute, effizientere Abfragen zu schreiben.
rink.attendant.6

Verwendet diese Antwort keine Unterabfrage? Bittet das Originalplakat nicht um eine Lösung, bei der KEINE Unterabfrage verwendet wird?
TV-C-15

1
@ TV-C-15 Das Problem ist das Zurücksetzen der Unterabfrage, und ich erkläre, warum das Zurücksetzen einer Unterabfrage nicht funktioniert. Sogar die akzeptierte Antwort verwendet eine Unterabfrage, aber es beginnt zu erklären, warum das Zurücksetzen eine schlechte Idee ist (die Verwendung eines ORDER BY in einer Unterabfrage ist nicht die beste Lösung für dieses Problem )
fthiella

9

Was Sie lesen werden, ist ziemlich hackig, versuchen Sie es also nicht zu Hause!

In SQL lautet die Antwort auf Ihre Frage im Allgemeinen NEIN . Aufgrund des entspannten Modus von GROUP BY(von @bluefeet erwähnt ) lautet die Antwort in MySQL JA .

Angenommen, Sie haben einen BTREE-Index für (post_status, post_type, post_author, post_date). Wie sieht der Index unter der Haube aus?

(post_status = 'veröffentlichen', post_type = 'post', post_author = 'Benutzer A', post_date = '2012-12-01') (post_status = 'veröffentlichen', post_type = 'post', post_author = 'Benutzer A', post_date = '2012-12-31') (post_status = 'veröffentlichen', post_type = 'post', post_author = 'Benutzer B', post_date = '2012-10-01') (post_status = 'veröffentlichen', post_type = ' post ', post_author =' Benutzer B ', post_date =' 2012-12-01 ')

Das heißt, die Daten werden nach all diesen Feldern in aufsteigender Reihenfolge sortiert.

Wenn Sie eine GROUP BYstandardmäßig post_authorausführen, werden die Daten nach dem Gruppierungsfeld sortiert ( in unserem Fall sind post_status, post_type für die WHEREKlausel erforderlich ). Wenn ein übereinstimmender Index vorhanden ist, werden die Daten für jeden ersten Datensatz in aufsteigender Reihenfolge erfasst . Das heißt, die Abfrage ruft Folgendes ab (den ersten Beitrag für jeden Benutzer):

(post_status = 'veröffentlichen', post_type = 'post', post_author = 'Benutzer A', post_date = '2012-12-01') (post_status = 'veröffentlichen', post_type = 'post', post_author = 'Benutzer B', post_date = '2012-10-01')

Aber GROUP BYin MySQL können Sie die Reihenfolge explizit angeben. Und wenn Sie post_userin absteigender Reihenfolge anfordern , wird unser Index in umgekehrter Reihenfolge durchlaufen, wobei immer noch der erste Datensatz für jede Gruppe erstellt wird, die tatsächlich die letzte ist.

Das ist

...
WHERE wp_posts.post_status='publish' AND wp_posts.post_type='post'
GROUP BY wp_posts.post_author DESC

wird uns geben

(post_status = 'veröffentlichen', post_type = 'post', post_author = 'Benutzer B', post_date = '2012-12-01') (post_status = 'veröffentlichen', post_type = 'post', post_author = 'Benutzer A', post_date = '2012-12-31')

Wenn Sie nun die Ergebnisse der Gruppierung nach post_date ordnen, erhalten Sie die gewünschten Daten.

SELECT wp_posts.*
FROM wp_posts
WHERE wp_posts.post_status='publish' AND wp_posts.post_type='post'
GROUP BY wp_posts.post_author DESC
ORDER BY wp_posts.post_date DESC;

NB :

Dies ist nicht das, was ich für diese spezielle Abfrage empfehlen würde. In diesem Fall würde ich eine leicht modifizierte Version dessen verwenden , was @bluefeet vorschlägt. Aber diese Technik könnte sehr nützlich sein. Schauen Sie sich meine Antwort hier an: Abrufen des letzten Datensatzes in jeder Gruppe

Fallstricke : Die Nachteile des Ansatzes sind folgende

  • Das Ergebnis der Abfrage hängt vom Index ab, was dem Geist der SQL widerspricht (Indizes sollten nur Abfragen beschleunigen).
  • Der Index weiß nichts über seinen Einfluss auf die Abfrage (Sie oder jemand anderes könnte den Index in Zukunft als zu ressourcenintensiv empfinden und ihn irgendwie ändern, wodurch die Abfrageergebnisse und nicht nur die Leistung beeinträchtigt werden).
  • Wenn Sie nicht verstehen, wie die Abfrage funktioniert, werden Sie höchstwahrscheinlich die Erklärung in einem Monat vergessen und die Abfrage wird Sie und Ihre Kollegen verwirren.

Der Vorteil ist die Leistung in schwierigen Fällen. In diesem Fall sollte die Leistung der Abfrage aufgrund der Datenmenge beim Sortieren dieselbe sein wie bei der Abfrage von @ bluefeet (alle Daten werden in eine temporäre Tabelle geladen und dann sortiert; übrigens erfordert seine Abfrage auch den (post_status, post_type, post_author, post_date)Index). .

Was ich vorschlagen würde :

Wie gesagt, diese Abfragen führen dazu, dass MySQL Zeit damit verschwendet, potenziell große Datenmengen in einer temporären Tabelle zu sortieren. Falls Sie Paging benötigen (dh LIMIT ist beteiligt), werden die meisten Daten sogar verworfen. Was ich tun würde, ist die Menge der sortierten Daten zu minimieren: das heißt, ein Minimum an Daten in der Unterabfrage zu sortieren und zu begrenzen und dann wieder mit der gesamten Tabelle zu verbinden.

SELECT * 
FROM wp_posts
INNER JOIN
(
  SELECT max(post_date) post_date, post_author
  FROM wp_posts
  WHERE post_status='publish' AND post_type='post'
  GROUP BY post_author
  ORDER BY post_date DESC
  -- LIMIT GOES HERE
) p2 USING (post_author, post_date)
WHERE post_status='publish' AND post_type='post';

Dieselbe Abfrage unter Verwendung des oben beschriebenen Ansatzes:

SELECT *
FROM (
  SELECT post_id
  FROM wp_posts
  WHERE post_status='publish' AND post_type='post'
  GROUP BY post_author DESC
  ORDER BY post_date DESC
  -- LIMIT GOES HERE
) as ids
JOIN wp_posts USING (post_id);

Alle diese Abfragen mit ihren Ausführungsplänen in SQLFiddle .


Das ist eine interessante Technik, die Sie dort anwenden müssen. Zwei Dinge: Sie sagen, versuchen Sie dies nicht zu Hause. Was sind die möglichen Gefahren? zweitens erwähnen Sie eine leicht modifizierte Version von bluefeets Antwort, was wäre das?
Rob Forrest

Vielen Dank dafür, es ist interessant zu sehen, wie jemand das Problem auf andere Weise angreift. Da sich mein Datensatz bei weitem nicht in der Nähe Ihrer über 18 Millionen Zeilen befindet, ist die Leistung meiner Meinung nach nicht so wichtig wie die Wartbarkeit. Daher sind Ihre späteren Optionen wahrscheinlich besser geeignet. Ich mag die Idee der Begrenzung auf der Innenseite der Unterabfrage.
Rob Forrest

8

Probier diese. Holen Sie sich einfach die Liste der neuesten Post-Daten von jedem Autor . Das ist es

SELECT wp_posts.* FROM wp_posts WHERE wp_posts.post_status='publish'
AND wp_posts.post_type='post' AND wp_posts.post_date IN(SELECT MAX(wp_posts.post_date) FROM wp_posts GROUP BY wp_posts.post_author) 

@ Rob Forrest, überprüfe meine Lösung. Es löst hoffentlich Ihre Frage!
Sanchitkhanna26

1
Es tut mir leid, ich glaube nicht, dass das funktionieren würde. Wenn beispielsweise sowohl Autor 1 als auch Autor 2 am 01.02.13 etwas veröffentlichen und dann Autor 2 am 08.02.13 etwas Neues veröffentlicht, werden alle 3 Beiträge zurückgegeben. Ja, das Datum / Uhrzeit-Feld enthält die Uhrzeit, sodass die Situation weniger wahrscheinlich ist, aber keinesfalls für einen ausreichend großen Datensatz garantiert ist.
Rob Forrest

+1 für die Verwendung der post_date IN (select max(...) ...). Dies ist effizienter als das Erstellen
Seaux

Nur zur Klarstellung, das ist nur dann optimaler, wenn Sie post_author indiziert haben.
Seaux

1
IN ( SELECT ... )ist viel weniger effizient als das entsprechende JOIN.
Rick James

3

Nein. Es ist nicht sinnvoll, die Datensätze vor dem Gruppieren zu ordnen, da durch Gruppieren die Ergebnismenge mutiert wird. Der Unterabfrageweg ist der bevorzugte Weg. Wenn dies zu langsam geht, müssen Sie Ihr Tabellendesign ändern, indem Sie beispielsweise die ID des letzten Beitrags für jeden Autor in einer separaten Tabelle speichern oder eine boolesche Spalte einfügen, die für jeden Autor angibt, welcher seiner Beiträge der letzte ist einer.


Dennish, wie würden Sie auf die Kommentare von Bluefeet antworten, dass diese Art von Abfrage nicht die richtige SQL-Syntax aufweist und daher nicht auf Datenbankplattformen portierbar ist? Es gibt auch Bedenken, dass es keine Garantie dafür gibt, dass dies jedes Mal zu den richtigen Ergebnissen führt.
Rob Forrest

2

Verwenden Sie einfach die Max-Funktion und die Gruppenfunktion

    select max(taskhistory.id) as id from taskhistory
            group by taskhistory.taskid
            order by taskhistory.datum desc

3
Was ist, wenn der mit der höchsten ID nicht der zuletzt veröffentlichte ist? Ein Beispiel hierfür könnte sein, dass der Autor seinen Beitrag lange Zeit im Entwurf gehalten hat, bevor er veröffentlicht wurde.
Rob Forrest

0

Um es noch einmal zusammenzufassen: Die Standardlösung verwendet eine nicht korrelierte Unterabfrage und sieht folgendermaßen aus:

SELECT x.*
  FROM my_table x
  JOIN (SELECT grouping_criteria,MAX(ranking_criterion) max_n FROM my_table GROUP BY grouping_criteria) y
    ON y.grouping_criteria = x.grouping_criteria
   AND y.max_n = x.ranking_criterion;

Wenn Sie eine alte Version von MySQL oder einen relativ kleinen Datensatz verwenden, können Sie die folgende Methode verwenden:

SELECT x.*
  FROM my_table x
  LEFT
  JOIN my_table y
    ON y.joining_criteria = x.joining_criteria
   AND y.ranking_criteria < x.ranking_criteria
 WHERE y.some_non_null_column IS NULL;  

Wenn Sie die alte Version sagen, auf welcher MySQL-Version würde dies laufen? Und sorry nein, der Datensatz ist in meinem Beispiel ziemlich groß.
Rob Forrest

Es wird (langsam) auf jeder Version funktionieren. Ältere Versionen können keine Unterabfragen verwenden.
Erdbeere

Ja, die Methode Nr. 2 (die Version, die ich von hier aus ausprobiert habe ) funktioniert nicht mit einem großen Datensatz (Millionen von Zeilen) und löst einen Verbindungsverlust aus . Methode 1 benötigt ~ 15 Sekunden, um eine Abfrage auszuführen. Ich wollte zunächst vermeiden, verschachtelte Abfragen zu verwenden, aber dies brachte mich dazu, es mir noch einmal zu überlegen. Danke dir!
Aexl

@TheSexiestManinJamaica Ja. In 3,5 Jahren hat sich nicht viel geändert. Angenommen, eine Abfrage ist an sich effizient, hängt die Ausführungszeit der Abfrage weitgehend von der Größe des Datasets, der Anordnung der Indizes und der verfügbaren Hardware ab.
Erdbeere

-1

** Unterabfragen können sich bei Verwendung mit großen Datenmengen negativ auf die Leistung auswirken **

Ursprüngliche Abfrage

SELECT wp_posts.*
FROM   wp_posts
WHERE  wp_posts.post_status = 'publish'
       AND wp_posts.post_type = 'post'
GROUP  BY wp_posts.post_author
ORDER  BY wp_posts.post_date DESC; 

Geänderte Abfrage

SELECT p.post_status,
       p.post_type,
       Max(p.post_date),
       p.post_author
FROM   wp_posts P
WHERE  p.post_status = "publish"
       AND p.post_type = "post"
GROUP  BY p.post_author
ORDER  BY p.post_date; 

Da ich maxin select clause==> verwende max(p.post_date), ist es möglich, Unterauswahlabfragen zu vermeiden und nach der Spalte max nach der Gruppe nach zu sortieren .


1
Dies gibt zwar das aktuellste post_date pro Autor zurück, es gibt jedoch keine Garantie dafür, dass sich der Rest der zurückgegebenen Daten auf den Beitrag mit dem neuesten post_date bezieht.
Rob Forrest

@RobForrest -> Ich verstehe nicht warum? Es ist eine gute Idee, Ihre Antwort auszuarbeiten und Ansprüche einfach wegzuwerfen. Soweit ich weiß, werden die Daten garantiert in Beziehung gesetzt, da ich die where-Klausel verwende, um die verwandten Daten zu filtern.
Guykaplan

1
Bis zu einem gewissen Grad sind Sie völlig korrekt. Jedes der 4 Felder, die Sie auswählen, bezieht sich auf das maximale post_date, aber dies beantwortet nicht die gestellte Frage. Wenn Sie beispielsweise die post_id oder den Inhalt des Posts hinzugefügt haben, kann nicht sichergestellt werden, dass diese Spalten aus demselben Datensatz stammen wie das maximale Datum. Um Ihre obige Abfrage dazu zu bringen, die restlichen Details des Beitrags zurückzugeben, müssten Sie eine zweite Abfrage ausführen. Wenn es bei der Frage darum ging, das Datum des letzten Beitrags zu finden, wäre Ihre Antwort in Ordnung.
Rob Forrest

@guykaplan, Unterabfragen sind nicht langsam. Die Größe des Datensatzes spielt keine Rolle. Es hängt davon ab, wie Sie es verwenden. Siehe percona.com/blog/2010/03/18/when-the-subselect-runs-faster
Pacerier

@Pacerier: Der Artikel zeigt in der Tat, wie Sie Leistungsvorteile aus Unterabfragen ziehen können, aber ich würde gerne sehen, dass Sie das angegebene Szenario konvertieren, um eine bessere Leistung zu erzielen. und Datengröße ist wichtig. Auch in dem von Ihnen veröffentlichten Artikel wird davon ausgegangen, dass nur eine Tabelle zum Arbeiten vorhanden ist. Die Datengröße richtet sich nicht nach der Zeilengröße, sondern nach der Komplexitätsgröße. Wenn Sie jedoch mit wirklich großen Tabellen arbeiten (es sind nicht viele Tabellen beteiligt), kann die Unterabfrage eine viel bessere Leistung erzielen.
Guykaplan

-4

Verwenden Sie * in select nicht, da dies die Leistung beeinträchtigt und die Verwendung der Gruppe nach und nach der Reihenfolge behindert. Versuchen Sie diese Abfrage:

SELECT wp_posts.post_author, wp_posts.post_date as pdate FROM wp_posts
WHERE wp_posts.post_status='publish'
AND wp_posts.post_type='post'
GROUP BY wp_posts.post_author           
ORDER BY pdate DESC

Wenn Sie in ORDER BY nicht nur die Tabelle angeben, sondern nur den Alias, wird das Ergebnis der Auswahl sortiert.


Ignorieren Sie die ausgewählten *, sie sind der Kürze halber in diesem Beispiel. Ihre Antwort ist genau die gleiche wie das erste Beispiel, das ich gegeben habe.
Rob Forrest

Der Alias ​​hat weder Einfluss darauf, welche Zeile zurückgegeben wird, noch auf die Sortierung der Ergebnisse.
Rob Forrest
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.