Einführung
Oft besteht die Notwendigkeit, das Wachstum aller Tabellen und Dateien aller Datenbanken zu kontrollieren.
In diesem Artikel werden wir anhand eines Beispiels untersuchen, wie die Datenerfassung zum Wachstum von SQL Server-Datenbanktabellen und -dateien automatisiert werden kann.
Lösung
- Erstellen Sie eine Ansicht über die Größe aller Tabellen für jede Datenbank
USE [DATABASE_NAME] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE view [inf].[vTableSize] as with pagesizeKB as ( SELECT low / 1024 as PageSizeKB FROM master.dbo.spt_values WHERE number = 1 AND type = 'E' ) ,f_size as ( select p.[object_id], sum([total_pages]) as TotalPageSize, sum([used_pages]) as UsedPageSize, sum([data_pages]) as DataPageSize from sys.partitions p join sys.allocation_units a on p.partition_id = a.container_id left join sys.internal_tables it on p.object_id = it.object_id WHERE OBJECTPROPERTY(p.[object_id], N'IsUserTable') = 1 group by p.[object_id] ) ,tbl as ( SELECT t.[schema_id], t.[object_id], i1.rowcnt as CountRows, (COALESCE(SUM(i1.reserved), 0) + COALESCE(SUM(i2.reserved), 0)) * (select top(1) PageSizeKB from pagesizeKB) as ReservedKB, (COALESCE(SUM(i1.dpages), 0) + COALESCE(SUM(i2.used), 0)) * (select top(1) PageSizeKB from pagesizeKB) as DataKB, ((COALESCE(SUM(i1.used), 0) + COALESCE(SUM(i2.used), 0)) - (COALESCE(SUM(i1.dpages), 0) + COALESCE(SUM(i2.used), 0))) * (select top(1) PageSizeKB from pagesizeKB) as IndexSizeKB, ((COALESCE(SUM(i1.reserved), 0) + COALESCE(SUM(i2.reserved), 0)) - (COALESCE(SUM(i1.used), 0) + COALESCE(SUM(i2.used), 0))) * (select top(1) PageSizeKB from pagesizeKB) as UnusedKB FROM sys.tables as t LEFT OUTER JOIN sysindexes as i1 ON i1.id = t.[object_id] AND i1.indid < 2 LEFT OUTER JOIN sysindexes as i2 ON i2.id = t.[object_id] AND i2.indid = 255 WHERE OBJECTPROPERTY(t.[object_id], N'IsUserTable') = 1 OR (OBJECTPROPERTY(t.[object_id], N'IsView') = 1 AND OBJECTPROPERTY(t.[object_id], N'IsIndexed') = 1) GROUP BY t.[schema_id], t.[object_id], i1.rowcnt ) SELECT @@Servername AS Server, DB_NAME() AS DBName, SCHEMA_NAME(t.[schema_id]) as SchemaName, OBJECT_NAME(t.[object_id]) as TableName, t.CountRows, t.ReservedKB, t.DataKB, t.IndexSizeKB, t.UnusedKB, f.TotalPageSize*(select top(1) PageSizeKB from pagesizeKB) as TotalPageSizeKB, f.UsedPageSize*(select top(1) PageSizeKB from pagesizeKB) as UsedPageSizeKB, f.DataPageSize*(select top(1) PageSizeKB from pagesizeKB) as DataPageSizeKB FROM f_size as f inner join tbl as t on t.[object_id]=f.[object_id] GO
- Erstellen Sie eine spezifische Datenbank und bestimmen Sie eine Tabelle zum Speichern von Informationen über das Wachstum aller Datenbanktabellen:
USE [DATABASE_NAME] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO SET ANSI_PADDING ON GO CREATE TABLE [srv].[TableStatistics]( [Row_GUID] [uniqueidentifier] NOT NULL CONSTRAINT [DF_TableStatistics_Row_GUID] DEFAULT (newid()), [ServerName] [nvarchar](255) NOT NULL, [DBName] [nvarchar](255) NOT NULL, [SchemaName] [nvarchar](255) NOT NULL, [TableName] [nvarchar](255) NOT NULL, [CountRows] [bigint] NOT NULL, [DataKB] [int] NOT NULL, [IndexSizeKB] [int] NOT NULL, [UnusedKB] [int] NOT NULL, [ReservedKB] [int] NOT NULL, [InsertUTCDate] [datetime] NOT NULL CONSTRAINT [DF_TableStatistics_InsertUTCDate] DEFAULT (getutcdate()), [Date] AS (CONVERT([date],[InsertUTCDate])) PERSISTED, [CountRowsBack] [bigint] NULL, [CountRowsNext] [bigint] NULL, [DataKBBack] [int] NULL, [DataKBNext] [int] NULL, [IndexSizeKBBack] [int] NULL, [IndexSizeKBNext] [int] NULL, [UnusedKBBack] [int] NULL, [UnusedKBNext] [int] NULL, [ReservedKBBack] [int] NULL, [ReservedKBNext] [int] NULL, [AvgCountRows] AS ((([CountRowsBack]+[CountRows])+[CountRowsNext])/(3)) PERSISTED, [AvgDataKB] AS ((([DataKBBack]+[DataKB])+[DataKBNext])/(3)) PERSISTED, [AvgIndexSizeKB] AS ((([IndexSizeKBBack]+[IndexSizeKB])+[IndexSizeKBNext])/(3)) PERSISTED, [AvgUnusedKB] AS ((([UnusedKBBack]+[UnusedKB])+[UnusedKBNext])/(3)) PERSISTED, [AvgReservedKB] AS ((([ReservedKBBack]+[ReservedKB])+[ReservedKBNext])/(3)) PERSISTED, [DiffCountRows] AS (([CountRowsNext]+[CountRowsBack])-(2)*[CountRows]) PERSISTED, [DiffDataKB] AS (([DataKBNext]+[DataKBBack])-(2)*[DataKB]) PERSISTED, [DiffIndexSizeKB] AS (([IndexSizeKBNext]+[IndexSizeKBBack])-(2)*[IndexSizeKB]) PERSISTED, [DiffUnusedKB] AS (([UnusedKBNext]+[UnusedKBBack])-(2)*[UnusedKB]) PERSISTED, [DiffReservedKB] AS (([ReservedKBNext]+[ReservedKBBack])-(2)*[ReservedKB]) PERSISTED, [TotalPageSizeKB] [int] NULL, [TotalPageSizeKBBack] [int] NULL, [TotalPageSizeKBNext] [int] NULL, [UsedPageSizeKB] [int] NULL, [UsedPageSizeKBBack] [int] NULL, [UsedPageSizeKBNext] [int] NULL, [DataPageSizeKB] [int] NULL, [DataPageSizeKBBack] [int] NULL, [DataPageSizeKBNext] [int] NULL, [AvgDataPageSizeKB] AS ((([DataPageSizeKBBack]+[DataPageSizeKB])+[DataPageSizeKBNext])/(3)) PERSISTED, [AvgUsedPageSizeKB] AS ((([UsedPageSizeKBBack]+[UsedPageSizeKB])+[UsedPageSizeKBNext])/(3)) PERSISTED, [AvgTotalPageSizeKB] AS ((([TotalPageSizeKBBack]+[TotalPageSizeKB])+[TotalPageSizeKBNext])/(3)) PERSISTED, [DiffDataPageSizeKB] AS (([DataPageSizeKBNext]+[DataPageSizeKBBack])-(2)*[DataPageSizeKB]) PERSISTED,--shows as the casting is changed [DiffUsedPageSizeKB] AS (([UsedPageSizeKBNext]+[UsedPageSizeKBBack])-(2)*[UsedPageSizeKB]) PERSISTED,--shows as the casting is changed [DiffTotalPageSizeKB] AS (([TotalPageSizeKBNext]+[TotalPageSizeKBBack])-(2)*[TotalPageSizeKB]) PERSISTED,--shows as the casting is changed CONSTRAINT [PK_TableStatistics] PRIMARY KEY CLUSTERED ( [Row_GUID] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] GO SET ANSI_PADDING ON GO
TotalPageSizeKB gibt die Tabellengröße an.
Die Summe von TotalPageSizeKB aller Datenbanktabellen + die Größe der Systemtabellen =die Größe der Datenbankdaten.
- Bestimmen Sie das Verfahren zum Sammeln der Informationen:
USE [DATABASE_NAME] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE PROCEDURE [srv].[InsertTableStatistics] AS BEGIN SET NOCOUNT ON; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; declare @dt date=CAST(GetUTCDate() as date); declare @dbs nvarchar(255); declare @sql nvarchar(max); select [name] into #dbs from sys.databases; while(exists(select top(1) 1 from #dbs)) begin select top(1) @dbs=[name] from #dbs; set @sql= N'INSERT INTO [srv].[TableStatistics] ([ServerName] ,[DBName] ,[SchemaName] ,[TableName] ,[CountRows] ,[DataKB] ,[IndexSizeKB] ,[UnusedKB] ,[ReservedKB] ,[TotalPageSizeKB] ,[UsedPageSizeKB] ,[DataPageSizeKB]) SELECT [Server] ,[DBName] ,[SchemaName] ,[TableName] ,[CountRows] ,[DataKB] ,[IndexSizeKB] ,[UnusedKB] ,[ReservedKB] ,[TotalPageSizeKB] ,[UsedPageSizeKB] ,[DataPageSizeKB] FROM ['[email protected]+'].[inf].[vTableSize];'; exec sp_executesql @sql; delete from #dbs where [name][email protected]; end drop table #dbs; declare @dt_back date=CAST(DateAdd(day,-1,@dt) as date); ;with tbl1 as ( select [Date], [CountRows], [DataKB], [IndexSizeKB], [UnusedKB], [ReservedKB], [ServerName], [DBName], [SchemaName], [TableName], [TotalPageSizeKB], [UsedPageSizeKB], [DataPageSizeKB] from [srv].[TableStatistics] where [Date][email protected]_back ) , tbl2 as ( select [Date], [CountRows], [CountRowsBack], [DataKBBack], [IndexSizeKBBack], [UnusedKBBack], [ReservedKBBack], [ServerName], [DBName], [SchemaName], [TableName], [TotalPageSizeKBBack], [UsedPageSizeKBBack], [DataPageSizeKBBack] from [srv].[TableStatistics] where [Date][email protected] ) update t2 set t2.[CountRowsBack] =t1.[CountRows], t2.[DataKBBack] =t1.[DataKB], t2.[IndexSizeKBBack] =t1.[IndexSizeKB], t2.[UnusedKBBack] =t1.[UnusedKB], t2.[ReservedKBBack] =t1.[ReservedKB], t2.[TotalPageSizeKBBack]=t1.[TotalPageSizeKB], t2.[UsedPageSizeKBBack] =t1.[UsedPageSizeKB], t2.[DataPageSizeKBBack] =t1.[DataPageSizeKB] from tbl1 as t1 inner join tbl2 as t2 on t1.[Date]=DateAdd(day,-1,t2.[Date]) and t1.[ServerName]=t2.[ServerName] and t1.[DBName]=t2.[DBName] and t1.[SchemaName]=t2.[SchemaName] and t1.[TableName]=t2.[TableName]; ;with tbl1 as ( select [Date], [CountRows], [CountRowsNext], [DataKBNext], [IndexSizeKBNext], [UnusedKBNext], [ReservedKBNext], [ServerName], [DBName], [SchemaName], [TableName], [TotalPageSizeKBNext], [UsedPageSizeKBNext], [DataPageSizeKBNext] from [srv].[TableStatistics] where [Date][email protected]_back ) , tbl2 as ( select [Date], [CountRows], [DataKB], [IndexSizeKB], [UnusedKB], [ReservedKB], [ServerName], [DBName], [SchemaName], [TableName], [TotalPageSizeKB], [UsedPageSizeKB], [DataPageSizeKB] from [srv].[TableStatistics] where [Date][email protected] ) update t1 set t1.[CountRowsNext] =t2.[CountRows], t1.[DataKBNext] =t2.[DataKB], t1.[IndexSizeKBNext] =t2.[IndexSizeKB], t1.[UnusedKBNext] =t2.[UnusedKB], t1.[ReservedKBNext] =t2.[ReservedKB], t1.[TotalPageSizeKBNext]=t2.[TotalPageSizeKB], t1.[UsedPageSizeKBNext] =t2.[UsedPageSizeKB], t1.[DataPageSizeKBNext] =t2.[DataPageSizeKB] from tbl1 as t1 inner join tbl2 as t2 on t1.[Date]=DateAdd(day,-1,t2.[Date]) and t1.[ServerName]=t2.[ServerName] and t1.[DBName]=t2.[DBName] and t1.[SchemaName]=t2.[SchemaName] and t1.[TableName]=t2.[TableName]; END GO
Diese Lösung kann modifiziert werden, um Daten über die Tabellengrößen aller Datenbanken von allen erforderlichen Instanzen von MS SQL Server zu sammeln.
- Definieren Sie die Ansicht anhand der gesammelten Informationen:
USE [DATABASE_NAME] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO create view [srv].[vTableStatisticsShort] as with d as (select DateAdd(day,-1,max([Date])) as [Date] from [srv].[TableStatistics]) SELECT t.[ServerName] ,t.[DBName] ,t.[SchemaName] ,t.[TableName] ,t.[CountRows] ,t.[DataKB] ,t.[IndexSizeKB] ,t.[UnusedKB] ,t.[ReservedKB] ,t.[InsertUTCDate] ,t.[Date] ,t.[CountRowsBack] ,t.[CountRowsNext] ,t.[DataKBBack] ,t.[DataKBNext] ,t.[IndexSizeKBBack] ,t.[IndexSizeKBNext] ,t.[UnusedKBBack] ,t.[UnusedKBNext] ,t.[ReservedKBBack] ,t.[ReservedKBNext] ,t.[AvgCountRows] ,t.[AvgDataKB] ,t.[AvgIndexSizeKB] ,t.[AvgUnusedKB] ,t.[AvgReservedKB] ,t.[DiffCountRows] ,t.[DiffDataKB] ,t.[DiffIndexSizeKB] ,t.[DiffUnusedKB] ,t.[DiffReservedKB] ,t.[TotalPageSizeKB] ,t.[TotalPageSizeKBBack] ,t.[TotalPageSizeKBNext] ,t.[UsedPageSizeKB] ,t.[UsedPageSizeKBBack] ,t.[UsedPageSizeKBNext] ,t.[DataPageSizeKB] ,t.[DataPageSizeKBBack] ,t.[DataPageSizeKBNext] ,t.[AvgDataPageSizeKB] ,t.[AvgUsedPageSizeKB] ,t.[AvgTotalPageSizeKB] ,t.[DiffDataPageSizeKB] ,t.[DiffUsedPageSizeKB] ,t.[DiffTotalPageSizeKB] FROM d inner join [SRV].[srv].[TableStatistics] as t on d.[Date]=t.[Date] where t.[CountRowsBack] is not null and t.[CountRowsNext] is not null GO
An dieser Stelle möchte ich Ihre Aufmerksamkeit auf Diff lenken. Wenn es höher als 0 ist, bedeutet dies, dass die Tabelle jeden Tag schneller wächst.
Die Sammlung soll einmal alle 24 Stunden erfolgen.
Auf die gleiche Weise können wir die Erfassung des Dateiwachstums aller Datenbanken automatisieren, indem wir die folgende Ansicht verwenden:
USE [DATABASE_NAME] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO select t2.[DB_Name] as [DBName] ,t1.FileId ,t1.NumberReads ,t1.BytesRead ,t1.IoStallReadMS ,t1.NumberWrites ,t1.BytesWritten ,t1.IoStallWriteMS ,t1.IoStallMS ,t1.BytesOnDisk ,t1.[TimeStamp] ,t1.FileHandle ,t2.[Type_desc] ,t2.[FileName] ,t2.[Drive] ,t2.[Physical_Name] ,t2.[Ext] ,t2.[CountPage] ,t2.[SizeMb] ,t2.[SizeGb] ,t2.[Growth] ,t2.[GrowthMb] ,t2.[GrowthGb] ,t2.[GrowthPercent] ,t2.[is_percent_growth] ,t2.[database_id] ,t2.[State] ,t2.[StateDesc] ,t2.[IsMediaReadOnly] ,t2.[IsReadOnly] ,t2.[IsSpace] ,t2.[IsNameReserved] ,t2.[CreateLsn] ,t2.[DropLsn] ,t2.[ReadOnlyLsn] ,t2.[ReadWriteLsn] ,t2.[DifferentialBaseLsn] ,t2.[DifferentialBaseGuid] ,t2.[DifferentialBaseTime] ,t2.[RedoStartLsn] ,t2.[RedoStartForkGuid] ,t2.[RedoTargetLsn] ,t2.[RedoTargetForkGuid] ,t2.[BackupLsn] from fn_virtualfilestats(NULL, NULL) as t1 inner join [inf].[ServerDBFileInfo] as t2 on t1.[DbId]=t2.[database_id] and t1.[FileId]=t2.[File_Id] GO
Ergebnis
In diesem Artikel haben wir das Beispiel der Automatisierung der Datenerfassung über die Größe und das Wachstum aller SQL Server-Tabellen und -Dateien aller Datenbanken untersucht. Es bietet uns die vollständige Kontrolle über die Änderung der Größe sowohl der Datenbankdateien als auch ihrer Tabellen sowie das rechtzeitige Ergreifen von Maßnahmen zur Reduzierung der Tabelle oder Datei, zur Vergrößerung des Datenspeichergeräts oder zur Aufteilung von Informationen auf mehrere Datenspeichergeräte.