好吧,让我们分解一下:
- 如何在多个数据库的两个表之间构造联接?(这里的代码示例会有所帮助)。
这很简单。SQL对象具有一到四部分的命名约定:
服务器名。数据库名。架构名。表名
如果所有表都位于同一数据库的同一服务器上,并且具有相同的所有者/模式,则可以忽略前三个部分,并使用最常用的方法:
Select a.*,b.* from
tableA a inner join
tableB b on a.col1=b.col1
如果您的一个表位于另一个数据库中,并且两个表均使用其数据库的默认架构,则只需将数据库添加到第二个表中:
Select a.*,b.* from
tableA a inner join
databaseC..tableB b on a.col1 = b.col1
如果您恰巧位于与您要查询的另一个数据库都不相同的第三个数据库中,则显式使用两个数据库名称:
Select a.*,b.* from
databaseD..tableA a inner join
databaseC..tableB b on a.col1 = b.col1
如果最终使用了不同的模式和/或所有者,则可以在以下位置添加它们:
Select a.*,b.* from
databaseD.john.tableA a inner join
databaseC.accounting.tableB b on a.col1 = b.col1
最后,如果您对此非常谨慎并且有充分的理由,则可以在另一台服务器上加入一个(通常很小的)表:
Select a.* from
databaseD.john.TableA a inner join
ATLANTA.databaseC.accounting.tableB b on a.col1 = b.col1
- 什么时候可以超越1数据库/ 1服务器设置?需要这样做有多普遍?是否有用于跟踪哪个数据库中的表的特殊策略?
我将两者结合起来,因为它们在一起。通常,假设一台数据库一台服务器就足够了,直到您的设计/业务/技术约束迫使您使用更多数据库时,您通常总是可以的。
因此,首先回答您的第二个问题,因为通常您都有单独的数据库的理由,所以从了解系统的设计位置应该很明显。
至于何时/为什么有必要超越单个数据库。通常,这是业务规则,政治和/或技术原因的混合。
例如,在我工作的地方,我们有16个数据库分布在4台服务器上。我们有一个MainDB,ImageDB,referencetableDB,HighvolumeTransactionDB,ReportingDB,StagingDB,ProcessingDB,ArchiveDB,FinancialDB。举例说明它们为何不同:
- FinancialDB,敏感信息
- 映像数据库,特定的不同存储和恢复要求
- ReferenceDB,低事务,高读取
- 与许多其他数据不同,ReportingDB具有很高的读取率,需要将其还原/复制到其他各种环境中
- StagingDB,没有永久的东西,只是增强了的tempdb,我们可以更好地控制
- MainDB,与所有其他DB接口,但需要差异备份,因此...我们将
- HighVolumeTransaction表(相对短暂)到其自己的DB,以保持备份的合理大小。
- 存档,来自Main和Reporting的许多相同数据,但是保留期更长,并且难以深入数据查询。如果仍然与Main / Reporting结合使用,则会使我们的系统瘫痪。
• 应用程序代码是否需要知道一个或多个数据库分布在多个服务器上?如果不是,则在什么级别过滤请求?
从广义上讲,它们可能会这样做。他们至少需要知道数据库连接字符串中指向的服务器。处理,报告,主要等
从那里,他们确实需要在其下执行的数据库上下文。通常,那将是该应用程序中最常用的一种,甚至可能是该应用程序的一个数据库/一台服务器中的原始版本。您可以让应用程序在每次调用时显式切换数据库上下文,但是这使得在不更改应用程序的情况下很难调整数据库。
通常(或至少是MY通常)的方法是始终通过一个或两个主要数据库进行访问。
然后根据需要在其他数据库中创建视图,并通过存储过程与数据库接口相结合。
所以来说明一下:
假设您要获取客户的人口统计信息,销售数据和贷方余额,并且这些数据最初分布在MainDB中的三个表中。
因此,您可以通过应用编写呼叫:
Select c.ClientName, c.ClientAddress, s.totalSales,f.CreditBlance from
Clients c join Sales s on c.clientid = s.clientid inner join AccountReceivable f on
c.clientid=f.clientid where c.clientid = @clientid
太棒了 但是,现在无论何时我们更改列名或重命名/移动表,都必须更新应用程序代码。因此,我们改为做两件事:
创建客户,销售,AccountReceivables视图(您不会使用Select *,但我在这里进行演示)
Use MainDB
GO
Create view v_Clients as select * from Clients
Create view v_Sales as select * from Sales
Create view v_AccountReceivable as select * from AccountReceivable
Go
然后,我们还将创建一个存储过程spGetClientSalesAR
Create proc spGetClientSalesAR @clientID int
as
Select c.ClientName as ClientName,
c.ClientAddress as ClientAddress,
s.totalSales as TotalSales,
f.CreditBlance as CreditBalance
from
v_Clients c join v_Sales s
on c.clientid = s.clientid
inner join v_AccountReceivable f
on c.clientid=f.clientid
where c.clientid = @clientid
并让您的应用调用它。
现在,只要不更改该存储proc上的接口,我几乎就可以对后端数据库进行任何需要扩展或扩展的操作。
在极端情况下,我什至可以使我的旧MainDB变成一堆带壳的存储过程和视图,以便在我们创建的这些视图下看起来像这样:
Create view v_Clients as select * from ServerX.DatabaseY.dbo.Clients
Create view v_Sales as select * from ServerQ.DatabaseP.dbo.Sales
Create view v_AccountReceivable as select * from ServerJ.DatabaseK.dbo.AccountReceivable
而且您的应用永远也不会知道两者之间的区别(假设快速的管道传输和良好的暂存数据等等)。
显然,这是极端的,如果我说所有事情都是以这种方式计划的,那我会撒谎,但是即使您在重构时使用存储过程/视图(即使您这样做了)也可以让您有很大的灵活性,因为您的应用程序从其谦逊的一台数据库/一台服务器成长而来开始。