Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Mehrere MySQL-Unterabfragen im Vergleich zu ganzen Abfragen

Da diese drei Aggregate aus derselben Tabelle mit demselben WHERE stammen Bedingungen benötigen Sie keine Unterauswahlen. Alle drei Aggregate arbeiten mit derselben Zeilengruppierung (kein GROUP BY angegeben, also eine Zeile für die ganze Tabelle), damit sie alle im SELECT existieren können direkt auflisten.

SELECT
  SUM(number) AS number_sum,
  MAX(number) AS number_max,
  MIN(number) AS number_min
FROM `table`

Wenn eines der Aggregate auf anderen Bedingungen basieren muss, würden Sie in einem WHERE filtern -Klausel, dann müssen Sie entweder eine Unterauswahl für die abweichende Bedingung verwenden oder eine kartesische Verknüpfung durchführen. Diese Unterauswahl und das folgende LEFT JOIN -Methode sollte hinsichtlich der Leistung für Aggregate, die nur eine Zeile zurückgeben, gleichwertig sein:

SELECT
  /* Unique filtering condition - must be done in a subselect */
  (SELECT SUM(number) FROM `table` WHERE `somecolumn` = `somevalue`) AS number_sum,
  MAX(number) AS number_max,
  MIN(number) AS number_min
FROM `table`

Oder äquivalent zur obigen Abfrage können Sie LEFT JOIN gegen eine Unterabfrage ohne ON Klausel . Dies sollte nur in Situationen erfolgen, in denen Sie wissen, dass die Unterabfrage nur eine Zeile zurückgibt. Andernfalls erhalten Sie ein kartesisches Produkt – so viele Zeilen, wie von einer Seite des Joins multipliziert mit zurückgegeben werden die Anzahl der von der anderen Seite zurückgegebenen Zeilen.

Dies ist praktisch, wenn Sie einige Spalten mit einem Satz von WHERE zurückgeben müssen Klauselbedingungen und ein paar Spalten mit einem anderen Satz von WHERE Bedingungen, aber nur eine Reihe von jeder Seite des JOIN . In diesem Fall sollte JOIN schneller sein als zwei zu tun Unterauswahlen mit demselben WHERE Klausel.

Das sollte schneller gehen....

SELECT
  /* this one has two aggregates sharing a WHERE condition */
  subq.number_sum_filtered,
  subq.number_max_filtered,
  /* ...and two aggregates on the main table with no WHERE clause filtering */
  MAX(`table`.number) AS number_max,
  MIN(`table`.number) AS number_min
FROM
  `table`
  LEFT JOIN (
    SELECT 
       SUM(number) AS number_sum_filtered,
       MAX(number) AS number_max_filtered
    FROM `table`
    WHERE `somecolumn = `somevalue`
  ) subq /* No ON clause here since there's no common column to join on... */

Als das...

SELECT
  /* Two different subselects each over the same filtered set */
  (SELECT SUM(number) FROM `table` WHERE `somecolumn` = `somevalue`) AS number_sum_filtered,
  (SELECT MAX(number) FROM `table` WHERE `somecolumn` = `somevalue`) AS number_max_filtered,
  MAX(`table`.number) AS number_max,
  MIN(`table`.number) AS number_min
FROM
  `table`