В своих оценках размера вы учли количество места, занимаемое индексами? Кроме того, если у вас есть текстовые поля, которые заданы как многобайтовые ( N[VAR]CHAR
а не [VAR]CHAR
), а входные файлы имеют формат UTF-8 или обычный однобайтовый символ, то это увеличит ваши требования к хранилищу почти в два раза. Кроме того, помните, что если у вас есть кластеризованный ключ / индекс в таблице, размер этого параметра влияет на все остальные индексы в таблице, потому что они включают значение кластеризованного ключа для каждой строки (поэтому приведем крайний пример, если в таблице есть NCHAR (10). ) ключ, в котором будет использоваться INT, и это ваш кластеризованный ключ / индекс: вы не только используете дополнительные 16 байтов на строку на страницах данных, вы также тратите 16 байтов на строку в каждом другом индексе этой таблицы ) .
Кроме того, некоторое пространство будет выделено, но неиспользовано, либо потому, что механизм БД оставил некоторое пространство, выделенное после удаления, чтобы его можно было быстро снова использовать для новых данных в этой таблице, либо потому, что шаблон вставок и удалений оставил многие страницы только частью полный.
Вы можете запустить:
SELECT o.name
, SUM(ps.reserved_page_count)/128.0 AS ReservedMB
, SUM(ps.used_page_count)/128.0 AS UsedMB
, SUM(ps.reserved_page_count-ps.used_page_count)/128.0 AS DiffMB
FROM sys.objects o
JOIN sys.dm_db_partition_stats ps ON o.object_id = ps.object_id
WHERE OBJECTPROPERTYEX(o.object_id, 'IsMSShipped') = 0
GROUP BY o.name
ORDER BY SUM(ps.reserved_page_count) DESC
чтобы быстро взглянуть на то, какие таблицы занимают место.
Также EXEC sp_spaceused
запуск в этой БД вернет два набора результатов. Первый перечисляет общее пространство, выделенное в файловой системе для файлов данных, и сколько из этого нераспределенного, второй перечисляет, сколько выделенного пространства используется для страниц данных, страниц индекса или в настоящее время не используется.
sp_spaceused
вернет пространство, используемое данным объектом, так что вы можете зациклить это, чтобы построить таблицу для анализа:
-- TEMP TABLES FOR ANALYSIS
CREATE TABLE #tTables (sName NVARCHAR(MAX), iRows BIGINT, iReservedKB BIGINT, iDataKB BIGINT, iIndexKB BIGINT, iUnusedKB BIGINT)
CREATE TABLE #tTmp (sName NVARCHAR(MAX), iRows BIGINT, sReservedKB NVARCHAR(MAX), sDataKB NVARCHAR(MAX), sIndexKB NVARCHAR(MAX), sUnusedKB NVARCHAR(MAX))
-- COLLECT SPACE USE PER TABLE
EXEC sp_msforeachtable 'INSERT #tTmp EXEC sp_spaceused [?];'
-- CONVERT NUMBER-AS-TEXT COLUMNS TO NUMBER TYPES FOR EASIER ANALYSIS
INSERT #tTables SELECT sName, iRows
, CAST(REPLACE(sReservedKB, ' KB', '') AS BIGINT)
, CAST(REPLACE(sDataKB , ' KB', '') AS BIGINT)
, CAST(REPLACE(sIndexKB , ' KB', '') AS BIGINT)
, CAST(REPLACE(sUnusedKB , ' KB', '') AS BIGINT)
FROM #tTmp
DROP TABLE #tTmp
-- DO SOME ANALYSIS
SELECT sName='TOTALS', iRows=SUM(iRows), iReservedKB=SUM(iReservedKB), iDataKB=SUM(iDataKB), iIndexKB=SUM(iIndexKB), iUnusedKB=SUM(iUnusedKB) FROM #tTables ORDER BY sName
SELECT * FROM #tTables ORDER BY iReservedKB DESC
-- CLEAN UP
DROP TABLE #tTables
Приведенный выше код выведет все размеры таблиц в одном списке плюс одна строка для итогов. При необходимости вы можете использовать различные системные представления (как sys.objects
и sys.dm_db_partition_stats
в первом запросе выше, см. Http://technet.microsoft.com/en-us/library/ms177862.aspx для получения более подробной информации), чтобы получить более подробную информацию, такую как пространство, используемое каждым индексом.
В файле данных есть три класса неиспользуемого пространства:
- То, что ни для чего не выделено (это показано в первом наборе результатов
sp_spaceused
без указанного объекта)
- То, что выделено для объекта (зарезервировано), но не используется в данный момент (это показано в «неиспользованном» количестве в
sp_spaceused
выходных данных).
- Это заблокировано на частично использованных страницах (это будет выглядеть так, как будто все размещено на отдельных страницах, одна страница длиной 8192 байта). Это сложнее обнаружить / рассчитать. Это связано с сочетанием двух факторов:
- Разделить страницы. По мере добавления данных вы часто получаете пустые страницы (механизм хранения всегда может нормализовать содержимое страницы, но это было бы очень неэффективно), а при удалении строк содержимое страницы не упаковывается автоматически (опять же, это может быть, но дополнительная Нагрузка ввода / вывода вообще далека от того)
- Механизм хранения не будет разбивать строку на несколько страниц (вместе с размером страницы, откуда берется ограничение в 8 192 байта на строку). Если ваши строки имеют фиксированный размер и занимают 1100 байт каждая, то вы будете «тратить» не менее 492 байт каждого блока данных, выделенного для этой таблицы (7 строк занимают 7 700 байт, а 8-й не помещается, поэтому оставшиеся байты выигрывают ' не будет использоваться). Чем шире ряды, тем хуже это может быть. Таблицы / индексы со строками переменной длины (которые встречаются гораздо чаще, чем строки с полностью фиксированной длиной), как правило, лучше (но их труднее рассчитать).
Еще одна оговорка здесь, большие объекты ( TEXT
столбцы,[N]VARCHAR(MAX)
значения выше определенного размера и т. д.) поскольку они размещаются вне страницы, просто беря 8 байтов в данных основной строки для хранения указателя на данные в другом месте), что может нарушить ограничение 8192 байта на строку.
tl; dr: оценка ожидаемых размеров базы данных может быть гораздо более сложной, чем это изначально предполагалось.