小编Zap*_*002的帖子

如何在没有递归的情况下使用触发器更新同一行上的列?

SQL Server 2012。

每当我的表中的记录发生更改时,我都需要使用当前日期和时间更新列 [LastUpdated]。目前我有:

CREATE TRIGGER Trig_LastUpdated ON Contact AFTER UPDATE
AS
SET NOCOUNT ON

UPDATE ct
SET LastUpdated = GETDATE()
FROM Contact ct
INNER JOIN Inserted i
    ON ct.IDContact = i.IDContact
Run Code Online (Sandbox Code Playgroud)

但这是递归的,我不希望这样,会导致死锁和其他奇怪的事情。我无法全局关闭递归触发器。我看到 INSTEAD OF 触发器是非递归的,但是如果我这样做,我是否必须检查 Inserted 中的所有其他列以查看它是否已更新,或者 SQL Server 是否会为我处理?做到这一点的最佳方法是什么?

trigger sql-server deadlock sql-server-2012 row-modification-time

6
推荐指数
2
解决办法
2万
查看次数

我如何有效地处理非常倾斜的数据?最新的统计数据,但似乎没有帮助

我有一个表dbo.ClaimBilling,有 130,000 行。在该表中,列OperatorID是 avarchar(max)并且严重倾斜。125,000 行是 'user1',其余 5000 行分为 6 个其他值,'user2' 共有 3 条记录。

上有一个非聚集索引OperatorID,聚集索引是主键,IDClaimBilling

我目前有以下查询:

SELECT DISTINCT IDClaimBilling
FROM dbo.ClaimBilling cb
INNER JOIN dbo.BillingItem bi
    ON cb.IDClaimBilling = bi.ClaimID
WHERE OperatorID = @operator
Run Code Online (Sandbox Code Playgroud)

不管是什么值@operator,来自行的估计ClaimBilling都是~4000,这与任何值会返回的值都不接近,而且它始终是聚集索引扫描,它不使用operatorID索引。如果我删除加入并做

SELECT DISTINCT IDClaimBilling
FROM dbo.ClaimBilling
WHERE OperatorID = @operator
Run Code Online (Sandbox Code Playgroud)

然后它确实使用了OperatorID索引,但是无论 的值如何,估计都是错误的@operator,这次总是估计 ~18,000 左右。

UPDATE STATISTICS dbo.ClaimBilling WITH FULLSCAN在运行查询之前做了一个。

即使统计信息确切地知道每个值有多少行,为什么这些估计值如此错误?

@operator在测试中声明并分配一个值。它最初是程序的一部分,我认为这就是问题所在,但在临时声明中使用时它的行为也是一样的。

该查询仅在用户首次登录时运行,因此每个用户每天可能只运行几次。

performance sql-server statistics sql-server-2012 cardinality-estimates query-performance

6
推荐指数
1
解决办法
610
查看次数

INSERT/UPDATE 存储过程本身死锁

我有一个表 (Database2.dbo.OrganizerDataDependencyChange),其中包含有关某些其他表中的行上次更改时间的信息。在这些表中的每一个上,我都有一个触发器,它调用一个存储过程 (Database2.dbo.SaveOrganizerDataDependencyChange),该过程简单地用触发器触发的时间更新 Database2.dbo.OrganizerDataDependencyChange。这些触发器是从 Database1 或 Database2 触发的,因此它们通常是跨数据库调用。

当更新表上的两个不同行时,我在 Database1.dbo.OrganizerDataDependencyChange 表上遇到读写死锁,我不明白为什么。表上只有一个索引,而且它是完全覆盖查询的聚集索引,因此不可能出现查找死锁,尽管 proc 中有两条语句,但我特地将其重写为我所理解的最佳方法避免并发问题,使用 WHERE NOT EXISTS 而不是使用 IF/ELSE 逻辑,所以它不应该从不同的角度出现在这个索引上,对吗?由于它是在触发器和跨数据库中触发的,因此我在重现该问题时遇到了一些困难,我当然可以重现阻塞,但这应该没问题,这正是我所期望的。

有人可以帮助我了解这里发生了什么吗?我可能可以使用 NOLOCK 提示或 applock 修复它,但我仍然不明白为什么会发生这种情况。

这是表:

CREATE TABLE [dbo].[OrganizerDataDependencyChange](
[TableID] [INT] NOT NULL,
[Database] [VARCHAR](150) NOT NULL,
[Updated] [DATETIME] NULL
)
CREATE CLUSTERED INDEX [CX_OrganizerDataDependencyChange_TableID_DB] ON [dbo].[OrganizerDataDependencyChange]
(
[TableID] ASC,
[Database] ASC
)
Run Code Online (Sandbox Code Playgroud)

这是存储过程:

CREATE PROCEDURE [dbo].[SaveOrganizerDataDependencyChange]
(
@TableID int,
@Database varchar(150)
)
AS
BEGIN

SET NOCOUNT ON;

    DECLARE @rowcount INT;

INSERT INTO dbo.OrganizerDataDependencyChange
        ( TableID, [Database], Updated )
SELECT TOP …
Run Code Online (Sandbox Code Playgroud)

sql-server deadlock insert update sql-server-2014

4
推荐指数
1
解决办法
4307
查看次数

由于从多个数据库创建高并发临时表而导致对 tempdb 的争用?

我有一个包含约 100 个数据库的环境,所有数据库都具有相同的架构。每个数据库上都有一个存储过程,它创建一个#temp 表并删除它,并且运行非常频繁(每个用户每 30 秒左右,并且有 1000 多个用户)。它的作用远不止于此:我们正在将潜在的数千行加载到这个临时表中,然后将整个内容转储出来,基本上它聚合了一堆数据。

由于所有数据库都创建相同的临时表,它们是否都相互竞争?还是每个数据库都在 tempdb 中获得了自己的临时表版本?

似乎他们有争用,因为我看到大量PAGE_LATCH等待,都在 tempdb ( 2:3:1041580)的同一页面上,这不是 GAM、SGAM 或 PFS 页面,并且 90% 的等待似乎来自同一个页面跨所有数据库的存储过程。这些等待占服务器总等待的 90%,并导致阻塞。

我做了一个DBCC PAGE,它似乎是sysobjvalues(来自标题中的 object_ID 60)。我跑了:

SELECT OBJECT_Name(object_ID), * 
FROM sys.dm_db_database_page_allocations(2,60,NULL,NULL,'DETAILED')
Run Code Online (Sandbox Code Playgroud)

我得到 153 行,不确定我在这里看到的是什么。看起来像它IN_ROW_DATALOB_DATAallocation_unit_type_desc

我在与其他文件不同的卷上有 8 个 tempdb 文件。我有 16 个内核,但我的理解是,由于它不是分配页面,因此可能无助于增加文件数量。使用 SQL Server 2017 企业版。

我觉得最好的办法是告诉开发人员在这里删除临时表,但这需要重新处理逻辑并且需要一些时间。在等待开发修复时,我还能做些什么来避免这些页面闩锁?

sql-server concurrency tempdb blocking sql-server-2017

4
推荐指数
1
解决办法
1115
查看次数