Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Várias subconsultas do MySQL versus consultas inteiras


Como esses três agregados vêm da mesma tabela com o mesmo WHERE condições, você não precisa de subseleções. Todos os três agregados estão operando no mesmo agrupamento de linhas (sem GROUP BY especificado, então uma linha para toda a tabela), para que todos possam existir no SELECT lista diretamente.
SELECT
  SUM(number) AS number_sum,
  MAX(number) AS number_max,
  MIN(number) AS number_min
FROM `table`

Se algum dos agregados precisar ser baseado em condições diferentes, você filtrará em um WHERE cláusula, então você precisará usar uma subseleção para a condição diferente ou fazer uma junção cartesiana. Esta subseleção e o seguinte LEFT JOIN O método deve ser equivalente, em termos de desempenho, para agregações que retornam apenas uma linha:
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 equivalente à consulta acima, você pode LEFT JOIN contra uma subconsulta sem ON cláusula . Isso só deve ser feito em situações em que você sabe que a subconsulta retornará apenas uma linha. Caso contrário, você terá um produto cartesiano -- quantas linhas forem retornadas por um lado da junção multiplicado por o número de linhas retornadas pelo outro lado.

Isso é útil se você precisar retornar algumas colunas com um conjunto de WHERE condições da cláusula e algumas colunas com um conjunto diferente de WHERE condições, mas apenas uma linha de cada lado do JOIN . Nesse caso, deve ser mais rápido JOIN do que fazer dois subseleções com o mesmo WHERE cláusula.

Isso deve ser mais rápido....
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... */

Do que isso...
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`