2009-11-04 16 views
3

我有一个服务器(SQL Server 2005)与多个档案数据库(每个季度拉伸8年),都是结构相同。最有效的方法来查询单独的数据库中的多个相同的表

我经常需要查询跨越n个数据库的某个日期范围,通常n是小的1-3,但可能需要查询整个集合。

任何想法n从代码清洁度和性能角度来看这是最有效的方法吗?

当前的解决方案相当特别,有一个跨所有或最近数据库的视图集合,其他解决方案是生成动态SQL,以确定哪些数据库包含所需的数据。

显然,理想的解决办法是分区表,但我不能这样做,因为它提供的第三方数据库

戴夫

编辑:我不能结合数据库,因为他们是第3总数据大小约为50GB,因此不是很大,最大的表格每季度包含大约150万行

EDIT2:数据仓库绝对是长期的正确解决方案(它在计划中),但我可以'今天做这个:(

+0

最有效的方法是将它们组合成一个单一的数据库 – 2009-11-04 19:13:06

回答

6

一种方式做到这一点:使用sp_msForEachDb。

- 回合1 -------

呼叫用VARCHAR参数此系统过程。 (它实际上是一个很大混乱比这,检查主数据库的代码,如果你想知道它的真正在做什么。) 参数必须是动态的代码块 - 例如,

DECLARE @DemoParameter varchar(1000) 
SET @DemoParameter = 'SELECT MyCol from MyTable where CreatedOn between ''Jan 1, 1980'' and ''Dec 21, 2012''' 
EXECUTE sp_msForEachDb @DemoParameter 

这将针对SQL实例上的每个数据库运行查询,每个数据库返回一个集合 - 除了那些没有必要的表的数据库,这将导致错误(特别是系统数据库)的错误。这使我们...

- 回合2 ---------

在动态代码,数据库遍历问号的所有实例?将被替换为当前正在处理的数据库的名称。您可以使用它来过滤哪些数据库将被处理,哪些不是。还要注意,“当前”数据库将而不是由例程更改,您必须自己做。这给了我们这样的代码:

SET @DemoParameter = ' 

IF ''?'' like ''%Foo%'' 
BEGIN 
    USE ? 
    SELECT MyCol from MyTable where CreatedOn between ''Jan 1, 1980'' and ''Dec 21, 2012'' 

' 

这将只针对那些名称中包含字符“foo”的数据库运行查询。可能您可以检查每个数据库中的表格是否存在;其他方法表明自己。

这将猎枪回为每一个数据库,这不利于如果你需要他们都在一个整洁有序的数据集太大一个数据集,并可以让我们来...

- 回合3 ------------

简述:创建一个临时表,并从动态查询中填充它。正如我在下面显示的那样,您可以包含数据库的名称以及服务器名称 - 当您跨越几台服务器跨越数十个数据库查找丢失的数据时非常有用。

创建(或清除)临时表:

IF object_id('tempdb.dbo.##Foo') is null 
    CREATE TABLE ##Foo 
    (
     ServerName   varchar(100) not null 
     ,DBName    varchar(100) not null 

     -- Add your own columns here 
     ,MyCol    int not null 
    ) 

ELSE 
    --Option: Delete this line to not clear on each run 
    TRUNCATE TABLE ##Foo 

运行的代码(这是我的主模板,你可以轻松地工作@DemoParameter回到那里):

EXECUTE sp_msForEachDB ' 
IF ''?'' like ''%Foo%'' 
BEGIN 
    USE ? 

    INSERT ##Foo 
    select @@servername, db_name() 
     ,MyCol 
     from MyTable 
END 
' 

.. 。这应该会产生一个包含您的数据的临时表。测试了这一点,我没有真正测试代码编写这个,并且typso将塞进(#temp表格应该和## temp一样工作,我通常是这样做的,并且有ad-hoc系统支持问题)

+1

由此,我普遍同意所有说“合并您的数据”的人。很容易说,但很难做到。只要你认识到像我这样的例程是停工或者变通的,并且你自己学习并且从不建立这样的数据库系统,你应该是好的。 – 2009-11-04 19:56:18

0

根据数据库的大小,实际上最好将它们合并到一个数据库并对它们进行适当索引。

您可以编写自己的SSIS包并安排它定期合并数据(日/小时/等)。

3

这是要做的事情!

声明
@Database VARCHAR(8000),
@sql VARCHAR(8000)
BEGIN 声明数据库名光标LOCAL FAST_FORWARD 对于选择名称 FROM sys.databases中 其中名称像 'Your_DB_Names%'

打开数据库名 WHILE(1 = 1) 开始 FETCH NEXT从数据库名成@Database

如果@@ FETCH_STATUS = -1,如果@@ FETCH_STATUS =打破
-2继续

设置@sql = '使用' + @数据库 打印@sql 执行(@sql)

SELECT * FROM表 - 您的查询这里 结束 关闭数据库名
解除分配数据库名 END

+1

SHEESH !!不要开始使用速度慢的** CURSORS **!真是糟糕的想法..... – 2009-11-04 19:54:22

+0

可以说游标只用于获取数据库名称,而不是遍历实际SQL查询的结果集。 – 2009-11-04 19:57:30

+1

这里的游标代价相对于从数据库中抽出30米行数是最小的 – 2009-11-04 19:58:05

2

我经常这样做,让我告诉你,保持独立的数据库是在一个痛苦的屁股。它迫使你在各处做各种各样的逻辑 - 它首先打破了作为数据库的封装。

你在看什么是数据仓库。您应该考虑将所有数据库合并为一个,并使其成为只读。然后,您每晚对您的实时数据进行增量备份,并对您的仓库进行恢复。然后,您的仓库始终处于最新状态,并针对该报告运行报告,而不是实时数据。

这有让您的报告中从杀死你的现场制作数据库的结果,我猜向上的90%的业务需求并不需要100%的准确刚刚在时间的数字。

做硬的东西一次 - 创建一个仓库。 :-)

编辑

东西我已经在过去做的是创造我使用的表的视图,并使用链接数据库(如果DBS是在其他机器上)

Create view view_tale as 
    select * from activedb.dbo.table 
    union 
    select * from db1.dbo.table 
    union 
    select * from db2.dbo.table 

隐晦,性能明智,但整齐地解决了问题。然后,您仍然只有一次性安装问题(为每个要查询的表创建一个视图),以及一个集中的地方进行修改,以使您的数据库列表保持最新以进行持续维护,而不是将N个报告保留至今。

+0

数据仓库绝对是未来的计划(也许明年如果我得到了我的方式),但我仍然有我的短期问题 – 2009-11-04 19:55:31

+0

视图的方法是我们现在使用,但我从视图扩散的痛苦,我有一个回到2个季度,一个只看最新版本的顺序......它可以工作,但是这是一种痛苦,是继承另一个人的“设计”的喜悦。 – 2009-11-04 21:52:55

+0

然后,您最好做的事情是使用某种脚本工具在您每次创建数据库时重建视图。你可以想象通过在master..sysdatabases中运行一个光标来获取数据库名称,并动态地构建你的视图。这是一个痛苦,但它不得不定制写每个报告。如果你能摆脱它的话,我最好甚至把视图放在另一个数据库中。在工作数据库中将您的扩散保持在最低限度,并且仍然可以让您获得统一的数据视图。 – 2009-11-05 13:39:07

1

Danielle's答案为我工作,稍作改动。我们的服务器上有数十个开发数据库,​​用于我们所有的客户,使用常规前缀和后缀命名的组中。使用游标可以查看某个组的所有数据库中的所有记录。不过,我必须进行更改,因为“执行”对于“使用”命令不起作用,所以我只用数据库名称创建了整个命令。

 
Declare 
@Database varchar(8000), 
@Sql varchar(8000) 
BEGIN Declare DBName Cursor LOCAL FAST_FORWARD For Select name FROM sys.databases where name like 'MyPrefix%MySuffix' 

Open DBName WHILE (1=1) Begin Fetch Next From DBName into @Database 

if @@Fetch_status = -1 Break 
if @@Fetch_status = -2 Continue 

set @Sql = 'select * from '[email protected]+'MyTable' 
print @sql 
execute (@sql) 
End 
Close DBName 
Deallocate DBName 
END 
相关问题