Мне нужно создать широкую денормализованную таблицу с большим количеством десятичных (26,8) столбцов (ограничение не более 1024 столбцов, большинство столбцов будет нулевым или нулевым). Я знаю около 8060 байт на ограничение строки, поэтому я попытался создать таблицу со сжатием страницы. Код ниже создает таблицу, вставляет одну строку и запрашивает размер строки. Размер строки намного ниже предела, но если я попытаюсь добавить еще один десятичный (26,8) столбец в таблицу, операция завершится неудачно с ошибкой «Создание или изменение таблицы« t1 »завершилось неудачно, поскольку минимальный размер строки составил бы 8074, включая 1256» байты внутренней служебной информации. Есть ли способ создать одну таблицу с таким количеством столбцов?
drop table t1
GO
create table t1(c1 decimal(26, 8) null)
with (data_compression = page)
GO
declare @i int = 2;
declare @sql varchar(100);
while @i <= 486
begin
set @sql = 'alter table t1 add c' + convert(varchar, @i) + ' decimal(26, 8) null';
execute (@sql);
set @i += 1;
end;
GO
insert into t1(c1) select 0
GO
declare @i int = 2;
declare @sql varchar(100);
while @i <= 486
begin
set @sql = 'update t1 set c' + convert(varchar, @i) + ' = 0';
execute (@sql);
set @i += 1;
end;
GO
select max_record_size_in_bytes from sys.dm_db_index_physical_stats (db_id(), object_id('t1'), NULL, NULL, 'DETAILED')
GO
DECIMAL(26, 8) NULL
полей в таблицу, без сжатия страниц или десятичного сжатия. При включении vardecimal, но не сжатии страниц, накладные расходы превышают 1 K. Существует внешняя вероятность, что вы сможете хранить больше полей на странице без vardecimal, в зависимости от ваших значений.Ответы:
Ограничение, с которым вы сталкиваетесь, не имеет ничего общего с данными, хранящимися на странице. Расчет производится на основе типов данных столбцов. Вот почему вы столкнулись с ошибкой без каких-либо данных в таблице. Сжатие делает этот предел хуже. Вы можете прочитать о технических деталях за накладными расходами здесь .
Вы можете обойти эту проблему, используя столбцы SPARSE . Это означает, что для вставок может произойти сбой в зависимости от того, что вы вставляете, но вы можете обойти ограничение в 8060 байт. Следующий код показывает, что вы можете просто создать 1023 столбца:
Тем не менее, все ограничения (см. Связанную статью) могут сделать это не подходящим для вашего варианта использования. В частности, только
NULL
значения (не0
) оптимизированы, чтобы занять очень мало места. Если вы попытаетесь вставить слишком много0
s в одну строку, вы получите ошибку. Вот что я вижу, когда пытаюсь вставить 10230
значения:Я полагаю, что если вы действительно впали в отчаяние, вы можете создать столбцы
VARCHAR(27)
вместо этого. Столбцы переменной длины можно переместить за пределы страницы, чтобы вы могли превысить ограничение в 8060 байт в определении таблицы, но вставить определенные комбинации значений не удастся. SQL Server предупреждает вас об этом при создании таблицы:Сжатие страниц или строк может быть полезно, если вы придерживаетесь этого
VARCHAR(27)
подхода. Это минимизирует пространство, используемое обоими0
иNULL
. С помощьюVARCHAR(27)
я могу вставить 10230
значения просто отлично.источник
Помимо технических аспектов и предлагаемого обходного пути (с использованием
VARCHAR(27)
столбцов), обсуждаемых в ответе @ Joe , я подвергаю сомнению « необходимость создания широкой денормализованной таблицы», как это выражено в OP, если не существует какого-то странного технического требования, что все эти столбцы должно быть в одной таблице, я бы посоветовал / рекомендовал распределить их по столько раз, сколько необходимо. Родственные таблицы - это таблицы, которые:IDENTITY
колонка (и нет ФК для других)IDENTITY
Здесь вы разбиваете логическую строку на две или более физических таблицы. Но это по сути то, что нормализация в любом случае, и какие реляционные базы данных предназначены для обработки.
В этом сценарии вам потребуется некоторое дополнительное пространство, используемое при дублировании PK, и некоторая дополнительная сложность запросов из-за необходимости
INNER JOIN
объединения таблиц (часто, но не всегда, если всеSELECT
запросы не используют все столбцы, но обычно это не происходит) или создать явную транзакциюINSERT
илиUPDATE
их вместе (DELETE
может быть обработано с помощьюON DELETE CASCADE
набор на FK).ОДНАКО вы получаете преимущества от наличия надлежащей модели данных с правильными родными типами данных и без хитрости, которая может привести к непредвиденным последствиям в дальнейшем. Даже если использовать
VARCHAR(27)
позволяет работать на техническом уровне, прагматически я не думаю, что хранение десятичных дробей как строк отвечает интересам вашего проекта.Итак, если вам «нужна» только одна таблица из-за того, что вы не понимаете, что один логический объект не должен быть физически представлен в одном контейнере, то не пытайтесь заставить все это объединить в одну таблицу, когда она будет работать изящно через несколько столов.
Пример ниже иллюстрирует основную концепцию:
НАСТРОИТЬ
ТЕСТОВОЕ ЗАДАНИЕ
Возвращает:
источник