5

我有一个 1 TB、600m 行的表,它错误地选择了索引列,特别是主键列上的聚集索引,它从未在选择查询中使用。

我想从这一行中删除聚集索引并在许多其他行上创建它。

表目前是这样的:

  • colA (PK, nvarchar(3)) [聚集索引 pt b]

  • colB (PK, bigint) [聚集索引 pt a]

  • colC (DateTime) [非聚集索引]

  • colD (Money) [非聚集索引]

  • colE(位)[无索引]

  • colF(位)[无索引]

  • colG (int) [无索引]

  • 更多非索引列

我想把它改成这样:

  • colA (PK, nvarchar(3)) [聚集索引 pt a]

  • colB (PK, bigint) [非聚集索引]

  • colC (DateTime) [非聚集索引]

  • colD (Money) [聚集索引 pt d]

  • colE (bit) [聚集索引 pt b]

  • colF (bit) [聚集索引 pt c]

  • colG (int) [聚集索引 pt e]

  • 更多非索引列

两个问题:1)您估计这种更改需要多长时间(消息末尾的服务器规范)。不幸的是,它是一个实时数据库,如果不知道它会停机多长时间,我就无法停机。

2) 将这么多列添加到聚集索引中是不是一个糟糕的主意?几乎从不执行更新。有许多插入和许多选择总是使用所有建议的索引行作为选择参数。

服务器规格:RAID 5 中的 5 个 15kRPM 驱动器,MS-SQL Sever 2005 和一些保持它们运行的​​位。

4

8 回答 8

10

一方面,我会避免使聚集索引比它绝对必须的更宽。把它分成五个部分似乎适得其反。这个复合聚集索引中的所有列是否稳定,例如从不改变?

如果没有,我会不惜一切代价避免它们。聚集索引应该是:

  • 独特的
  • 稳定的
  • 尽可能窄

您可以更改非聚集索引 - 没问题。但要避免使聚集索引混乱!那肯定会降低你的表现!

查看 Kimberly Tripp 关于索引的优秀博客文章:

马克

于 2009-03-27T16:38:28.663 回答
6

我进行了更改,并没有花费太长时间。以下是每个操作的时间,第一次是在具有单个 7200RPM 驱动器的备份服务器上运行,第二次是在具有 15k RAID 驱动器的主服务器上运行。

ALTER TABLE Table DROP CONSTRAINT [PK_Table]

2:39 小时 / 19 分钟

CREATE CLUSTERED INDEX [IX_Clustered] ON [Table] 
(
 [a] ASC,
 [b] ASC,
 [c] ASC,
 [d] ASC,
 [e] ASC,
 [f] ASC
)WITH (PAD_INDEX  = ON, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, IGNORE_DUP_KEY = OFF, FILLFACTOR = 90, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = OFF) ON [PRIMARY]

15:30 / 2 小时

ALTER TABLE Table ADD CONSTRAINT
PK_hands PRIMARY KEY NONCLUSTERED 
(
 e,
 h
) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

4 小时 / 1 小时

最常用的选择查询现在需要 < 10 秒,而以前通常需要 10 到 15 分钟。不错的改进!插入时间似乎也快了一些。

于 2009-04-05T00:32:58.157 回答
3

您应该有一个具有类似规格的开发环境,您可以使用它来尝试使用实时数据库的副本。

于 2009-03-27T16:35:52.663 回答
2

虽然更改聚集索引听起来肯定会有所帮助,但您为什么不先尝试添加(非聚集)覆盖索引呢?

在构建新索引时不应该关闭表,并且应该告诉您哪些性能改进(如果有)将导致这种重组。

于 2009-03-27T17:09:07.560 回答
0

您可能无需担心停机时间,因为可以实时进行更改(无需任何停机时间)。适用于 SQL Server 2005 企业版。

于 2009-03-27T16:34:34.243 回答
0

如果您有磁盘空间,您可以做的一件事是使用正确的聚集索引创建第二个表,通过增量过程在几天内将行复制到新表中。一旦所有行都存在,在两个表上执行 sp_rename (这将只需要几分钟的停机时间。如果您的应用程序引用的是视图而不是物理表,那么您可以在零停机时间的情况下完成此操作。我希望这会有所帮助.

[编辑]您还必须处理对行的更新,您需要在源表上有一个时间戳或最后更新的字段,以便在复制所有行后同步更新。

于 2009-03-27T16:36:27.373 回答
0

1)您估计此更改需要多长时间(消息末尾的服务器规范)。不幸的是,它是一个实时数据库,如果不知道它会停机多长时间,我就无法停机。

这真的,真的取决于数据。仅表参数并不能提供足够的信息。可能是几分钟(不太可能)到几天(不太可能),最有可能的时间介于两者之间。

2) 将这么多列添加到聚集索引中是不是一个糟糕的主意?几乎从不执行更新。有许多插入和许多选择总是使用所有建议的索引行作为选择参数。

不,这不应该造成任何问题。只有在您进行少量更新时,性能才会有所提高。但是,当这些更新发生时,修复索引需要一段时间,并且在此期间性能会受到影响,具体取决于数据。

-亚当

于 2009-03-27T16:41:23.947 回答
0

我同意布赖恩的观点,您应该有一个具有相同数据量的测试数据库并运行索引更改。但是,我认为您正在进行此更改,因为您认为它会加快查询速度。您应该运行基准测试(在索引更改之前和之后)并确保您的优化不会变得悲观。

于 2009-03-27T17:31:42.030 回答