【问题标题】:Slowness at Indexed View for SQL 2005SQL 2005 的索引视图缓慢
【发布时间】:2011-01-26 01:45:36
【问题描述】:

假设我有一个很长的表(约 3500 万行),名为 TimeCard,只有 5 列(tableID、CompanyID、UserID、ProjectID、DailyHoursWorked、entryDate)。这是一个非常简单的表格,记录了每个公司每个项目每天的员工工作时间。

我现在需要生成一份报告,以了解任何给定公司每个项目的员工每月的总工作时间。我不想在报表运行时执行所需的聚合,而是想构建一个类似表格的数据结构,其中已经包含按月聚合的所有公司/项目/用户数据,因此当报表运行时,我可以直接查询该数据结构无需执行任何运行时聚合,因为大约 3500 万条记录可能需要几分钟。

所以我有两种不同的方法。一个人创建了一个额外的物理表(CompanyID、UserID、ProjectID、MonthlyHoursWorked、Month)作为我的列,然后在 TimeCard 表中使用触发器来修改额外表中的值。或者我可以创建一个索引视图。所以我两个都试了。我首先使用以下代码尝试了索引视图:

CREATE VIEW [dbo].[vw_myView] WITH SCHEMABINDING AS
SELECT 
 JobID,
 ProjectID,
 Sum(DailyHoursWorked) AS MonthTotal,
 DATEADD( Month, DATEDIFF( Month, 0, entryDate), 0 ) AS entryMonth,
 CompanyID,
 COUNT_BIG(*) AS Counter
FROM
 dbo.TimeCard 
Group By DATEADD( Month, DATEDIFF( Month, 0, entryDate ), 0 ), JobID, ProjectID, CompanyID

Go
CREATE UNIQUE CLUSTERED INDEX [IX_someIndex] ON [dbo].[vw_myView] 
(
 [CompanyID] ASC,
 [entryMonth] ASC,
 [UserID] ASC,
 [ProjectID] ASC
)

正确创建的索引视图总共有大约 500 万行。

但是,如果我每次清除 SQL 缓存,并运行以下查询:*select * from vw_myView where companyID = 1*,大​​约需要 3 分钟。如果我使用上面提到的额外表路由,清除缓存,大约需要 4 秒。

我的问题是,索引视图对于这种特殊情况是不是一个糟糕的选择?特别是我很想知道每次更改基础表 (TimeCard) 或针对它运行查询时,是否会重新计算/重新聚合整个索引视图?

谢谢!

【问题讨论】:

  • 您使用的是哪个版本的 SQL Server 2005?
  • entryMonth 中不包含当月第一天的完整日期,您不能只将MONTH(entryDate) 和可能的YEAR(entryDate) 作为INT 吗?对我来说似乎容易多了(但话又说回来 - 我不知道你的确切要求)......

标签: sql sql-server sql-server-2005 indexed-view


【解决方案1】:

如果您没有使用 EnterpriseDeveloper 版本,则需要使用with (noexpand) 提示:

select * 
from vw_myView with (noexpand)
where companyID = 1

当底层数据发生变化时,视图只会更新与变化数据相关的行,而不是整个表。这可能会对具有高度插入的 OLTP 数据库产生不利影响,但如果使用量适中,则不会造成性能问题。

tip from Microsoft:

作为一般建议,任何 修改或更新视图 或视图下的基表 应分批进行,如果 可能,而不是单例 操作。这可能会减少一些 视图维护的开销。

【讨论】:

  • 我不明白的是,如果我清除缓存并且基表值都没有改变,为什么一个简单的查询需要 3 分钟。它真的会再次进行整个聚合吗?
  • @TheYouth:你试过with (noexpand)提示吗?
  • +1 如果您忘记在 SQL Server 的 EXPRESS 或 DEVELOPER 版本上添加 WITH (NOEXPAND),优化器将不会使用索引视图,而是从基础表中进行选择。
【解决方案2】:

我认为您在使用索引视图方面走在正确的道路上。但是,您是否在要查询的表上放置了索引,TimeCard 用于聚合列。您需要创建一个JobID, ProjectID, entryDate, CompanyID 的索引(1 个索引)。如果您为每列使用 1 个索引,它不会解决您的问题,因为查询必须同时使用所有 4 个索引。

我确实认为使用触发器会很慢,但方式不同。它会使您的查询更快,但它会减慢您对TimeCard 的每次插入。如果您决定使用触发器,那么我会确保我也为该表建立索引,或者也可能很慢,不是慢 3 分钟,但排序和返回数据仍然很慢。

【讨论】:

  • 我看不出更多的索引会有什么帮助,查询是由 CompanyID 选择的,它已经被索引了。
  • TimeCard 使用 entryDate、companyID、userID、projectID 进行索引,所有这些都在单独的非聚集索引中。我不明白的是,如果我清除缓存,为什么一个简单的查询需要 3 分钟。它真的会再次进行整个聚合吗?
  • 我认为是。但是,我认为如果 entryDate、companyID、userID、projectID 有 1 个非集群索引会更好。有 4 个索引,每个列一个索引并不能真正帮助您,因为您的 Group By 将所有 4 个索引一起使用。因此,您需要 1 个索引,其中包含所有 4 列。
  • 我认为这里有一些混淆 - 上面 DDL 中的 group by 仅在创建索引视图时使用,而不是在从视图中选择数据时使用,因此根据什么在视图上放置索引在group by 子句中没有意义。
【解决方案3】:

我不会为此使用视图。我认为由触发器填充的表是要走的路。但不要忘记调整更新和删除以及插入的总数。

【讨论】:

  • 视图通常比触发器慢(尤其是如果您将它们堆叠在一起),并且可以正确编写触发器以使其更快。
【解决方案4】:

我不认为,您需要索引视图(我不是说,索引视图是坏/好主意)。 我认为,您需要列“CompanyID”和“EntryDate”的索引。之后,您应该使用 where 条件“WHERE CompanyID = @CompanyID AND EntryDate >= @StartDate AND EntryDate

如果表主要由“EntryDate”处理,您可以在“EntryDate”列上使用聚集索引。

在这之后,我认为select语句会比现在快很多。

【讨论】:

  • 视图上的聚集索引已经使用 CompanyID 作为其第一列 - 这应该可以解决问题,真的。我在 (CompanyID, EntryDate) 上的索引中看不到任何好处 - 似乎没有使用 EntryDate 的任何查询,那么索引它的意义何在?
  • TimeCard 使用 entryDate、companyID、userID、projectID 进行索引,所有这些都在单独的非聚集索引中。我不明白的是,如果我清除缓存,为什么一个简单的查询需要 3 分钟。它真的会再次进行整个聚合吗?
  • 您应该按 EntryDate 过滤它。如果您知道,您已经有关于 Januar 2010 的汇总信息,您不需要再次从主表中选择 ti。如果您在“EntryDate”列(没有 CompanyID)上使用集群索引 - 您应该基于此列获得更好的选择性能。
【解决方案5】:

您是否考虑过对表进行分区。你可以想到列表和哈希分区表的组合。

【讨论】:

    【解决方案6】:

    好吧,索引视图的想法非常好,如果您可以在其上创建聚集索引 - 完美。它应该很快 - 比 3 分钟查询要好得多!

    另一方面:如果这些信息块只更新过,例如每月一次或每周一次(甚至每晚),最好将它们放入单独的DailyTimeCard 表中,该表由例如填充/更新。定期一个 SSIS 包。

    我也不建议使用触发器来不断更新这样的事实表 - 如果您真的需要在一天中的每一秒都有最新的数据,那么请继续使用索引视图。

    但是,您的索引视图做了很多繁重的工作 - 它求和、分组等等。始终保持最新状态,而您的底层 TimeCard 表会更改并更新,这会导致您的系统出现一些负载 - 很难说有多少 - 但它可能非常明显。

    如果您找到一种方法来提取您需要的信息 - 一次分组和求和,然后将聚合数据存储到一个单独的事实表中 - 您应该同时拥有:对 DailyTimeCard 表的快速和快速查询,以及其余的您的系统应该可以减轻保持索引视图始终处于最新状态的负担。

    也许这不是您正在寻找的解决方案 - 但请考虑一下。它可能(也可能不会)适合您!

    【讨论】:

      猜你喜欢
      • 2011-07-16
      • 2010-10-27
      • 2019-02-11
      • 2014-06-26
      • 2017-09-24
      • 1970-01-01
      • 2010-10-26
      • 1970-01-01
      • 2010-09-15
      相关资源
      最近更新 更多