-
Notifications
You must be signed in to change notification settings - Fork 67
Баг с некорректным выполнением UPDATE при использовании в where секционированной таблицы #110
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
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 не срабатывало, и обновлялось больше чем нужно.
хотя запрос вида:
отдавал все верно.
поведение повторяется. Могу, при необходимости, попробовать написать скрипт.
The text was updated successfully, but these errors were encountered: