当前位置: 首页 > 面试题库 >

如何保证带有子查询的原子SQL插入?

牟飞沉
2023-03-14
问题内容

给定一个简化的表结构,如下所示:

 CREATE TABLE t1 (
        id INT,
        num INT,
        CONSTRAINT t1_pk
        PRIMARY KEY (id),
        CONSTRAINT t1_uk
        UNIQUE (id, num)
    )

我可以使用这样的子查询插入记录而不会导致竞争条件吗?

INSERT INTO t1 (
    id,
    num
) VALUES (
    1,
    (
        SELECT MAX(num) + 1
        FROM   t1
    )
)

还是子查询不是原子的?我担心同时INSERTs获取相同的值num,然后导致唯一约束冲突。


问题答案:

是的,这肯定可以创建竞争条件,因为尽管保证所有语句都是原子的,但这并不要求它们在查询执行的各个部分中对不变的数据集进行操作。

客户提交您的上述查询。只要引擎找到MAX(num)只持有与其他读取器兼容的锁的锁,则另一个客户端可以MAX(num)INSERT执行之前找到相同的锁。

我知道有四种方法可以解决此问题:

  1. _使用 序列。_在中,INSERT您只需sequencename.nextval返回下一个要插入的唯一编号即可。

    SQL> create sequence t1num;
    

    Sequence created.

    SQL> select t1num.nextval from dual;

    NEXTVAL

         1
    

    SQL> select t1num.nextval from dual;

    NEXTVAL

         2
    
  2. 重试失败。 我读了一篇可靠的文章,内容涉及每秒非常高的事务处理系统,该系统并非完全类似于这种情况,但处于INSERT可能使用错误值的相同竞争条件下。他们发现,最高的TPS是通过首先赋予num唯一约束,然后照常进行的,如果INSERT由于违反唯一约束而被拒绝,则客户只需重试即可。

  3. 添加一个锁定提示,以强制引擎阻止其他阅读器,直到INSERT完成。尽管从技术上讲这可能很容易,但它可能不适合高并发性。如果MAX()仅通过一次搜索执行,并且阻塞时间不长并且不会阻塞许多客户端,则从理论上讲是可以接受的,但是大多数系统会随着时间的推移而增长,从而迅速带来这种风险。

  4. 使用单独的单行帮助程序表记录的下一个/最新值numUPDATE在助手表上执行同时读取,然后将读取值分别用于INSERT主表。在我看来,这令人烦恼,因为它不是一个查询,而且确实存在一个问题,即如果客户端设法“保留”值num,但是由于任何原因而未能实际执行INSERT,那么可能会出现间隙在num表格中的值中。



 类似资料:
  • 问题内容: 怪物编辑:查询现在将运行,但返回错误答案。添加了一个粗略的架构。PatientID不是tblPatientVisits表中的主键,因为同一患者ID可以出现多次。 列出了每个县名,但每个计数(s.countyName)和计数(t.countyname)为1 编辑:我有一个查询,现在运行,但它返回 问题答案: 没有样本数据和理想的结果很难说,但是也许这是您要追求的?

  • 主要内容:1.带有Select语句的子查询,2.带有INSERT语句的子查询,3.带有UPDATE语句的子查询,4.带有DELETE语句的子查询子查询是另一个SQL查询中的查询,并嵌入在子句中。 重要规则: 子查询可以放在许多SQL子句中,如子句,子句,子句。 可以将子查询与,,,语句以及,,, ,,,等运算符一起使用。 子查询是另一个查询中的查询。外部查询称为主查询,内部查询称为子查询。 子查询位于比较运算符的右侧。 子查询括在括号中。 在子查询中,不能使用命令。 但命令可用于执行与命令相同的

  • 主要内容:语法,示例子查询也称“内部查询”或者“嵌套查询”,是指将一个 SELECT 查询(子查询)的结果作为另一个 SQL 语句(主查询)的数据来源或者判断条件。 子查询可以嵌入 SELECT、INSERT、UPDATE 和 DELETE 语句中,也可以和 =、<、>、IN、BETWEEN、EXISTS 等运算符一起使用。 子查询常用在 WHERE 子句和 FROM 子句后边: 当用于 WHERE 子句时,根据不同

  • SQL 子查询 子查询是一个SELECT 语句,它嵌套在一个 SELECT、SELECT...INTO 语句、INSERT...INTO 语句、DELETE 语句、或UPDATE 语句或嵌套在另一子查询中。 语法 可用三种语法来创建子查询: comparison [ANY | ALL | SOME] (sqlstatement) expression [NOT] IN (sqlstatement)

  • 问题内容: 这对我来说看起来很奇怪: 是一个临时表,但是其余的对我来说毫无意义。 你怎么能有两个子句? 问题答案: 从DELETE的文档中可以看出,它可以包含两个子句。 第一个: FROM:是可选关键字,可以在DELETE关键字和目标table_or_view_name或rowset_function_limited之间使用。 第二个: :指定一个附加的FROM子句。Transact- SQL的D

  • 问题内容: 我有这样的查询- 由于将rowz = 1放入查询中,因此该查询无法正常工作?如果我只想要在嵌套后rowz = 1的结果该怎么办。 当我这样做时- 从news_article中选择unnest(string_to_array(na.news_category_id,’,’)):: int rowz; 我的桌子是- 然后它给了我这个结果- 问题答案: 这回答了您的问题: 诀窍是将数组放入一