SQL, вычисление суммы двух столбцов A, B на основе значения (флага) в столбце C, производительность - PullRequest
0 голосов
/ 12 марта 2019

Допустим, у вас есть таблица Table1 со следующими столбцами: | A | B | C | D | и вам нужно получить следующий набор результатов через SELECT and GROUP BY D statement

| X1 | X2 | X3 | X4 | X5 | X6 |

, где эти столбцы определены как:

X1 = sum(A) if C = 0 OR 12
X2 = sum(B) if C = 0 OR 12 
X3 = sum(A) if C = 2 
X4 = sum(B) if C = 2
X5 = sum(A) if C = 1
X6 = sum(B) if C = 1

Значения для столбца C взяты из 0, 1, 2, 3, ..., 12.
Один из подходов заключается в использовании subquery для каждого вычисления, такого как:

SELECT
    (
      SELECT COALESCE(SUM(A), 0.00)
      FROM Table1
      WHERE C = 0 OR C = 12
    ) AS 'X1',
    (
      SELECT COALESCE(SUM(B), 0.00)
      FROM Table1
      WHERE C = 0 OR C = 12
    ) AS 'X2',
    (
      SELECT COALESCE(SUM(A), 0.00)
      FROM Table1
      WHERE C = 2
    ) AS 'X3',
    (
      SELECT COALESCE(SUM(B), 0.00)
      FROM Table1
      WHERE C = 2
    ) AS 'X4',
    (
      SELECT  COALESCE(SUM(A), 0.00)
      FROM Table1
      WHERE C = 1
    ) AS 'X5',
    (
      SELECT COALESCE(SUM(B), 0.00)
      FROM Table1
      WHERE C = 1
    ) AS 'X6'
FROM Table 1
WHERE C IN (0, 1, 2, 12)
GROUP BY D

Производительность мудрая, мне кажется грубой силой. Вероятно, то же самое можно преобразовать, используя CASE вместо subqueries, но я сомневаюсь, что это повлияет на производительность в позитивном ключе? или это должно? Любой другой / лучший подход (ы) на уме? Как общий вопрос, как количество подзапросов влияет на производительность?

Ответы [ 2 ]

2 голосов
/ 12 марта 2019

Использовать условное агрегирование:

select d,
       sum(case when c in (0, 12) then a else 0 end) as x1,
       sum(case when c in (0, 12) then b else 0 end) as x2, 
       sum(case when c = 2 then a else 0 end) as x3,
       . . .
from t
group by d;

Это определенно должно быть быстрее, чем подзапросы.

1 голос
/ 12 марта 2019

Гордон избил меня до ответа.Это можно сделать с помощью стандартного SQL.

SQL Fiddle

Настройка схемы MySQL 5.6 :

CREATE TABLE t1 (a int, b int, c int, d int) ; 

INSERT INTO t1 (a,b,c,d)
SELECT 1,1,0,10 UNION ALL
SELECT 1,1,0,10 UNION ALL
SELECT 1,1,0,20 UNION ALL
SELECT 1,1,0,20 UNION ALL
SELECT 1,1,1,10 UNION ALL
SELECT 1,1,1,20 UNION ALL
SELECT 1,1,2,10 UNION ALL
SELECT 1,1,2,30 UNION ALL
SELECT 1,1,3,10 UNION ALL
SELECT 1,1,5,10 UNION ALL
SELECT 1,1,12,10 UNION ALL
SELECT 1,1,5,10 UNION ALL
SELECT 1,1,5,10 UNION ALL
SELECT 1,1,5,20 UNION ALL
SELECT 1,1,5,20

Запрос 1 :

SELECT d
    , sum(CASE WHEN c IN (0,12) THEN a ELSE 0 END) AS x1 
    , sum(CASE WHEN c IN (0,12) THEN b ELSE 0 END) AS x2
    , sum(CASE WHEN c = 2 THEN a ELSE 0 END) AS x3
    , sum(CASE WHEN c = 2 THEN b ELSE 0 END) AS x4
    , sum(CASE WHEN c = 1 THEN a ELSE 0 END) AS x5
    , sum(CASE WHEN c = 1 THEN b ELSE 0 END) AS x6
FROM t1
WHERE c IN (0,1,2,12)
GROUP BY d

Результаты :

|  d | x1 | x2 | x3 | x4 | x5 | x6 |
|----|----|----|----|----|----|----|
| 10 |  3 |  3 |  1 |  1 |  1 |  1 |
| 20 |  2 |  2 |  0 |  0 |  1 |  1 |
| 30 |  0 |  0 |  1 |  1 |  0 |  0 |

Если в c имеется много значений, которых нет в 0,1,2,12затем вы можете использовать WHERE, чтобы сократить результирующий набор, который вы будете агрегировать.В противном случае, вы можете удалить его.

...