为什么使用服务代理 在开始探讨代码之前,我要讲一下为什么我选择使用SQL 服务代理替代SQL复制的一点幕后原因。这样可能对阐述有好处。 (选择使用SQL服务代理代替SQL复制的)主要原因是我们想在数据从生产环境OLTP数据库迁移到报表数据库时,能对数据做ETL(数据提取转换加载)。我们还需要很容易地就能从一个报表数据库扩展为多个数据库的能力,以满足报表服务器在不同地点的情况。
表 下面你会发现一些SQL代码,我们将用这些代码创建一些示例表。在我们的OLTP数据库中,我们创建了两个表,它们是表“LoanApplication”和表“Customer”,而在我们的报表数据库中我们只……
我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。
我原创,你原创,我们的内容世界才会更加精彩!
【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】
微信公众号
TechTarget
官方微博
TechTarget中国
为什么使用服务代理
在开始探讨代码之前,我要讲一下为什么我选择使用SQL 服务代理替代SQL复制的一点幕后原因。这样可能对阐述有好处。
(选择使用SQL服务代理代替SQL复制的)主要原因是我们想在数据从生产环境OLTP数据库迁移到报表数据库时,能对数据做ETL(数据提取转换加载)。我们还需要很容易地就能从一个报表数据库扩展为多个数据库的能力,以满足报表服务器在不同地点的情况。
表
下面你会发现一些SQL代码,我们将用这些代码创建一些示例表。在我们的OLTP数据库中,我们创建了两个表,它们是表“LoanApplication”和表“Customer”,而在我们的报表数据库中我们只有一个表“LoanApplication”。当数据插入或者更新到表“LoanApplication ”和表“Customer”时,数据会打包成XML文档并发送到报表数据库。在我这里的示例代码中,所有东西都在一台服务器上,但是数据库要挪到分离的服务器上也是非常容易的。
SQL:
- IF EXISTS (SELECT * FROM sys.DATABASES WHERE name = ‘Sample_OLTP’)
- DROP DATABASE Sample_OLTP
- GO
- IF EXISTS (SELECT * FROM sys.DATABASES WHERE name = ‘Sample_Reporting’)
- DROP DATABASE Sample_Reporting
- GO
-
- CREATE DATABASE Sample_OLTP
- CREATE DATABASE Sample_Reporting
- GO
-
- ALTER DATABASE Sample_OLTP SET NEW_BROKER
- ALTER DATABASE Sample_Reporting SET NEW_BROKER
- GO
- ALTER DATABASE Sample_OLTP SET TRUSTWORTHY ON
- ALTER DATABASE Sample_Reporting SET TRUSTWORTHY ON
- GO
-
- USE Sample_OLTP
- GO
- CREATE TABLE LoanApplication
- (ApplicationId INT IDENTITY(1,1),
- CreateTimestamp DATETIME,
- LoanAmount MONEY,
- SubmittedOn DATETIME,
- ApprovedOn DATETIME,
- LoanStatusId INT,
- PrimaryCustomerId INT,
- CoSignerCustomerId INT)
- GO
- CREATE TABLE Customer
- (CustomerId INT IDENTITY(1,1).
- FirstName VARCHAR(50),
- LastName VARCHAR(50),
- EmailAddress VARCHAR(255))
- GO
- USE Sample_Reporting
- GO
- CREATE TABLE LoanReporting
- (ApplicationId INT,
- CreateTimestamp DATETIME,
- LoanAmount MONEY,
- SubmittedOn DATETIME,
- ApprovedOn DATETIME,
- LoanStatusId INT,
- PrimaryCustomerId INT,
- PrimaryFirstName VARCHAR(50),
- PrimaryLastName VARCHAR(50),
- PrimaryEmailAddress VARCHAR(255),
- CoSignerCustomerId INT,
- CoSignerFirstName VARCHAR(50),
- CoSignerLastName VARCHAR(50),
- CoSignerEmailAddress VARCHAR(255))
- GO
服务代理对象
在这个系统中,我只利用一对服务代理队列来处理所有数据传输。这样可以在数据流入时维持相互一致性。这些SQL服务代理对象应该被在示例OLTP数据库和示例报表数据库中创建。
SQL:
- CREATE MESSAGE TYPE ReplData_MT
- GO
- CREATE CONTRACT ReplData_Ct
- (ReplData_MT SENT BY ANY)
- GO
- CREATE QUEUE ReplData_Source_Queue
- GO
- CREATE QUEUE ReplData_Destination_Queue
- GO
- CREATE SERVICE ReplData_Source_Service
- ON QUEUE ReplData_Source_Queue
- (ReplData_Ct)
- GO
- CREATE SERVICE ReplData_Destination_Service
- ON QUEUE ReplData_Destination_Queue
- (ReplData_Ct)
- GO
路由(route)
在该OLTP数据库中,你创建了这样一个route(根据你的实际服务器修改BROKER_INSTANCE)。
SQL:
- CREATE ROUTE ReplData_Route
- WITH SERVICE_NAME=‘ReplData_Destination_Service’,
- BROKER_INSTANCE=‘566C7F7A-9373-460A-8BCC-5C1FD4BF49C9′,
- ADDRESS=‘LOCAL’
在该报表数据库中,你创建了这样一个route(根据你的实际服务器修改BROKER_INSTANCE)。
SQL:
- CREATE ROUTE ReplData_Route
- WITH SERVICE_NAME=‘ReplData_Source_Service’,
- BROKER_INSTANCE=‘A4EC5E44-60AF-4CD3-AAAD-C3D467AC682E’,
- ADDRESS=‘LOCAL’
OLTP数据库中的存储过程
在该OLTP数据库中我们只需要一个存储过程。这个存储过程将处理信息的发送,这样我们就不必在每个表中写相同的代码。
SQL:
- CREATE PROCEDURE SendTriggerData
- @XMLData XML
- AS
- BEGIN
- DECLARE @handle UNIQUEIDENTIFIER
-
- BEGIN DIALOG CONVERSATION @handle
- FROM SERVICE ReplData_Source_Service
- TO SERVICE ‘ReplData_Destination_Queue’
- ON CONTRACT ReplData_Ct
- WITH ENCRYPTION=OFF;
-
- SEND ON CONVERSATION @handle
- MESSAGE TYPE ReplData_MT
- (@XMLData)
- END
- GO
OLTP数据库触发器
该OLTP数据库中每个表上的触发器被保持尽可能小,以便我们给该OLTP服务器增加尽可能少的负载负担。很明显我们会给该OLTP数据库带来额外负载,但是我们希望把它保持在最小。
SQL:
- CREATE TRIGGER t_LoanApplication ON LoanApplication
- FOR INSERT, UPDATE
- AS
- BEGIN
- DECLARE @xml XML
-
- SET @xml = (SELECT *
- FROM inserted AS LoanApplication
- FOR XML AUTO, ROOT(‘root’))
-
- EXEC SendTriggerData @xml
- END
- GO
-
- CREATE TRIGGER t_Customer ON Customer
- FOR INSERT, UPDATE
- AS
- BEGIN
- DECLARE @xml XML
-
- SET @xml = (SELECT *
- FROM inserted AS Customer
- FOR XML AUTO, ROOT(‘root’))
-
- EXEC SendTriggerData @xml
- END
- GO
报表数据库中的存储过程
该报表数据库是实际工作执行的地方。在这里我们获取XML文档,识别数据从哪个表来,然后把XML文档传递给子存储过程,然后处理数据并更新表。
SQL:
- CREATE PROCEDURE ProcessOLTPData_LoanApplication
- @xml XML
- AS
- DECLARE @hDoc INT
- EXEC sp_xml_preparedocument @hDoc OUTPUT, @xml
-
- UPDATE LoanReporting
- SET ApplicationId=a.ApplicationId,
- CreateTimestamp = a.CreateTimestamp,
- LoanAmount=a.LoanAmount,
- SubmittedOn=a.SubmittedOn,
- ApprovedOn=a.ApprovedOn,
- LoanStatusId=a.LoanStatusId
- FROM OPENXML (@hDoc, ‘/root/LoanApplication’)
- WITH (ApplicationId INT ‘@ApplicationId’,
- CreateTimestamp DATETIME ‘@CreateTimestamp’,
- LoanAmount MONEY ‘@LoanAmount’,
- SubmittedOn DATETIME ‘@SubmittedOn’,
- ApprovedOn DATETIME ‘@ApprovedOn’,
- LoanStatusId INT ‘@LoanStatusId’,
- PrimaryCustomerId INT ‘@PrimaryCustomerId’,
- CoSignerCustomerId INT ‘@CoSignerCustomerId’) a
- WHERE a.ApplicationId = LoanReporting.ApplicationId
-
- INSERT INTO LoanReporting
- (ApplicationId, CreateTimestamp, LoanAmount, SubmittedOn, ApprovedOn, LoanStatusId, PrimaryCustomerId, CoSignerCustomerId)
- SELECT ApplicationId, CreateTimestamp, LoanAmount, SubmittedOn, ApprovedOn, LoanStatusId, PrimaryCustomerId, CoSignerCustomerId
- FROM OPENXML (@hDoc, ‘/root/LoanApplication’)
- WITH (ApplicationId INT ‘@ApplicationId’,
- CreateTimestamp DATETIME ‘@CreateTimestamp’,
- LoanAmount MONEY ‘@LoanAmount’,
- SubmittedOn DATETIME ‘@SubmittedOn’,
- ApprovedOn DATETIME ‘@ApprovedOn’,
- LoanStatusId INT ‘@LoanStatusId’,
- PrimaryCustomerId INT ‘@PrimaryCustomerId’,
- CoSignerCustomerId INT ‘@CoSignerCustomerId’) a
- WHERE NOT EXISTS (SELECT * FROM LoanReporting WHERE a.ApplicationId = LoanReporting.ApplicationId)
-
- EXEC sp_xml_removedocument @hDoc
- GO
- CREATE PROCEDURE PRocessOLTPData_Customer
- @xml XML
- AS
- DECLARE @hDoc INT
- EXEC sp_xml_preparedocument @hDoc OUTPUT, @xml
-
- UPDATE LoanReporting
- SET PrimaryEmailAddress = EmailAddress,
- PrimaryFirstName = FirstName,
- PrimaryLastName = LastName
- FROM OPENXML(@hDoc, ‘/root/Customer’)
- WITH (CustomerId INT ‘@CustomerId’,
- FirstName VARCHAR(50) ‘@FirstName’,
- LastName VARCHAR(50) ‘@LastName’,
- EmailAddress VARCHAR(255) ‘@EmailAddress’) a
- WHERE PrimaryCustomerId = a.CustomerId
-
- UPDATE LoanReporting
- SET CoSignerEmailAddress = EmailAddress,
- CoSignerFirstName = FirstName,
- CoSignerLastName = LastName
- FROM OPENXML(@hDoc, ‘/root/Customer’)
- WITH (CustomerId INT ‘@CustomerId’,
- FirstName VARCHAR(50) ‘@FirstName’,
- LastName VARCHAR(50) ‘@LastName’,
- EmailAddress VARCHAR(255) ‘@EmailAddress’) a
- WHERE CoSignerCustomerId = a.CustomerId
-
- EXEC sp_xml_removedocument @hDoc
- GO
-
- CREATE PROCEDURE ProcessOLTPData
- AS
- DECLARE @xml XML
- DECLARE @handle UNIQUEIDENTIFIER, @hDoc INT
-
- WHILE 1=1
- BEGIN
- SELECT @xml = NULL, @handle = NULL
-
- WAITFOR (RECEIVE TOP (1) @handle=conversation_handle,
- @xml=CAST(message_body AS XML)
- FROM ReplData_Destination_Queue), TIMEOUT 1000
-
- IF @handle IS NULL
- BREAK
-
- EXEC sp_xml_preparedocument @hDoc OUTPUT, @xml
-
- IF EXISTS (SELECT *
- FROM OPENXML(@hDoc, ‘/root/LoanApplication’)
- )
- BEGIN
- EXEC ProcessOLTPData_LoanApplication @xml
- END
-
- IF EXISTS (SELECT *
- FROM OPENXML (@hDoc, ‘/root/Customer’)
- )
- BEGIN
- EXEC PRocessOLTPData_Customer @xml
- END
-
- EXEC sp_xml_removedocument @hDoc
-
- END CONVERSATION @handle
- END
- GO
你现在可以设置该队列作为激活的存储过程运行存储过程“ProcessOLTPData ”,它会在数据到达时处理数据。
作者
翻译
相关推荐
-
SAP HANA数据存储:OLTP与OLAP存储方法对比
本文选自《Implementing SAP HANA》,我们主要介绍了OLTP和OLAP所用到的不同数据存储方法。
-
理解MongoDB数据库底层I/O机制
当MongoDB涉及到大数据可扩展性的问题时,开发者还是需要了解一下它的底层,弄明白那些潜在的问题,然后才能快速地进行解决。
-
Oracle TimesTen的内存结构与应用场景
TimesTen内存结构比Oracle数据库简单很多。与Oracle不同,TimesTen并没有数据库缓冲区、保存池或丢弃池的概念。
-
中小企业如何做好BI项目管理
中小企业的IT部门通常小而精,做事也更有效率,可以比较大的公司消耗更低成本。但是他们也有自己的局限。