Sql server 2005 SQL Server 2008动态跨数据库视图

Sql server 2005 SQL Server 2008动态跨数据库视图,sql-server-2005,sql-server-2008,Sql Server 2005,Sql Server 2008,我们在SQLServer2008R2 SE中有一个名为AVL的数据库。这个数据库有许多表,但有一个特别称为ASSETLOCATION的表,它现在有4600万行,占数据库总大小的99.9% 此表包含2008年至今的信息,实际增长率约为每天12万条记录。 现在,我们要解决两种情况: 性能开始慢慢下降,而且一切都很好 优化了,所以没什么可做的 备份时间在增加,并且正在成为一个问题(我们只做1次完整备份) 每天备份)。winrar完成他的工作后,BAK文件是11GB 最终大小为2GB,然后脚本将文件发

我们在SQLServer2008R2 SE中有一个名为AVL的数据库。这个数据库有许多表,但有一个特别称为ASSETLOCATION的表,它现在有4600万行,占数据库总大小的99.9%

此表包含2008年至今的信息,实际增长率约为每天12万条记录。 现在,我们要解决两种情况:

  • 性能开始慢慢下降,而且一切都很好 优化了,所以没什么可做的
  • 备份时间在增加,并且正在成为一个问题(我们只做1次完整备份) 每天备份)。winrar完成他的工作后,BAK文件是11GB 最终大小为2GB,然后脚本将文件发送到异地。我们有 一个T1和拉2GB通过电线大约需要5个小时
所有这些都很正常,但我想抓住一个机会:+90%的SQL语句只使用了3个月或更短的信息,换句话说,2008年、2009年和2010年的数据不经常被访问

我在考虑每年创建一个新的数据库。让我们说: -AVL2008数据库,只有该表将包含2008年的记录 -AVL2009数据库,只有该表将包含2009年的记录 -AVL2010数据库,只有该表将有ASSETLOCATION,其中包含2010年的记录

正如您已经猜到的,过去的数据不会被更改,因此从备份的角度来看,这将是非常好的,因为AVL数据库将只包含今年的记录。这种方法也将大大提高性能

现在来看问题。假设ASSETLOCATION表包含以下列: -IDASSETLOCATION(int、PK标识) -IDASSET(整数,FK到资产表) -何时(日期时间) -LATLONG(varchar(22),空间信息)

我需要在AVL数据库中创建一个名为“vASSETLOCATION”的视图,这个视图非常简单,但我不希望该视图访问所有数据库并通过UNION连接ASSETLOCATION表,而希望该视图是基于WHEN字段所需的唯一视图。例如:

select * from vASSETLOCATION where [WHEN] between '2008-01-01' and '2008-01-02'
CREATE PROCEDURE dbo.DetermineViews
    @StartDate     DATETIME,
    @EndDate       DATETIME,
    @optionalToday BIT = 0
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @sql NVARCHAR(MAX) = N'';

    SET @sql = @sql + N'SELECT * FROM ' + CASE
      WHEN @StartDate >= '20080101' AND @EndDate < '20090101' THEN 'AVL2008.dbo.ASSETLOCATION'
      WHEN @StartDate >= '20080101' AND @EndDate < '20100101' THEN 'dbo.vAL_2008_2009'
      WHEN @StartDate >= '20080101' AND @EndDate < '20110101' THEN 'dbo.vAL_2008_2010'
      -- etc. etc.

      WHEN YEAR(@StartDate) = YEAR(CURRENT_TIMESTAMP) THEN 'AVL.dbo.ASSETLOCATION'
    ELSE '' END;

    IF @OptionalToday = 1 AND YEAR(@StartDate) <> YEAR(CURRENT_TIMESTAMP)
    BEGIN
        SET @sql = @sql + N'UNION ALL SELECT * FROM AVL.dbo.ASSETLOCATION'
    END

    SET @sql = @sql + ' WHERE [WHEN] BETWEEN ''' 
        + CONVERT(CHAR(8), @StartDate, 112) + ''' AND '''
        + CONVERT(CHAR(8), @EndDate,   112) + '''';

    IF @OptionalToday = 1
    BEGIN
        SET @sql = @sql + ' OR ([WHEN] >= DATEDIFF(DAY, 0, CURRENT_TIMESTAMP)
            AND [WHEN] < DATEADD(DAY, 1, DATEDIFF(DAY, 0, CURRENT_TIMESTAMP)';
    END

    PRINT @sql;
    -- EXEC sp_executeSQL @sql;
END
GO
在这种情况下,视图应该只访问AVL2008.ASSETLOCATION表

select * from vASSETLOCATION where [WHEN] between '2008-12-29' and '2009-01-05'
在这种情况下,视图应该访问AVL2008.ASSETLOCATION和AVL2009.ASSETLOCATION

select * from vASSETLOCATION where 
    ([WHEN] between '2008-01-01' and '2008-01-01')
or 
    ([WHEN] = getdate())
在这种情况下,视图应访问AVL2008.ASSETLOCATION和AVL.ASSETLOCATION

我知道用表标量UDF代替视图可以解决这个问题,但是有4个以上的字段,[WHEN]并不是我们希望在where部分中包含的唯一字段。 在任何人提出建议之前,表分区功能可能会有助于提高性能,但不会解决备份问题

在视图中是否有这样做的方法?
谢谢。-

这听起来像是or的经典案例

但是,您可以使用一些智能代码来解决这个问题,而无需为Enterprise edition(企业版)支付价格(或进行支持这些功能所需的所有准备工作),这些代码对问题的看法略有不同。您不希望一个视图访问不同数据库中的所有表,但是如果您有多个视图和一个存储过程来控制如何访问它们呢

为最常见的访问模式创建视图。也许您的视图涵盖了2008-2010、2008-2009、2009-2010等的日期范围。它们可能如下所示:

CREATE VIEW dbo.vAL_2008_2009 
AS
    SELECT * FROM AVL2008.dbo.ASSETLOCATION
    UNION ALL
    SELECT * FROM AVL2009.dbo.ASSETLOCATION;
GO

CREATE VIEW dbo.vAL_2008_2010
AS
    SELECT * FROM AVL2008.dbo.ASSETLOCATION
    UNION ALL
    SELECT * FROM AVL2009.dbo.ASSETLOCATION
    UNION ALL
    SELECT * FROM AVL2010.dbo.ASSETLOCATION;
GO
-- etc. etc.
现在,处理查询的代码可以获取输入日期参数并计算需要查询的视图。例如:

select * from vASSETLOCATION where [WHEN] between '2008-01-01' and '2008-01-02'
CREATE PROCEDURE dbo.DetermineViews
    @StartDate     DATETIME,
    @EndDate       DATETIME,
    @optionalToday BIT = 0
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @sql NVARCHAR(MAX) = N'';

    SET @sql = @sql + N'SELECT * FROM ' + CASE
      WHEN @StartDate >= '20080101' AND @EndDate < '20090101' THEN 'AVL2008.dbo.ASSETLOCATION'
      WHEN @StartDate >= '20080101' AND @EndDate < '20100101' THEN 'dbo.vAL_2008_2009'
      WHEN @StartDate >= '20080101' AND @EndDate < '20110101' THEN 'dbo.vAL_2008_2010'
      -- etc. etc.

      WHEN YEAR(@StartDate) = YEAR(CURRENT_TIMESTAMP) THEN 'AVL.dbo.ASSETLOCATION'
    ELSE '' END;

    IF @OptionalToday = 1 AND YEAR(@StartDate) <> YEAR(CURRENT_TIMESTAMP)
    BEGIN
        SET @sql = @sql + N'UNION ALL SELECT * FROM AVL.dbo.ASSETLOCATION'
    END

    SET @sql = @sql + ' WHERE [WHEN] BETWEEN ''' 
        + CONVERT(CHAR(8), @StartDate, 112) + ''' AND '''
        + CONVERT(CHAR(8), @EndDate,   112) + '''';

    IF @OptionalToday = 1
    BEGIN
        SET @sql = @sql + ' OR ([WHEN] >= DATEDIFF(DAY, 0, CURRENT_TIMESTAMP)
            AND [WHEN] < DATEADD(DAY, 1, DATEDIFF(DAY, 0, CURRENT_TIMESTAMP)';
    END

    PRINT @sql;
    -- EXEC sp_executeSQL @sql;
END
GO
创建过程dbo.DetermineViews
@开始日期时间,
@EndDate日期时间,
@可选当前位=0
作为
开始
不计数;
声明@sql NVARCHAR(MAX)=N';
SET@sql=@sql+N'SELECT*FROM'+CASE
当@StartDate>='20080101'和@EndDate<'20090101'时,则为'AVL2008.dbo.ASSETLOCATION'
当@StartDate>='20080101'和@EndDate<'20100101'时,则为'dbo.vAL_2008_2009'
当@StartDate>='20080101'和@EndDate<'20110101'时,则为'dbo.vAL\u 2008\u 2010'
--等等等等。
当YEAR(@StartDate)=YEAR(当前时间戳)时,则为“AVL.dbo.ASSETLOCATION”
否则“结束”;
如果@OptionalToday=1和年份(@StartDate)年份(当前时间戳)
开始
SET@sql=@sql+N'UNION ALL SELECT*FROM AVL.dbo.ASSETLOCATION'
结束
设置@sql=@sql+,其中[何时]介于“”之间
+转换(字符(8),@StartDate,112)+“和”
+转换(字符(8),@EndDate,112)+'';
如果@OptionalToday=1
开始
设置@sql=@sql+”或([WHEN]>=DATEDIFF(天,0,当前时间戳)
和[当]

我可能遗漏了您的一些业务逻辑,您肯定想在其中添加一些错误处理,并测试其中的垃圾,但这是一个相对容易维护的解决方案,只需要在创建新数据库以存档去年的数据时进行更新,这听上去好像每年只发生一次。

a t参考您关于表分区的评论,如果您使用分区方案将数据分散到不同的文件组,然后单独备份文件组(可能在不同的方案上),这可能会有助于解决备份问题。至少要注意一些事情。@WT\W绝对地,分区不一定意味着“备份是巨大的”…当然有办法布置分区和文件组,以便旧数据是只读的,而不是活动备份例程的一部分。+1表示聪明!但我需要大量更改使用AL表的所有SP。例如,当前sql类似于“从AL中选择最大值(何时),其中IDASSET=1和[WHEN]“在x和y之间”将需要大量的工作才能转换为这种方法。这看起来很像一种表标量UDF方法,但被包装在SP中。好吧,我很想让你有信心