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 / 问题 / 312246
Accepted
the Ben B
the Ben B
Asked: 2022-05-18 06:54:46 +0800 CST2022-05-18 06:54:46 +0800 CST 2022-05-18 06:54:46 +0800 CST

最小化表锁的持续时间

  • 772

我有一个需要每天更新的 SQL 表。在更新发生时,可能有也可能没有对该表的查询。它大约有 500,000 行。

当更新表的作业与针对它的查询同时运行时,我们遇到了锁定冲突的问题。

所以我重写了更新表的过程如下:

ALTER procedure [dbo].[Table_Generate] as

declare @d datetime = getdate(), @c as int

--Check temp tables
IF OBJECT_ID('tempdb..#final') IS NOT NULL
    DROP TABLE #final

IF OBJECT_ID('tempdb..#base') IS NOT NULL
    DROP TABLE #base

--Get source data from linked server
select
    ID, 
    Reference, 
    StartDate, 
    EndDate, 
    Description,
    SomeCode
into #base


from    [LinkedServer].[Database].dbo.[A_View]

--Generate row_hash
select 
    ID, 
    Reference, 
    StartDate, 
    EndDate, 
    Description,
    SomeCode,
    hashbytes('SHA2_256',(
     select
        ID, 
        Reference, 
        StartDate, 
        EndDate, 
        Description,
        SomeCode 
     from #base sub where sub.ID = main.ID for xml raw)) as row_hash
    into #final
    from #base main

select @c = count(*) from #final
if @c >0 begin

merge [The_Table_Staging] as target
using #final as source
on source.ID = target.ID

--New rows
when not matched by target then
insert (    RunDate,
            ID, 
            Reference, 
            StartDate, 
            EndDate, 
            Description,
            SomeCode,
            Row_Hash
        ) values (
            @d,
            source.ID, 
            source.Reference, 
            source.StartDate,
            source.EndDate, 
            source.Description,
            source.SomeCode,
            source.row_hash)

--Existing changed rows
when matched and source.row_hash != target.row_hash then update set
     target.RunDate         = @d
    ,target.Reference       = source.Reference
    ,target.StartDate       = source.StartDate
    ,target.EndDate         = source.EndDate
    ,target.Description     = source.Description
    ,target.SomeCode        = source.SomeCode
    ,target.row_hash        = source.row_hash

--Deleted rows
when not matched by source then delete;

--Existing unchanged rows
update [The_Table_Staging] set RunDate = @d where RunDate != @d

--Commit changes
begin transaction

exec sp_rename 'The_Table_Live', 'The_Table_Staging_T'
exec sp_rename 'The_Table_Staging', 'The_Table_Live'
exec sp_rename 'The_Table_Staging_T', 'The_Table_Staging'

commit transaction
end

这个想法是为了减少不必要的行更新,同时也尽量减少对活动表的锁定。我不太喜欢重命名表,但更新/插入需要 5-10 秒,而表重命名几乎是即时的。

所以我的问题是:这种方法可以吗,和/或我可以改进它吗?

谢谢!

编辑以回应 JD:

嗨,JD,请不要道歉 - 我在这里接受建设性的批评。

  1. 我不知道MERGE有问题。我自己从来没有遇到过问题,但是谢谢
  2. 我可能会将这部分重写为单独的INSERT/UPDATE/DELETE语句
  3. 我通常同意。我这样做的原因是,如果我TRUNCATE/INSERT在那个时候从 staging 开始,它需要 6-10 秒,而sp_rename需要不到一秒。所以锁定表的时间更少
  4. 这不会影响表锁定,因为它首先将数据放入临时表。我别无选择,只能使用链接服务器或 SSIS,在这种情况下,我更喜欢链接服务器将所有 SQL 保存在一个地方
  5. 我总是使用XML而不是CONCAT因为否则 'a', 'bc' 的哈希值与 'ab', 'c' 相同,这是不正确的

从登台到填充活动表的所有处理都很好 - 我只想尽量减少最终活动表的锁定时间,

sql-server locking
  • 1 1 个回答
  • 313 Views

1 个回答

  • Voted
  1. Best Answer
    J.D.
    2022-05-18T10:49:40+08:002022-05-18T10:49:40+08:00

    不幸的是,我一眼就看到了你的代码中的很多罪恶:

    1. 声明中存在许多已知的错误,MERGE即在生产代码中确实应该完全避免它。

    2. MERGE也被认为不如编写个人INSERT,UPDATE和DELETE语句的表现; 这可能是您的一些阻塞问题的原因。

    3. 虽然很诱人,但使用该sp_rename功能来最小化阻塞问题实际上会导致更严重的阻塞问题,正如 Kendra Little 的为什么你应该切换临时表而不是重命名它们中所讨论的那样。(如果我没记错的话,这讨论了使用分区切换作为更好的解决方案。)

    4. 链接服务器有时也被称为性能瓶颈(用于固定基数估计并在处理之前将所有数据带到网络中)。如果您以前在代码的事务中依赖它,则可以只将该部分保留在事务之外,以最大限度地减少本地表的锁定时间。

    5. 此外,我确实喜欢使用该HASHBYTES()函数来生成行哈希,这是我过去使用过的东西。CONCAT()但是您可能还会发现,通过在每一列中使用安全的列分隔符(例如双管道||)作为参数,而不是在利用 XML 的子查询周围使用它,在行本身上调用它会更高效。

    6. 话虽如此,正如 Erik Darling 所指出的,HASHBYTES()它本身有时也容易受到大规模性能问题的影响。如果这是您的瓶颈,您可以尝试在计算列或索引视图中具体化函数的结果(它是确定性的),或者使用链接帖子中提到的替代方法,例如 CLR。

    • 8

相关问题

  • 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