Как заставить индексы SQL Server занимать меньше места? - PullRequest
3 голосов
/ 29 декабря 2010

У меня есть база данных, созданная некоторым приложением.Общая база данных - более 50 ГБ, возникают некоторые проблемы с резервным копированием, и моя задача - сделать эту базу данных как можно меньше.

Особенно одна таблица очень большая (22 ГБ), из которой 16,5 ГБ взято индексами, остальные 5,5 ГБ - данные.Он содержит чуть более 12 000 000 строк.

Не могли бы вы сказать, можно ли уменьшить индексы?Я уже пытался перестроить, реорганизовать, воссоздать кластерный индекс, dbcc cleantable.Я также знаю, что тип nvarchar занимает вдвое больше размера, чем varchar, поэтому я изменил тип столбцов на varchar, но благодаря этому я сэкономил только около 2 ГБ (1 ГБ на данные и 1 ГБ на индексы).

Вот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 ]

7 голосов
/ 29 декабря 2010

Глядя на ваше определение таблицы

Первичный ключ:

  • У вас есть кластерный индекс char (32). Эти 32 байта появляются в каждом некластеризованном индексе

Колонки:

  • Почему char (32)? -> varchar (32)
  • Почему nvarchar ()? -> varchar
  • Почему дата и время? -> smalldatetime
  • Почему ntext? -> varchar (max)

Индексы:

  • Можете ли вы использовать INCLUDE вместо ключевых столбцов

Ваша главная проблема - неправильный выбор кластерного индекса. Если вы не можете это исправить, почти все остальное бессмысленно: если только вы не удалите данные ...

Когда вы перешли на varchar, вы сохранили 2 ГБ из 22 ГБ. Это 9%, что вполне разумно, без других оптимизаций. Это также показывает, что вам не нужен nvarchar ...

Если вы перейдете к суррогатному ключу int, вы сэкономите 28 байтов в строке на некластеризованный индекс. Это минимум 3,7 ГБ (12 x 12 000 000 x 28), но будет больше из-за большего количества строк на странице. И это прозрачно для клиентского кода.

Затем вы начинаете проверять использование индекса ...

Тем не менее, вам следует взглянуть на планирование емкости и план роста данных. Изменения, которые я предлагаю здесь, уменьшат темпы роста , а также текущий размер, но если вам нужно еще 50 миллионов строк, вам нужно запланировать это. Например, вы можете сжать свои резервные копии?

6 голосов
/ 29 декабря 2010

Найдите неиспользуемые индексы и удалите их. Это также сократит количество записей, которые диск должен сделать для dui (удаляет, обновляет и вставляет). Посмотрите блог Брента Озара о том, как это сделать: http://www.toadworld.com/platforms/sql-server/w/wiki/10062.find-indexes-not-in-use

В основном, если ваши чтения / записи низкие (<0,1), то индекс причиняет вам больший вред, чем помогает, и, возможно, в любом случае должен пойти дальше. Вам нужно будет тщательно обдумать, прежде чем отбрасывать индекс. </p>

Вы также можете воспользоваться отфильтрованными индексами. http://sqlfool.com/2009/04/filtered-indexes-what-you-need-to-know/

4 голосов
/ 29 декабря 2010

Вы можете проверить, все ли индексы фактически используются, и отбросить те, которые вам не нужны, но, как правило, вы подходите к проблеме неправильно - даже если вам удастся уменьшить базу данных сегодня он будет расти, и через несколько месяцев вы столкнетесь с той же проблемой .

Если база данных не содержит много ненужных данных и / или индексов, которые вы можете удалить, вам придется найти способ управления базой данных такого размера .

Прежде чем вы начнете отбрасывать столбцы и индексы, измените типы данных столбцов, вы должны быть абсолютно уверены, как это повлияет на работу и производительность приложения. Однако это программное обеспечение сторонних производителей, и его разработчики не будут отвечать на ваши вопросы в течение следующих нескольких дней ( они не будут работать до конца года ), поэтому абсолютно невозможно предсказать все негативные последствия таких слепых изменений структуры базы данных . Система, вероятно, не сразу выйдет из строя, но ваши изменения в сочетании с будущими обновлениями программного обеспечения (подготовленными людьми, не подозревающими о внесенных вами изменениях), могут привести к катастрофическим результатам.

1 голос
/ 30 декабря 2010

Определенно просмотрите индекс, действительно ли вам нужны все эти индексы паттерна? [POOLID], [FLD]? Если их существование не может быть оправдано, то они не должны существовать.

Я предполагаю, что DOCID и т. Д. - ГИДЫ без дефисов. Если бы вы могли начать заново, я бы предпочел использовать встроенный тип guid, а не char32, что бы вдвое уменьшило размер ваших значений, но это не простое изменение, потому что Microsoft была глупой и сделала так, что вам пришлось вставлять дефисы в их типы guid, а затем приложение должно иметь дополнительное пространство в структурах или переводить дефисы.

0 голосов
/ 30 декабря 2010

Поиграв с этой проблемой, я пришел к финальной стадии, где: - объем данных уменьшен с 5 451 477 МБ до 4 088 609 МБ - индексы уменьшены с 15 361 391 МБ до 6 003 094 МБ

Вот шаги, которые я сделал (может быть, кому-то это пригодится):

  1. Изменено 9 типов столбцов с nvarchar на varchar - данные: 4 460 305 МБ, индексы - 14 456 383 МБ
  2. Удалены избыточные столбцы, которые встречаются в нескольких индексах - данные: 4 460 305 МБ, индексы - 9 592 320 МБ
  3. Изменены два столбца с char (32) на varchar (32) и один столбец с ntext на varchar (max) - данные: 4 088 609 МБ, индексы: 9 294 117 МБ
  4. Создан новый столбец целочисленных идентификаторов, удален кластеризованный индекс из столбца DOCID char (32), создан новый некластеризованный индекс со столбцом DOCID, создан новый кластеризованный индекс с вновь добавленным столбцом идентификаторов - данные: 4 088 609 МБ индексы: 6 003 094 МБ

Спасибо, что помогли мне решить эту проблему:)

...