Мультиколоночный подзапрос в 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) должно работать хорошо.

→ Ссылка