如何检查 SQL 服务器中的实际列数据类型

How can I check actual column datatype in SQL Server

我想检查数据库中所有列的实际数据类型,并将结果与​​ table information_schema.columns 进行比较。目的是检测超大列数据类型以减少它。

例如,如果列定义为 varchar(255) 但所有值都只有 10 个字符或更少,我希望在结果中看到它。

我知道这个查询是为了获取每一列的信息:

SELECT *
FROM information_schema.columns
WHERE table_schema = 'dbo'
ORDER BY TABLE_NAME, ORDINAL_POSITION

有人知道如何计算任何数据类型的最大值并将其与设置进行比较吗?

示例示例:

| ColA (varchar255)| ColB (nvarchar255) |
| -------- | -------------- |
| First    | first row            |
| Second   | row 2            |
| Third    | a row            |

预期结果:

| Col | type len | actual max len |
| -------- | -------------- | -------------- |
| ColA    | 255            | 6 |
| ColB   | 255            | 9 |

下面的脚本对每个 variable-length 列执行 MAX DATALENGTH 查询以确定实际的最大大小(以字节为单位)并列出结果以及定义的最大大小。此版本使用 SQL 服务器系统目录视图而不是 INFORMATION_SCHEMA

请注意,如果您的数据库很大并且会影响性​​能,这可能需要一些时间。如果您 运行 针对没有 RCSI 的活动数据库,考虑 READ_UNCOMMITTED 并理解结果可能不那么准确。

SET NOCOUNT ON;
DECLARE @results TABLE(
     SchemaName sysname NOT NULL
    ,TableName sysname NOT NULL
    ,ColumnName sysname NOT NULL
    ,DefinedMaxLength int NOT NULL
    ,ActualMaxLength int NULL
);

DECLARE
     @SchemaName sysname
    ,@TableName sysname
    ,@ColumnName sysname
    ,@DefinedMaxLength int
    ,@ActualMaxLength int
    ,@MaxLengthQuery nvarchar(MAX);

DECLARE MaxColumnSizes CURSOR LOCAL FAST_FORWARD FOR
    SELECT 
          OBJECT_SCHEMA_NAME(t.object_id) AS SchemaName
         ,OBJECT_NAME(t.object_id) AS TableName
         ,c.name AS ColumnName
         ,CASE WHEN c.max_length = -1 THEN 2147483647 ELSE c.max_length END AS DefinedMaxMength
         ,N'SELECT @ActualMaxLength = MAX(DATALENGTH(' + c.name + N'))'
         + N' FROM ' + QUOTENAME(OBJECT_SCHEMA_NAME(t.object_id)) + N'.' + QUOTENAME(OBJECT_NAME(t.object_id)) AS MaxLengthQuery
    FROM sys.tables AS t
    JOIN sys.columns AS c ON c.object_id = t.object_id
    JOIN sys.types AS ty ON ty.system_type_id = c.system_type_id AND ty.system_type_id = c.user_type_id
    WHERE 
        ty.name IN(N'varchar', 'nvarchar', N'varbinary')
        AND OBJECTPROPERTY(t.object_id, 'IsMSShipped') = 0;

OPEN MaxColumnSizes;
WHILE 1 = 1
BEGIN
    FETCH NEXT FROM MaxColumnSizes INTO
         @SchemaName
        ,@TableName
        ,@ColumnName
        ,@DefinedMaxLength
        ,@MaxLengthQuery;
    IF @@FETCH_STATUS = -1 BREAK;
    --PRINT @MaxLengthQuery; --for debugging

    SET @ActualMaxLength = NULL;
    EXEC sp_executesql @MaxLengthQuery, N'@ActualMaxLength int OUTPUT', @ActualMaxLength = @ActualMaxLength OUTPUT;
    INSERT INTO @results (SchemaName, TableName, ColumnName, DefinedMaxLength, ActualMaxLength) 
        VALUES(@SchemaName, @TableName, @ColumnName, @DefinedMaxLength, @ActualMaxLength);
    
END;
CLOSE MaxColumnSizes;
DEALLOCATE MaxColumnSizes;

SELECT 
     SchemaName
    ,TableName
    ,ColumnName
    ,DefinedMaxLength
    ,ActualMaxLength
FROM @results
ORDER BY
     SchemaName
    ,TableName
    ,ColumnName;
GO