Добавление SPARSE сделало таблицу намного больше


9

У меня есть общая таблица журнала, около 5 м строк.
Есть «строго типизированное» поле, в котором хранится тип события, и набор «ошибочно типизированных» столбцов, которые содержат данные, относящиеся к событию. То есть значение этих «плохо напечатанных» столбцов зависит от типа события.

Эти столбцы определены как:

USER_CHAR1 nvarchar(150) null,
USER_CHAR2 nvarchar(150) null,
USER_CHAR3 nvarchar(150) null,
USER_CHAR4 nvarchar(150) null,
USER_CHAR5 nvarchar(150) null,

USER_INTEGER1 int null,
USER_INTEGER2 int null,
USER_INTEGER3 int null,
USER_INTEGER4 int null,
USER_INTEGER5 int null,

USER_FLAG1 bit null,
USER_FLAG2 bit null,
USER_FLAG3 bit null,
USER_FLAG4 bit null,
USER_FLAG5 bit null,

USER_FLOAT1 float null,
USER_FLOAT2 float null,
USER_FLOAT3 float null,
USER_FLOAT4 float null,
USER_FLOAT5 float null

Столбцы 1 и 2 в каждом типе используются интенсивно, но, начиная с номера 3, очень немногие типы событий могут предоставить такую ​​большую информацию. Поэтому я решил пометить столбцы 3-5 в каждом типе как SPARSE.

Сначала я провел некоторый анализ и увидел, что, по крайней мере, 80% данных в каждом из этих столбцов есть null, а в некоторых - около 100% null. В соответствии с пороговой таблицей сбережений 40% , SPARSEэто будет огромной победой для них.

Поэтому я пошел и применил SPARSEк столбцам 3-5 в каждой группе. Теперь моя таблица занимает около 1,8 ГБ в пространстве данных, как сообщалось sp_spaceused, тогда как до разбора она была 1 ГБ.

Я пытался dbcc cleantable, но это не имело никакого эффекта.
Тогда dbcc shrinkdatabaseтоже никакого эффекта.

Озадаченный, я удалил SPARSEи повторил dbccс. Размер таблицы остался на уровне 1,8 Гб.

Что дает?


Постараюсь и воспроизведу. Просто если есть какая-то разница, является ли таблица кучей или она имеет кластерный индекс?
— Мартин Смит

@MartinSmith Имеет кластерный индекс rowid int not null identity(1,1) primary key clustered.
— GSerg

Ответы:


14

Вам нужно перестроить кластерный индекс после того, как столбцы будут редкими. Пропущенные столбцы все еще существуют на странице данных, пока вы не сделаете это, как можно увидеть с помощью запроса sys.system_internals_partition_columnsили использованияDBCC PAGE

SET NOCOUNT ON;
CREATE TABLE Thing 
(
ThingId int IDENTITY CONSTRAINT PK PRIMARY KEY,
USER_CHAR1 nvarchar(150) null,
USER_CHAR2 nvarchar(150) null,
USER_CHAR3 nvarchar(150) null,
USER_CHAR4 nvarchar(150) null,
USER_CHAR5 nvarchar(150) null
)
INSERT INTO Thing
SELECT REPLICATE('A',150),
       CASE WHEN number % 5 = 1 THEN REPLICATE('A',150) END,
       CASE WHEN number % 5 = 2 THEN REPLICATE('A',150) END,
       CASE WHEN number % 5 = 3 THEN REPLICATE('A',150) END,              
       CASE WHEN number % 5 = 4 THEN REPLICATE('A',150) END
FROM master..spt_values   

EXEC sp_spaceused 'Thing'

ALTER TABLE dbo.Thing ALTER COLUMN USER_CHAR2 ADD SPARSE
ALTER TABLE dbo.Thing ALTER COLUMN USER_CHAR3 ADD SPARSE
ALTER TABLE dbo.Thing ALTER COLUMN USER_CHAR4 ADD SPARSE
ALTER TABLE dbo.Thing ALTER COLUMN USER_CHAR5 ADD SPARSE

DECLARE @DynSQL NVARCHAR(MAX);

SELECT @DynSQL =  'DBCC TRACEON (3604);
                   DBCC PAGE(0, ' + LEFT(file_id,10) + ', ' + LEFT(page_id,10) + ', 3); 
                   DBCC TRACEOFF(3604); ' 
FROM Thing
CROSS APPLY sys.fn_PhysLocCracker(%%physloc%%)
WHERE ThingId=76

EXEC(@DynSQL)    

SELECT pc.*
FROM sys.system_internals_partition_columns pc
JOIN sys.partitions p on p.partition_id=pc.partition_id
WHERE p.object_id = object_id('Thing')
AND pc.is_dropped=1

 EXEC sp_spaceused 'Thing'

ALTER INDEX PK ON Thing REBUILD;    

SELECT @DynSQL =  'DBCC TRACEON (3604);
                   DBCC PAGE(0, ' + LEFT(file_id,10) + ', ' + LEFT(page_id,10) + ', 3); 
                   DBCC TRACEOFF(3604); ' 
FROM Thing
CROSS APPLY sys.fn_PhysLocCracker(%%physloc%%)
WHERE ThingId=76

EXEC(@DynSQL)    

SELECT pc.*
FROM sys.system_internals_partition_columns pc
JOIN sys.partitions p on p.partition_id=pc.partition_id
WHERE p.object_id = object_id('Thing')
AND pc.is_dropped=1

EXEC sp_spaceused 'Thing'

DROP TABLE Thing 

1
Потрясающие. Должны ли мы принять это как ошибку в документации ? «SQL Server Database Engine использует следующую процедуру для выполнения этого изменения: 1) Добавляет новый столбец в таблицу в новом размере и формате хранилища. 2) Для каждой строки в таблице обновляет и копирует значение, сохраненное в старом столбец к новому столбцу. 3) Удаляет старый столбец из схемы таблицы. 4) Перестраивает таблицу, чтобы освободить пространство, используемое старым столбцом. "
— GSerg

3
@GSerg - Ах да. Согласитесь, кажется, пункт 4 не является правильным тогда. Учитывая, что вы делаете это для 12 столбцов, вы не хотели бы, чтобы перестройка происходила неявно для каждого столбца, хотя поведение кажется правильным, но не документация.
— Мартин Смит

1
@SQLKiwi - Спасибо. Готово
— Мартин Смит
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.