sql >> Database >  >> RDS >> Mysql

MySQL Meerdere subquery's versus hele query's

Aangezien deze drie aggregaten uit dezelfde tabel komen met dezelfde WHERE voorwaarden, hebt u geen subselecties nodig. Alle drie de aggregaten werken op dezelfde rijgroepering (geen GROUP BY opgegeven, dus één rij voor de hele tabel), zodat ze allemaal kunnen bestaan ​​in de SELECT lijst direct.

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

Als een van de aggregaten op verschillende voorwaarden moet worden gebaseerd, filtert u in een WHERE clausule, dan moet u ofwel een subselect gebruiken voor de verschillende voorwaarde, of een cartesische join uitvoeren. Deze subselectie en de volgende LEFT JOIN methode moet qua prestaties gelijkwaardig zijn voor aggregaten die slechts één rij retourneren:

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`

Of gelijkwaardig aan de bovenstaande zoekopdracht, u kunt LEFT JOIN tegen een subquery zonder ON clausule . Dit moet alleen worden gedaan in situaties waarin u weet dat de subquery slechts één rij retourneert. Anders krijg je een cartesiaans product -- zoveel rijen als geretourneerd met één zijde van de join vermenigvuldigd met het aantal rijen dat door de andere kant wordt geretourneerd.

Dit is handig als u een paar kolommen moet retourneren met één set WHERE clausulevoorwaarden en een paar kolommen met een andere set van WHERE voorwaarden, maar slechts één rij vanaf elke kant van de JOIN . In dit geval zou het sneller moeten zijn om JOIN dan om twee te doen subselecteert met dezelfde WHERE clausule.

Dit zou sneller moeten zijn....

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

Dan dit...

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`



  1. Hoe de bindValue-methode toe te passen in de LIMIT-clausule?

  2. Beperkte PostgreSQL-machtigingen voor webapp

  3. Hoe migratie (schema en gegevens) voor PHP/MySQL-toepassing te automatiseren

  4. Postgresql truncate-tabel met externe sleutelbeperking