我正在使用SQL Server 2012,并编写了一个存储过程,该存储过程使用sys
表计算表统计信息。我知道SSMS中有报告可以为您完成此操作,但是,我需要其他信息。似乎我不得不使用动态SQL来实现这一目标,但它似乎又慢又笨拙。我的存储过程可以工作,但是我很好奇,甚至在没有动态SQL的情况下,还有一种更有效的查询写方法?
DECLARE @my_cursor CURSOR,
@sql nvarchar(250), @table_name nvarchar(100),
@days_loaded int, @row_count int, @row_count_per_day int,
@used_mb numeric(36,2), @used_mb_per_day numeric(36,2),
@first_date_loaded date, @last_date_loaded date,
@expected_first_date date, @gaps_exist nvarchar(1)
-- Delete temp table #tables in case the stored procedure is ran twice in the same session
IF OBJECT_ID('tempdb.dbo.#tables', 'U') IS NOT NULL
DROP TABLE #tables
-- Select all the tables and stats from the dallas schema into a temp table
SELECT
s.name + '.' + t.name AS table_name,
p.rows AS row_count,
CAST(ROUND(SUM(a.used_pages) / 128.00, 2) AS NUMERIC(36, 2)) AS used_mb
INTO
#tables
FROM
sys.tables AS t
INNER JOIN
sys.indexes AS i ON t.object_id = i.object_id
INNER JOIN
sys.partitions AS p ON i.object_id = p.object_id AND i.index_id = p.index_id
INNER JOIN
sys.allocation_units AS a ON p.partition_id = a.container_id
INNER JOIN
sys.schemas AS s ON t.schema_id = s.schema_id
WHERE
s.name = 'dallas'
GROUP BY
t.name, s.name, p.rows
-- Add some additional fields in the temp table to be used for population in loop below
ALTER TABLE #tables ADD days_loaded INT NULL
ALTER TABLE #tables ADD used_mb_per_day numeric(36,2) NULL
ALTER TABLE #tables ADD row_count_per_day INT NULL
ALTER TABLE #tables ADD first_date_loaded DATE NULL
ALTER TABLE #tables ADD expected_first_date DATE NULL
ALTER TABLE #tables ADD gaps_exist nvarchar(1) NULL
-- Loop through each table in dallas schema
BEGIN
SET @my_cursor = CURSOR FOR SELECT table_name, row_count, used_mb FROM #tables
OPEN @my_cursor
FETCH NEXT FROM @my_cursor INTO @table_name, @row_count, @used_mb
WHILE @@FETCH_STATUS = 0
BEGIN
-- Calculate first date that was loaded to see history of how far back table goes
SET @sql = N'SELECT TOP 1 @first_date_loaded = CONVERT(date,Min(data_load_timestamp)) FROM ' + @table_name
EXECUTE sp_executesql @sql, N'@first_date_loaded date OUTPUT', @first_date_loaded=@first_date_loaded OUTPUT
-- Calculate last date that was loaded to offset expected first date if needed (data that is loaded day of instead of day before)
SET @sql = N'SELECT TOP 1 @last_date_loaded = CONVERT(date,Max(data_load_timestamp)) FROM ' + @table_name
EXECUTE sp_executesql @sql, N'@last_date_loaded date OUTPUT', @last_date_loaded=@last_date_loaded OUTPUT
-- Calculate days loaded by retrieving count of distinct dates in table
SET @sql = N'SELECT @days_loaded=COUNT(*) FROM (SELECT DISTINCT CONVERT(date, data_load_timestamp) AS data_load_date FROM ' + @table_name + ') tt'
EXECUTE sp_executesql @sql, N'@days_loaded int OUTPUT', @days_loaded=@days_loaded OUTPUT
IF @days_loaded <> 0
BEGIN
SET @row_count_per_day = @row_count / @days_loaded
SET @used_mb_per_day = @used_mb / @days_loaded
SET @expected_first_date = DATEADD(d,@days_loaded * -1,GETDATE())
IF @last_date_loaded = CONVERT(date,GETDATE()) SET @expected_first_date = DATEADD(d,1,@expected_first_date)
IF @first_date_loaded = @expected_first_date
SET @gaps_exist = 'N'
ELSE
SET @gaps_exist = 'Y'
END
-- Update temp table with additional fields that were calculated
SET @sql = N'UPDATE #tables SET days_loaded=' + CONVERT(nvarchar,@days_loaded) +
', row_count_per_day=' + CONVERT(nvarchar, @row_count_per_day) +
', used_mb_per_day=' + CONVERT(nvarchar,@used_mb_per_day) + ', first_date_loaded=''' +
CONVERT(nvarchar,@first_date_loaded) + ''', expected_first_date=''' +
CONVERT(nvarchar,@expected_first_date) + ''', gaps_exist=''' + @gaps_exist + ''' WHERE table_name=''' + @table_name + ''''
EXECUTE sp_executesql @sql
FETCH NEXT FROM @my_cursor INTO @table_name, @row_count, @used_mb
END
CLOSE @my_cursor
DEALLOCATE @my_cursor
END
-- Final return showing results from temp table sorted by largest utilization first
SELECT * FROM #tables ORDER BY used_mb DESC