2015-06-26 3 views
0

У меня есть запрос, как это:Postgres оставил присоединение 3 таблицы с условием

SELECT x.id 
FROM x 
    LEFT JOIN (
     SELECT a.id FROM a 
     WHERE [condition1] [condition2] 
    ) AS A USING (id) 
    LEFT JOIN (
     SELECT b.id FROM b 
     WHERE [condition1] [condition3] 
    ) AS B USING (id) 
    LEFT JOIN (
     SELECT c.id FROM c 
     WHERE [condition1] [condition4] 
    ) AS C USING (id) 
    WHERE [condition1] 

Как вы можете видеть [condition1] является общим для подзапросов и внешнего запроса.

Когда [в целом] может быть целесообразно удалить [condition1] из подзапросов (в результате это же) по соображениям производительности? Пожалуйста, не давайте ответов, как «запустите его и посмотрите». Есть много данных и их изменение, поэтому нам нужно хорошее худшее поведение.

Я попытался сделать некоторые тесты, но они далеки от окончательного. Будет ли Postgres выяснять, что условие применяется к подзапросам и распространяет его?

Примеры condition1:

  • WHERE a.id NOT IN (SELECT id FROM {ft_geom_in}) (это медленно, я знаю, это только для примера)
  • WHERE a.id > x
+0

'EXPLAIN' Некоторые запросы по меньшей схеме должны быть информативными. Это будет зависеть от того, что вы надеялись найти во внешнем запросе и о том, какие индексы могут помочь. В общем, я подозреваю, что выполнение условия только в подзапросах левого соединения будет лучше, если нет соответствующих индексов, но может быть менее полезным, если есть индексы с возможностью использования. –

ответ

0

Трудно дать ясный общий ответ, т.к. многое зависит от фактической модели данных (особенно индексов) и запросов (условий). Однако во многих случаях имеет смысл разместить condition1 в объединенных подзапросах. Это относится, в частности, когда condition2 исключает гораздо меньше строк, чем condition1. В таких случаях фильтр на condition1 может значительно уменьшить количество проверок condition2.

С другой стороны, маловероятно, что наличие в подзапросах condition1 может существенно замедлить запрос.

Простые тесты не дают общих ответов, но могут служить иллюстрацией.

create table x (id integer, something text); 
create table a (id integer, something text); 

insert into x select i, i::text from generate_series (1, 1000000) i; 
insert into a select i, i::text from generate_series (1, 1000000) i; 

Запрос A: condition2 исключает несколько строк.

А1: с condition1

explain analyse 
select x.id 
from x 
    left join (
     select id from a 
     where id < 500000 and length(something) > 1 
    ) as a using (id) 
where id < 500000; 

Average execution time: ~620.000 ms 

A2: без condition1

explain analyse 
select x.id 
from x 
    left join (
     select id from a 
     where length(something) > 1 
    ) as a using (id) 
where id < 500000; 

Average execution time: ~810.000 ms 

Запрос B: condition2 исключает большое количество строк.

B1: с condition1

explain analyse 
select x.id 
from x 
    left join (
     select id from a 
     where id < 500000 and length(something) = 1 
    ) as a using (id) 
where id < 500000; 

Average execution time: ~220.000 ms 

B2: без condition1

explain analyse 
select x.id 
from x 
    left join (
     select id from a 
     where length(something) = 1 
    ) as a using (id) 
where id < 500000; 

Average execution time: ~230.000 ms 

Обратите внимание, что запросы не должны иметь подзапросов.Запросы с простыми левыми соединениями и условиями в общем where clause должны быть немного быстрее. Например, это эквивалент запроса B1:

explain analyse 
select x.id 
    from x 
    left join a using(id) 
    where x.id < 500000 
    and a.id < 500000 
    and length(a.something) = 1 

Average execution time: ~210.000 ms 
+0

Спасибо за подробный ответ. Как вы сказали, это действительно зависит от распределения данных, возможно, ваш ответ не может быть улучшен, не задумываясь о том, как работает планировщик запросов – iggy

Смежные вопросы