Додавання 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і повторив dbccs. Розмір столу залишився на рівні 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 використовує наступну процедуру для здійснення цієї зміни: 1) додає новий стовпець до таблиці в новому розмірі та форматі зберігання. 2) для кожного рядка таблиці оновлення та копіювання значення, збереженого в старому 3) Вилучає старий стовпець зі схеми таблиці. 4) Перебудовує таблицю, щоб повернути простір, використаний старим стовпцем. "
GSerg

3
@GSerg - Ага. Погодьтеся, здається, точка 4 тоді не є правильною. Зважаючи на те, що ви робите це для 12 стовпців, тоді ви не хочете, щоб відбудова відбувалася неявно для кожного стовпця, хоча так здається, що поведінка правильна, але не документація.
Мартін Сміт

1
@SQLKiwi - Дякую Готово
Мартін Сміт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.