具有大量记录的表的分区视图和性能
Posted
技术标签:
【中文标题】具有大量记录的表的分区视图和性能【英文标题】:Partitioned view and performance for the table with huge records 【发布时间】:2013-01-15 09:25:01 【问题描述】:目前我面临查询和性能问题 存储过程。以下是场景:
我们在一个数据库 (SQL Server 2000 SP4
) 中有 3-4 个表
有大量的记录。其中一张表超过2500万
记录。这些表保存着销售记录和成千上万的
每天添加到其中的记录。每当执行存储过程时,它需要
15-30分钟完成。表上有 3-4 个连接。用户是
经常抱怨它。索引是正确的。为了提高性能
我们已经实现了分区视图。该解决方案由
引用以下article on MSDN
我们按年度和业绩划分了销售记录
已改进,查询/存储过程现在需要 3-5 分钟才能运行。改善
进一步,我们按月划分销售记录。我们在维护
4 年的数据,现在我们接近 48 个销售数据表(之后
按月拆分销售数据)。我期待这可以提高性能。但
这没有发生。查询的执行速度比前一个慢得多
(数据的年度拆分)这让我感到惊讶。也看过之后
查询计划我发现它正在对所有 48 个销售表进行索引扫描
只扫描相关表。例如。当被查询存储过程时
期间19-NOV-2012
和20-DEC-2012
,应该只考虑2个表NOV-2012
和DEC-2012
。但它正在考虑所有 48 张桌子。所以我的问题是:
为什么要考虑所有表而不是只考虑
相关表格。例如。在上面的例子中NOV-2012
和DEC-2012
为什么年度逻辑(按年份拆分销售记录)是 表现优于按月逻辑(按月拆分销售记录)
以下是分区视图的代码。 例如年份 其他年份省略。
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
【问题讨论】:
表设计、分区视图详细信息、索引详细信息和实际查询真的很有帮助 2500 万可能比你习惯的要多,但也不是巨大。 我想看看查询计划。我看不出分区消除在这里不起作用的原因。但是,您已经交换了月份和年份,这可能会让您相信它不起作用...... 【参考方案1】:设置分区的人并没有真正想到他在做什么。除了不使用分区(这是一个 SQL Server 功能)之外,很可能是为了成本......
SELECT * FROM tbl_Sales_Jan2010
在联合中添加 WHERE 条件,然后查询分析器可以排除由于错误的 where 子句而不相关的表。 IE。添加:
(([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 应该完成的方式,不是逻辑所说的应该完成的方式,并且不会给出任何结果,因为您的分区未集成到查询中。
如果你查看表和查询,它仍然必须检查每个表。
【讨论】:
非常感谢您的详细回复。我已经实施了您的建议(在视图中添加 where 子句并修复 SaleMonthYear 列)。性能肯定有所提高。但是查询计划仍然显示它正在扫描所有销售表。所以我认为肯定有改进的余地。正如您提到的,分区未正确实施可能是因为成本。您能否提供有关分区的建议以及它对成本的影响? SQL Server Enterprise License 支持分区功能。检查文档。许可成本开销是 - 啊 - 陡峭。在您的方法中,查询计划将始终显示所有表 - 问题是它们是否发生了真正的 IO。逻辑上它们被评估(只是错误的,所以没有真正的 IO)。在 management studio 中运行查询,检查 REAL(未评估)查询计划的实际开销。 是的。我已经检查了前面提到的查询的实际执行计划。以下是实际执行计划中的一些值。对于 tbl_Sales_Jan2012 估计 I/O 成本 - 3.27397744 执行次数 - 4 CPU 成本 -0.1980018 对于 tbl_Sales_Feb2012 估计 I/O 成本 - 5.8109117 执行次数 - 0.3508584 CPU 成本 - 4 @parag 这些数字非常低。 3POINT2 io 不是很多。我会假设“真实”表格的表格要高得多?喜欢 - 一百次或更多? @parag Btw.,感谢您告诉我我的回答很有帮助,然后直接转到另一个答案,这只是一个文档引用并使其正确,因此他得到了破坏。干得好。【参考方案2】:来自您引用的同一篇 MSDN 文章:
分区视图不需要检查约束来返回正确的结果。但是,如果尚未定义 CHECK 约束,则查询优化器必须搜索所有表,而不是仅搜索那些覆盖分区列上的搜索条件的表。如果没有 CHECK 约束,视图的运行方式与任何其他带有 UNION ALL 的视图一样。查询优化器不能对存储在不同表中的值做出任何假设,也不能跳过搜索参与视图定义的表。
在您的问题中,您指定了一个日期范围为 2012 年 11 月 19 日至 2012 年 12 月 20 日的查询。我假设这将是 SaleDate 列中包含的值,但您的约束是 SaleMonthYear 列。
您确定定义的约束是正确的吗?您能否也发布您的查询?
拉吉
【讨论】:
我认为您打算将该块作为引用,而不是作为代码(作为代码,它都在一行中,产生了一个巨大的滚动条,并且它也试图在语法上突出显示它。跨度> 是的,我确实想引用。很抱歉混淆了。感谢修复。 -1。完全不相关,不解释重点,也不是问题的答案。 TomTom - 在 OP 发布实际查询之前发布了响应。感谢您的反对以上是关于具有大量记录的表的分区视图和性能的主要内容,如果未能解决你的问题,请参考以下文章