Mysql
 sql >> Database >  >> RDS >> Mysql

MySQL Multiple Subquery rispetto a intere query

Poiché questi tre aggregati provengono dalla stessa tabella con lo stesso WHERE condizioni, non sono necessarie selezioni secondarie. Tutti e tre gli aggregati operano sullo stesso raggruppamento di righe (nessun GROUP BY specificato, quindi una riga per l'intera tabella), in modo che possano esistere tutti in SELECT elenca direttamente.

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

Se uno qualsiasi degli aggregati deve essere basato su condizioni diverse, filtri in un WHERE clausola, quindi sarà necessario utilizzare una sottoselezione per la condizione diversa o eseguire un join cartesiano. Questa sottoselezione e il seguente LEFT JOIN il metodo dovrebbe essere equivalente, in termini di prestazioni per gli aggregati che restituiscono una sola riga:

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`

O equivalente alla query precedente, puoi LEFT JOIN contro una sottoquery senza ON clausola . Questo dovrebbe essere fatto solo in situazioni in cui sai che la sottoquery restituirà solo una riga. Altrimenti, ti ritroverai con un prodotto cartesiano -- tante righe quante sono restituite da un lato del join moltiplicato per il numero di righe restituite dall'altro lato.

Questo è utile se devi restituire alcune colonne con un set di WHERE condizioni della clausola e alcune colonne con un diverso insieme di WHERE condizioni, ma solo uno riga da ciascun lato di JOIN . In questo caso, dovrebbe essere più veloce JOIN piuttosto che farne due sottoseleziona con lo stesso WHERE clausola.

Dovrebbe essere più veloce....

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... */

Allora...

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`