Sparsing
При выполнении некоторых тестов для разреженных столбцов, как и у вас, произошел спад производительности, который я хотел бы узнать по прямой причине.
DDL
Я создал две идентичные таблицы, одну с 4 разреженными столбцами и одну без разреженных столбцов.
--Non Sparse columns table & NC index
CREATE TABLE dbo.nonsparse( ID INT IDENTITY(1,1) PRIMARY KEY NOT NULL,
charval char(20) NULL,
varcharval varchar(20) NULL,
intval int NULL,
bigintval bigint NULL
);
CREATE INDEX IX_Nonsparse_intval_varcharval
ON dbo.nonsparse(intval,varcharval)
INCLUDE(bigintval,charval);
-- sparse columns table & NC index
CREATE TABLE dbo.sparse( ID INT IDENTITY(1,1) PRIMARY KEY NOT NULL,
charval char(20) SPARSE NULL ,
varcharval varchar(20) SPARSE NULL,
intval int SPARSE NULL,
bigintval bigint SPARSE NULL
);
CREATE INDEX IX_sparse_intval_varcharval
ON dbo.sparse(intval,varcharval)
INCLUDE(bigintval,charval);
DML
Затем я вставил около 2540 значений NULL в оба.
INSERT INTO dbo.nonsparse WITH(TABLOCK) (charval, varcharval,intval,bigintval)
SELECT 'Val1','Val2',20,19
FROM MASTER..spt_values;
INSERT INTO dbo.sparse WITH(TABLOCK) (charval, varcharval,intval,bigintval)
SELECT 'Val1','Val2',20,19
FROM MASTER..spt_values;
После этого я вставил 1M NULL значения в обе таблицы
INSERT INTO dbo.nonsparse WITH(TABLOCK) (charval, varcharval,intval,bigintval)
SELECT TOP(1000000) NULL,NULL,NULL,NULL
FROM MASTER..spt_values spt1
CROSS APPLY MASTER..spt_values spt2;
INSERT INTO dbo.sparse WITH(TABLOCK) (charval, varcharval,intval,bigintval)
SELECT TOP(1000000) NULL,NULL,NULL,NULL
FROM MASTER..spt_values spt1
CROSS APPLY MASTER..spt_values spt2;
Запросы
Неполное выполнение таблицы
При выполнении этого запроса дважды для вновь созданной непрореженной таблицы:
SET STATISTICS IO, TIME ON;
SELECT * FROM dbo.nonsparse
WHERE 1= (SELECT 1) -- force non trivial plan
OPTION(RECOMPILE,MAXDOP 1);
Логические чтения показывают 5257 страниц
(1002540 rows affected)
Table 'nonsparse'. Scan count 1, logical reads 5257, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
И время процессора составляет 343 мс
SQL Server Execution Times:
CPU time = 343 ms, elapsed time = 3850 ms.
разреженное выполнение таблицы
Выполнение одного и того же запроса дважды для разреженной таблицы:
SELECT * FROM dbo.sparse
WHERE 1= (SELECT 1) -- force non trivial plan
OPTION(RECOMPILE,MAXDOP 1);
Показания ниже, 1763
(1002540 rows affected)
Table 'sparse'. Scan count 1, logical reads 1763, physical reads 3, read-ahead reads 1759, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Но время процессора выше, 547 мс .
SQL Server Execution Times:
CPU time = 547 ms, elapsed time = 2406 ms.
План выполнения разреженных таблиц
план разбора не разреженных таблиц
Вопросов
Оригинальный вопрос
Поскольку значения NULL не сохраняются непосредственно в разреженных столбцах, может ли увеличение времени процессора быть связано с возвратом значений NULL в качестве набора результатов? Или это просто поведение, указанное в документации ?
Разреженные столбцы уменьшают требования к пространству для нулевых значений за счет дополнительных затрат на извлечение ненулевых значений
Или накладные расходы связаны только с чтением и хранением?
Даже при запуске ssms с опциями отмены после выполнения время процессора разреженного выбора было выше (407 мс) по сравнению с непрореженным (219 мс).
РЕДАКТИРОВАТЬ
Возможно, это были издержки ненулевых значений, даже если присутствуют только 2540, но я все еще не убежден.
Кажется, это примерно одинаковая производительность, но разреженный фактор был потерян.
CREATE INDEX IX_Filtered
ON dbo.sparse(charval,varcharval,intval,bigintval)
WHERE charval IS NULL
AND varcharval IS NULL
AND intval IS NULL
AND bigintval IS NULL;
CREATE INDEX IX_Filtered
ON dbo.nonsparse(charval,varcharval,intval,bigintval)
WHERE charval IS NULL
AND varcharval IS NULL
AND intval IS NULL
AND bigintval IS NULL;
SET STATISTICS IO, TIME ON;
SELECT charval,varcharval,intval,bigintval FROM dbo.sparse WITH(INDEX(IX_Filtered))
WHERE charval IS NULL AND varcharval IS NULL
AND intval IS NULL
AND bigintval IS NULL
OPTION(RECOMPILE,MAXDOP 1);
SELECT charval,varcharval,intval,bigintval
FROM dbo.nonsparse WITH(INDEX(IX_Filtered))
WHERE charval IS NULL AND
varcharval IS NULL
AND intval IS NULL
AND bigintval IS NULL
OPTION(RECOMPILE,MAXDOP 1);
Кажется, примерно одинаковое время выполнения:
SQL Server Execution Times:
CPU time = 297 ms, elapsed time = 292 ms.
SQL Server Execution Times:
CPU time = 281 ms, elapsed time = 319 ms.
Но почему логические чтения сейчас одинаковы? Разве в отфильтрованном индексе для разреженного столбца не должно храниться ничего, кроме включенного поля идентификатора и некоторых других страниц без данных?
Table 'sparse'. Scan count 1, logical reads 5785,
Table 'nonsparse'. Scan count 1, logical reads 5785
И размер обоих показателей:
RowCounts Used_MB Unused_MB Total_MB
1000000 45.20 0.06 45.26
Почему они одинакового размера? Была ли потеряна редкость?
Оба плана запроса при использовании отфильтрованного индекса
Дополнительная информация
select @@version
Microsoft SQL Server 2017 (RTM-CU16) (KB4508218) - 14.0.3223.3 (X64) 12 июля 2019 г. 17:43:08 Авторское право (C) 2017 Выпуск Microsoft Corporation для разработчиков (64-разрядная версия) в Windows Server 2012 R2 Datacenter 6.3 (сборка) 9600 :) (гипервизор)
При выполнении запросов и выборе только поля идентификатора время процессора сравнимо с меньшим логическим чтением для разреженной таблицы.
Размер столов
SchemaName TableName RowCounts Used_MB Unused_MB Total_MB
dbo nonsparse 1002540 89.54 0.10 89.64
dbo sparse 1002540 27.95 0.20 28.14
При принудительном использовании кластеризованного или некластеризованного индекса разница во времени процессора сохраняется.