У меня есть таблица в производственной базе данных, которая имеет размер 525 ГБ, из которых 383 ГБ не используется:
Я хотел бы освободить часть этого пространства, но, прежде чем связываться с производственной БД, я тестирую некоторые стратегии на идентичной таблице в тестовой БД с меньшим количеством данных. Эта таблица имеет похожую проблему:
Некоторая информация о столе:
- Коэффициент заполнения установлен на 0
- Есть около 30 столбцов
- Один из столбцов - это большой объект типа изображения, в котором хранятся файлы размером от нескольких КБ до нескольких сотен МБ.
- Таблица не имеет каких-либо гипотетических индексов, связанных с ней
Сервер работает под управлением SQL Server 2017 (RTM-GDR) (KB4505224) - 14.0.2027.2 (X64). База данных использует SIMPLE
модель восстановления.
Некоторые вещи, которые я пробовал:
- Перестройка индексов:
ALTER INDEX ALL ON dbo.MyTable REBUILD
. Это оказало незначительное влияние. - Реорганизация индексов:
ALTER INDEX ALL ON dbo.MyTable REORGANIZE WITH(LOB_COMPACTION = ON)
. Это оказало незначительное влияние. Скопировал столбец большого объекта в другую таблицу, удалил столбец, заново создал столбец и скопировал данные обратно (как описано в этом сообщении: освобождение таблицы SQL Server неиспользуемого пространства ). Это уменьшило неиспользуемое пространство, но, казалось, просто преобразовало его в используемое пространство:
Использовал утилиту bcp для экспорта таблицы, ее обрезания и перезагрузки (как описано в этом посте: Как освободить неиспользуемое пространство для таблицы ). Это также уменьшило неиспользуемое пространство и увеличило используемое пространство в той же степени, что и изображение выше.
- Хотя это и не рекомендуется, я пробовал команды DBCC SHRINKFILE и DBCC SHRINKDATABASE, но они не оказали никакого влияния на неиспользуемое пространство.
- Бег
DBCC CLEANTABLE('myDB', 'dbo.myTable')
не имел значения - Я пробовал все вышеперечисленное как при сохранении типов данных изображения и текста, так и после изменения типов данных на varbinary (max) и varchar (max).
- Я попытался импортировать данные в новую таблицу в новой базе данных, и это также только преобразовало неиспользуемое пространство в используемое пространство. Я изложил подробности этой попытки в этом посте .
Я не хочу делать эти попытки на производственной базе данных, если это ожидаемые результаты, поэтому:
- Почему неиспользованное пространство просто превращается в использованное пространство после некоторых из этих попыток? Я чувствую, что не понимаю, что происходит под капотом.
- Что еще я могу сделать, чтобы уменьшить неиспользуемое пространство, не увеличивая его?
РЕДАКТИРОВАТЬ: Вот отчет использования диска и сценарий для таблицы:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[MyTable](
[Column1] [int] NOT NULL,
[Column2] [int] NOT NULL,
[Column3] [int] NOT NULL,
[Column4] [bit] NOT NULL,
[Column5] [tinyint] NOT NULL,
[Column6] [datetime] NULL,
[Column7] [int] NOT NULL,
[Column8] [varchar](100) NULL,
[Column9] [varchar](256) NULL,
[Column10] [int] NULL,
[Column11] [image] NULL,
[Column12] [text] NULL,
[Column13] [varchar](100) NULL,
[Column14] [varchar](6) NULL,
[Column15] [int] NOT NULL,
[Column16] [bit] NOT NULL,
[Column17] [datetime] NULL,
[Column18] [varchar](50) NULL,
[Column19] [varchar](50) NULL,
[Column20] [varchar](60) NULL,
[Column21] [varchar](20) NULL,
[Column22] [varchar](120) NULL,
[Column23] [varchar](4) NULL,
[Column24] [varchar](75) NULL,
[Column25] [char](1) NULL,
[Column26] [varchar](50) NULL,
[Column27] [varchar](128) NULL,
[Column28] [varchar](50) NULL,
[Column29] [int] NULL,
[Column30] [text] NULL,
CONSTRAINT [PK] PRIMARY KEY CLUSTERED
(
[Column1] ASC,
[Column2] ASC,
[Column3] 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
ALTER TABLE [dbo].[MyTable] ADD CONSTRAINT [DF_Column4] DEFAULT (0) FOR [Column4]
GO
ALTER TABLE [dbo].[MyTable] ADD CONSTRAINT [DF_Column5] DEFAULT (0) FOR [Column5]
GO
ALTER TABLE [dbo].[MyTable] ADD CONSTRAINT [DF_Column15] DEFAULT (0) FOR [Column15]
GO
ALTER TABLE [dbo].[MyTable] ADD CONSTRAINT [DF_Column16] DEFAULT (0) FOR [Column16]
GO
Вот результаты выполнения команд в ответе Макса Вернона:
╔════════════╦═══════════╦════════════╦═════════════════╦══════════════════════╦════════════════════╗
║ TotalBytes ║ FreeBytes ║ TotalPages ║ TotalEmptyPages ║ PageBytesFreePercent ║ UnusedPagesPercent ║
╠════════════╬═══════════╬════════════╬═════════════════╬══════════════════════╬════════════════════╣
║ 9014280192║ 8653594624║ 1100376║ 997178 ║ 95.998700 ║ 90.621500 ║
╚════════════╩═══════════╩════════════╩═════════════════╩══════════════════════╩════════════════════╝
╔═════════════╦═══════════════════╦════════════════════╗
║ ObjectName ║ ReservedPageCount ║ UsedPageCount ║
╠═════════════╬═══════════════════╬════════════════════╣
║ dbo.MyTable ║ 5109090 ║ 2850245 ║
╚═════════════╩═══════════════════╩════════════════════╝
ОБНОВИТЬ:
Я запустил следующее по предложению Макса Вернона:
DBCC UPDATEUSAGE (N'<database_name>', N'<table_name>');
И вот был выход:
DBCC UPDATEUSAGE: Usage counts updated for table 'MyTable' (index 'PK_MyTable', partition 1):
USED pages (LOB Data): changed from (568025) to (1019641) pages.
RSVD pages (LOB Data): changed from (1019761) to (1019763) pages.
Это обновило использование диска для таблицы:
И общее использование диска:
Таким образом, похоже, что проблема заключалась в том, что использование диска, отслеживаемое SQL Server, стало совершенно несоответствующим фактическому использованию диска. Я считаю, что эта проблема решена, но мне было бы интересно узнать, почему это произошло бы в первую очередь!
DBCC UPDATEUSAGE
обновление неиспользуемого пространства и количества неиспользуемых страниц. Похоже, что использование диска и информация о страницах, сообщаемая SQL Server, была чрезвычайно несинхронизирована - я обновил свой пост с подробностями. Мне интересно, как это могло бы произойти в первую очередь, но, по крайней мере, проблема была найдена. Спасибо за вашу помощь, я действительно ценю это!