Мультиколоночный подзапрос в select или иной способ предвыборки тяжелого агрегата
Есть 2 таблицы связанные один-ко-многим.
CREATE TABLE main (
id INTEGER,
filter_c TEXT
);
INSERT INTO main (id, filter_c) VALUES
(1, 'data1'),
(2, 'data2');
CREATE TABLE feature (
main_id INTEGER,
mark_c TEXT
);
INSERT INTO feature (main_id, mark_c) VALUES
(1, 'mark1'),
(1, 'mark1'),
(1, 'mark2'),
(1, null);
Нужные индексы прописаны. Размер таблиц 7к и 2м соответственно. Ожидается рост в 3-4 раза. Тяжелый агрегат связан с получением статистики:
SELECT main_id, sum(amount) as total, mark_c as best, max(marked) as goods, sum(marked) - max(marked) as bads
FROM (
SELECT main_id, mark_c,
count(*) as amount, --включая Null
count(mark_c) as marked --исключая Null
FROM feature
GROUP BY main_id, mark_c
)
GROUP BY main_id
Время выполнения по всей таблице ~7 секунд. Но такое практически никогда не нужно. Из main
будет отфильтровываться до 10 записей, по которым нужно получить статистику. Ожидаемый способ ее получения
SELECT id, filter_c,
(SELECT main_id, sum(amount) as total, mark_c as best, max(marked) as goods, sum(marked) - max(marked) as bads
FROM (
SELECT main_id, mark_c,
count(*) as amount, --включая Null
count(mark_c) as marked --исключая Null
FROM feature
WHERE main_id = id --ПРЕФИЛЬТР
GROUP BY main_id, mark_c
)
GROUP BY main_id)
FROM main
WHERE filter_c = 'data1'
Но нельзя возвращать несколько полей в таком подзапросе. Какие еще есть способы собрать статистику только для нужных записей?
Ответы (1 шт):
Автор решения: ValNik
→ Ссылка
Можно попробовать так
SELECT main_id, sum(amount) as total, mark_c as best,
max(marked) as goods,
sum(marked) - max(marked) as bads
FROM (
SELECT main_id, mark_c,
count(*) as amount, --включая Null
count(mark_c) as marked --исключая Null
FROM feature
where main_id in (select id from main where WHERE filter_c = 'data1')
GROUP BY main_id, mark_c
)
GROUP BY main_id
Если есть индекс в таблице feature по (main_id,mark_c) должно работать хорошо.