如何使SQL Server索引占用更少的空间?

时间:2010-12-29 10:57:11

标签: sql sql-server database backup

我有一个由某个应用程序创建的数据库。整个数据库超过50 GB,备份出现了一些问题,我的任务是让这个数据库尽可能小。

特别是一个表非常大(22 gb),其中16.5 gb是由索引获取的,其余5.5 gb是数据。它包含的行数不超过12 000 000行。

你能告诉我是否可以缩小索引?我已经尝试过重建,重新组织,重新创建聚簇索引,dbcc清晰。我也知道nvarchar类型的大小比varchar大两倍,所以我将列类型更改为varchar,但是由于我节省了大约2 GB(数据上1 gb和索引上1 gb)。

这是这个表的一个sql(fld0和fld1总是NULL):

CREATE TABLE [dbo].[DOC8](
 [ASSOCIATION] [nvarchar](64) NULL DEFAULT (NULL),
 [DOCID] [char](32) NOT NULL,
 [FLD0] [nvarchar](255) NULL DEFAULT (NULL),
 [FLD1] [nvarchar](2048) NULL DEFAULT (NULL),
 [FLD10] [nvarchar](255) NULL DEFAULT (NULL),
 [FLD2] [nvarchar](32) NULL DEFAULT (NULL),
 [FLD3] [nvarchar](255) NULL DEFAULT (NULL),
 [FLD4] [nvarchar](255) NULL DEFAULT (NULL),
 [FLD5] [datetime] NULL DEFAULT (NULL),
 [FLD6] [nvarchar](255) NULL DEFAULT (NULL),
 [FLD7] [nvarchar](255) NULL DEFAULT (NULL),
 [FLD8] [nvarchar](255) NULL DEFAULT (NULL),
 [FLD9] [datetime] NULL DEFAULT (NULL),
 [PARENTID] [char](32) NULL DEFAULT (NULL),
 [POOLID] [char](32) NULL DEFAULT (NULL),
 [PROPERTIES] [ntext] NULL DEFAULT (NULL),
 [FLD11] [nvarchar](255) NULL DEFAULT (NULL),
 [FLD12] [nvarchar](255) NULL DEFAULT (NULL),
PRIMARY KEY CLUSTERED 
(
 [DOCID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
CREATE NONCLUSTERED INDEX [DOC8_IDX_0] ON [dbo].[DOC8] 
(
 [ASSOCIATION] ASC,
 [PARENTID] ASC,
 [POOLID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [DOC8_IDX_1] ON [dbo].[DOC8] 
(
 [POOLID] ASC,
 [FLD0] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [DOC8_IDX_10] ON [dbo].[DOC8] 
(
 [POOLID] ASC,
 [FLD11] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [DOC8_IDX_11] ON [dbo].[DOC8] 
(
 [POOLID] ASC,
 [FLD12] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [DOC8_IDX_2] ON [dbo].[DOC8] 
(
 [POOLID] ASC,
 [FLD2] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [DOC8_IDX_3] ON [dbo].[DOC8] 
(
 [POOLID] ASC,
 [FLD3] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [DOC8_IDX_4] ON [dbo].[DOC8] 
(
 [POOLID] ASC,
 [FLD4] ASC,
 [FLD5] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [DOC8_IDX_5] ON [dbo].[DOC8] 
(
 [POOLID] ASC,
 [FLD6] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [DOC8_IDX_6] ON [dbo].[DOC8] 
(
 [POOLID] ASC,
 [FLD7] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [DOC8_IDX_7] ON [dbo].[DOC8] 
(
 [POOLID] ASC,
 [FLD8] ASC,
 [FLD9] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [DOC8_IDX_8] ON [dbo].[DOC8] 
(
 [POOLID] ASC,
 [FLD10] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [DOC8_IDX_9] ON [dbo].[DOC8] 
(
 [PARENTID] ASC,
 [POOLID] ASC,
 [DOCID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

5 个答案:

答案 0 :(得分:7)

查看您的表定义

主键:

  • 您有一个char(32)聚集索引。这32个字节出现在每个非聚集索引

列:

  • 为什么选择char(32)? - > VARCHAR(32)
  • 为什么是nvarchar()? - > VARCHAR
  • 为什么选择日期? - > SMALLDATETIME
  • 为什么ntext? - > VARCHAR(最大)

索引:

  • 您可以使用INCLUDE而不是使用键列

您的主要问题是聚集索引选择不当。如果你无法解决这个问题,那么其他一切都是毫无意义的:除非你删除数据......

当您更改为varchar时,您从22GB中节省了2GB。这是9%,这是相当合理的,没有其他优化。它还表明你不需要nvarchar ...

如果更改为int代理键,则每个非聚集索引每行可节省28个字节。 这是最低3.7 GB(12 x 12,000,000 x 28),但由于每页有更多行,因此会更多。它对客户端代码透明。

然后开始检查索引使用情况......

但是,您应该查看容量规划和数据增长计划。我在这里建议的更改将减少增长以及当前大小,但如果您需要另外5000万行,那么您需要为此计划。例如,您可以压缩备份吗?

答案 1 :(得分:6)

查找未使用的索引并将其删除。这也将减少驱动器为dui(删除,更新和插入)所做的写入量。 请参阅Brent Ozar的博客,了解如何执行此操作: http://www.toadworld.com/platforms/sql-server/w/wiki/10062.find-indexes-not-in-use

基本上,如果你的读/写很低(<0.1),那么索引对你的伤害超过了它的帮助,并且可能还需要去。在删除索引之前,您需要仔细考虑。

您也可以从过滤后的索引中受益。 http://sqlfool.com/2009/04/filtered-indexes-what-you-need-to-know/

答案 2 :(得分:4)

您可以检查是否实际使用了所有索引并删除了您不需要的索引,但通常您正以错误的方式解决问题 - 即使您设法创建数据库今天变小,它会继续增长,并且在几个月内你将再次遇到同样的问题

除非数据库包含许多您可以删除的不必要的数据和/或索引,否则您必须找到管理此类大小的数据库的方法

在开始删除列和索引之前,更改列的数据类型,您需要绝对确定这将如何影响应用程序操作和性能。但是,这是第三方软件,其开发人员将在接下来的几天内不回答您的问题(他们直到今年年底才开始工作),所以绝对没有办法预测这种盲目数据库结构变化的所有负面影响。系统不会立即失败,但是您的更改与未来的软件更新(由不了解您所做的修改的人准备)可能会产生灾难性的后果。

答案 3 :(得分:1)

明确地检查索引,你真的需要模式的所有索引吗? [POOLID],[FLD]?如果他们的存在不合理,那么他们就不应该存在。

我假设DOCID等是没有连字符的GUIDS。 如果你可以重新开始,我会选择使用内置的guid类型而不是char32,这会减少你所拥有的凹痕的大小,但这不是一个简单的改变,因为微软是愚蠢的,所以你必须把连字符放在他们的guid类型然后应用程序必须在结构中有额外的空间或翻译连字符。

答案 4 :(得分:0)

在解决这个问题后,我来到了最后阶段: - 数据从5 451 477 MB减少到4 088 609 MB - 索引从15 361 391 MB减少到6 003 094 MB

以下是我所做的步骤(可能对某些人有用):

  1. 将9种列类型从nvarchar更改为varchar - 数据:4 460 305 MB,索引 - 14 456 383 MB
  2. 删除了多个索引中出现的reduntant列 - 数据:4 460 305 MB,索引 - 9 592 320 MB
  3. 将两列从char(32)更改为varchar(32),将一列从ntext更改为varchar(max) - 数据:4 088 609 MB,索引:9 294 117 MB
  4. 创建了新的整数indentity列,删除了由DOCID char(32)列创建的聚簇索引,用DOCID列创建了新的非聚集索引,用新添加的标识列创建了新的聚簇索引 - 数据:4 088 609 MB,索引:6 003 094 MB
  5. 感谢您帮助我解决此问题:)