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 / 问题 / 120073
Accepted
JohnG
JohnG
Asked: 2015-11-05 07:25:08 +0800 CST2015-11-05 07:25:08 +0800 CST 2015-11-05 07:25:08 +0800 CST

触发器创建要发送到服务代理的变量表

  • 772

我第一次设置了服务代理并对其进行了测试……看起来不错。每次在特定表上发生 DML 操作时;假设价格表,一个触发器调用一个存储过程,将插入和删除的表作为 XML 参数传递给它,这会将消息(包含 2 个 XML)发送到队列。

激活过程然后处理队列,并将对初始表所做的更改插入到审计表中......效果很好。

当价格表上的更新量很大时,就会出现问题。就我而言,我测试了 105 000 件商品的价格变化更新。XML Inserted 和 Deleted 变量,每个包含 130 万行......这会导致主要问题:TempDB 无限增长,处理器上升到 95%,这是可以理解的......但似乎从未完成操作。

触发器的代码是Price_TAB_Audit_trig。触发器调用SendMsgServiceBroker过程将消息发送到队列。有关激活过程,请参阅下面的评论。

我试图弄清楚如何将插入和删除的变量(消息)分解成更小的 XML。我的问题/想法是:我可以创建表变量并将其传递到消息而不是 XML 中吗?如果是这样,如何在触发器中创建变量表?我应该创建全局唯一临时表并在消息中引用它们吗?

任何其他建议,欢迎。提前谢谢你

sql-server trigger
  • 2 2 个回答
  • 2524 Views

2 个回答

  • Voted
  1. Best Answer
    Hannah Vernon
    2015-11-05T10:04:44+08:002015-11-05T10:04:44+08:00

    您可以使用以下设置中的触发器之类的东西以预定义的块发送 xml 数据。

    在 tempdb 中创建测试平台:

    USE tempdb;
    
    IF EXISTS (SELECT 1 FROM sys.triggers t WHERE t.name = 'TriggerTest_Chunked')
    DROP TRIGGER dbo.TriggerTest_Chunked;
    
    
    IF EXISTS(SELECT 1 FROM sys.tables t WHERE t.name = 'TriggerTest')
    DROP TABLE dbo.TriggerTest;
    
    CREATE TABLE dbo.TriggerTest
    (
        ID INT NOT NULL
    );
    
    IF EXISTS(SELECT 1 FROM sys.tables t WHERE t.name = 'TriggerTestTarget')
    DROP TABLE dbo.TriggerTestTarget;
    
    CREATE TABLE dbo.TriggerTestTarget
    (
        OperationType INT NOT NULL
        , DEETS XML NOT NULL
    );
    

    触发:

    CREATE TRIGGER dbo.TriggerTest_Chunked
    ON dbo.TriggerTest
    AFTER INSERT, UPDATE, DELETE
    AS
    BEGIN
        DECLARE @RowStart INT;
        DECLARE @RowEnd INT;
        DECLARE @RowCount INT;
        DECLARE @BatchSize INT;
        SET @BatchSize = 1000;
    
        SET @RowStart = 0;
    
        SELECT @RowCount = COUNT(1) 
        FROM inserted;
    
        IF @RowCount > @BatchSize 
            SET @RowEnd = @BatchSize
        ELSE
            SET @RowEnd = @RowCount;
    
        WHILE @RowEnd <= @RowCount AND (@RowStart < @RowEnd)
        BEGIN
            INSERT INTO dbo.TriggerTestTarget (OperationType, DEETS)
            SELECT 1, (
                SELECT ID
                FROM (
                        SELECT *
                            , rn = ROW_NUMBER() OVER (ORDER BY ID)
                        FROM inserted
                    ) i_rn
                WHERE i_rn.rn > @RowStart
                    AND i_rn.rn <= @RowEnd
                FOR XML PATH('')
            );
    
            SET @RowStart = @RowStart + @BatchSize;
            IF @RowEnd + @BatchSize > @RowCount
                SET @BatchSize = @RowCount - @RowEnd;
            SET @RowEnd = @RowEnd + @BatchSize;
        END
    
        SET @RowStart = 0;
    
        SELECT @RowCount = COUNT(1) 
        FROM deleted;
    
        IF @RowCount > @BatchSize 
            SET @RowEnd = @BatchSize
        ELSE
            SET @RowEnd = @RowCount;
    
        WHILE @RowEnd <= @RowCount AND (@RowStart < @RowEnd)
        BEGIN
            INSERT INTO dbo.TriggerTestTarget (OperationType, DEETS)
            SELECT 2, (
                SELECT ID
                FROM (
                        SELECT *
                            , rn = ROW_NUMBER() OVER (ORDER BY ID)
                        FROM deleted
                    ) i_rn
                WHERE i_rn.rn > @RowStart
                    AND i_rn.rn <= @RowEnd
                FOR XML PATH('')
            );
    
            SET @RowStart = @RowStart + @BatchSize;
            IF @RowEnd + @BatchSize > @RowCount
                SET @BatchSize = @RowCount - @RowEnd;
            SET @RowEnd = @RowEnd + @BatchSize;
        END
    END
    GO
    

    插入一些测试数据以查看触发器的作用:

    INSERT INTO dbo.TriggerTest (ID)
    SELECT ROW_NUMBER() OVER (ORDER BY o1.object_id, o2.object_id) 
    FROM sys.objects o1
        , sys.objects o2;
    

    显示结果:

    SELECT *
    FROM dbo.TriggerTest;
    
    SELECT *
    FROM dbo.TriggerTestTarget;
    
    DELETE TOP(100)
    FROM dbo.TriggerTest;
    
    SELECT *
    FROM dbo.TriggerTestTarget;
    
    • 1
  2. Hannah Vernon
    2015-11-05T11:16:51+08:002015-11-05T11:16:51+08:00

    通过使用表值参数将详细信息传递到存储过程的示例,请看一下:

    清理测试台对象(如果它们已经存在):

    USE tempdb;
    
    IF EXISTS (SELECT 1 FROM sys.triggers t WHERE t.name = 'TriggerTest1')
    DROP TRIGGER dbo.TriggerTest1;
    
    IF EXISTS (SELECT 1 FROM sys.sql_modules sm 
        INNER JOIN sys.objects o ON sm.object_id = o.object_id 
        WHERE o.name = 'InsertFromTrigger')
    DROP PROCEDURE dbo.InsertFromTrigger;
    
    IF EXISTS (SELECT 1
        FROM sys.types t
        WHERE t.name = 'TriggerData'
    )
    DROP TYPE TriggerData;
    
    IF EXISTS(SELECT 1 FROM sys.tables t WHERE t.name = 'TriggerTest')
    DROP TABLE dbo.TriggerTest;
    
    IF EXISTS(SELECT 1 FROM sys.tables t WHERE t.name = 'TriggerTestTarget')
    DROP TABLE dbo.TriggerTestTarget;
    

    创建测试台对象:

    /*
        Creates a custom table-type definition
    */
    CREATE TYPE TriggerData AS TABLE
    (
        OperationType INT NOT NULL
        , ID INT NOT NULL
    );
    
    CREATE TABLE dbo.TriggerTest
    (
        ID INT NOT NULL
    );
    
    CREATE TABLE dbo.TriggerTestTarget
    (
        OperationType INT NOT NULL
        , ID INT NOT NULL
    );
    GO
    
    /*
        create a procedure to accept data from the trigger
    */
    CREATE PROCEDURE dbo.InsertFromTrigger
    (
        @td AS TriggerData READONLY
    )
    AS
    BEGIN
        INSERT INTO dbo.TriggerTestTarget
        SELECT *
        FROM @td;
    END
    GO
    
    
    /*
        create a trigger to send data to the stored proc
    */
    CREATE TRIGGER dbo.TriggerTest1
    ON dbo.TriggerTest
    AFTER INSERT, UPDATE, DELETE
    AS
    BEGIN
        DECLARE @t TriggerData;
        INSERT INTO @t (OperationType, ID)
        SELECT 1, *
        FROM inserted
        UNION ALL 
        SELECT 2, *
        FROM deleted;
        EXEC dbo.InsertFromTrigger @t;
    END
    GO
    

    测试触发器/存储过程:

    INSERT INTO dbo.TriggerTest
    SELECT ROW_NUMBER() OVER (ORDER BY o1.object_id, o2.object_id)
    FROM sys.objects o1
        , sys.objects o2;
    
    DELETE TOP(50) 
    FROM dbo.TriggerTest;
    

    查看目标表中的内容:

    SELECT *
    FROM dbo.TriggerTest;
    
    SELECT *
    FROM dbo.TriggerTestTarget;
    

    如果空间很宝贵,并且您决定更新大量行,这可能仍然会带来相当大的问题,因为 SQL Server 需要在表变量中为inserted和中存在的所有数据分配空间deleted。

    然而,至少从代码可读性的角度来看,这是解决问题的一种优雅方式。

    • 1

相关问题

  • 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