powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Пакетное добавление/обновление данных
7 сообщений из 32, страница 2 из 2
Пакетное добавление/обновление данных
    #38678362
Ivan Durak
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
LeXa NalBatIvan Durakну да, проще но сильно тормознее.вот что говорит EXPLAIN ANALYZE, через тригер проходит более тысячи строк в секунду:
Trigger usage_2014_06_upsert: time=610256.635 calls=887272
"все познается в сравнении"
...
Рейтинг: 0 / 0
Пакетное добавление/обновление данных
    #38678640
cr@nk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Раз участник Troglodit пропал, то немного оффтопика
Вот такая конструкция
Код: sql
1.
2.
3.
4.
5.
6.
7.
		IF _tovar_found.lastdate<=new.lastdate THEN
			IF _tovar_found.cost<>new.cost THEN
				UPDATE _tovar SET lastdate=new.lastdate, cost=new.cost WHERE id=_tovar_found.id;
			ELSE
				UPDATE _tovar SET lastdate=new.lastdate WHERE id=_tovar_found.id;
			END IF;
		END IF;


Разделил на 2 UPDATE, чтобы не дёргать базу на запись лишний раз. А есть ли в этом смысл? Может имеет смысл оставить только 1 UPDATE? В котором обновляются сразу 2 поля, а PostgreSQL сам обновит поля, которые изменились? Я просто не знаю, как ведёт себя СУБД при запросе на обновление данных, если данные и так там те, которые нам нужны.
...
Рейтинг: 0 / 0
Пакетное добавление/обновление данных
    #38678838
LeXa NalBat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ivan Durak"все познается в сравнении"времянка в два с лишним раза быстрее тригера
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
drop table t;
create table t(
    k integer,
    v real
);
create index on t(k);

copy (
    select generate_series(1, 1000000), random()
) to '/tmp/d1';

copy (
    select generate_series(1, 2000000, 2), random()
) to '/tmp/d2';

copy t from '/tmp/d1';


Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
-- 1
drop function f();
create function f() returns trigger language plpgsql as
$$
declare
    rc integer;
begin
    update t set v = v + new.v where k = new.k;
    get diagnostics rc = row_count;
    if rc > 0 then
        return null;
    end if;
    return new;
end;
$$;

create trigger r before insert on t
    for each row execute procedure f() ;

copy t from '/tmp/d2';


Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
-- 2
drop table tmp;
create table tmp(like t);

copy tmp from '/tmp/d2';

update t set v = t.v + tmp.v
    from tmp
    where t.k = tmp.k;

insert into t
    select * from tmp
    where not exists (
        select 1 from t where k = tmp.k
    );


-- 1
COPY 500000
Time: 46944,017 ms

-- 2
COPY 1000000
Time: 4624,439 ms
UPDATE 500000
Time: 9140,216 ms
INSERT 0 500000
Time: 5983,546 ms
...
Рейтинг: 0 / 0
Пакетное добавление/обновление данных
    #38678895
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
cr@nkРаз участник Troglodit пропал, то немного оффтопика
Вот такая конструкция
Код: sql
1.
2.
3.
4.
5.
6.
7.
		IF _tovar_found.lastdate<=new.lastdate THEN
			IF _tovar_found.cost<>new.cost THEN
				UPDATE _tovar SET lastdate=new.lastdate, cost=new.cost WHERE id=_tovar_found.id;
			ELSE
				UPDATE _tovar SET lastdate=new.lastdate WHERE id=_tovar_found.id;
			END IF;
		END IF;


Разделил на 2 UPDATE, чтобы не дёргать базу на запись лишний раз. А есть ли в этом смысл? Может имеет смысл оставить только 1 UPDATE? В котором обновляются сразу 2 поля, а PostgreSQL сам обновит поля, которые изменились? Я просто не знаю, как ведёт себя СУБД при запросе на обновление данных, если данные и так там те, которые нам нужны.

в PostgreSQL всегда целиком обновляется вся строка (даже если обновлять так что ничего не меняется типа update table set id=id;)
update в первом приближении всегда делается как delete полной старой строки и Insert новой (опять же полной) строки.
так что вышеприведенный метод только лишнюю работу и замедление даст.
...
Рейтинг: 0 / 0
Пакетное добавление/обновление данных
    #38678982
cr@nk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Maxim Boguk,

Спасибо за разъяснение. Получается, что конструкция упрощается до такой:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
	SELECT * INTO _tovar_found FROM _tovar WHERE (article=new.article) AND (distrib=new.distrib);
	SELECT COUNT(*) INTO _tovar_count FROM _tovar WHERE (article=new.article) AND (distrib=new.distrib);
	IF _tovar_count=0 THEN
		RETURN NEW;
	ELSIF _tovar_count=1 THEN
			UPDATE _tovar SET name=new.name, lastdate=new.lastdate, cost=new.cost WHERE id=_tovar_found.id;
		END IF;
...
Рейтинг: 0 / 0
Пакетное добавление/обновление данных
    #38680412
Troglodit
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Вы потеряли часть логики в вашем последнем запросе.
Мое предложение было следующим
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
WITH updated_rows AS (
UPDATE _tovar SET 
name=new.name, 
lastdate=case when lastdate =new.lastdate then  lastdate=new.lastdate else lastdate end, 
cost=new.cost,
WHERE (article=new.article) AND (distrib=new.distrib)
RETURNING lastdate
)
SELECT COUNT(*) INTO _tovar_count FROM updated_rows
IF _tovar_count=0 THEN
	RETURN NEW;
END IF;


Возможно где то синтаксис не корректен, но логика думаю будет понятна.
...
Рейтинг: 0 / 0
Пакетное добавление/обновление данных
    #38680574
Ivan Durak
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
LeXa NalBatIvan Durak"все познается в сравнении"времянка в два с лишним раза быстрее тригера

я даже не сомневался
...
Рейтинг: 0 / 0
7 сообщений из 32, страница 2 из 2
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Пакетное добавление/обновление данных
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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