Mysql
 sql >> Base de données >  >> RDS >> Mysql

MySQL sous-requêtes multiples vs requêtes entières

Puisque ces trois agrégats proviennent de la même table avec le même WHERE conditions, vous n'avez pas besoin de sous-sélections. Les trois agrégats fonctionnent sur le même groupement de lignes (pas de GROUP BY spécifié, donc une ligne pour toute la table), afin qu'ils puissent tous exister dans le SELECT liste directement.

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

Si l'un des agrégats doit être basé sur des conditions différentes, vous filtrerez dans un WHERE clause, vous devrez soit utiliser une sous-sélection pour la condition différente, soit effectuer une jointure cartésienne. Cette sous-sélection et le LEFT JOIN suivant doit être équivalente, en termes de performances, pour les agrégats ne renvoyant qu'une seule ligne :

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`

Ou équivalent à la requête ci-dessus, vous pouvez LEFT JOIN contre une sous-requête sans ON clause . Cela ne doit être fait que dans les situations où vous savez que la sous-requête ne renverra qu'une seule ligne. Sinon, vous vous retrouverez avec un produit cartésien - autant de lignes renvoyées par un côté de la jointure multipliées par le nombre de lignes renvoyées par l'autre côté.

C'est pratique si vous devez renvoyer quelques colonnes avec un ensemble de WHERE conditions de clause et quelques colonnes avec un ensemble différent de WHERE conditions, mais seulement une ligne de chaque côté du JOIN . Dans ce cas, il devrait être plus rapide de JOIN que d'en faire deux sous-sélectionne avec le même WHERE clause.

Cela devrait être plus rapide....

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

Plus que ça...

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`