Почему postgres не повторно использует результаты подзапроса при запросе формы `A UNION A`? - PullRequest
2 голосов
/ 28 мая 2019

Скажем, у нас есть следующая схема БД Postgres:

CREATE TABLE users
(
  id serial PRIMARY KEY,
  name text,
  birthdate date NOT NULL
);

INSERT INTO users (id, name, birthdate) VALUES
(1, 'Joe', '2018-01-01'),
(2, 'Robert', '2017-01-02'),
(3, 'Mike', '1997-03-01');

И мы выполняем запрос, подобный этому:

(SELECT * FROM users) UNION (SELECT * FROM users)

Ссылка на SQLfiddle с этим примером

тогда EXPLAIN результаты, которые мы получаем следующим образом :

                    HashAggregate  (cost=86.00..110.00 rows=2400 width=40)
                      Group Key: users.id, users.name, users.birthdate
                      ->  Append  (cost=0.00..68.00 rows=2400 width=40)
                            ->  Seq Scan on users  (cost=0.00..22.00 rows=1200 width=40)
                            ->  Seq Scan on users users_1  (cost=0.00..22.00 rows=1200 width=40)

Кажется, что Postgres выполняет два последовательных сканирования таблицы users, добавляярезультаты и отбрасывание дубликатов.

Есть ли причина, по которой Postgres не понимает, что этот запрос может быть упрощен до SELECT * FROM users?


Данный пример, конечно, супер-просто, и если подобные запросы написаны от руки, мы можем понять, что можем оптимизировать их.Но в реальном проекте, над которым я работаю, у нас есть запросы, сгенерированные из набора объектов «правил»: некоторые из подзапросов в правилах зависят от времени (A: «пользователь присоединился менее чем за X дней»назад '), но многие нет (B: «пользователь-женщина»).

При объединении этих правил для просмотра, например, результатов за последние три дня, мы имеем что-то вроде (A UNION B) UNION (A' UNION B) UNION (A'' UNION B), которое можно упроститьна A UNION A' UNION A''' UNION B, но в настоящее время не похоже, что Postgres делает это.

И связанные с этим, многие из этих подзапросов выполняют одинаковые ВНУТРЕННИЕ СОЕДИНЕНИЯ с другими таблицами, но кажется, что все эти таблицыповторяется также в каждом из подзапросов.

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

...