1

目前我正面临查询和存储过程的性能问题。以下是场景:

我们在一个数据库中有 3-4 个表 ( SQL Server 2000 SP4),它们有大量的记录。其中一张表有超过 2500 万条记录。这些表维护着销售记录,并且每天都有数千条记录添加到其中。每当执行存储过程时,都需要 15-30 分钟才能完成。表上有 3-4 个连接。用户经常抱怨它。索引是正确的。为了提高性能,我们实现了分区视图。该解决方案是通过参考MSDN上的以下文章实现的

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

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

  2. 为什么按年逻辑(按年拆分销售记录)比按月逻辑(按月拆分销售记录)表现更好

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

    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     
4

2 回答 2

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 之间),而您现在无法有效地进行该测试,并且如果您曾经使用它,那么您将完全破坏任何索引排序。

这太荒谬了,因为这是一个你完全没有收获的数字。

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

让我在这里说清楚。在这样的情况下可接受的中档硬件(即适当的服务器、32-64gb 内存、一打到 24 个高速磁盘)上,这不可能需要 15 到 30 分钟。不是你在那里写的代码。

除非你有锁拥塞(糟糕的应用程序设计)或服务器过载的其他东西(糟糕的应用程序设计/糟糕的管理)。我希望这样的查询具有适当的索引,以低于一分钟的速度返回。

无论如何,分区通过快速消除大量检查来工作 - 并且在您的情况下也是/主要是删除优化(您可以只删除表,不需要删除语句进行硬索引更新)。但是,您实现它的方式不是 MS sasys 应该完成的方式,不是逻辑所说的应该完成的方式,并且不会给出任何结果,因为您的分区未集成到查询中。

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

于 2013-01-15T11:28:39.760 回答
1

从您引用的同一篇 MSDN 文章中:

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

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

您确定定义的约束是正确的吗?您也可以发布您的查询吗?

拉吉

于 2013-01-15T10:30:49.387 回答