2016-12-05 1 views
2

전제 조건을위한 데이터베이스 크기를 예측해야하므로 예제 SQL Server에서 데이터를 저장하는 방법을 이해하려고합니다.SQL Server에서 테이블 크기를 계산하십시오.

IdInfoComp : Integer Not Null (PK) 
IdDefinition : Integer Not Null (FK) 
IdObject : Integer Not Null (FK) 
Value : NVarChar(Max) Not Null 

나는 테이블의 크기를 추정하려면 : 내 SQL 서버 데이터베이스에

, 나는 InfoComp 느릅 나무라는 이름의 테이블이 4 행이 포함되어 있습니다.

SELECT AVG(Value) FROM InfoComp 
Result : 8 

그래서, 내 계산 (바이트) 것 같다 : 실제 사용에서,이 SQL 쿼리와 Value에 저장된 평균 길이를 얻을 수 있습니다

(Size(IdInfoComp) + Size(IdDefinition) + Size(IdObject) + AVG Size(Value)) * Rows count 

(4 + 4 + 4 + ((8 * 2) + 2)) * NbRows 

그러나 나는 시도하고있을 때 이 계산을 실제 사례에 적용하려면 잘못되었습니다. 내 경우에는 3,250,273 개의 행을 가지므로 결과는 92MB 여야하지만 MS SQL 보고서에 의하면 :

(데이터) 147 888 KB (인덱스) 113 072 KB 및 (예약 됨) 261 160 KB입니다.

내가 잘못 들었습니까?

+3

확실하지 않지만 빠른 검색을 통해보다 구체적인 지침이있는 MSDN 공식 페이지가 표시됩니다. https://msdn.microsoft.com/en-us/library/ms175991.aspx (아마도 전체 데이터 풋 프린트와는 상당히 다른 인덱스의 크기를 계산하는 것처럼 보입니다) – jleach

+0

저는 실제로이를 시도하고 있습니다. 하지만 약간의 차이점이 있습니다 (약 10MB). – Cedric

+1

평균보다,'value'의 값을 합할 수 있습니다. –

답변

2

시도해보십시오. 내가 만들 msdn 기사를 사용합니다. 행 수를 설정할 수 있습니다. 이것은 인덱스를 포함하여 db의 모든 테이블을 수행합니다. 열 스토어를 아직하지 않으며 관계를 처리하지 않습니다. 모든 테이블에 행 개수 추정치가 적용됩니다. 테이블이 생성되고 데이터베이스가 어떻게 구성 방법에 대한 더 충분한 정보가 없기 때문에 계산이 잘못된 이유

/*Do NOT change this section*/ 
GO 
CREATE TABLE RowSizes (TypeName VARCHAR(30), TableName VARCHAR(255), IndexName VARCHAR(255), Null_Bitmap SMALLINT, VariableFieldSize BIGINT, FixedFieldSize BIGINT, Row_Size BIGINT, LOBFieldSize BIGINT); 
CREATE TABLE LeafSizes (TypeName VARCHAR(30), TableName VARCHAR(255), IndexName VARCHAR(255), Row_Size BIGINT, Rows_Per_Page BIGINT, Free_Rows_Per_Page BIGINT, Non_Leaf_Levels BIGINT, Num_Leaf_Pages BIGINT, Num_Index_Pages BIGINT, Leaf_space_used_bytes BIGINT); 
GO 
CREATE PROCEDURE dbo.cp_CalcIndexPages 
    @IndexType VARCHAR(20) 
AS 
BEGIN 
    DECLARE @IndexName VARCHAR(255) 
     , @TableName varchar(255) 
     , @Non_Leaf_Levels bigint = 127 
     , @Rows_Per_Page bigint = 476 
     , @Num_Leaf_Pages bigint =10000; 

    WHILE EXISTS(SELECT TOP 1 1 FROM dbo.LeafSizes WHERE TypeName = @IndexType AND Num_Index_Pages = 0)-- AND IndexName = 'PK_ProcessingMessages') 
    BEGIN 
     SELECT TOP 1 @IndexName = IndexName 
      , @TableName = TableName 
      , @Non_Leaf_Levels = Non_Leaf_Levels 
      , @Rows_Per_Page = Rows_Per_Page 
      , @Num_Leaf_Pages = Num_Leaf_Pages 
     FROM dbo.LeafSizes 
     WHERE TypeName = @IndexType 
      AND Num_Index_Pages = 0; 

     DECLARE @Counter INT = 1 
      , @Num_Index_Pages INT = 0; 

     WHILE @Counter <= @Non_Leaf_Levels 
     BEGIN 
      BEGIN TRY 

      SELECT @Num_Index_Pages += ROUND(CASE WHEN @Num_Leaf_Pages/POWER(@Rows_Per_Page, @Counter) < CONVERT(FLOAT, 1) THEN 1 ELSE @Num_Leaf_Pages/POWER(@Rows_Per_Page, @Counter) END, 0) 
      END TRY 

      BEGIN CATCH 
       SET @Num_Index_Pages += 1 
      END CATCH 

      SET @Counter += 1 
     END 

     IF @Num_Index_Pages = 0 
      SET @Num_Index_Pages = 1; 

     UPDATE dbo.LeafSizes 
     SET Num_Index_Pages = @Num_Index_Pages 
      , Leaf_space_used_bytes = 8192 * @Num_Index_Pages 
     WHERE TableName = @TableName 
      AND IndexName = @IndexName; 

    END 
END 
GO 
/*Do NOT change above here*/ 

--Set parameters here 
DECLARE @NumRows INT = 1000000 --Number of rows for estimate 
    ,@VarPercentFill money = .6; --Percentage of variable field space used to estimate. 1 will provide estimate as if all variable columns are 100% full. 


/*Do not change*/ 
WITH cte_Tables AS (--Get Tables 
    SELECT o.object_id, s.name+'.'+o.name AS ObjectName 
    FROM sys.objects o 
    INNER JOIN sys.schemas s ON o.schema_id = s.schema_id 
    WHERE type = 'U' 
), cte_TableData AS (--Calculate Field Sizes 
    SELECT o.ObjectName AS TableName 
     , SUM(CASE WHEN t.name IN ('int', 'bigint', 'tinyint', 'char', 'datetime', 'smallint', 'date') THEN 1 ELSE 0 END) AS FixedFields 
     , SUM(CASE WHEN t.name IN ('int', 'bigint', 'tinyint', 'char', 'datetime', 'smallint', 'date') THEN c.max_length ELSE 0 END) AS FixedFieldSize 
     , SUM(CASE WHEN t.name IN ('varchar') THEN 1 ELSE 0 END) AS VariableFields 
     , SUM(CASE WHEN t.name IN ('varchar') THEN c.max_length ELSE 0 END)*@VarPercentFill AS VariableFieldSize 
     , SUM(CASE WHEN t.name IN ('xml') THEN 1 ELSE 0 END) AS LOBFields 
     , SUM(CASE WHEN t.name IN ('xml') THEN 10000 ELSE 0 END) AS LOBFieldSize 
     , COUNT(1) AS TotalColumns 
    FROM sys.columns c 
    INNER JOIN cte_Tables o ON o.object_id = c.object_id 
    INNER JOIN sys.types t ON c.system_type_id = t.system_type_id 
    GROUP BY o.ObjectName 
), cte_Indexes AS (--Get Indexes and size 
    SELECT s.name+'.'+o.name AS TableName 
     , ISNULL(i.name, '') AS IndexName 
     , i.type_desc 
     , i.index_id 
     , SUM(CASE WHEN t.name IN ('tinyint','smallint', 'int', 'bigint', 'char', 'datetime', 'date') AND c.key_ordinal > 0 THEN 1 ELSE 0 END) AS FixedFields 
     , SUM(CASE WHEN t.name IN ('tinyint','smallint', 'int', 'bigint', 'char', 'datetime', 'date') AND c.key_ordinal > 0 THEN tc.max_length ELSE 0 END) AS FixedFieldSize 
     , SUM(CASE WHEN t.name IN ('varchar') AND c.key_ordinal > 0 THEN 1 ELSE 0 END) AS VariableFields 
     , SUM(CASE WHEN t.name IN ('varchar') AND c.key_ordinal > 0 THEN tc.max_length ELSE 0 END)*@VarPercentFill AS VariableFieldSize 
     , SUM(CASE WHEN t.name IN ('xml') AND c.key_ordinal > 0 THEN 1 ELSE 0 END) AS LOBFields 
     , SUM(CASE WHEN t.name IN ('xml') AND c.key_ordinal > 0 THEN 10000 ELSE 0 END) AS LOBFieldSize 
     , SUM(CASE WHEN t.name IN ('tinyint','smallint', 'int', 'bigint', 'char', 'datetime', 'date') AND c.is_included_column > 0 THEN 1 ELSE 0 END) AS FixedIncludes 
     , SUM(CASE WHEN t.name IN ('tinyint','smallint', 'int', 'bigint', 'char', 'datetime', 'date') AND c.is_included_column > 0 THEN 1 ELSE 0 END) AS FixedIncludesSize 
     , SUM(CASE WHEN t.name IN ('varchar') AND c.is_included_column > 0 THEN 1 ELSE 0 END)*@VarPercentFill AS VariableIncludes 
     , SUM(CASE WHEN t.name IN ('varchar') AND c.is_included_column > 0 THEN tc.max_length ELSE 0 END) AS VariableIncludesSize 
     , COUNT(1) AS TotalColumns 
    FROM sys.indexes i 
    INNER JOIN sys.columns tc ON i.object_id = tc.object_id 
    INNER JOIN sys.index_columns c ON i.index_id = c.index_id 
     AND c.column_id = tc.column_id 
     AND c.object_id = i.object_id 
    INNER JOIN sys.objects o ON o.object_id = i.object_id AND o.is_ms_shipped = 0 
    INNER JOIN sys.schemas s ON o.schema_id = s.schema_id 
    INNER JOIN sys.types t ON tc.system_type_id = t.system_type_id 
    GROUP BY s.name+'.'+o.name, ISNULL(i.name, ''), i.type_desc, i.index_id 
) 
INSERT RowSizes 
SELECT 'Table' AS TypeName 
    , n.TableName 
    , '' AS IndexName 
    , 2 + ((n.FixedFields+n.VariableFields+7)/8) AS Null_Bitmap 
    , 2 + (n.VariableFields * 2) + n.VariableFieldSize AS Variable_Data_Size 
    , n.FixedFieldSize 
    /*FixedFieldSize + Variable_Data_Size + Null_Bitmap*/ 
    , n.FixedFieldSize + (2 + (n.VariableFields * 2) + (n.VariableFieldSize)) + (2 + ((n.FixedFields+n.VariableFields+7)/8)) + 4 AS Row_Size 
    , n.LOBFieldSize 
FROM cte_TableData n 
UNION 
SELECT i.type_desc 
    , i.TableName 
    , i.IndexName 
    , 0 AS Null_Bitmap 
    , CASE WHEN i.VariableFields > 0 THEN 2 + (i.VariableFields * 2) + i.VariableFieldSize + 4 ELSE 0 END AS Variable_Data_Size 
    , i.FixedFieldSize 
    /*FixedFieldSize + Variable_Data_Size + Null_Bitmap if not clustered*/ 
    , i.FixedFieldSize + CASE WHEN i.VariableFields > 0 THEN 2 + (i.VariableFields * 2) + i.VariableFieldSize + 4 ELSE 0 END + 7 AS Row_Size 
    , i.LOBFieldSize 
FROM cte_Indexes i 
WHERE i.index_id IN(0,1) 
UNION 
SELECT i.type_desc 
    , i.TableName 
    , i.IndexName 
    , CASE WHEN si.TotalColumns IS NULL THEN 2 + ((i.FixedFields+i.VariableFields+i.VariableIncludes+i.FixedIncludes+8)/8) 
      ELSE 2 + ((i.FixedFields+i.VariableFields+i.VariableIncludes+i.FixedIncludes+7)/8) 
     END AS Null_Bitmap 
    , CASE WHEN si.TotalColumns IS NULL THEN 2 + ((i.VariableFields + 1) * 2) + (i.VariableFieldSize + 8) 
      ELSE 2 + (i.VariableFields * 2) + i.VariableFieldSize 
     END AS Variable_Data_Size 
    , CASE WHEN si.TotalColumns IS NULL THEN si.FixedFieldSize 
      ELSE i.FixedFieldSize + si.FixedFieldSize 
     END AS FixedFieldSize 
    /*FixedFieldSize + Variable_Data_Size + Null_Bitmap if not clustered*/ 
    , CASE WHEN si.TotalColumns IS NULL THEN i.FixedFieldSize + (2 + ((i.VariableFields + 1) * 2) + (i.VariableFieldSize + 8)) + (2 + ((i.TotalColumns+8)/8)) + 7 
      ELSE i.FixedFieldSize + (2 + (i.VariableFields * 2) + i.VariableFieldSize) + (2 + ((i.TotalColumns+7)/8)) + 4 
     END AS Row_Size 
    , i.LOBFieldSize 
FROM cte_Indexes i 
LEFT OUTER JOIN cte_Indexes si ON i.TableName = si.TableName AND si.type_desc = 'CLUSTERED' 
WHERE i.index_id NOT IN(0,1) AND i.type_desc = 'NONCLUSTERED'; 

--SELECT * FROM RowSizes 

/*Calculate leaf sizes for tables and HEAPs*/ 
INSERT LeafSizes 
SELECT r.TypeName 
    , r.TableName 
    ,'' AS IndexName 
    , r.Row_Size 
    , 8096/(r.Row_Size + 2) AS Rows_Per_Page 
    , 8096 * ((100 - 90)/100)/(r.Row_Size + 2) AS Free_Rows_Per_Page 
    , 0 AS Non_Leaf_Levels 
    /*Num_Leaf_Pages = Number of Rows/(Rows_Per_Page - Free_Rows_Per_Page) OR 1 if less than 1*/ 
    , CASE WHEN @NumRows/((8096/(r.Row_Size + 2)) - (8096 * ((100 - 90)/100)/(r.Row_Size + 2))) < 1 
      THEN 1 
      ELSE @NumRows/((8096/(r.Row_Size + 2)) - (8096 * ((100 - 90)/100)/(r.Row_Size + 2))) 
     END AS Num_Leaf_Pages 
    , 0 AS Num_Index_Pages 
    /*Leaf_space_used = 8192 * Num_Leaf_Pages*/ 
    , 8192 * CASE WHEN @NumRows/((8096/(r.Row_Size + 2)) - (8096 * ((100 - 90)/100)/(r.Row_Size + 2))) < 1 
       THEN 1 
       ELSE @NumRows/((8096/(r.Row_Size + 2)) - (8096 * ((100 - 90)/100)/(r.Row_Size + 2))) 
      END + (@NumRows * LOBFieldSize) AS Leaf_space_used_bytes 
FROM RowSizes r 
WHERE r.TypeName = 'Table' 
ORDER BY TypeName, TableName; 

/*Calculate leaf sizes for CLUSTERED indexes*/ 
INSERT LeafSizes 
SELECT r.TypeName 
    , r.TableName 
    , r.IndexName 
    , r.Row_Size 
    , 8096/(r.Row_Size + 2) AS Rows_Per_Page 
    , 0 AS Free_Rows_Per_Page 
    , 1 + ROUND(LOG(8096/(r.Row_Size + 2)), 0)*(l.Num_Leaf_Pages/(8096/(r.Row_Size + 2))) AS Non_Leaf_Levels 
    , l.Num_Leaf_Pages 
    , 0 AS Num_Index_Pages 
    , 0 AS Leaf_space_used_bytes 
FROM RowSizes r 
INNER JOIN LeafSizes l ON r.TableName = l.TableName AND l.TypeName = 'Table' 
WHERE r.TypeName = 'CLUSTERED'; 

PRINT 'CLUSTERED' 
EXEC dbo.cp_CalcIndexPages @IndexType = 'CLUSTERED' 

/*Calculate leaf sizes for NONCLUSTERED indexes*/ 
INSERT LeafSizes 
SELECT r.TypeName 
    , r.TableName 
    , r.IndexName 
    , r.Row_Size 
    , 8096/(r.Row_Size + 2) AS Rows_Per_Page 
    , 0 AS Free_Rows_Per_Page 
    , 1 + ROUND(LOG(8096/(r.Row_Size + 2)), 0)*(l.Num_Leaf_Pages/(8096/(r.Row_Size + 2))) AS Non_Leaf_Levels 
    , l.Num_Leaf_Pages 
    , 0 AS Num_Index_Pages 
    , 0 AS Leaf_space_used_bytes 
FROM RowSizes r 
INNER JOIN LeafSizes l ON r.TableName = l.TableName AND l.TypeName = 'Table' 
WHERE r.TypeName = 'NONCLUSTERED'; 

PRINT 'NONCLUSTERED' 
EXEC dbo.cp_CalcIndexPages @IndexType = 'NONCLUSTERED' 

SELECT * 
FROM dbo.LeafSizes 
--WHERE TableName = 'eligibility.clientrequest' 

SELECT TableName 
    , @NumRows AS RowsPerTable 
    , @VarPercentFill*100 AS VariableFieldFillFactor 
    , SUM(CASE WHEN TypeName = 'Table' THEN Leaf_space_used_bytes ELSE 0 END)/1024/1024 AS TableSizeMB 
    , SUM(Leaf_space_used_bytes)/1024/1024 AS SizeWithIndexesMB 
FROM LeafSizes 
--WHERE TableName = 'eligibility.clientrequest' 
GROUP BY TableName 
ORDER BY TableName; 


GO 
/*Cleanup when done*/ 
DROP PROCEDURE dbo.cp_CalcIndexPages; 
DROP TABLE dbo.RowSizes; 
DROP TABLE dbo.LeafSizes; 
0

불행하게도, 내가 말할 수 없습니다. 그래서 나는 공통적으로 대답하려고 노력할 것이고, 당신은 팁을 가질 것이다.

먼저 SQL Server 데이터베이스의 크기가 model 데이터베이스의 크기보다 크다는 것을 알아야합니다. model 데이터베이스는 새 데이터베이스의 템플릿이기 때문에 CREATE DATABASE 문을 실행할 때마다 복사됩니다.

데이터베이스의 모든 정보는 디스크의 8KB 페이지에 저장됩니다. 많은 종류의 페이지가 있습니다. 일부는 (할당 맵 및 메타 데이터와 같은) 내부 목적으로 사용되지만 나머지는 데이터 저장 용도로 사용됩니다.

테이블 크기는 디스크에 구성된 데이터 (클러스터 된 인덱스 여부), 열 유형 및 데이터 압축에 따라 다릅니다. 인덱스의 크기는 인덱스 된 테이블에 대한 고유 인덱스의 존재 여부, 인덱스의 레벨 수, 채우기 비율 등에 따라 다릅니다.

앞서 말한 것처럼 모든 것이 페이지와 데이터에도 저장됩니다. SQL Server에는 행 내부 데이터 용 페이지, 행 오버플로 데이터 용 페이지 및 LOB 데이터 용 페이지가 있습니다. 데이터 페이지는 페이지 헤더, 데이터 행 및 데이터 오프셋 배열의 세 가지 주요 부분으로 구성됩니다.

페이지 머리글은 각 데이터 페이지의 처음 96 바이트를 차지하며 다른 구성 요소에는 8,096 바이트가 남습니다. 행 오프셋 배열은 페이지 끝 부분에 저장된 2 바이트 항목의 블록입니다. 항목 수는 헤더에 저장되고 슬롯 수라고합니다.

헤더와 행 오프셋 배열 사이의 영역은 데이터 행이 저장되는 영역입니다. 각 행은 고정 된 크기 부분과 가변 길이 부분의 두 가지 구성 요소로 구성됩니다.

데이터 행의 구조는 다음

  • 상태 비트 A, 1 바이트
  • 상태 비트 B, 1 바이트
  • 고정 길이 크기 (FSIZE), 2 바이트
  • 고정 소수점 길이 데이터 (FData) FSIZE - 열 (에는 NcoI) 4
  • 번호 2 바이트
  • NULL 비트 맵, 천장 (을 NcoI/8)
  • 행 (VarCount)에 저장된 가변 길이의 열
  • 번호 2 바이트
  • 가변 칼럼 오프셋 어레이 (VarOffset) 2 * VarCount
  • 가변 길이 데이터 (VARDATA) VarOff [VarCount - (FSIZE + 4 + 천장 (을 NcoI/8) + 2 * VarCount) 인덱스 행이 데이터 행과 동일한 방식으로 저장된다

NOTE.

여기에 설명 된 모든 내용이 아니지만 SQL Server가 할당 된 공간을 사용하는 목적을 이해하는 데 도움이되기를 바랍니다. 또한 데이터베이스 파일은 FILEGROWTH 옵션으로 지정된 크기만큼 커지므로 예상보다 큰 실제 크기가 될 수 있습니다.

Microsoft SQL Server 2012 Internals 책을보고 Estimate the Size of a Database을 읽으십시오. 아마 너에게 흥미로울거야.

관련 문제