powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / LEFT OUTER JOIN не использует индекс
15 сообщений из 15, страница 1 из 1
LEFT OUTER JOIN не использует индекс
    #39128866
bemtaill
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Добрый день,

Подскажите, почему так - есть 2 таблицы c несколькими тысячами записей и индексом:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
CREATE TABLE A (NAMES JSONB);
CREATE TABLE B (NAME JSONB);

-- INSERT SOME TEST DATA
DO $$
BEGIN
FOR i IN 0..1000 LOOP
    INSERT INTO A VALUES (TO_JSON(ARRAY['X'||i, 'Y'||i]::VARCHAR[])::JSONB);
    INSERT INTO B VALUES (TO_JSON(ARRAY['X'||i]::VARCHAR[])::JSONB);
    INSERT INTO B VALUES (TO_JSON(ARRAY['Y'||i]::VARCHAR[])::JSONB);
END LOOP;
END;
$$;

CREATE INDEX ON A USING GIN (NAMES);



После этого немного тюнинга и апдэйт статистики:
Код: plsql
1.
2.
3.
SET enable_seqscan = off;
SET enable_nestloop = off;
VACUUM ANALYZE;



И делаю идентичные запросы с разницой INNER JOIN vs LEFT OUTER LOIN:
Код: plsql
1.
2.
3.
EXPLAIN ANALYZE
SELECT * FROM A
 JOIN B ON (A.NAMES @> B.NAME)


'Nested Loop (cost=20000000000.04..20000008170.60 rows=2004 width=32) (actual time=0.079..25.214 rows=2002 loops=1)'
' -> Seq Scan on b (cost=10000000000.00..10000000042.02 rows=2002 width=12) (actual time=0.031..0.663 rows=2002 loops=1)'
' -> Bitmap Heap Scan on a (cost=0.04..4.05 rows=1 width=20) (actual time=0.010..0.010 rows=1 loops=2002)'
' Recheck Cond: (names @> b.name)'
' Heap Blocks: exact=2002'
' -> Bitmap Index Scan on a_names_idx1 (cost=0.00..0.04 rows=1 width=0) (actual time=0.006..0.006 rows=1 loops=2002)'
' Index Cond: (names @> b.name)'
'Planning time: 0.196 ms'
'Execution time: 25.583 ms'


и
Код: plsql
1.
2.
3.
EXPLAIN ANALYZE
SELECT * FROM A
 LEFT OUTER JOIN B ON (A.NAMES @> B.NAME)


'Nested Loop Left Join (cost=30000000000.00..30000030134.07 rows=2004 width=32) (actual time=0.077..1793.021 rows=2002 loops=1)'
' Join Filter: (a.names @> b.name)'
' Rows Removed by Join Filter: 2002000'
' -> Seq Scan on a (cost=10000000000.00..10000000027.01 rows=1001 width=20) (actual time=0.033..0.439 rows=1001 loops=1)'
' -> Materialize (cost=10000000000.00..10000000052.03 rows=2002 width=12) (actual time=0.000..0.226 rows=2002 loops=1001)'
' -> Seq Scan on b (cost=10000000000.00..10000000042.02 rows=2002 width=12) (actual time=0.024..0.378 rows=2002 loops=1)'
'Planning time: 0.156 ms'
'Execution time: 1793.319 ms'


В обоих случаях результат 2002 записей, но из-за того что LEFT OUTER JOIN не использует индекс запрос выполняется в тысячу раз медленнее. Подскажите как побороть? И почему планировщик не пользует индекс когда он есть?
...
Рейтинг: 0 / 0
LEFT OUTER JOIN не использует индекс
    #39128879
Фотография vyegorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
bemtaill,

Потому что внешняя связка "склоняет" планировщик к единственному варианту исполнения запроса:
When the query involves outer joins, the planner has less freedom than it does for plain (inner) joins.
Сравните таблицы во внешней и внутренней частях обеих связок, а также значения `loops`.
...
Рейтинг: 0 / 0
LEFT OUTER JOIN не использует индекс
    #39128903
bemtaill
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
vyegorovbemtaill,

Потому что внешняя связка "склоняет" планировщик к единственному варианту исполнения запроса:
When the query involves outer joins, the planner has less freedom than it does for plain (inner) joins.
...

Там вроде про порядок в котором таблицы джойнятся, а у меня только 2 таблицы. Идея в том что мне необходим быстрый LEFT OUTER JOIN, так как на самом деле таблица a может содержать names=null и мне надо получить все записи из a независимо от записей в b . Это вообще реально?:)
...
Рейтинг: 0 / 0
LEFT OUTER JOIN не использует индекс
    #39128926
Фотография Щукина Анна
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
bemtaill,

Тут если бы и помог индекс, то только при условии того, что он построен по таблице B.
Таблица A без условий фильтрации по ней в любом случае будет читаться полностью, так как наличия ВСЕХ записей из неё требует тот факт, что она является ГЛАВНОЙ таблицей в левом соединении.
...
Рейтинг: 0 / 0
LEFT OUTER JOIN не использует индекс
    #39128940
p2.
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
bemtaill,

что за выёживание, хранить в таблицах неструктурированные данные и колоться, но продолжать упорно лезть на structured query language.
...
Рейтинг: 0 / 0
LEFT OUTER JOIN не использует индекс
    #39129004
bemtaill
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
p2.,
это жизнь:) рефакторинг выливается в довольно "дорогостоющую" процедуру, поэтому пока пытаемся решить вопрос по другому с тем чтобы в след году сделать по "правильному".


Щукина Анна,
В реальном запросе есть фильтр на A который отсеивает ~ половину строк из А, все равно медленно. Индекс в B тоже не помогает.

vyegorov,
Я кажется понял, что вы имели ввиду: при INNER JOIN пранеровщик присоединяет А к В, тогда как при LEFT JOIN он не имеет такой возможности и вынужден присоединять В к А.


Попробовал увеличить количество записей в таблицах, проапдейтить статистику, не помогло.
...
Рейтинг: 0 / 0
LEFT OUTER JOIN не использует индекс
    #39129005
bemtaill
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
bemtaillВ реальном запросе есть фильтр на A который отсеивает ~ половину строк из А, все равно медленно...
И план тот же самый.
...
Рейтинг: 0 / 0
LEFT OUTER JOIN не использует индекс
    #39129021
Lonepsycho
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
bemtaillvyegorovbemtaill,

Потому что внешняя связка "склоняет" планировщик к единственному варианту исполнения запроса:
пропущено...

...

Там вроде про порядок в котором таблицы джойнятся, а у меня только 2 таблицы. Идея в том что мне необходим быстрый LEFT OUTER JOIN, так как на самом деле таблица a может содержать names=null и мне надо получить все записи из a независимо от записей в b . Это вообще реально?:)
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
SELECT 
  a.*
FROM 
  a INNER JOIN b 
  (a.names @> b.name) AND
  a.something IS NOT NULL

UNION ALL

SELECT
  a.*
FROM
  a
WHERE
  a.something IS NULL


не?
...
Рейтинг: 0 / 0
LEFT OUTER JOIN не использует индекс
    #39129223
Фотография vyegorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Lonepsycho
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
SELECT 
  a.*
FROM 
  a INNER JOIN b 
  (a.names @> b.name) AND
  a.something IS NOT NULL

UNION ALL

SELECT
  a.*
FROM
  a
WHERE
  a.something IS NULL


Вторая часть должна выбирать всё из `a`, что не содержится в `b`:
Код: sql
1.
2.
3.
4.
5.
6.
SELECT a.*
  FROM a JOIN b ON a.names @> b.name
UNION ALL
SELECT a.*
  FROM a
 WHERE NOT EXISTS (SELECT 1 FROM b WHERE a.names @> b.name);
...
Рейтинг: 0 / 0
LEFT OUTER JOIN не использует индекс
    #39129352
Ivan Durak
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А этот мега хинт зачем????
авторSET enable_nestloop = off;
...
Рейтинг: 0 / 0
LEFT OUTER JOIN не использует индекс
    #39129355
Ivan Durak
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Щукина Аннаbemtaill,

Тут если бы и помог индекс, то только при условии того, что он построен по таблице B.
Таблица A без условий фильтрации по ней в любом случае будет читаться полностью, так как наличия ВСЕХ записей из неё требует тот факт, что она является ГЛАВНОЙ таблицей в левом соединении.
кстати давно пора ПГ допилить напильником. У (некоторых) конкурентов есть возможность в NL left join делать главной любую таблицу.
...
Рейтинг: 0 / 0
LEFT OUTER JOIN не использует индекс
    #39129695
bemtaill
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Спасибо всем за помощь, разобрался )
...
Рейтинг: 0 / 0
LEFT OUTER JOIN не использует индекс
    #39131462
p2.
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ivan DurakУ (некоторых) конкурентов есть возможность в NL left join делать главной любую таблицу.пример планов можешь привести?
...
Рейтинг: 0 / 0
LEFT OUTER JOIN не использует индекс
    #39131479
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
p2.Ivan DurakУ (некоторых) конкурентов есть возможность в NL left join делать главной любую таблицу.пример планов можешь привести?

Очень сомневаюсь что так физически возможно (для merge/hash join дело другое но вот nestloop LJ с ведущей таблицей на стороне LJ у меня как то ну совсем не вырисовывается алгоритм).

--
Maxim Boguk
www.postgresql-consulting.ru
...
Рейтинг: 0 / 0
LEFT OUTER JOIN не использует индекс
    #39131680
Ivan Durak
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maxim Bogukp2.пропущено...
пример планов можешь привести?

Очень сомневаюсь что так физически возможно (для merge/hash join дело другое но вот nestloop LJ с ведущей таблицей на стороне LJ у меня как то ну совсем не вырисовывается алгоритм).

--
Maxim Boguk
www.postgresql-consulting.ru
согласен, прогнал. То было про HJ.
...
Рейтинг: 0 / 0
15 сообщений из 15, страница 1 из 1
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / LEFT OUTER JOIN не использует индекс
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]