【问题标题】:SQL Azure Alternative to Service Broker服务代理的 SQL Azure 替代方案
【发布时间】:2019-11-11 23:34:03
【问题描述】:

我们的软件是一组连接到 SQL 数据库的 Windows 应用程序。目前我们所有的客户站点都有自己的服务器和 SQL Server 数据库,但是我正在努力使我们的软件也可以与 Azure 托管的数据库一起使用。

我遇到了一个问题,到目前为止,在谷歌搜索时没有发现任何特别有用的东西。

当前的 SQL Server 版本包括我编写的数据库审计系统,它执行以下操作:-

C# 应用程序在连接字符串中包含有关它是哪个程序和版本以及当前登录的用户的信息。

重要表具有更新和删除触发器,它们将任何更改的详细信息发送到 Service Broker 队列。 (我不记录插入)。

Service Broker 然后遍历队列,并将更改的详细信息记录到单独的 AuditLog 表中。

这些细节包括:-

表、更改的行的 PK、字段、旧值、新值、更新还是删除、更改日期/时间、登录到我们软件的用户的用户 ID,以及哪个程序和版本使改变。

这一切都很好,我希望在 Azure 版本中保持系统原样,但不幸的是 SQL Azure 没有 Service Broker。

所以,我需要寻找替代方案,正如我所提到的,这很麻烦。

有 SQL Azure 托管实例,它确实有 Service Broker,但是它们太贵了,我们甚至无法考虑。我们没有一个客户愿意每月支付这么多钱。

我看过的其他任何东西似乎都没有我需要的一切。特别是,记录哪个程序、版本和用户 ID。请注意,这不是 SQL 登录用户 ID,每个人都一样,这是用户表中他们登录到我们软件时使用的 ID,并在连接字符串中传递。

所以,理想情况下,我想要与我所拥有的类似的东西,只是用其他东西代替 Service Broker:-

C# 应用程序在连接字符串中包含有关它是哪个程序和版本以及当前登录的用户的信息。

重要表具有更新和删除触发器,它们将任何更改的详细信息发送到某种异步队列

然后有东西通过队列在正常程序流程之外,并将更改的详细信息记录到单独的 AuditLog 表中。

正常程序流程之外的异步队列和处理很重要。显然我可以很容易地让 Update 和 Delete 触发器完成所有处理并将记录添加到 AuditLog 表中,实际上这是系统的 v1.0,但问题是 SQL 会等到触发器完成之前返回 C# 程序。当发生多个更新或删除时,这会导致 C# 程序显着变慢。

我很乐意研究其他日志系统而不是上述系统,但是仅记录数据更改而没有我传递的额外信息(特别是程序、版本和用户 ID)的东西对我没有任何用处。每当我们的用户查询他们认为不正确的更改时,他们总是想知道这些信息。

那么,对于 SQL Azure 的 Service Broker 的替代方案有什么建议吗?蒂亚!

【问题讨论】:

  • 您是否考虑过使用 Azure SQL 托管实例?它确实支持服务代理。也可以在这里查看stackoverflow.com/a/49175326/1537195 //edit: 对不起,忽略了你上面的评论
  • 您是否考虑过在虚拟机中运行 SQL Server?

标签: sql-server logging azure-sql-database audit service-broker


【解决方案1】:

好的,看来我有一个潜在的解决方案:临时表

临时表在 Azure 中工作,并在发生变化时在历史表中记录一个新行:-

CREATE TABLE dbo.LMSTemporalTest   
(    
  [EmployeeID] INT NOT NULL PRIMARY KEY CLUSTERED   
  , [Name] NVARCHAR(100) NOT NULL  
  , [Position] NVARCHAR(100) NOT NULL   
  , [Department] NVARCHAR(100) NOT NULL  
  , [Address] NVARCHAR(1024) NOT NULL  
  , [AnnualSalary] DECIMAL (10,2) NOT NULL  
  , [UpdatedBy] UniqueIdentifier NOT NULL
  , [UpdatedDate] DateTime NOT NULL
  , [ValidFrom] DateTime2 (2) GENERATED ALWAYS AS ROW START HIDDEN
  , [ValidTo] DateTime2 (2) GENERATED ALWAYS AS ROW END HIDDEN
  , PERIOD FOR SYSTEM_TIME (ValidFrom, ValidTo)  
)    
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.LMSTemporalTestHistory));  
GO

然后我可以在表中插入一条记录...

INSERT INTO LMSTemporalTest(EmployeeID,Name,Position,Department,Address,AnnualSalary, UpdatedBy, UpdatedDate)
VALUES(1, 'Bob', 'Builder', 'Fixers','Oops I forgot', 1, '0D7F5584-C79B-4044-87BD-034A770C4985', GetDate())
GO

更新行...

UPDATE LMSTemporalTest SET 
Address = 'Sunflower Valley, Bobsville',
UpdatedBy = '2C62290B-61A9-4B75-AACF-02B7A5EBFB80',
UpdatedDate = GetDate()
WHERE EmployeeID = 1
GO

再次更新该行...

UPDATE LMSTemporalTest SET 
AnnualSalary = 420.69,
UpdatedBy = '47F25135-35ED-4855-8050-046CD73E5A7D',
UpdatedDate = GetDate()WHERE EmployeeID = 1
GO

然后查看结果:-

SELECT * FROM LMSTemporalTest
GO

EmployeeID  Name    Position    Department  Address AnnualSalary    UpdatedBy   UpdatedDate
1   Bob Builder Fixers  Sunflower Valley, Bobsville 420.69  47F25135-35ED-4855-8050-046CD73E5A7D    2019-07-01 16:20:00.230

注意:因为我将它们设置为隐藏,所以 Valid From 和 Valid To 不显示

检查日期/时间范围的更改:-

SELECT * FROM LMSTemporalTest  
FOR SYSTEM_TIME BETWEEN '2019-Jul-01 14:00' AND '2019-Jul-01 17:10'   
WHERE EmployeeID = 1
ORDER BY ValidFrom;
GO

EmployeeID  Name    Position    Department  Address AnnualSalary    UpdatedBy   UpdatedDate
1   Bob Builder Fixers  Oops I forgot   1.00    0D7F5584-C79B-4044-87BD-034A770C4985    2019-07-01 16:20:00.163
1   Bob Builder Fixers  Sunflower Valley, Bobsville 1.00    2C62290B-61A9-4B75-AACF-02B7A5EBFB80    2019-07-01 16:20:00.197
1   Bob Builder Fixers  Sunflower Valley, Bobsville 420.69  47F25135-35ED-4855-8050-046CD73E5A7D    2019-07-01 16:20:00.230

我什至可以查看历史记录表

SELECT * FROM LMSTemporalTestHistory
GO

EmployeeID  Name    Position    Department  Address AnnualSalary    UpdatedBy   UpdatedDate ValidFrom   ValidTo
1   Bob Builder Fixers  Oops I forgot   1.00    0D7F5584-C79B-4044-87BD-034A770C4985    2019-07-01 16:20:00.163 2019-07-01 16:20:00.16  2019-07-01 16:20:00.19
1   Bob Builder Fixers  Sunflower Valley, Bobsville 1.00    2C62290B-61A9-4B75-AACF-02B7A5EBFB80    2019-07-01 16:20:00.197 2019-07-01 16:20:00.19  2019-07-01 16:20:00.22

注意:当前行不显示,因为它仍然有效

我们所有的重要表都已经有 CreatedBy、CreatedDate、UpdatedBy 和 UpdatedDate,所以我可以将它们用于 UserID 日志记录。没有将程序和版本作为标准处理的明显方法,但我总是可以添加另一个隐藏字段并使用触发器来设置它。

编辑:实际测试过

第一个障碍是:您是否真的可以将现有表更改为临时表,答案是:可以!

ALTER TABLE Clients ADD 
    [ValidFrom] DateTime2 (2) GENERATED ALWAYS AS ROW START HIDDEN NOT NULL DEFAULT '1753-01-01 00:00:00.000',
    [ValidTo] DateTime2 (2) GENERATED ALWAYS AS ROW END HIDDEN NOT NULL DEFAULT '9999-12-31 23:59:59.997',
    PERIOD FOR SYSTEM_TIME (ValidFrom, ValidTo)  
GO

ALTER TABLE Clients SET (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.ClientsHistory))
GO

上面的重要一点是 ValidFrom 和 ValidTo 字段的默认值。它仅在 ValidTo 是 DateTime2 可以达到的最大值时才有效,因此是 '9999-12-31 23:59:59.997'。 ValidFrom 似乎无关紧要,所以我将其设置为最低限度以涵盖所有内容。

好的,所以我已经转换了一个表,但它现在有两个非 Azure 表没有的额外字段,理论上是隐藏的,但是我们的软件会抱怨它们吗?

好像没有。启动软件,在Clients表中编辑一条记录并保存,软件完全没有报错。

检查了 Clients 和 ClientsHistory 表:-

SELECT * FROM Clients  
FOR SYSTEM_TIME BETWEEN '1753-01-01 00:00:00.000' AND '9999-12-31 23:59:59.997'   
WHERE sCAccountNo = '0001064'
ORDER BY ValidFrom

显示两条记录,原始记录和已编辑记录,并且现有的 UpdatedUser 和 UpdatedDate 字段显示正确,因此我知道谁进行了更改以及何时进行了更改。

SELECT * FROM ClientsHistory

显示原始记录,ValidTo 设置为更改日期,

一切似乎都很好,现在我只需要检查它是否仍然只返回查询中的当前记录和我们的软件:-

SELECT * FROM Clients  
WHERE sCAccountNo = '0001064'

只返回一条记录,不显示 HIDDEN 字段 ValidFrom 和 ValidTo。

在我们的软件中搜索了客户端 0001064,它再次只返回了一条记录,并没有抱怨两个额外的字段。

仍然需要设置一些触发器并添加另一个 HIDDEN 字段来记录连接字符串中的程序和版本,但看起来 Temporal Tables 给了我一个可行的审计选项。

到目前为止唯一的缺点是它为每组更改创建一个完整的记录行,这意味着您必须将其与其他记录进行比较以找出更改的内容,但我可以写一些东西来简化这一点。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-11-01
    • 2014-03-31
    • 1970-01-01
    • 2020-08-23
    • 2022-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多