如何在没有并发问题的情况下将一行中的字段设置为同一 table 中某些行的数量?

How to set a field in a row to number of some rows in the same table without concurrency problems in postgresql?

假设我有这样的架构:

CREATE TABLE "test2" (
    "id" SERIAL NOT NULL,
    "text" CHAR(10),

    PRIMARY KEY ("id")
);
CREATE TABLE "test1" (
    "id" SERIAL NOT NULL,
    "fkey" INTEGER NOT NULL,
    "order" INTEGER NOT NULL,
    "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,

    PRIMARY KEY ("id")
);

ALTER TABLE "test1" ADD FOREIGN KEY ("fkey") REFERENCES "test2"("id") ON DELETE CASCADE ON UPDATE CASCADE;

为了一些性能优化,我想在 "order" 字段中存储 "test1" [=31] 中的行数=] 引用 “test2” 中的同一行。所以我在插入时尝试这个:

insert INTO "test1"
        ("fkey","order")
        select '3', count(*) from "test1" where "fkey"='3';

这会不会有并发问题? (例如,当两个线程同时使用相同的 fkey 插入到 test1 时,order 的值可以变得不正确?如何解决这个问题?

是的,当多个插入同时完成时,您需要考虑并发问题。

有几种解决方案。在我的脑海中,我可以看到:

  • 在数据库中获取独占锁。可能主要 table 中的一行就可以了。
  • 管理数据库外的锁或信号量。
  • 插入行,但以延迟的方式更新 order,可能使用队列(很可能是优先级队列)或单个单独的进程。
  • 插入时使用乐观锁定。

其中每一个都有一些缺点,因此这取决于您的具体要求。

我猜你不想在每次插入新的 child 时更新 所有兄弟姐妹 ;就性能而言,这可能有点矫枉过正。如果这听起来合理,也许您可​​以使用优先级队列,运行 每 10 分钟(左右)一个进程,将相同 parent 的所有 children 分组并立即更新它们。