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 / 问题 / 80088
Accepted
GoodwinSQL
GoodwinSQL
Asked: 2014-10-14 11:47:17 +0800 CST2014-10-14 11:47:17 +0800 CST 2014-10-14 11:47:17 +0800 CST

只插入死锁

  • 772

我们有一个将数据插入表的应用程序。不幸的是,我们遇到了死锁,而死锁仅来自插入。我们看到插入在导致问题的非聚集索引上以不同的顺序获取键锁。

为什么插入行为会这样?我们应该怎么做才能缓解死锁?任何帮助或见解表示赞赏。

在下面的示例中,只涉及两个插入,但我们有多达 4 个不同的插入涉及死锁。

这是死锁图:

    <deadlock>
    <victim-list>
        <victimProcess id="process3ab355868" />
    </victim-list>
    <process-list>
        <process id="process3ab355868" taskpriority="0" logused="1184" waitresource="KEY: 5:72057594043629568 (6234ed5bf036)" waittime="7493" ownerId="92332106" transactionname="implicit_transaction" lasttranstarted="2014-10-13T12:37:43.060" XDES="0x123699668" lockMode="X" schedulerid="3" kpid="3540" status="suspended" spid="89" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2014-10-13T12:37:44.333" lastbatchcompleted="2014-10-13T12:37:44.333" lastattention="1900-01-01T00:00:00.333" clientapp="Microsoft JDBC Driver for SQL Server" hostname="" hostpid="0" loginname="" isolationlevel="read committed (2)" xactid="92332106" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128058">
            <executionStack>
                <frame procname="adhoc" line="1" stmtstart="278" stmtend="818" sqlhandle="0x0200000053a65d302154b91e9fee55234669030a42479c050000000000000000000000000000000000000000">
                    INSERT INTO table (col1, col2, col3, col4, col5, col6, col7, col8, col9) VALUES (@P0, @P1, @P2, @P3, @P4, @P5, @P6, @P7, @P8)
                </frame>
                <frame procname="unknown" line="1" sqlhandle="0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000">
                    unknown
                </frame>
            </executionStack>
            <inputbuf>
                (@P0 datetime2,@P1 nvarchar(4000),@P2 nvarchar(4000),@P3 datetime2,@P4 nvarchar(4000),@P5 nvarchar(4000),@P6 decimal(38,1),@P7 int,@P8 int)INSERT INTO table (col1, col2, col3, col4, col5, col6, col7, col8, col9) VALUES (@P0, @P1, @P2, @P3, @P4, @P5, @P6, @P7, @P8)                                                                         select SCOPE_IDENTITY() AS GENERATED_KEYS
            </inputbuf>
        </process>
        <process id="process14b38c928" taskpriority="0" logused="2564" waitresource="KEY: 5:72057594043629568 (275232b7b238)" waittime="7491" ownerId="92325909" transactionname="implicit_transaction" lasttranstarted="2014-10-13T12:37:39.567" XDES="0x16b38b988" lockMode="X" schedulerid="3" kpid="3668" status="suspended" spid="65" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2014-10-13T12:37:44.337" lastbatchcompleted="2014-10-13T12:37:44.337" lastattention="1900-01-01T00:00:00.337" clientapp="Microsoft JDBC Driver for SQL Server" hostname="" hostpid="0" loginname="" isolationlevel="read committed (2)" xactid="92325909" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128058">
            <executionStack>
                <frame procname="adhoc" line="1" stmtstart="278" stmtend="818" sqlhandle="0x0200000053a65d302154b91e9fee55234669030a42479c050000000000000000000000000000000000000000">
                    INSERT INTO table (col1, col2, col3, col4, col5, col6, col7, col8, col9) VALUES (@P0, @P1, @P2, @P3, @P4, @P5, @P6, @P7, @P8)
                </frame>
                <frame procname="unknown" line="1" sqlhandle="0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000">
                    unknown
                </frame>
            </executionStack>
            <inputbuf>
                (@P0 datetime2,@P1 nvarchar(4000),@P2 nvarchar(4000),@P3 datetime2,@P4 nvarchar(4000),@P5 nvarchar(4000),@P6 decimal(38,1),@P7 int,@P8 int)INSERT INTO table (col1, col2, col3, col4, col5, col6, col7, col8, col9) VALUES (@P0, @P1, @P2, @P3, @P4, @P5, @P6, @P7, @P8)                                                                         select SCOPE_IDENTITY() AS GENERATED_KEYS
            </inputbuf>
        </process>
    </process-list>
    <resource-list>
        <keylock hobtid="72057594043629568" dbid="5" objectname="table1" indexname="unique_index" id="lock17bc3a480" mode="X" associatedObjectId="72057594043629568">
            <owner-list>
                <owner id="process14b38c928" mode="X" />
            </owner-list>
            <waiter-list>
                <waiter id="process3ab355868" mode="X" requestType="wait" />
            </waiter-list>
        </keylock>
        <keylock hobtid="72057594043629568" dbid="5" objectname="table1" indexname="unique_index" id="lock10735ce00" mode="X" associatedObjectId="72057594043629568">
            <owner-list>
                <owner id="process3ab355868" mode="X" />
            </owner-list>
            <waiter-list>
                <waiter id="process14b38c928" mode="X" requestType="wait" />
            </waiter-list>
        </keylock>
    </resource-list>
</deadlock>

这是 DDL 表:

CREATE TABLE [table1](
    [col0] [int] IDENTITY(1,1) NOT NULL,
    [col1] [int] NOT NULL,
    [col2] [int] NOT NULL,
    [col3] [decimal](15, 4) NULL,
    [col4] [datetime2](7) NOT NULL,
    [col5] [varchar](8) NOT NULL,
    [col6] [varchar](30) NOT NULL,
    [col7] [datetime2](7) NOT NULL,
    [col8] [varchar](8) NOT NULL,
    [col9] [varchar](30) NOT NULL,
 CONSTRAINT [PK] PRIMARY KEY CLUSTERED 
(
    [col0] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
 CONSTRAINT [unique_index] UNIQUE NONCLUSTERED 
(
    [col2] ASC,
    [col1] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

SET ANSI_PADDING OFF
GO

ALTER TABLE table1 ADD  DEFAULT (sysdatetime()) FOR [col4]
GO

ALTER TABLE table1 ADD  DEFAULT (sysdatetime()) FOR [col7]
GO
sql-server sql-server-2012
  • 2 2 个回答
  • 1730 Views

2 个回答

  • Voted
  1. Best Answer
    GoodwinSQL
    2014-10-16T06:12:54+08:002014-10-16T06:12:54+08:00

    我在这里回答我自己的问题,因为我们终于找到了问题所在。

    简短版本:我们在非聚集索引中添加了第三列。死锁消失了。

    长版:

    首先,查看James Rowland-Jones 的有关锁散列冲突的 dynamite 博客文章(我的解释与他的质量相去甚远)。

    来自博客文章:

    当 SQL Server 需要锁定一行时,它会根据表的键值创建一个哈希值。锁管理器使用的正是这个散列值,这意味着在检查行是否已被锁定时,它只有一个值可供查看。

    当生成重复的哈希值时,就会发生锁哈希冲突。

    在对许多死锁图进行更深入的分析后,我们注意到很多 WAITRESOURCE Key 哈希值(括号之间的值)是相同的。我开始制作一个简短的清单来跟踪:

    waitresource="KEY: 5:72057594043629568 (a27543d90a1a)
    waitresource="KEY: 5:72057594043629568 (a27543d90a1a)
    waitresource="KEY: 5:72057594043629568 (8328314847df)
    waitresource="KEY: 5:72057594043629568 (bb0d06c12baa)
    waitresource="KEY: 5:72057594043629568 (a27543d90a1a)
    waitresource="KEY: 5:72057594043629568 (bb0d06c12baa)
    waitresource="KEY: 5:72057594043629568 (8328314847df)
    waitresource="KEY: 5:72057594043629568 (bb0d06c12baa)
    waitresource="KEY: 5:72057594043629568 (a27543d90a1a)
    waitresource="KEY: 5:72057594043629568 (5b39284eef16)
    waitresource="KEY: 5:72057594043629568 (a27543d90a1a)
    waitresource="KEY: 5:72057594043629568 (8328314847df)
    waitresource="KEY: 5:72057594043629568 (5b39284eef16)
    

    果然,我们从不同的死锁图中得到了很多重复的哈希值。我决定查看 unique_index 索引(发生死锁的位置)的两列(col2 和 col1)中的数据。所有表格 DDL 都在问题的上方。

    对于 col1 列中的单个值,col2 列的值始终为 1-6。所以这开始有意义了。SQL 可用于生成哈希值的数据种类有限 - 这解释了为什么我们会得到重复的哈希值。

    JRJ在博客中提到的修复之一是在索引中添加一个额外的列。这为数据增加了一些多样性,并为散列算法提供了更多选择。幸运的是,我们能够向索引添加一个 create_timestamp 列,并保持与两列相同的唯一性。繁荣!将第三列添加到索引后,死锁就消失了。

    旁注:博客上的评论之一建议禁用索引上的行锁定。我们首先尝试了这个。它确实摆脱了死锁,但导致更多的锁定并将整体吞吐量降低了大约 40-50%,所以我们不喜欢我们的系统使用这个选项。但是,在工作负载较轻的数据库上,这可能会正常工作。

    希望这一切都有意义。

    • 7
  2. Shanky
    2014-10-14T12:07:08+08:002014-10-14T12:07:08+08:00

    我不确定这是否真的可以回答,但我不能将其发布为评论,所以把这个

    如果你看到你的应用程序代码就像

    @P1 nvarchar(4000)
    ,@P2 nvarchar(4000),
    @P3 datetime2,
    @P4 nvarchar(4000),
    @P5 nvarchar(4000),
    @P6 decimal(38,1),
    @P7 int,
    @P8 int)
    INSERT INTO OBC.MBL_CPU_POS_MSR_ATB (
    CRT_S, 
    CRT_PGM_C, 
    CRT_UID, 
    LST_UPD_S, 
    LST_UPD_PGM_C,
     LST_UPD_UID, 
    MSR_ATB_VAL, 
    MBL_CPU_POS_I, 
    POS_MSR_TYP_I) 
    VALUES (@P0, @P1, @P2, @P3, @P4, @P5, @P6, @P7, @P8)                                                                         select SCOPE_IDENTITY() AS GENERATED_KEYS
    

    如果您看到您已声明@p4,@p5...@P6为,nvarchar()但如果您看到表定义

    CREATE TABLE [OBC].[MBL_CPU_POS_MSR_ATB](
        [MBL_CPU_POS_MSR_ATB_I] [int] IDENTITY(1,1) NOT NULL,
        [POS_MSR_TYP_I] [int] NOT NULL,
        [MBL_CPU_POS_I] [int] NOT NULL,
        [MSR_ATB_VAL] [decimal](15, 4) NULL,
        [CRT_S] [datetime2](7) NOT NULL,
        [CRT_UID] [varchar](8) NOT NULL,
        [CRT_PGM_C] [varchar](30) NOT NULL,
        [LST_UPD_S] [datetime2](7) NOT NULL,
        [LST_UPD_UID] [varchar](8) NOT NULL,
        [LST_UPD_PGM_C] [varchar](30) NOT NULL,
    

    他们在其中插入值的列被声明为varchar并且您传递的值是nvarchar。您的表列都没有nvarchar数据类型。如果这是真的,就会发生隐式转换,并且会发生索引扫描,而不是寻求持有锁(特别是当你有 update 时)更长的时间。我想这可能是导致僵局的原因。

    还有 trancount=2 这意味着有未提交的事务,如果需要查询调整,当然还有位。

    参与死锁的两个事务都在争用相同的资源waitresource="KEY: 5:72057594043629568 (6234ed5bf036)"

    • 0

相关问题

  • 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