尝试使用PostgreSQL 9.2在表上运行这样的更新语句:
UPDATE table
SET a_col = array[col];
我们需要能够在 ~10M 行表上运行它,而不是让它锁定表(因此在更新运行时仍然可以进行正常操作)。我相信使用游标可能是正确的解决方案,但我真的不知道它是否是正确的,或者我应该如何使用游标实现它。
我想出了这个光标代码,我认为这可能很好。
编辑:添加光标功能
CREATE OR REPLACE FUNCTION update_fields() RETURNS VOID AS $$ DECLARE cursor CURSOR FOR SELECT * FROM table ORDER BY id FOR UPDATE; BEGIN FOR row IN cursor LOOP UPDATE table SET a_col = array[col], a_col2= array[col2] WHERE CURRENT OF cursor; END LOOP; END; $$ LANGUAGE plpgsql;
首先,如果“正常操作”由 SELECT
查询组成,MVCC 模型将自动处理它。UPDATE
不会阻止 SELECT
,反之亦然。SELECT
只看到已提交的数据(或在同一事务中执行的操作),因此大 UPDATE
的结果在完成(提交)之前对其他事务不可见。
如果没有其他对象引用该表,
并且没有并发写入操作(这将丢失!)
而且您可以在表上提供一个非常短的独占锁,
并且您当然有额外的磁盘空间:
您可以通过在后台创建表的更新版本来将锁定保持在最小。确保它有所有可以替换的东西,然后删除原始文件并重命名重复文件。
CREATE TABLE tbl_new (LIKE tbl_org INCLUDING CONSTRAINTS);
INSERT INTO tbl_new
SELECT col_a, col_b, array[col] aS col_c
FROM tbl_org;
我正在使用创建表(如..包括约束),
因为(在此处引用手册):
非空约束总是被复制到新表中。只有在指定了< code > INCLUDING CONSTRAINTS 时,才会复制< code>CHECK约束;其他类型的约束永远不会被复制。
确保新桌子准备好了。然后:
DROP tbl_org;
ALTER TABLE tbl_new RENAME TO tbl_org;
导致非常短的时间窗口,其中表以独占方式锁定。
这实际上只是关于性能。它会很快地创建一个没有任何膨胀的新表。如果你有外键或视图,你仍然可以走这条路,但你必须准备一个脚本来删除和重新创建这些对象,可能会创建额外的独占锁。
对于并发写操作,您真正能做的就是将您的更新拆分成块。您不能在单个事务中做到这一点,因为锁只在事务结束时释放。
您可以使用dblink,它可以在另一个数据库(包括数据库本身)上启动独立的事务。这样,您可以在一个do
语句或一个带循环的plpgsql函数中完成所有操作。下面是一个松散相关的答案,其中包含有关dblink的更多信息:
函数中的光标不会给你带来任何东西。任何函数都自动包含在一个事务中,所有的锁只在事务结束时释放。即使您使用了< code>CLOSE cursor(实际上您并没有这样做),它也只会释放一些资源,而不会释放表上获得的锁。我引用手册上的话:
< code>CLOSE关闭打开的光标下的门户。这可用于在事务结束之前释放资源,或者释放游标变量以便再次打开。
您需要运行单独的事务或(滥用)使用为您执行此操作的dblink。
问题内容: 鉴于: 我想自动执行以下操作:更新客户(如果已经存在);否则,插入一个新客户。 从理论上讲,这听起来似乎非常适合SQL- MERGE, 但是我正在使用的数据库不支持将AUTO_INCREMENT列与MERGE配合使用。 似乎表明,如果对不存在的行执行查询或更新语句,数据库将锁定索引,从而防止并发插入。 SQL标准可以保证这种行为吗?是否有任何数据库无法以这种方式运行? 更新 :对不起,
问题内容: 我使用下面的代码 来更新查询 使用。 但是我越来越。 我尝试搜索一些SO链接,建议关闭数据库,但是我再次遇到相同的错误。我已经提到我在代码中出现错误的地方。 问题答案: 通常,如果您同时进行多个查询(您没有完成一些早期的SQL语句,或者您打开了多个线程,或者您多次打开了数据库),就会得到此信息。 这段代码对和的使用有些混乱,(和缺少),这可能是问题的根源。 在《 SQLite C /
我有一个cron作业每30秒运行一次,检查未结束的游戏。我将用于固定线程池。cron作业调用此方法: 其中是。在方法内部,我在循环中调用一个api,直到没有下一个页面。在这个方法中,我想更新数据库,以记住我最后看到的页面。 是否可以在一个线程中更新数据库,然后启动另一个线程,其中数据库再次更新?
问题内容: 我正在使用()查找PostLikes表中的(PostId,UserId),如果找到该行,则用于生成delete指令并删除基础行,如果未找到该行,则用于生成insert命令并使用将该行插入表中。但是该行未插入数据库中的表中。这是我到目前为止所做的 和表 PostLikes(LikeId,PostId,UserId) 问题答案: 有几个问题: 您正在寻找重复使用相同的命令,这两个检测行是否
我是Android的新手,需要一些帮助。 我的问题是我到底什么时候调用命令,以及room如何知道哪一行发生了更改?我不想更新到整个表。 如果我应该用另一种方式解释,请告诉我。
我目前正在重构遗留代码,以使用Android架构组件,并在一种存储库模式中设置一个房间数据库和截取请求。因此,表示层/域层要求存储库获取LiveData对象进行观察,或告诉他与服务器同步,然后删除旧的db条目,并从服务器中重新提取所有当前条目。 我已经写了同步部分的测试,所以我确信,对象被正确地获取并插入到数据库中。但是当写一个测试来观察db表的条目时(并测试对象是否被正确保存,以及在将它们放入d