我已经尝试对内置 upsert (INSERT ... ON CONFLICT UPDATE ...) 的性能影响进行了一段时间的研究,当进行了大量 upsert 时。规模大约是每小时 100 万条记录,分为每组大约 300 条记录。
该表相当简单,只有几个 int/bool 字段和一个日期字段。该表的总大小介于 50-6000 万条记录之间。本质上,所有行都应该在某个周期(目前大约为 2 天)内保持最新。有时很多信息会发生变化,有时很少/没有信息变化(例如 300 条记录被更新,但它们与现有记录相同)。
到目前为止,一个假设是,这个项目似乎正在遭受不断发生的大量写入的痛苦,因为即使 upsert 导致没有插入/更新,来自 upsert 的“失败”插入仍然会被写入某个地方(根据我们的知识)。因此,我们的想法是利用老式的 upsert(可写 CTE)并执行更精细的操作,以确保仅插入尚不存在的数据,并且仅更新实际更改的数据。然而,这自然会给数据库带来更多的读取负载并增加查询的复杂性。
问题是,从性能的角度来看,内置 upsert 是无用的(例如,它只适用于更小的任务),我们的假设是正确的,还是我们错了?我阅读了一些关于 HOT 更新和 autovacuum 调整的内容,但没有任何内容引用与此问题更相似的内容。
值得一提的是,这个数据库(PostgreSQL 10.9)在 Heroku 上运行,所以我们无法根据需要对其进行调整。我们计划在某个时候搬家,这取决于它最终的重要性。最后,还值得一提的是,这个DB还有一个follower(即只读副本)。
真的很感激对此有一些好的见解!先谢谢了。
我想使用 Postgres(CloudSQL 中的 11)作为高效的键值存储。我有大约 200GB 的字典(平均大小为 10kB,结构可以不同并且可以嵌套)。我正在考虑利用改进的哈希索引。这是架构:
\n\n CREATE EXTENSION IF NOT EXISTS "uuid-ossp";\n\n CREATE TABLE IF NOT EXISTS key_val (\n id uuid DEFAULT uuid_generate_v4(),\n value jsonb,\n EXCLUDE using hash (id with =)\n );\n\n CREATE INDEX IF NOT EXISTS idx_key_val ON key_val USING hash (id);\nRun Code Online (Sandbox Code Playgroud)\n\n获取、更新和插入非常简单,但我不知道如何实现高效的更新插入。
\n\nINSERT INTO key_val VALUES ($1, $2) ON CONFLICT ON CONSTRAINT key_val_id_excl DO UPDATE SET value = ($2)\nRun Code Online (Sandbox Code Playgroud)\n\n结果是WrongObjectTypeError ON CONFLICT DO UPDATE not supported with exclusion constraints
可能的解决方案:
\n\n …我们维护一个用 PostgreSQL 和 python 实现的大型数据仓库。我们所做的一种非常常见的模式是进行更新插入,并在更新时进行记录。我们有一些独特的键my_key和值,例如my_uuid, my_text, my_int, my_date。如果给定的任何这些值发生变化,my_key我们希望更新该行。没关系,我们有一个运行良好的模式:
insert into my_table (
my_key,
my_uuid,
my_text,
my_int,
my_date
)
select
some_key,
some_uuid,
some_text,
some_int,
some_date
from some_table
on conflict (my_key) do update set
some_uuid = excluded.some_uuid,
some_text = excluded.some_text,
some_int = excluded.some_int,
some_date = excluded.some_date,
update_timestamp = now()
where
coalesce(my_table.some_uuid, uuid_nil()) <> coalesce(excluded.some_uuid, uuid_nil())
or coalesce(my_table.some_text, '') <> coalesce(excluded.some_text, '')
or coalesce(my_table.some_int, -1) <> coalesce(excluded.some_int, -1)
or coalesce(my_table.some_date, '3000-01-01'::date) <> coalesce(excluded.some_date, '3000-01-01'::date)
Run Code Online (Sandbox Code Playgroud)
最后一个on conflict …
从 PostgreSQL 维基,
MERGE通常用于合并两个表,并在 2003 SQL 标准中引入。该REPLACE声明(一个MySQL扩展)或UPSERT序列尝试一个UPDATE或失败时INSERT。这类似于UPDATE,然后对于不匹配的行,INSERT。并发访问是否允许可能导致行丢失的修改与实现无关。
进一步的 PostgreSQLINSERT ... ON CONFLICT DO NOTHING/UPDATE以UPSERT的形式销售,并在 9.5 中添加
那是MERGE什么?它是如何融入这个组合的?
我有以下查询:
INSERT INTO ReservationCounter (student_id, reservation_count) VALUES (1, 1)
ON CONFLICT (student_id) DO
UPDATE SET reservation_count=excluded.reservation_count+1;
Run Code Online (Sandbox Code Playgroud)
当没有冲突时就INSERTS成功了。
然而,当存在冲突时,该UPDATE语句实际上并不用增量更新值。
当我第一次在冲突时运行它时,它会按预期返回 2,但是当我再次运行它时,我希望它会增加 2 到 3(因为reservation_count=excluded.reservation_count+1)。它没有这样做,它再次返回 2;让我相信那reservation_count总是 1。
我究竟做错了什么?
我有一个功能:
merge_vehicles(vid, cid, vname, reg_no, name, name_1st)
Run Code Online (Sandbox Code Playgroud)
我可以在输入上多次调用它吗
(2335, 55, '246BDH', '246BDH', '811', 1),
(2336, 55, '038THX', '038THX', '831', 1),
....
Run Code Online (Sandbox Code Playgroud)
该函数是一个UPSERT实现返回void. 这是一个仓库数据库(事实表)。我们有一个实时数据库,每小时可以获取 1000 多个输入。我们想使用此命令将我们的数据与新数据合并。
它是一个表函数。(我已经为我们拥有的每个表定义了类似的函数 - 即 5。)结果是,它将更新现有行(如果存在),否则插入新行。
Postgres 版本是 9.3。
函数是此处接受的答案的一个版本:
WITH upsert AS (UPDATE tbl SET a = 2 WHERE a = 1 RETURNING tbl.*)
INSERT INTO tbl (a)
SELECT 1 WHERE NOT EXISTS( SELECT * FROM upsert )
RETURNING *
Run Code Online (Sandbox Code Playgroud)
这个“upsert”语句有效,但是我想检索 UPDATE 或 INSERTED 值。当 upsert 执行INSERT(行尚未在 db 中)时,插入的值将从查询中正确返回。
但是,当UPDATE执行时,不会返回任何值(但行是更新的)。我试过添加,RETURNING upsert.*但它产生错误missing FROM-clause entry for table \"upsert\"。
我们有一个UPSERT功能通过on conflict do set. 如何在 set 语句中有条件地设置值,例如
if(excluded.col1 is null) col1=table.col1 else col1=excluded.col1
Run Code Online (Sandbox Code Playgroud)
我们使用的是 Postgres 9.5。
我是 MySQL 的新手,但我对 SQL Server 有一定的经验。我知道在 SQL Server 中我应该非常谨慎地使用MERGE语句,因为它们会导致一些问题。使用时有什么特别需要注意的ON DUPLICATE KEY UPDATE吗?在 MySQL 社区中,INSERT/UPDATE像 SQL Server 一样坚持使用单独的语句是否被认为是最佳实践,或者ON DUPLICATE KEY UPDATE广泛用于简单的 upserts 是否可以?
我有一个运行良好的 UPSERT 函数,但我批量更新和插入记录,可以修改此函数,以便我将所有记录作为数组传递给此函数,然后它将作为一个事务一次性插入/更新所有记录? 如果记录号 x 失败,它应该回滚撤消在 x 之前插入/更新的任何记录?这是我的 upsert 函数:
CREATE OR REPLACE FUNCTION save_weights(rec tbl_weightment)
RETURNS text AS
$BODY$
DECLARE
myoutput text :='Nothing has occured';
BEGIN
update tbl_weightment set
vname=rec.vname,
iquality=rec.iquality,
vhooks=rec.vhooks,
tstamp=rec.tstamp
vtare=rec.vtare,
vgross=rec.vgross
WHERE id=rec.id;
IF FOUND THEN
myoutput:= 'Record successfully updated';
RETURN myoutput;
END IF;
BEGIN
INSERT INTO tbl_weightment SELECT(rec).*;
myoutput:= 'Record successfully added';
END;
RETURN myoutput;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
Run Code Online (Sandbox Code Playgroud)
这个功能可以修改成这样save_weights(rec tbl_weightment[])吗??任何帮助将不胜感激
Postgres 已经有一种方法可以执行“upsert”,但我不喜欢发送这些长查询,我想知道它是否可以实现为一个存储过程,它将接受 json 并执行
INSERT INTO ... (keys)
VALUES (values)
ON CONFLICT DO UPDATE SET (setEverythingFromExcluded)
Run Code Online (Sandbox Code Playgroud)
我知道我可以以某种方式使用json_object_keysandjson_extract_path或直接使用json_each,但我最初的尝试毫无结果,所以也许有人已经这样做了?
upsert ×11
postgresql ×10
functions ×2
update ×2
array ×1
hashing ×1
insert ×1
json ×1
merge ×1
mysql ×1
mysql-5.6 ×1
null ×1
performance ×1
terminology ×1