具有大量记录的表的分区视图和性能

时间:2013-01-15 09:25:02

标签: sql sql-server

目前我遇到查询和性能问题 存储过程。以下是场景:

我们在数据库(SQL Server 2000 SP4)中有3-4个表 有大量的记录。其中一个表有超过2500万 记录。这些表保持销售记录和数千个 记录每天添加到他们。每当执行存储过程时都需要 15-30分钟即可完成。桌子上有3-4个连接。用户是 经常抱怨它。索引是正确的。提高性能 我们已经实现了分区视图。该解决方案由实施 参考以下article on MSDN

我们按年度和业绩划分了销售记录 已经改进,查询/存储过程现在需要3-5分钟才能运行。改善 表现进一步,我们按月划分销售记录。我们正在维持 4年的数据,现在我们已接近48个销售数据表(After 按月拆分销售数据)。我期待这可以提高性能。但 这没有发生。查询执行速度比前一个慢得多 (年度明智的数据拆分)让我感到惊讶。也看了之后 查询计划我发现它正在对所有48个销售表进行索引扫描 仅扫描相关表格。例如。当查询存储过程时 期间19-NOV-201220-DEC-2012,它应该只考虑2个表NOV-2012DEC-2012。但它正考虑所有48个表。所以我的问题是:

  1. 为什么只考虑所有表而不是考虑 相关表格。例如。在上面的示例NOV-2012DEC-2012

  2. 为什么年度明智的逻辑(按年分割销售记录)是 表现优于月份逻辑(按月拆分销售记录)

  3. 以下是分区视图的代码 例如,其他年份被省略。

        SELECT * FROM tbl_Sales_Jan2010
    UNION ALL
    SELECT * FROM tbl_Sales_Feb2010
    UNION ALL
    SELECT * FROM tbl_Sales_Mar2010
    UNION ALL
    SELECT * FROM tbl_Sales_Apr2010
    UNION ALL
    SELECT * FROM tbl_Sales_May2010
    UNION ALL
    SELECT * FROM tbl_Sales_Jun2010
    UNION ALL
    SELECT * FROM tbl_Sales_Jul2010
    UNION ALL
    SELECT * FROM tbl_Sales_Aug2010
    UNION ALL
    SELECT * FROM tbl_Sales_Sep2010
    UNION ALL
    SELECT * FROM tbl_Sales_Oct2010
    UNION ALL
    SELECT * FROM tbl_Sales_Nov2010
    UNION ALL
    SELECT * FROM tbl_Sales_Dec2010
    

    以下是表格结构。

    CREATE TABLE [dbo].[tbl_Sales_Jan2010](
        [SalesID] [numeric](10, 0) NOT NULL,
        [StoreNumber] [char](3) NOT NULL,
        [SomeColumn1] [varchar](15) NOT NULL,
        [Quantity] [int] NOT NULL,
        [SalePrice] [numeric](18, 2) NOT NULL,
        [SaleDate] [datetime] NOT NULL,
        [DeptID] [int] NOT NULL,
        [CatCode] [char](3) NOT NULL,
        [AuditDate] [datetime] NOT NULL CONSTRAINT [DF_tbl_Sales_Jan2010_EditDate]  DEFAULT (getdate()),
        [SomeColumn2] [varchar](15) NULL,
        [SaleMonthYear] [int] NULL CONSTRAINT [DF__tbl_Sales__SaleY__Jan2010]  DEFAULT (12010),
        [SaleDateInIntFormat] [int] NULL,
     CONSTRAINT [PK_tbl_Sales_Jan2010] PRIMARY KEY CLUSTERED 
    (
        [SalesID] ASC
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    
    GO
    SET ANSI_PADDING OFF
    GO
    ALTER TABLE [dbo].[tbl_Sales_Jan2010]  WITH CHECK ADD CHECK  (([SaleMonthYear] = 12010))
    

    以下是查询

    SELECT     SUM(C.Quantity) as total
        FROM         Productdatabase.dbo.tbl_Product A , Productdatabase.dbo.tbl_Product_Category B, XDatabase.dbo.vw_Sales_Test C, tbl_Store D
        WHERE     A.ProductID = B.ProductID AND B.CategoryID = @CateID
        AND C.SomeColumn = A.PRoductCode
        AND D.StoreCode = C.StoreNumber
        AND D.country = @country
        AND D.status = 0
        And C.SaleMonthYear between @BeginMonthYear and @EndMonthYear               
        AND C.SalDate between @FromSaleDate and @ToSaleDate     
    

2 个答案:

答案 0 :(得分:3)

任何设置分区的人都没有想到他在做什么。除了不使用分区(这是一个SQL Server函数),最有可能是成本......

SELECT * FROM tbl_Sales_Jan2010
在联盟中

添加WHERE条件,然后查询分析器可以排除由于那里的坏where子句而不相关的表。即添加:

(([SaleMonthYear] = 12010

就在那里。

其次,解决您的其他问题。真。重点是:

  

我们在数据库(SQL Server 2000 SP4)中有3-4个表,这些表有很大的   记录数量。其中一个表有超过2500万   记录。

让我笑。 2500万不小,不小,但“休”是什么?我的意思是,我使用表格每天增加数亿行并保持数据2年。 2500万是中端服务器轻松处理的东西。我建议你有坏硬件(我的意思是坏),或者其他一些事情正在发生。

设计问题如:

[SaleMonthYear]

这应该不存在 - 它应该是SaleYearMonth,所以你可以进行一个范围测试(在201005和201008之间)你现在不能有效地做,并且如果你曾经使用它,你完全bork任何索引排序。

这很荒谬,因为这是一个你在这里完全增加的数字。

Whenever a stored procedure is executed it takes 15-30 minutes to complete

让我在这里说清楚。在可接受的中档硬件上,这样的静音(即适当的服务器,32-64gb内存,十几到24个高速光盘)没有办法这需要15到30分钟。不是你在那里写的代码。

除非你有锁拥塞(糟糕的应用程序设计)或服务器超载其他东西(糟糕的应用程序设计/糟糕的管理)之类的东西。我会用适当的索引来表达这样的查询,以便在分钟之下返回。

无论如何,分区的工作方式是快速消除大量检查 - 在你的情况下也是/大多数是删除优化(你可以只删除表,不需要删除语句使硬索引更新)。但是,你实现它的方式不是MS sasys应该完成的方式,而不是逻辑说它应该完成的方式,并且不会产生任何结果,因为你的分区没有集成到查询中。

如果你查看表和查询,它仍然必须检查每个表。

答案 1 :(得分:1)

来自您引用的同一篇MSDN文章:

  

分区视图不需要CHECK约束来返回正确的结果。但是,如果尚未定义CHECK约束,则查询优化器必须搜索所有表,而不是仅搜索覆盖分区列上的搜索条件的表。如果没有CHECK约束,视图将像使用UNION ALL的任何其他视图一样运行。查询优化器不能对存储在不同表中的值进行任何假设,也不能跳过搜索参与视图定义的表。

在您的问题中,您指定的查询具有日期范围 - 2012年11月19日至2012年12月20日。我假设这是SaleDate列中包含的值,但您的约束是在SaleMonthYear列上。

您确定定义的约束是否正确?你也可以发帖询问吗?

拉​​吉