Пожалуйста, попробуйте следующее решение.
Оно будет работать, начиная с SQL Server 2017 и более поздних версий.
Дополнительные пояснения
- SQL Server размещает таблицы на основе 8-килобайтных страниц. не
на фактических размерах записей (rows).
- UPDATE/DELETE не работает in-place, они создают дополнительные
фрагментации.
SQL
-- DDL и образец вставки данных, начало
USE tempdb;
GO
DROP TABLE IF EXISTS dbo.tbl;
CREATE TABLE tbl (ID INT IDENTITY PRIMARY KEY, city VARCHAR(20), State CHAR(2), Population INT, InsertedOn DATETIMEOFFSET(3) DEFAULT SYSDATETIMEOFFSET());
INSERT tbl (city, State, Population, InsertedOn) VALUES
('Miami', 'FL', 350000, Default),
('Orlando', 'FL', 300000, Default),
('Dallas', 'TX', 5000000, Default);
-- DDL и образец вставки данных, конец
SELECT * FROM tbl;
DECLARE @tbl_catalog sysname = 'tempdb'
, @tbl_name sysname = 'tbl'
, @schema_name sysname = 'dbo'
, @columnList VARCHAR(MAX)
, @CrLf NCHAR(2) = NCHAR(13) + NCHAR(10)
, @Tab NCHAR(1) = NCHAR(9)
, @SQL NVARCHAR(MAX);
-- SQL Server 2017 onwards
SET @columnList = (SELECT STRING_AGG(CONCAT(QUOTENAME(COLUMN_NAME),'='
,'SUM(DATALENGTH(',QUOTENAME(COLUMN_NAME),'))',@CrLf,@Tab), ',')
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_CATALOG = @tbl_catalog
AND TABLE_SCHEMA = @schema_name
AND TABLE_NAME = @tbl_name
);
PRINT @columnList;
SET @SQL =
N';WITH rs(xmldata) AS
(
SELECT ' + @columnList +
N'FROM tbl
FOR XML PATH(''''), TYPE, ROOT(''root'')
)
SELECT column_name = c.value(''local-name(.)'', ''SYSNAME'')
, column_value_bytes = c.value(''text()[1]'', ''INT'')
FROM rs
CROSS APPLY xmldata.nodes(''/root/*'') AS t(c)
ORDER BY column_value_bytes DESC;';
PRINT @SQL;
EXEC sp_executesql @SQL;
Результат
column_name |
column_value_bytes |
InsertedOn |
27 |
city |
18 |
ID |
12 |
Population |
12 |
State |
6 |