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 / 问题 / 342033
Accepted
Vaccano
Vaccano
Asked: 2024-08-30 07:25:26 +0800 CST2024-08-30 07:25:26 +0800 CST 2024-08-30 07:25:26 +0800 CST

如果触发器运行更新,它是否总是具有与时间表相同的时间戳?

  • 772

背景

这是一个与我正在使用的相似的示例:

CREATE TABLE sandboxTesting.TemporalTest (    
    GroupNumber VARCHAR(25) NOT NULL,
    StartEffectiveWhen DATE NOT NULL,
    EndEffectiveWhen DATE NULL,
    ModifiedWhen DATETIME NULL,
    IsReady BIT NOT NULL DEFAULT 0,
    RowValidFrom DATETIME2 GENERATED ALWAYS AS ROW START NOT NULL,
    RowValidTo DATETIME2 GENERATED ALWAYS AS ROW END NOT NULL,
    PERIOD FOR SYSTEM_TIME (RowValidFrom, RowValidTo),
    CONSTRAINT PK_TemporalTest PRIMARY KEY CLUSTERED  
    (
        GroupNumber, StartEffectiveWhen
    )
) WITH (SYSTEM_VERSIONING=ON (HISTORY_TABLE=sandboxTesting.TemporalTestHistory))
GO 

CREATE TRIGGER sandboxTesting.OnModify ON sandboxTesting.TemporalTest AFTER UPDATE AS
BEGIN
    
    UPDATE  temporalTst
    SET     temporalTst.IsReady = 0,
            temporalTst.ModifiedWhen = GETDATE()
    FROM    sandboxTesting.TemporalTest temporalTst
            JOIN deleted del
                ON del.GroupNumber = temporalTst.GroupNumber
                AND del.StartEffectiveWhen = temporalTst.StartEffectiveWhen
    WHERE   -- All business columns go here with OR statements in between them.
            -- The idea is that if anything changes except the IsReady flag, then we 
            -- set the IsReady back to false.  (IsReady has to be set by itself)
            del.EndEffectiveWhen <> temporalTst.EndEffectiveWhen 
            OR (del.EndEffectiveWhen IS NULL AND temporalTst.EndEffectiveWhen IS NOT NULL)
            OR (del.EndEffectiveWhen IS NOT NULL AND temporalTst.EndEffectiveWhen IS NULL)
END
GO

-- Insert new test
INSERT INTO [sandboxTesting].[TemporalTest] ([GroupNumber], [StartEffectiveWhen], [EndEffectiveWhen],  [ModifiedWhen])
VALUES ('12345', '2024-01-1', NULL, NULL)
GO

-- Set is as ready 
UPDATE  sandboxTesting.TemporalTest
SET     IsReady = 1
WHERE   GroupNumber = '12345' AND StartEffectiveWhen = '2024-01-1'
GO 

-- Change the End date
UPDATE  sandboxTesting.TemporalTest
SET     EndEffectiveWhen = '2024-09-02'
WHERE   GroupNumber = '12345' AND StartEffectiveWhen = '2024-01-1'
        
-- Set the new end date as ready for billing.
UPDATE  sandboxTesting.TemporalTest
SET     IsReady = 1
WHERE   GroupNumber = '12345' AND StartEffectiveWhen = '2024-01-1'
GO 


-- Select the Data
SELECT * FROM sandboxTesting.TemporalTest for SYSTEM_TIME ALL 
ORDER BY GroupNumber, StartEffectiveWhen desc, RowValidFrom DESC, RowValidTo DESC, ModifiedWhen desc

-- Select the Raw Data (for comparison)
SELECT * FROM sandboxTesting.TemporalTest
UNION ALL 
SELECT * FROM sandboxTesting.TemporalTestHistory
ORDER BY GroupNumber, StartEffectiveWhen desc, RowValidFrom DESC, RowValidTo DESC, ModifiedWhen desc

当我运行它时,这是第一个结果:

群组号码 开始生效时间 生效日期 修改时间 已就绪 行有效地址 RowValidTo
12345 2024-01-01 2024-09-02 2024-08-29 17:15:28.587 1 2024-08-29 23:15:28.5764223 9999-12-31 23:59:59.9999999
12345 2024-01-01 无效的 无效的 1 2024-08-29 23:15:28.5295658 2024-08-29 23:15:28.5764223
12345 2024-01-01 无效的 无效的 0 2024-08-29 23:15:28.4826980 2024-08-29 23:15:28.5295658

第二组输出如下:

群组号码 开始生效时间 生效日期 修改时间 已就绪 行有效地址 RowValidTo
12345 2024-01-01 2024-09-02 2024-08-29 17:15:28.587 1 2024-08-29 23:15:28.5764223 9999-12-31 23:59:59.9999999
12345 2024-01-01 2024-09-02 2024-08-29 17:15:28.587 0 2024-08-29 23:15:28.5764223 2024-08-29 23:15:28.5764223
12345 2024-01-01 2024-09-02 无效的 1 2024-08-29 23:15:28.5764223 2024-08-29 23:15:28.5764223
12345 2024-01-01 无效的 无效的 1 2024-08-29 23:15:28.5295658 2024-08-29 23:15:28.5764223
12345 2024-01-01 无效的 无效的 0 2024-08-29 23:15:28.4826980 2024-08-29 23:15:28.5295658

这是不同的,因为第一个查询结果使用了for SYSTEM_TIME ALL子句,而第二个查询结果只是查询原始数据。

不同之处在于,在第一个数据集中,第二个数据集的第二行和第三行已被过滤掉。它们被删除是因为第二行和第三行的开始日期和结束日期相同。(基本上说这些行从未真正生效。)

问题

我需要知道的是,对于通过触发器更新的数据,我是否可以依赖这个“零时间差” AFTER?(如果不是这种情况,我需要编写一些查询,这些查询将会失败。)

我的意思是:如果我的服务器被数千个查询所困扰,这些查询都进行着大量的 IO 和计算,那么第二个数据集的第二行和第三行的RowValidFrom和RowValidTo值的差是否仍然为 0?

换句话说,这些值是否因为事务逻辑而相同?还是因为我的服务器速度很快并且目前没有任何压力,所以它们相同?

sql-server
  • 2 2 个回答
  • 229 Views

2 个回答

  • Voted
  1. Rodger Kong
    2024-08-30T11:07:03+08:002024-08-30T11:07:03+08:00

    在您构建的场景中,不,第二行不能确定它是否由AFTER触发器更新。但第三行可以被视为触发触发器的操作。

    我在我的慢速笔记本电脑上运行了你的脚本,结果是这样的: 我的结果 第二行的起始时间和结束时间不一样。但第三行的起始时间和结束时间相同,这是因为一行在TemporalTest同一个事务中被修改了多次。在你的示例中,阶段 1:更新EndEffectiveWhen,这记录在第 3 行;阶段 2:AFTER TRIGGER被触发以更新IsReady,这记录在第 2 行。历史表标记了具有相同ValidFrom和ValidTo时间的记录,以识别更新是在同一事务中对同一 PK 执行的,并在最后一个历史记录中记录事务的结束时间。你可以在文档ValidTo中查看描述。

    • 3
  2. Best Answer
    Paul White
    2024-08-30T20:08:09+08:002024-08-30T20:08:09+08:00

    我能否依赖这个“零时间差”始终存在于通过 AFTER 触发器更新的数据中

    不会。只要您在同一事务中多次更新同一行(即使实际上没有更改任何列值),就会出现有效期为零的行。只有事务中的最终(有效)行更改才能具有非零有效期。

    在您的例子中,触发器会进行最终更改,因此其有效期通常不为零。如果整个事务和后续更改在所用计时器的分辨率以下完成,则其长度仍为零。

    请记住,触发器在触发语句的事务中运行。即使没有显式或隐式事务,也总会有由原始更新启动的自动提交事务。


    当我将您的示例作为单个批处理运行时,关闭执行计划以尽量减少语句之间的延迟,我看到:

    全速取得成果

    查询ASOF仅返回两行,因为语句完成得太快,三个历史记录条目的有效期为零。

    具体来说,更改结束日期、随后的触发器执行以及最终将IsReady设置为 1 似乎都是立即完成的。因此,视图ASOF看起来好像IsReady从未设置为零。

    您可以通过在触发器中引入小延迟或在 SSMS 中启用实际执行计划来避免测试中出现此类结果WAITFOR。无论如何,额外的延迟将防止非常快速的操作被记录为零有效期。

    通过执行计划,我看到:

    SSMS 结果和执行计划

    延迟意味着ASOF查询现在显示IsReady从 0 到 1 的转换。

    您还可以一次运行一个测试语句,而不是一次性在单个批次中运行所有测试语句。


    这些都不会改变这样一个事实:触发器所做的更改发生在触发语句的事务中,将是对该事务内特定行的最终更改,因此是唯一具有非零有效期的事件。

    • 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