26

我试图解决一个问题,这一次,我没有创造。

我在一个有许多 Web 应用程序的环境中工作,这些应用程序由不同服务器上的不同数据库支持。

每个数据库的设计和应用都相当独特,但每个数据库中仍然存在我想抽象出来的通用数据。例如,每个数据库都有一个供应商表、一个用户表等......

我想将这些公共数据抽象到一个数据库中,但仍然让其他数据库加入这些表,甚至有键来强制约束等......我在 MsSql 环境中。

在此处输入图像描述

有哪些可用选项?在我看来,我有以下选择:

  • 链接服务器
  • 只读登录以授予对视图的访问权限

还有什么要考虑的吗?

4

5 回答 5

27

有很多方法可以解决这个问题。我强烈推荐解决方案 1、2 或 3,具体取决于您的业务需求:

  1. 事务复制:如果公共数据库是帐户的记录,并且您希望将数据的只读版本提供给单独的应用程序,那么您可以将核心表,甚至可能只是表的核心列复制到每个单独的服务器。这种方法的一个优点是您可以根据需要复制到任意数量的订阅者数据库。这也意味着您可以根据订阅者的需要自定义哪些表和字段可供订阅者使用。因此,如果一个应用程序需要用户表而不是供应商表,那么您只需订阅用户表。如果另一个只需要供应商表而不需要用户表,那么您可以只订阅供应商表。另一个好处是复制保持同步,如果出现问题,您可以随时重新初始化订阅。

    我使用事务复制从数据仓库推出了 100 多个表,以分隔需要访问来自多个系统的聚合数据的下游应用程序。由于我们的数据仓库每小时从镜像和日志传送数据源更新一次,因此生产应用程序在每小时 20 到 80 分钟的滑动窗口内拥有来自多个系统的数据。

    对等事务复制作为发布类型可能更适合您提供的用例。如果您想逐节点推出模式或复制更改,这将非常有用。标准事务复制在这方面有一些限制。

    快照复制发布类型比事务发布类型具有更多延迟,但如果一定程度的延迟是可以接受的,您可能需要考虑它。

    尽管您提到您是一家 Microsoft SQL Server 商店,但请记住其他 RDBM 具有类似的技术。由于您专门讨论的是 MS SQL Server,请注意事务复制也允许您复制到 Oracle 数据库。因此,如果您的组织中有一些这样的解决方案,该解决方案仍然可以工作。

    使用事务复制的一个缺点是,如果您的中央服务器出现故障,您可能会开始在复制对象的下游副本中遇到数据延迟。如果复制的对象(文章)非常大并且您需要重新初始化表,那么这也可能需要很长时间才能完成。

  2. 镜像:如果您想在下游服务器上近乎实时地访问数据库,您最多可以设置两个异步镜像。我以这种方式将数据与 CRM 应用程序集成。所有读取都来自镜像的连接。所有写入都被推送到消息队列,然后将更改应用到中央生产服务器。这种方法的缺点是您不能创建超过 2 个异步镜像。您不想为此目的使用同步镜像,除非您也计划使用镜像进行灾难恢复。

  3. 消息系统:如果您希望有许多单独的应用程序需要来自单个中央数据库的数据,那么您可能需要考虑企业消息系统,如 IBM Web Sphere、Microsoft BizTalk、Vitria、TIBCO 等。这些应用程序专门用于解决这个问题。它们的实施和维护往往既昂贵又麻烦,但如果您拥有全球分布式系统或数十个单独的应用程序,它们都需要在某种程度上共享数据,它们可以扩展。

  4. 链接服务器:听起来您已经想到了这个。您可以通过链接服务器公开数据。我不相信这是一个好的解决方案。如果你真的想走这条路,那么考虑设置一个从中央数据库到另一台服务器的异步镜像,然后设置到镜像的链接服务器连接。这至少会降低来自 Web 应用程序的查询会导致中央生产数据库阻塞或性能问题的风险。

    IMO,链接服务器往往是为应用程序共享数据的危险方法。这种方法仍然将数据视为数据库中的二等公民。它会导致一些非常糟糕的编码习惯,特别是因为您的开发人员可能在不同的服务器上使用不同的语言和不同的连接方法工作。您不知道是否有人会针对您的核心数据编写真正可怕的查询。如果您设置了一个标准,要求将共享数据的完整副本下推到非核心服务器,那么您不必担心开发人员是否编写了错误的代码。至少从他们糟糕的代码不会危及其他编写良好的系统的性能的角度来看。

    有很多很多资源可以解释为什么在这种情况下使用链接服务器可能会很糟糕。一个非详尽的原因列表包括:(a)用于链接服务器的帐户必须具有 DBCC SHOW STATISTICS 权限,否则查询将无法使用现有统计信息,(b) 不能使用查询提示,除非作为 OPENQUERY 提交,(c) 与 OPENQUERY 一起使用时无法传递参数,(d) 服务器没有关于链接服务器的足够统计信息,因此会创建非常糟糕的查询计划,(e) 网络连接问题可能导致失败,(f)这五个性能问题中的任何一个,以及 (g)在双跳场景中尝试验证 Windows Active Directory 凭据时出现可怕的 SSPI 上下文错误. 链接服务器对于某些特定场景可能很有用,但不建议围绕此功能构建对中央数据库的访问,尽管在技术上是可行的。

  5. 批量 ETL 流程:如果 Web 应用程序可以接受高度延迟,那么您可以使用SSIS(此 StackOverflow 问题中有很多好的链接)编写批量 ETL 流程,这些流程由 SQL Server 代理作业执行以在服务器之间移动数据。还有其他替代 ETL 工具,如 Informatica、Pentaho 等,因此请使用最适合您的工具。

    如果您需要低延迟,这不是一个好的解决方案。我在与第三方托管的 CRM 解决方案同步时使用了这个解决方案,这些解决方案可以容忍高延迟。对于不能容忍高延迟的字段(基本帐户创建数据),我们依靠在帐户生成时通过 Web 服务调用在 CRM 中创建重复记录。

  6. 每晚备份和恢复:如果您的数据可以容忍高度延迟(最多一天)和不可用时段,那么您可以跨环境备份和恢复数据库。对于需要 100% 正常运行时间的 Web 应用程序,这不是一个好的解决方案。这个想法是您进行基线备份,将其还原为单独的还原名称,然后在新数据库准备好使用后立即重命名原始数据库和新数据库。我已经看到一些内部网站应用程序这样做了,但我通常不推荐这种方法。这更适合较低的开发环境,而不是生产环境。

  7. 日志传送辅助节点:您可以在主节点和任意数量的辅助节点之间设置日志传送。这类似于夜间备份和恢复过程,不同之处在于您可以更频繁地更新数据库。在一个实例中,该解决方案用于通过在两个日志传送接收者之间切换来向下游用户公开来自我们主要核心系统之一的数据。还有另一台服务器指向两个数据库,并在新数据库可用时在它们之间切换。我真的很讨厌这个解决方案,但有一次我看到这个实现确实满足了业务的需求。

于 2013-05-06T19:20:06.690 回答
2

可能还有其他选择,但认为您是通过链接服务器和视图组合获得最佳选择的正确途径。这可以像创建一个新数据库、添加两个链接服务器、设置您的权限然后创建必要的视图一样简单。

如果您的目标是,abstract out this common data to a single database but still let the other databases join on these tables, even have keys to enforce constraints那么这个解决方案应该可以正常工作。

在不利的一面,您可能会遇到链接服务器的性能问题,因此如果您预见到数据库会获得大量流量,那么您可能需要考虑使用 Doug 或 mwebber 建议的方法实际移动数据。

如果您确实使用链接服务器路线,我建议您阅读. OPENQUERY这里有一篇关于OPENQUERYvs 4 部分标识符的好文章

于 2013-05-06T19:08:37.493 回答
2

您还可以考虑在公共数据存储和应用程序数据库之间使用内置 SQL Server 复制。根据我的经验,它非常适合双向数据传输,并且每个数据库中都有一个表实例可以使用外键(我认为 FK 无法通过链接服务器实现)。

于 2013-05-04T06:09:02.823 回答
1

看看Microsoft 同步框架。您将不得不编写一个同步应用程序,但它可能会为您提供所需的灵活性。

于 2013-05-04T07:35:30.997 回答
1

正如许多答案所述,我认为您应该好好看看复制,特别是在高 TPS 环境中,或者您希望在许多表上都这样做。但是,我将提供一些代码,说明我如何使用链接服务器、同义词和检查约束在我的一些系统中实现您的既定目标。

我想将这些公共数据抽象到一个数据库中,但仍然让其他数据库加入这些表,甚至有键来强制约束等

您可以将数据库中的视图或同义词设置为链接服务器(或其他本地数据库)中的公用表。如果视图本来就是这样,我更喜欢同义词select * from table

如果您有权限,表同义词将允许您在远程项目上运行 DML。

不过,此时您的视图或同义词不能有外键,但我们可以通过检查约束来完成类似的事情。

让我们看一些代码:

create synonym MyCentralTable for MyLinkedServer.MyCentralDB.dbo.MyCentralTable
go

create function dbo.MyLocalTableFkConstraint (
    @PK int
)
returns bit
as begin
    declare @retVal bit
    select @retVal = case when exists (
                            select null from MyCentralTable where PK = @PK
                        ) then 1 else 0 end
    return @retVal
end
go

create table MyLocalTable (
    FK int check (dbo.MyLocalTableFKConstraint(FK) = 1)
)
go

-- Will fail: -1 not in MyLinkedServer.MyRemoteDatabase.dbo.MyCentralTable
insert into MyLocalTable select -1
-- Will succeed: RI on a remote table w/o triggers
insert into MyLocalTable select FK from MyCentralTable

当然,重要的是要注意,如果您删除中央表中的引用记录,您不会收到错误消息。

于 2013-05-06T20:07:39.243 回答