Столбцы в строки за одно сканирование и один запрос

С примером таблицы (> 20 миллионов строк) следующим образом:

CREATE TABLE T (
  D DATE,
  V INT
);

INSERT INTO T VALUES ('2024-07-01', 1), ('2024-07-02', 2), ('2024-07-02', 3);

У меня есть существующий запрос, который занимает около 5 секунд:

SELECT D, 'SUM', SUM(V)
FROM T
GROUP BY D
UNION
SELECT D, 'AVG', AVG(V)
FROM T
GROUP BY D
ORDER BY 1;

И необходимый вывод:

Столбец А Столбец Б Столбец Б 2024-07-01 СУММА 1.0 2024-07-01 AVG 1.0 2024-07-02 СУММА 5.0 2024-07-02 AVG 2,5

Чтобы избежать многократного сканирования, я переписываю так (около 1 с):

SELECT D, SUM(V), AVG(V)
FROM T
GROUP BY D;

Мне нужно сохранить вывод, я могу сделать это только в одном запросе, поэтому я попробовал общее табличное выражение:

WITH CTE AS (
  SELECT D, SUM(V) AS S, AVG(V) AS A
  FROM T
  GROUP BY D
)
SELECT D, 'SUM', S
FROM CTE
UNION
SELECT D, 'AVG', A
FROM CTE
ORDER BY 1;

Но таблица по-прежнему сканируется дважды, а запрос все еще выполняется в течение 5 секунд:

select_type стол НАЧАЛЬНЫЙ < производное2> ПОЛУЧЕННЫЙ Т СОЮЗ <производное4> ПОЛУЧЕННЫЙ Т РЕЗУЛЬТАТ СОЮЗА <объединение1,3>

Есть ли возможность сделать это одним запросом и только одним сканированием?

Обновлено:

Нашел решение с помощью json, но оно мне не нравится:

WITH CTE AS (
    SELECT D, JSON_ARRAY(SUM(V), AVG(V)) AS data
    FROM T
    GROUP BY D
)
SELECT
  c.D,
  CASE WHEN JT.Id = 1 THEN 'SUM'
       WHEN JT.Id = 2 THEN 'AVG'
  END AS F,
  JT.N
FROM CTE c,
JSON_TABLE(c.data, '$[*]'
  COLUMNS(
    Id for ordinality,
    N FLOAT PATH '$[0]'
  )
) AS JT;

У вас есть индекс на дату? Пожалуйста, добавьте план объяснения для обоих запросов.

P.Salmon 03.07.2024 16:06

@P.Salmon Этот запрос является примером. Реальный запрос более сложный, и индекс в порядке.

yotheguitou 03.07.2024 16:15

Вы используете MySQL или MariaDB? Вы отметили оба в своем вопросе, но это разные продукты, и они все более несовместимы друг с другом. Пожалуйста, поставьте SELECT VERSION(); и добавьте результат в свой пост.

Bill Karwin 03.07.2024 16:21

@BillKarwin mariadb 10.6.18

yotheguitou 03.07.2024 16:24

вы пробовали подзапрос вместо cte? если это не сработает, возможно, подзапрос с дополнительным уровнем вложенности?

ysth 03.07.2024 16:30

@ysth Нет, я не понимаю, как это сделать

yotheguitou 03.07.2024 16:32

Если вы видите, что ваш базовый запрос увеличился с 5 до 1 с удалением объединения, вы, вероятно, увидите некоторое улучшение, просто изменив union на union all. по умолчанию объединение имеет значение union distinct, что может снизить производительность

ysth 03.07.2024 16:33

@ysth На самом деле у меня 5 UNION, и каждый занимает 1 секунду. Я хочу избежать многократного сканирования большой таблицы. UNION ALL не помогает

yotheguitou 03.07.2024 16:38
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
0
8
52
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я бы использовал для этого подзапрос:

select D, rowtype, case rowtype when 'SUM' then sum_v else avg_v end value
from (
    select D, sum(V) sum_v, avg(V) avg_v
    from T
    group by D
) sum_or_avg
join (select 'SUM' rowtype union all select 'AVG') rowtype
order by D, rowtype desc

Другие вопросы по теме