Tập lệnh để ước tính kích thước hàng cho bất kỳ bảng nào


8

Tôi đang cố gắng ước tính các yêu cầu không gian cho một máy chủ cơ sở dữ liệu trung tâm sẽ thu thập dữ liệu từ khoảng 200 cơ sở dữ liệu trường giống hệt nhau. Tôi có số lượng hàng trung bình hàng ngày cho mỗi bảng và bây giờ cần ước tính kích thước hàng, bao gồm các chỉ mục, cho mỗi bảng.

Có một con vật như vậy tồn tại hay tôi cần phải tự lăn? Nếu tôi cần phải tự lăn, bạn có thể đề xuất một cách tiếp cận tốt không?

TIA


Một số thông tin ở đây: sqlskills.com/bloss/paul/ từ
Aaron Bertrand

Nếu bạn lấy kích thước của một bảng trong một trong những cơ sở dữ liệu trường lớn nhất và chia nó cho số lượng hàng, bạn sẽ có được ước tính hợp lý về kích thước có thể có trên mỗi hàng của cơ sở dữ liệu cuối cùng. Lưu trữ rất gần với tuyến tính với số lượng hàng. Có lẽ tôi đang thiếu một cái gì đó - bạn có cần một con số chính xác hơn không?
Jon của tất cả các giao dịch

Số lượng trung bình hàng ngày của hàng mới là 85.000.000. Tôi muốn đến gần với thực tế nhất có thể.
Ẩn dụ

Câu trả lời:


9

Sử dụng liên kết của Aaron để điều chỉnh thậm chí tốt hơn cho quy trình của tôi, tôi sẽ đề xuất một hàm và chế độ xem / truy vấn để báo cáo kích thước trên mỗi hàng trên mỗi bảng, bao gồm các chỉ mục.

create function dbo.getColumnSize (@typeName SYSNAME, @max_length INT, @precision INT)
RETURNS INT
AS
BEGIN
    RETURN (SELECT CASE @typeName
        WHEN 'tinyint'          THEN 1
        WHEN 'smallint'         THEN 2
        WHEN 'int'              THEN 4
        WHEN 'bigint'           THEN 8
        WHEN 'numeric'          THEN ((@precision - 1)/2) + 1
        WHEN 'decimal'          THEN ((@precision - 1)/2) + 1
        WHEN 'real'             THEN 4
        WHEN 'float'            THEN CASE WHEN @precision <=24 THEN 4 ELSE 8 END
        WHEN 'money'            THEN 8
        WHEN 'smallmoney'       THEN 4
        WHEN 'time'             THEN 5
        WHEN 'timestamp'        THEN 5
        WHEN 'date'             THEN 3
        WHEN 'smalldatetime'    THEN 4
        WHEN 'datetime'         THEN 8
        WHEN 'datetime2'        THEN 8
        WHEN 'datetimeoffset'   THEN 10
        WHEN 'char'             THEN @max_length
        WHEN 'varchar'          THEN @max_length + 2
        WHEN 'nchar'            THEN @max_length
        WHEN 'nvarchar'         THEN @max_length + 2
        WHEN 'binary'           THEN @max_length
        WHEN 'varbinary'        THEN @max_length + 2
        WHEN 'bit'              THEN 0.125
    END)
END

select SchemaName, ObjectName, SUM(CEILING(Bytes))+4+2+2+2+(ceiling(count(distinct columnname)*1.0/8.0)) As RowSize--, FLOOR((POWER(2,30)+(POWER(2,30)-1))*1.0/SUM(CEILING(Bytes))/30/2/60/24)
from (
    select s.name as SchemaName, o.name AS ObjectName, c.name as ColumnName, t.name as TypeName
        , dbo.getColumnSize(t.name,c.max_length, c.precision) AS Bytes
    from sys.objects o
        inner join sys.schemas s on s.schema_id=o.schema_id
        inner join sys.columns c on o.object_id=c.object_id
        inner join sys.types t on c.system_type_id=t.system_type_id
            and t.user_type_id=c.user_type_id
    where o.type='U'
        AND RIGHT(t.name,4) != 'text'
    UNION ALL
    select s.name as SchemaName, o.name AS ObjectName, c.name as ColumnName, t.name as TypeName
        , dbo.getColumnSize(t.name,c.max_length, c.precision) AS Bytes
    from sys.objects o
        inner join sys.schemas s on s.schema_id=o.schema_id
        inner join sys.indexes i on i.object_id = o.object_id
        inner join sys.index_columns ic on ic.object_id = o.object_id
            and i.index_id = ic.index_id
        inner join sys.columns c on o.object_id=c.object_id
            and ic.column_id = c.column_id
        inner join sys.types t on c.system_type_id=t.system_type_id
            and t.user_type_id=c.user_type_id
    where o.type='U'
        AND RIGHT(t.name,4) != 'text'
    ) Z
group by SchemaName, ObjectName

kích thước của nchar và nvarchar có nên gấp đôi kích thước chiều dài của chúng không?
Stefan Sieber

1
StefanSieber, Bạn cũng sẽ nghĩ như vậy và tôi cũng nghĩ vậy, nhưng khi thử nghiệm tôi thấy rằng sys.columns của SQL Server xem báo cáo max_length theo byte, không phải ký tự. vì vậy nvarchar (1) sẽ báo cáo max_length là 2.
Jaaz Cole

giống như sự tao nhã của câu trả lời và tôi có thể sẽ sử dụng nó ... với một sửa đổi nhỏ khi 'bit' trả về một số nguyên. do đó, làm tròn xuống hoặc làm tròn tùy thuộc vào ứng dụng của dữ liệu kết quả.
yeOldeDataSmythe

9

Script được chọn là asnwer có một số nhược điểm:

  1. Không tính đến một số kiểu dữ liệu SQL Server:

    hình ảnh, văn bản, định danh duy nhất, sql_variant, ntext, hVELyid, hình học, địa lý, xml, sysname

và (max) cấu trúc dữ liệu cấu trúc như varchar (max) để đặt tên cho một số ít.

  1. Đưa vào các cột được tính toán mà không ảnh hưởng đến kích thước của bản ghi.
  2. Không tính đến bảng thực tế có các cột NULLable.
  3. Không tính đến thực tế là một số kiểu dữ liệu có kích thước khác nhau tùy thuộc vào tỷ lệ được chỉ định (ví dụ: thời gian (0) và thời gian (7) nên có độ dài cột khác nhau)

Kịch bản sau đây cho thấy kích thước của bản ghi như trên trang dữ liệu. Nó hiển thị kích thước tối đa có thể được lấy bởi bản ghi, kích thước tối thiểu (trong trường hợp một giá trị tất cả trong bản ghi là NULL nếu được cho phép bởi cấu trúc bảng). Nó hiển thị loại bảng (CLUSTERED / NONCLUSTERED), tổng số cột dữ liệu và lược đồ nơi bảng thuộc về.

Lưu ý tập lệnh này không đưa vào chỉ mục tài khoản.

Cập nhật: Tập lệnh đếm mỗi cột bit là 1/8 của một byte. Kích thước tối thiểu và tối đa được điều chỉnh để đảm bảo rằng các bản ghi không thể nhỏ hơn kích thước gốc chuyển tiếp .

  SELECT 
     -- record cannot be smaller than the forwarding stub size =9 Bytes
     CASE WHEN [Max Size]>=9
     THEN [Max Size]
     ELSE 9 
     END AS [Max Size]
     -- record cannot be smaller than the forwarding stub size =9 Bytes
    , CASE WHEN [Min Size]>=9
     THEN [Min Size]
     ELSE 9 
     END AS [Min Size]
    , [Table Name]
    , [Table Type]
    , [Total Number of Columns]
    , [Schema]
    FROM
    (
SELECT 
    DISTINCT 
    -- Overhead for row header of a data row
    4
    +
    -- Overhead for NULL bitmap
    2+cast(([Total Number of Columns]+7)/8 AS BIGINT)+
    -- overhead for variable length
    CASE WHEN [IsVariableLength]>0
    THEN
    2
    ELSE
    0
    END
    +  
    --- Sum is on record level
    SUM(
    a1.[max_length]
    +
    -- Overhead for variable-length columns
    CASE WHEN 
    -- varchar
    [System Type]='varchar'
    --(([system_type_id]=167) AND ([user_type_id]=167))
    OR
    -- nvarchar 
    [System Type]='nvarchar'
    --(([system_type_id]=231) AND ([user_type_id]=231))
    OR
    -- IMAGE
    (([system_type_id]=34) OR ([user_type_id]=34))
    OR
    -- TEXT
    (([system_type_id]=35) OR ([user_type_id]=35))
    OR 
    --  NTEXT
    (([system_type_id]=99) OR ([user_type_id]=99))
    OR 
    --  SQLVARIANT
    (([system_type_id]=98) OR ([user_type_id]=98))
    OR
    -- hierarchyid geometry geography
    (([system_type_id]=240))
    THEN 2
    ELSE 0
    END
    )
    OVER (PARTITION BY a1.[Schema], a1.[Table Name]) AS [Max Size]

    , -- Overhead for row header of a data row
    4
    +
    -- Overhead for NULL bitmap
    2+cast(([Total Number of Columns]+7)/8 AS BIGINT)+
    -- overhead for variable length
    CASE WHEN ([IsVariableLength]>0) AND ([AnyFixedColumn]=0)
    THEN
    2
    ELSE
    0
    END
    +
    --- Sum is on record level
    SUM(
    -- overhead for variable length depending on number of variable columns
    CASE WHEN 
    -- varchar
    --[System Type]='varchar'
    (([system_type_id]=167) OR ([user_type_id]=167))
    OR
    -- nvarchar 
    --[System Type]='nvarchar'
    (([system_type_id]=231) OR ([user_type_id]=231))
    OR
    -- IMAGE
    (([system_type_id]=34) OR ([user_type_id]=34))
    OR
    -- TEXT
    (([system_type_id]=35) OR ([user_type_id]=35))
    OR 
    --  NTEXT
    (([system_type_id]=99) OR ([user_type_id]=99))
    --  VARBINARY
    OR
    (([system_type_id]=165) OR ([user_type_id]=165))
    OR 
    --  SQLVARIANT
    (([system_type_id]=98) OR ([user_type_id]=98))
    OR
    -- hierarchyid geometry geography
    (([system_type_id]=240))
    OR
    -- xml
    (([system_type_id]=241))
    THEN
        CASE WHEN [Is Nullable]=1
        THEN 0 
        ELSE 
        1
        END
    ELSE
        CASE
        WHEN
        -- bit
        (([system_type_id]=104) OR ([user_type_id]=104))
        and [Is Nullable]=1
        THEN 0
        ELSE
        a1.[max_length]
        END
    END
    -- 

    )
    OVER (PARTITION BY a1.[Schema], a1.[Table Name]) AS [Min Size]
    , a1.[Table Name]
    , [Table Type]
    , [Total Number of Columns]
    , a1.[Schema]
    FROM
    -- Start a1
    (   SELECT
        (SELECT [name] FROM [sys].[schemas]
        WHERE [sys].[schemas].[schema_id]=[sys].[objects].[schema_id])
        AS [Schema]
        , [sys].[objects].[name] AS [Table Name]
        , [sys].[all_columns].[name] AS [Column Name]
        , [sys].[all_columns].[system_type_id]
        , (
            SELECT name FROM [sys].[types]
            WHERE [sys].[types].[system_type_id]=[sys].[all_columns].[system_type_id]
            AND
                    [sys].[types].[user_type_id]=[sys].[all_columns].[user_type_id]
            ) AS [System Type]
        , [sys].[all_columns].[user_type_id]
        , 
        CASE 
        WHEN 
        -- IMAGE
        (([system_type_id]=34) OR ([user_type_id]=34))
        THEN 2147483647
        -- TEXT
        WHEN (([system_type_id]=35) OR ([user_type_id]=35))
        THEN 2147483647
        --  NTEXT
        WHEN (([system_type_id]=99) OR ([user_type_id]=99))
        THEN 1073741823
        -- varchar(max)
        WHEN (([system_type_id]=167) OR ([user_type_id]=167)) AND ([sys].[all_columns].[max_length]=-1)
        THEN 2147483647
        -- nvarchar(max) 
        WHEN (([system_type_id]=231) OR ([user_type_id]=231)) AND ([sys].[all_columns].[max_length]=-1)
        THEN 1073741823
        -- varbinary(max)
        WHEN (([system_type_id]=165) OR ([user_type_id]=165)) AND ([sys].[all_columns].[max_length]=-1)
        THEN 2147483647
        -- hierarchyid geometry geography
        WHEN (([system_type_id]=240))
        THEN 2147483647
        -- xml
        WHEN (([system_type_id]=241) AND ([sys].[all_columns].[max_length]=-1))
        THEN 2147483647
        -- bit
        WHEN (([system_type_id]=104) OR ([user_type_id]=104))
        THEN 1/8    
        ELSE 
        CAST([sys].[all_columns].[max_length] AS BIGINT)
        END [max_length]
        , [sys].[all_columns].[is_nullable] AS [Is Nullable]
        , 
        CASE 
        WHEN EXISTS 
            (   
                SELECT type_desc FROM sys.indexes
                WHERE type_desc='CLUSTERED'
                AND [sys].[objects].[object_id]=[sys].[indexes].[object_id]
            )
        THEN 'CLUSTERED'
        ELSE 'HEAP'
        END AS [Table Type]
        , COUNT([sys].[all_columns].[name]) OVER (PARTITION BY [sys].[objects].[object_id]) AS [Total Number of Columns]
        ,SUM (CASE WHEN 
        -- varchar
        (
        (([system_type_id]=167) AND ([user_type_id]=167))
        OR
        -- nvarchar 
        (([system_type_id]=231) AND ([user_type_id]=231))
        )
        AND [sys].[all_columns].[is_nullable]=0
        THEN 1
        ELSE 0
        END) OVER (PARTITION BY [sys].[objects].[name]) AS [IsNonNullableVariableLength]
        ,SUM (
        CASE WHEN 
        -- varchar
        (([system_type_id]=167) OR ([user_type_id]=167))
        OR
        -- nvarchar 
        (([system_type_id]=231) OR ([user_type_id]=231))
        OR
        -- IMAGE
        (([system_type_id]=34) OR ([user_type_id]=34))
        OR
        -- TEXT
        (([system_type_id]=35) OR ([user_type_id]=35))
        OR 
        --  NTEXT
        (([system_type_id]=99) OR ([user_type_id]=99))
        --  VARBINARY
        OR
        (([system_type_id]=165) OR ([user_type_id]=165))
        OR 
        --  SQLVARIANT
        (([system_type_id]=98) OR ([user_type_id]=98))
        OR
        -- hierarchyid geometry geography
        (([system_type_id]=240))        
        OR
        -- xml
        (([system_type_id]=241))    
        THEN 1
        ELSE 0
        END) OVER (PARTITION BY [sys].[objects].[name]) 
        AS [IsVariableLength]
        ,SUM (
        CASE WHEN 
        -- varchar
        (([system_type_id]=167) OR ([user_type_id]=167))
        OR
        -- nvarchar 
        (([system_type_id]=231) OR ([user_type_id]=231))
        OR
        -- IMAGE
        (([system_type_id]=34) OR ([user_type_id]=34))
        OR
        -- TEXT
        (([system_type_id]=35) OR ([user_type_id]=35))
        OR 
        --  NTEXT
        (([system_type_id]=99) OR ([user_type_id]=99))
        --  VARBINARY
        OR
        (([system_type_id]=165) OR ([user_type_id]=165))
        OR 
        --  SQLVARIANT
        (([system_type_id]=98) OR ([user_type_id]=98))
        OR
        -- hierarchyid geometry geography
        (([system_type_id]=240))    
        OR
        -- xml
        (([system_type_id]=241))    
        THEN 0
        ELSE 1
        END) OVER (PARTITION BY [sys].[objects].[name]) 
        AS [AnyFixedColumn]
    FROM [sys].[objects]
    INNER JOIN sys.all_columns
    ON [sys].[objects].[object_id]=[sys].[all_columns].[object_id]
    WHERE type_desc='USER_TABLE'
    ) a1
    ) a2

Đẹp. Tôi nghĩ bạn nên thực hiện CEILING()xung quanh cả hai SUM(...) AS [Max Size]SUM(...) AS [Min Size]để tính các giá trị BIT phân đoạn (khi số trường BIT không chia hết cho 8) vì một trường BIT duy nhất vẫn chiếm 1 byte. Ngoài ra, bất kỳ suy nghĩ về kế toán cho: SPARSE, vardecimal và nén? Tôi nhận ra rằng những thứ đó sẽ khá phức tạp để làm việc, nhưng tôi tò mò liệu các phép tính xấp xỉ có thể được sử dụng ít nhất trong trường hợp SPARSE, cũng có thể là vardecimal (bị phản đối nhưng cũng là văn bản, IMAGE, v.v. :)
Solomon Rutzky

@srutzky Điểm tốt, tôi sẽ sửa phần BIT và làm mới tập lệnh. Tập lệnh này được sử dụng như một phần của tập lệnh lớn hơn (thủ tục được lưu trữ) ước tính kích thước của các bảng trong cơ sở dữ liệu. vardecimal không phải là một loại như tôi nhớ. Nhưng tôi đang làm việc trên các cải tiến khác.
Pavel Nefyodov

Tôi đã không nói rằng đó VARDECIMALlà một kiểu dữ liệu. Tôi đã nói rằng nó, cùng với tùy chọn SPARSE và COMPRESSION, ảnh hưởng đến kích thước lưu trữ vật lý của nhiều kiểu dữ liệu mà bạn đang tính toán chính xác. Có nghĩa là, một BIGINTtrường được đánh dấu là SPARSE NULL0 byte hoặc 12 byte, không phải "luôn luôn là 8 byte". Vì vậy, nó sẽ yêu cầu một số ước tính về số lượng hàng và số lượng hàng sẽ là NULL so với NULL. Có lẽ tiếp tục cho rằng "luôn luôn 8" là một ước tính đủ tốt.
Solomon Rutzky
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.