Join GitHub today
GitHub is home to over 50 million developers working together to host and review code, manage projects, and build software together.
Sign upБаг с некорректным выполнением UPDATE при использовании в where секционированной таблицы #110
Comments
Добрый день, @siv163 Спасибо за отзыв.
Да, скрипт был бы очень полезен для воспроизведения проблемы. |
VERSION "1.4" пишет постгрес, выкачивали версию от 31.07.2017 |
Создаю две таблицы: create table abc (id int not null, val int);
insert into abc values (1,1), (2,2);
create table test(id int not null);
select create_range_partitions('test', 'id', 1, 10, 10);
insert into test values (1); Смотрим, что получается: explain (analyze, costs off, timing off)
select * from abc where not exists (select from test where test.id = abc.id);
QUERY PLAN
---------------------------------------------------------------
Hash Anti Join (actual rows=1 loops=1)
Hash Cond: (abc.id = test_1.id)
-> Seq Scan on abc (actual rows=2 loops=1)
-> Hash (actual rows=1 loops=1)
Buckets: 32768 Batches: 1 Memory Usage: 257kB
-> Append (actual rows=1 loops=1)
-> Seq Scan on test_1 (actual rows=1 loops=1)
-> Seq Scan on test_2 (actual rows=0 loops=1)
-> Seq Scan on test_3 (actual rows=0 loops=1)
-> Seq Scan on test_4 (actual rows=0 loops=1)
-> Seq Scan on test_5 (actual rows=0 loops=1)
-> Seq Scan on test_6 (actual rows=0 loops=1)
-> Seq Scan on test_7 (actual rows=0 loops=1)
-> Seq Scan on test_8 (actual rows=0 loops=1)
-> Seq Scan on test_9 (actual rows=0 loops=1)
-> Seq Scan on test_10 (actual rows=0 loops=1)
Planning time: 0.282 ms
Execution time: 0.138 ms
(18 rows)
set enable_hashjoin = f;
explain (analyze, costs off, timing off)
select * from abc where not exists (select from test where test.id = abc.id);
QUERY PLAN
---------------------------------------------------------------
Merge Anti Join (actual rows=1 loops=1)
Merge Cond: (abc.id = test_1.id)
-> Sort (actual rows=2 loops=1)
Sort Key: abc.id
Sort Method: quicksort Memory: 25kB
-> Seq Scan on abc (actual rows=2 loops=1)
-> Sort (actual rows=1 loops=1)
Sort Key: test_1.id
Sort Method: quicksort Memory: 25kB
-> Append (actual rows=1 loops=1)
-> Seq Scan on test_1 (actual rows=1 loops=1)
-> Seq Scan on test_2 (actual rows=0 loops=1)
-> Seq Scan on test_3 (actual rows=0 loops=1)
-> Seq Scan on test_4 (actual rows=0 loops=1)
-> Seq Scan on test_5 (actual rows=0 loops=1)
-> Seq Scan on test_6 (actual rows=0 loops=1)
-> Seq Scan on test_7 (actual rows=0 loops=1)
-> Seq Scan on test_8 (actual rows=0 loops=1)
-> Seq Scan on test_9 (actual rows=0 loops=1)
-> Seq Scan on test_10 (actual rows=0 loops=1)
Planning time: 0.302 ms
Execution time: 0.096 ms
(22 rows)
set enable_mergejoin = f;
explain (analyze, costs off, timing off)
select * from abc where not exists (select from test where test.id = abc.id);
QUERY PLAN
-----------------------------------------------------------
Nested Loop Anti Join (actual rows=1 loops=1)
-> Seq Scan on abc (actual rows=2 loops=1)
-> Custom Scan (RuntimeAppend) (actual rows=0 loops=2)
Prune by: (test.id = abc.id)
-> Seq Scan on test_1 (actual rows=0 loops=2)
Filter: (id = abc.id)
Rows Removed by Filter: 0
Planning time: 0.566 ms
Execution time: 0.098 ms
(9 rows) Можно заметить, что во всех случаях SELECT был запланирован и выполнен правильно. Теперь попробуем сделать то же самое с UPDATE: explain (analyze, costs off, timing off)
update abc set val = 4 where not exists (select from test where test.id = abc.id);
QUERY PLAN
---------------------------------------------------------------------
Update on abc (actual rows=0 loops=1)
-> Hash Anti Join (actual rows=1 loops=1)
Hash Cond: (abc.id = test_1.id)
-> Seq Scan on abc (actual rows=2 loops=1)
-> Hash (actual rows=1 loops=1)
Buckets: 32768 Batches: 1 Memory Usage: 257kB
-> Append (actual rows=1 loops=1)
-> Seq Scan on test_1 (actual rows=1 loops=1)
-> Seq Scan on test_2 (actual rows=0 loops=1)
-> Seq Scan on test_3 (actual rows=0 loops=1)
-> Seq Scan on test_4 (actual rows=0 loops=1)
-> Seq Scan on test_5 (actual rows=0 loops=1)
-> Seq Scan on test_6 (actual rows=0 loops=1)
-> Seq Scan on test_7 (actual rows=0 loops=1)
-> Seq Scan on test_8 (actual rows=0 loops=1)
-> Seq Scan on test_9 (actual rows=0 loops=1)
-> Seq Scan on test_10 (actual rows=0 loops=1)
Planning time: 3.251 ms
Execution time: 0.546 ms
(19 rows)
select * from abc;
id | val
----+-----
1 | 1
2 | 4
(2 rows)
set enable_hashjoin = f;
explain (analyze, costs off, timing off)
update abc set val = 6 where not exists (select from test where test.id = abc.id);
QUERY PLAN
---------------------------------------------------------------------
Update on abc (actual rows=0 loops=1)
-> Merge Anti Join (actual rows=1 loops=1)
Merge Cond: (abc.id = test_1.id)
-> Sort (actual rows=2 loops=1)
Sort Key: abc.id
Sort Method: quicksort Memory: 25kB
-> Seq Scan on abc (actual rows=2 loops=1)
-> Sort (actual rows=1 loops=1)
Sort Key: test_1.id
Sort Method: quicksort Memory: 25kB
-> Append (actual rows=1 loops=1)
-> Seq Scan on test_1 (actual rows=1 loops=1)
-> Seq Scan on test_2 (actual rows=0 loops=1)
-> Seq Scan on test_3 (actual rows=0 loops=1)
-> Seq Scan on test_4 (actual rows=0 loops=1)
-> Seq Scan on test_5 (actual rows=0 loops=1)
-> Seq Scan on test_6 (actual rows=0 loops=1)
-> Seq Scan on test_7 (actual rows=0 loops=1)
-> Seq Scan on test_8 (actual rows=0 loops=1)
-> Seq Scan on test_9 (actual rows=0 loops=1)
-> Seq Scan on test_10 (actual rows=0 loops=1)
Planning time: 0.779 ms
Execution time: 0.290 ms
(23 rows)
select * from abc;
id | val
----+-----
1 | 1
2 | 6
(2 rows)
set enable_mergejoin = f;
explain (analyze, costs off, timing off)
update abc set val = 8 where not exists (select from test where test.id = abc.id);
QUERY PLAN
-----------------------------------------------------------------
Update on abc (actual rows=0 loops=1)
-> Nested Loop Anti Join (actual rows=1 loops=1)
-> Seq Scan on abc (actual rows=2 loops=1)
-> Custom Scan (RuntimeAppend) (actual rows=0 loops=2)
Prune by: (test.id = abc.id)
-> Seq Scan on test_1 (actual rows=0 loops=2)
Filter: (id = abc.id)
Rows Removed by Filter: 0
Planning time: 0.795 ms
Execution time: 0.210 ms
(10 rows)
select * from abc;
id | val
----+-----
1 | 1
2 | 8
(2 rows) |
В этот день мы не выпускали официального релиза. Вы используете |
я понимаю что не выпускали) я не нашел где посмотреть минорную версию, и решил уточнить дату выкачки. |
Это очень важно, потому что мы не поддерживаем Вы вольны использовать pg_pathman каким угодно образом, в том числе модифицировать код и т.д., но если вы ставите В промежуточных коммитах мы можем менять уйму вещей, и единственный способ обновиться с мастера - дропнуть pg_pathman и поставить его с нуля, за исключением случаев, когда мы явно заявляем об отсутствии проблем с совместмостью. При удалении расширения, например, ломается hash-партицирование (т.к. check constraints завязаны на функции pg_pathman и удаляются при удалении расширения), поэтому за этой проблемой ожидаемо следует проблема снятия бэкапов партицированных таблиц при помощи pg_dump.
Попробуйте выполнить функцию |
Более того, мы не обновляем патч-версию каждый коммит, поэтому не факт, что ваша версия отражает суть. |
Если вы хотите ставить именно стабильные релизы, крайне советую взглянуть на PGXN. У них есть клиент для установки обновлений. |
Спасибо большое, будем разбираться. |
Я могу вас немного утешить) Я более чем уверен, что если вы соберете 1.4.2 со страницы релизов, то никаких проблем при эксплуатации и обновлении у вас не возникнет, а вы при этом получите последнюю стабильную версию. Вам не потребуется делать drop extension, просто установите новую версию библиотеки и перезапустите кластер. |
Если у вас останутся проблемы с запросами, прикладывайте explain analyze, примерную схему таблиц, либо тестовый скрипт. Жду подтверждения решения проблемы. |
drop table if exists entity;
CREATE TABLE entity
(
id integer,
active smallint
);
insert into entity (id, active)
select v.id,
v.active
from (values
(13533565,3),
(14227974,3),
(14227975,3),
(14230556,3),
(14230557,3)) v(id, active);
drop table if exists log cascade;
CREATE TABLE log
(
date timestamp without time zone NOT NULL,
entity_id integer
);
insert into log (date, entity_id)
select v.date::timestamp,
v.entity_id
from (values
('2017-02-16 09:52:40',13533565),
('2017-07-25 08:43:06',14227974),
('2017-07-25 08:43:06',14227975),
('2017-08-07 08:11:42',14230556),
('2017-08-07 08:20:27',14230557)) v(date, entity_id);
SELECT create_range_partitions('public.log', 'date', '2017-01-01 00:00:00'::timestamp,
'1 month'::interval, null, true);
select count(*) from log;
select count(*) from only log;
-- что должно обновиться
select e.id
from entity e
where active <> 4
and not exists (select null
from log l
where l.entity_id = e.id
and l.date > '2017-07-25 10:24:24.327106+00');
-- что обновилось по факту
begin;
with cte as
(update entity e
set active = 4
where e.active <> 4
and not exists (select null
from log l
where l.entity_id = e.id
and l.date > '2017-07-25 10:24:24.327106+00')
returning id)
select *
from cte -- у меня обновляются: последние 2 не должны попадать |
Вот что я вижу у себя: select e.id
from entity e
where active <> 4 and
not exists (select null
from log l
where l.entity_id = e.id and
l.date > (now() - make_interval(days := 14)));
id
----------
13533565
14227974
14227975
(3 rows)
with cte as (
update entity e
set active = 4
where e.active <> 4 and
not exists (select null
from log l
where l.entity_id = e.id and
l.date > (now() - make_interval(days := 14)))
returning id)
select * from cte;
id
----------
13533565
14227974
14227975
(3 rows) Какую версию PostgreSQL вы используете? |
Пожалуйста, покажите ваш explain analyze для UPDATE: explain (analyze, costs off, timing off)
with cte as (
update entity e
set active = 4
where e.active <> 4 and
not exists (select null
from log l
where l.entity_id = e.id and
l.date > (now() - make_interval(days := 14)))
returning id)
select * from cte;
QUERY PLAN
----------------------------------------------------------------------------------
CTE Scan on cte (actual rows=3 loops=1)
CTE cte
-> Update on entity e (actual rows=3 loops=1)
-> Hash Anti Join (actual rows=3 loops=1)
Hash Cond: (e.id = l.entity_id)
-> Seq Scan on entity e (actual rows=5 loops=1)
Filter: (active <> 4)
-> Hash (actual rows=2 loops=1)
Buckets: 8192 Batches: 1 Memory Usage: 65kB
-> Append (actual rows=2 loops=1)
-> Seq Scan on log_1 l (actual rows=0 loops=1)
Filter: (date > (now() - '14 days'::interval))
-> Seq Scan on log_2 l_1 (actual rows=0 loops=1)
Filter: (date > (now() - '14 days'::interval))
Rows Removed by Filter: 1
-> Seq Scan on log_3 l_2 (actual rows=0 loops=1)
Filter: (date > (now() - '14 days'::interval))
-> Seq Scan on log_4 l_3 (actual rows=0 loops=1)
Filter: (date > (now() - '14 days'::interval))
-> Seq Scan on log_5 l_4 (actual rows=0 loops=1)
Filter: (date > (now() - '14 days'::interval))
-> Seq Scan on log_6 l_5 (actual rows=0 loops=1)
Filter: (date > (now() - '14 days'::interval))
-> Seq Scan on log_7 l_6 (actual rows=0 loops=1)
Filter: (date > (now() - '14 days'::interval))
Rows Removed by Filter: 2
-> Seq Scan on log_8 l_7 (actual rows=2 loops=1)
Filter: (date > (now() - '14 days'::interval))
Planning time: 1.607 ms
Execution time: 0.535 ms
(30 rows) |
QUERY PLAN
CTE Scan on cte (actual rows=5 loops=1)
CTE cte
-> Update on entity e (actual rows=5 loops=1)
-> Hash Anti Join (actual rows=5 loops=1)
Hash Cond: (e.id = l.entity_id)
-> Seq Scan on entity e (actual rows=5 loops=1)
Filter: (active <> 4)
-> Hash (actual rows=0 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 8kB
-> Seq Scan on log l (actual rows=0 loops=1)
Filter: (date > (now() - 14 days::interval))
Planning time: 0.108 ms
Execution time: 0.062 ms |
И все-таки, какую версию PostgreSQL вы используете? |
select version(); |
Извините, пропустил ваш вопрос |
Хорошо, у вас есть две возможности:
|
давайте посмотрим как я вам смогу помочь с тестированием. |
Добрый день, @siv163 Извините за ожидание. Я подготовил ветку |
Мы решили отключить некоторые опасные оптимизации для UPDATE и DELETE, если расширение установлено на PostgreSQL 9.5. |
Спасибо большое! Только сегодня занялись проверкой, и к сожалению, не успели попробовать повторить ошибку на ветке master_hotfix_delete_using. Но выполнили следующие проверки: PostgreSQL 9.6.4 on x86_64-pc-linux-gnu, compiled by gcc (Debian 4.9.2-10) 4.9.2, 64-bit |
Спасибо! Я думаю, Если есть возможность и время, лучше попробуйте больше разных запросов, чтобы помочь нам протестировать исправление в ветке |
Вышла версия 1.4.3 с исправлением. |
Спасибо большое! |
Апдейт имел такой вид:
условие where не срабатывало, и обновлялось больше чем нужно.
хотя запрос вида:
отдавал все верно.
поведение повторяется. Могу, при необходимости, попробовать написать скрипт.