postgresql 参数替换 游标_如何加快PostgreSQL中的更新/替换操作?

文章探讨了在PostgreSQL 8.3中提高更新和替换操作性能的方法,包括创建replace()函数、insert_or_replace规则、多行插入和更新策略。作者通过一系列测试比较了不同方法的效率,如使用函数、规则、多行插入和更新,以及insert-to-temp-table等方法。测试结果显示,某些方法在更新速度上有显著提升,但插入速度可能会受到影响。文章寻求更优的replace_item()实现或性能优化建议。
摘要由CSDN通过智能技术生成

我们有一个相当特殊的应用程序,它使用PostgreSQL 8.3作为存储后端(使用Python和psycopg2)。我们对重要表执行的操作在大多数情况下都是插入或更新(很少删除或选择)。

出于理智的原因,我们创建了自己的类似数据映射器的层,它运行得相当好,但它有一个很大的瓶颈,即更新性能。当然,我不希望更新/替换场景像'插入空表'那样快速,但是接近它会很好。

请注意,此系统没有并发更新

我们总是在更新中设置每行的所有字段,这可以在我在测试中使用“替换”一词的术语中看到。到目前为止,我已经尝试了两种解决更新问题的方法:

创建一个replace()过程,该过程需要更新行数组:

CREATE OR REPLACE FUNCTION replace_item(data item[]) RETURNS VOID AS $$

BEGIN

FOR i IN COALESCE(array_lower(data,1),0) .. COALESCE(array_upper(data,1),-1) LOOP

UPDATE item SET a0=data[i].a0,a1=data[i].a1,a2=data[i].a2 WHERE key=data[i].key;

END LOOP;

END;

$$ LANGUAGE plpgsql

创建一个insert_or_replace规则,以便除偶尔删除之外的所有内容都成为多行插入

CREATE RULE "insert_or_replace" AS

ON INSERT TO "item"

WHERE EXISTS(SELECT 1 FROM item WHERE key=NEW.key)

DO INSTEAD

(UPDATE item SET a0=NEW.a0,a1=NEW.a1,a2=NEW.a2 WHERE key=NEW.key);

这些都加快了更新速度,虽然后者减慢了插入量:

Multi-row insert : 50000 items inserted in 1.32 seconds averaging 37807.84 items/s

executemany() update : 50000 items updated in 26.67 seconds averaging 1874.57 items/s

update_andres : 50000 items updated in 3.84 seconds averaging 13028.51 items/s

update_merlin83 (i/d/i) : 50000 items updated in 1.29 seconds averaging 38780.46 items/s

update_merlin83 (i/u) : 50000 items updated in 1.24 seconds averaging 40313.28 items/s

replace_item() procedure : 50000 items replaced in 3.10 seconds averaging 16151.42 items/s

Multi-row insert_or_replace: 50000 items inserted in 2.73 seconds averaging 18296.30 items/s

Multi-row insert_or_replace: 50000 items replaced in 2.02 seconds averaging 24729.94 items/s

关于测试运行的随机说明:

所有测试都在数据库所在的同一台计算机上运行;连接到localhost。

插入和更新以500个项目的批量应用于数据库,每个项目都在其自己的事务(UPDATED)中发送。

所有更新/替换测试都使用与数据库中已有的相同的值。

使用psycopg2 adapt()函数转义所有数据。

在使用之前,所有表都被截断并抽真空(ADDED,在之前的运行中仅发生截断)

该表如下所示:

CREATE TABLE item (

key MACADDR PRIMARY KEY,

a0 VARCHAR,

a1 VARCHAR,

a2 VARCHAR

)

所以,真正的问题是:如何加快更新/替换操作的速度? (我认为这些调查结果可能“足够好”,但我不想在不点击SO人群的情况下放弃:)

任何人都暗示更优雅的replace_item(),或者证明我的测试完全被破坏是非常受欢迎的。

如果您想尝试重现,可以在此处获得测试脚本。记得先检查一下......它是WorksForMe,但......

您需要编辑db.connect()行以适合您的设置。

编辑

感谢#postgresql @ freenode中的andres我有另一个单查询更新的测试;很像一个多行插入(在上面列为update_andres)。

UPDATE item

SET a0=i.a0, a1=i.a1, a2=i.a2

FROM (VALUES ('00:00:00:00:00:01', 'v0', 'v1', 'v2'),

('00:00:00:00:00:02', 'v3', 'v4', 'v5'),

...

) AS i(key, a0, a1, a2)

WHERE item.key=i.key::macaddr

编辑

感谢#postgresql @ freenode和jug / jwp中的merlin83,我有另一个带有insert-to-temp / delete / insert方法的测试(上面列为“update_merlin83(i / d / i)”)。

INSERT INTO temp_item (key, a0, a1, a2)

VALUES (

('00:00:00:00:00:01', 'v0', 'v1', 'v2'),

('00:00:00:00:00:02', 'v3', 'v4', 'v5'),

...);

DELETE FROM item

USING temp_item

WHERE item.key=temp_item.key;

INSERT INTO item (key, a0, a1, a2)

SELECT key, a0, a1, a2

FROM temp_item;

我的直觉是,这些测试对现实场景中的表现并不具有代表性,但我认为这些差异非常大,可以指出最有希望进一步调查的方法。 perftest.py脚本包含所有更新以及那些想要检查它的人。它虽然相当丑陋,所以不要忘记你的护目镜:)

编辑

#postgresql @ freenode中的andres指出我应该使用insert-to-temp / update变体进行测试(上面列为“update_merlin83(i / u)”)。

INSERT INTO temp_item (key, a0, a1, a2)

VALUES (

('00:00:00:00:00:01', 'v0', 'v1', 'v2'),

('00:00:00:00:00:02', 'v3', 'v4', 'v5'),

...);

UPDATE item

SET a0=temp_item.a0, a1=temp_item.a1, a2=temp_item.a2

FROM temp_item

WHERE item.key=temp_item.key

编辑

可能是最终编辑:

我更改了我的脚本以更好地匹配我们的加载方案,并且即使在缩放一些内容并添加一些随机性时,似乎数字也保持不变。如果有人从其他场景得到非常不同的数字,我会有兴趣了解它。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值