AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 187029
Accepted
Heinzi
Heinzi
Asked: 2017-09-28 01:40:49 +0800 CST2017-09-28 01:40:49 +0800 CST 2017-09-28 01:40:49 +0800 CST

“不相关”的 INSERT 和 UPDATE 相互阻塞

  • 772

重现场景:

CREATE TABLE test (
  ID int IDENTITY(1,1),
  mykey nvarchar(255) NOT NULL,
  exp_date datetime,
PRIMARY KEY (ID));
GO

CREATE INDEX not_expired_keys ON test (exp_date, mykey);

INSERT INTO test (mykey, exp_date) VALUES ('A', NULL);

我开始交易1:

-- add key B
BEGIN TRANSACTION;
INSERT INTO test (mykey, exp_date) VALUES ('B', NULL);
...

然后并行执行事务 2:

-- expire key A
BEGIN TRANSACTION;
UPDATE test SET exp_date = GETDATE() WHERE exp_date IS NULL AND mykey = 'A'; -- <-- Blocking
ROLLBACK;

事实证明,事务 1 的未提交 INSERT 会阻止事务 2 的 UPDATE,即使它们影响不相交的行集(mykey = 'B'vs. mykey = 'A')。

观察:

  • 阻塞也发生在最低事务隔离级别上READ UNCOMMITTED。
  • 如果我将唯一索引放在mykey. 不幸的是,我不能这样做,因为一旦密钥过期,密钥名称就可以重复使用。

我的问题:

  • (出于好奇:)为什么这些语句即使在READ UNCOMMITTED级别上也会相互阻止?

  • 有没有一种简单可靠的方法可以让它们不互相阻挡?

sql-server locking
  • 2 2 个回答
  • 2677 Views

2 个回答

  • Voted
  1. Best Answer
    Artashes Khachatryan
    2017-09-28T02:16:20+08:002017-09-28T02:16:20+08:00

    让我们看一下执行计划。

    第一个查询 - 插入

    BEGIN TRANSACTION;
    INSERT INTO test (mykey, exp_date) VALUES ('B', NULL);
    

    及其执行计划在此处输入图像描述

    我们看到 sql server 正在做 Clustered Index Insert 操作。

    现在让我们看看更新

    BEGIN TRANSACTION;
    UPDATE test 
    SET exp_date = GETDATE() 
    WHERE exp_date IS NULL AND mykey = 'A' -- <-- Blocking
    

    及其执行计划在此处输入图像描述

    SQL Server 会扫描表的聚集索引,并在其上加 U 锁,即使它可以选择另一个索引来查找匹配的行。原因是,因为我们在表中只有 1 行,并且 SQL Server Optimizer 发现更容易扫描聚集索引而不是在非聚集索引中搜索数据。

    但是如果我们强制 sql server 使用非聚集索引呢?

    BEGIN TRANSACTION;
    UPDATE test 
    SET exp_date = GETDATE() 
    FROM test WITH(INDEX = not_expired_keys)
    WHERE exp_date IS NULL AND mykey = 'A' -- <-- No Blocking!!!
    

    及其执行计划在此处输入图像描述

    我想如果我们在表中放更多的行,SQL Server 会选择非聚集索引来查找必须更新的行,并且不会出现阻塞。

    • 4
  2. Joshua
    2018-04-25T07:34:33+08:002018-04-25T07:34:33+08:00

    这本质上是 SQL Server 中的一个错误。MS 没有实现谓词锁,而是采用了一种廉价的方法来阻止用于从表中选择行的索引之一上的范围。如果它不使用索引(或者如果没有索引),它将改为阻止表上的范围。

    是的,强制索引会导致它锁定索引;但是它总是需要页面锁。页面锁不利于锁层次结构;碰巧在同一索引页或表页上的不相关行将被阻止。有两个书面陈述没有办法解决这个问题。如果您的其中一个语句正在阅读,WITH(ROWLOCK)则阅读器将绕过。

    我与 MS 开了一个案例,持续了两个月,然后他们完全拒绝修复它。

    • -2

相关问题

  • SQL Server - 使用聚集索引时如何存储数据页

  • 我需要为每种类型的查询使用单独的索引,还是一个多列索引可以工作?

  • 什么时候应该使用唯一约束而不是唯一索引?

  • 死锁的主要原因是什么,可以预防吗?

  • 如何确定是否需要或需要索引

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve