sql >> Databáze >  >> RDS >> Database

Uložená procedura pro získání informací o tabulkách databáze

Jako SQL Server DBA se vždy staráme o jednu z nejdůležitějších věcí pro podnikání, o data. V některých případech mohou být aplikace poměrně složité a vy skončíte s tunou databázových tabulek roztroušených po instancích SQL Serveru. To může vést k několika nepříjemnostem, jako například:

  • Vědět, jak se vaše data chovají každý den, pokud jde o trendy růstu (prostor a/nebo počet řádků).
  • Vědět, jaké databázové tabulky vyžadují (nebo budou vyžadovat) konkrétní/odlišnou strategii pro ukládání dat, protože se příliš rychle rozrůstají.
  • Vědět, které z vašich databázových tabulek zabírají příliš mnoho místa, což může vést k omezením úložiště.

Vzhledem k důležitosti těchto podrobností jsem vytvořil několik uložených procedur, které mohou být velkou pomocí pro každého SQL Server DBA, který by chtěl sledovat informace týkající se databázových tabulek ve svém prostředí. Věřte mi, jeden z nich je velmi cool.

Počáteční úvahy

  • Ujistěte se, že účet spouštějící tuto uloženou proceduru má dostatečná oprávnění. Pravděpodobně byste mohli začít se sysadminem a pak postupovat co nejpodrobněji, abyste se ujistili, že uživatel má minimální oprávnění potřebná pro správné fungování SP.
  • Databázové objekty (databázová tabulka a uložená procedura) budou vytvořeny uvnitř databáze vybrané v době spuštění skriptu, takže vybírejte pečlivě.
  • Skript je vytvořen tak, aby jej bylo možné provést několikrát, aniž by se vám zobrazila chyba. Pro uloženou proceduru jsem použil příkaz „CREATE OR ALTER PROCEDURE“, dostupný od SQL Server 2016 SP1. Proto se nedivte, že to v dřívější verzi nebude fungovat hladce.
  • Neváhejte změnit názvy vytvořených databázových objektů.
  • Věnujte pozornost parametrům uložené procedury, která shromažďuje nezpracovaná data. Mohou být zásadní ve výkonné strategii sběru dat pro vizualizaci trendů.

Jak používat uložené procedury?

  1. Zkopírujte a vložte kód T-SQL (k dispozici v tomto článku).
  2. První SP očekává 2 parametry:
    1. @persistData:„Y“, pokud chce správce databází uložit výstup do cílové tabulky, a ‚N‘, pokud chce správce vidět výstup přímo.
    2. @truncateTable:„Y“ pro zkrácení tabulky před uložením zachycených dat a „N“, pokud jsou v tabulce zachována aktuální data. Mějte na paměti, že hodnota tohoto parametru je irelevantní, pokud je hodnota parametru @persistData ‚N‘.
  3. Druhý SP očekává 1 parametr:
    1. @targetParameter:Název sloupce, který má být použit k transpozici shromážděných informací.

Prezentovaná pole a jejich význam

  • název_databáze: název databáze, kde se tabulka nachází.
  • schéma: název schématu, kde se tabulka nachází.
  • název_tabulky: zástupný symbol pro název tabulky.
  • row_count: počet řádků, které tabulka aktuálně obsahuje.
  • total_space_mb: počet megabajtů přidělených pro tabulku.
  • used_space_mb: počet megabajtů skutečně používaných tabulkou.
  • unused_space_mb: počet megabajtů, které tabulka nepoužívá.
  • created_date: datum/čas vytvoření tabulky.
  • data_collection_timestamp: viditelné pouze v případě, že je parametru @persistData předáno „Y“. Používá se ke zjištění, kdy byl SP proveden a informace byly úspěšně uloženy do tabulky DBA_Tables.

Testy provedení

Předvedu několik provedení uložených procedur:

/* Zobrazí informace o tabulkách pro všechny uživatelské databáze */

EXEC GetTablesData @persistData = 'N',@truncateTable = 'N'

/* Zachovat informace databázových tabulek a dotazovat se na cílovou tabulku, přičemž nejprve zkrátíte cílovou tabulku */

EXEC GetTablesData @persistData = 'Y',@truncateTable = 'Y'
SELECT * FROM DBA_Tables

Postranní dotazy

*Dotaz pro zobrazení databázových tabulek seřazených od největšího počtu řádků po nejnižší.

SELECT * FROM DBA_Tables ORDER BY row_count DESC;

*Dotaz pro zobrazení databázových tabulek seřazených od největšího celkového prostoru po nejnižší.

SELECT * FROM DBA_Tables ORDER BY total_space_mb DESC;

*Dotaz pro zobrazení databázových tabulek seřazených od největšího využitého prostoru po nejnižší.

SELECT * FROM DBA_Tables ORDER BY used_space_mb DESC;

*Dotaz pro zobrazení databázových tabulek seřazených od největšího nevyužitého prostoru po nejnižší.

SELECT * FROM DBA_Tables ORDER BY unused_space_mb DESC;

*Dotaz pro zobrazení databázových tabulek seřazených podle data vytvoření, od nejnovější po nejstarší.

SELECT * FROM DBA_Tables ORDER BY created_date DESC;

Zde je úplný kód uložené procedury, který zachycuje informace databázových tabulek:

*Na úplném začátku skriptu uvidíte výchozí hodnotu, kterou uložená procedura předpokládá, pokud není pro každý parametr předána žádná hodnota.

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE OR ALTER PROCEDURE [dbo].[GetTablesData] 
	@persistData   CHAR(1) = 'Y',
	@truncateTable CHAR(1) = 'Y'
AS
BEGIN
	SET NOCOUNT ON

	DECLARE @command NVARCHAR(MAX)    
	
	DECLARE @Tmp_TablesInformation TABLE(       
	[database]        [VARCHAR](255) NOT NULL,
	[schema]          [VARCHAR](64) NOT NULL,
	[table]           [VARCHAR](255) NOT NULL,
	[row_count]       [BIGINT]NOT NULL,
	[total_space_mb]  [DECIMAL](15,2) NOT NULL,
	[used_space_mb]   [DECIMAL](15,2) NOT NULL,
	[unused_space_mb] [DECIMAL](15,2) NOT NULL,
	[created_date]    [DATETIME] NOT NULL
	)      
	
	SELECT @command = '
	USE [?]
	
	IF DB_ID(''?'') > 4
	BEGIN
		SELECT 
			''?'',
			s.Name AS [schema],
			t.NAME AS [table],
			p.rows AS row_count,
			CAST(ROUND(((SUM(a.total_pages) * 8) / 1024.00), 2) AS DECIMAL(15, 2)) AS total_space_mb,
			CAST(ROUND(((SUM(a.used_pages) * 8) / 1024.00), 2) AS DECIMAL(15, 2)) AS used_space_mb, 
			CAST(ROUND(((SUM(a.total_pages) - SUM(a.used_pages)) * 8) / 1024.00, 2) AS DECIMAL(15, 2)) AS unused_space_mb,
			t.create_date as created_date
		FROM sys.tables t
		INNER JOIN sys.indexes i ON t.OBJECT_ID = i.object_id
		INNER JOIN sys.partitions p ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id
		INNER JOIN sys.allocation_units a ON p.partition_id = a.container_id
		LEFT OUTER JOIN sys.schemas s ON t.schema_id = s.schema_id
		WHERE t.NAME NOT LIKE ''dt%'' 
		  AND t.is_ms_shipped = 0
		  AND i.OBJECT_ID > 255
		GROUP BY t.Name, s.Name, p.Rows,t.create_date
		ORDER BY total_space_mb DESC, t.Name
	END'       
	
	INSERT INTO @Tmp_TablesInformation    
	EXEC sp_MSForEachDB @command      
	   
	IF @persistData = 'N'
		SELECT * FROM @Tmp_TablesInformation 
	ELSE 
	BEGIN
		IF(@truncateTable = 'Y')
		TRUNCATE TABLE DBA_Tables

		INSERT INTO DBA_Tables
		SELECT *,GETDATE() FROM @Tmp_TablesInformation ORDER BY [database],[schema],[table] 
	END
END
GO

Až do tohoto bodu se informace zdají trochu suché, ale dovolte mi změnit toto vnímání prezentací doplňkové uložené procedury. Jeho hlavním účelem je transponovat informace shromážděné v cílové tabulce, která slouží jako zdroj pro zprávy trendů.

Takto můžete spustit uloženou proceduru:

*Pro demonstrační účely jsem do cílové tabulky s názvem t1 vložil manuální záznamy, abych simuloval mé obvyklé provádění uložené procedury.

*Výsledková sada je trochu široká, takže pořídím několik snímků obrazovky, abych ukázal celý výstup.

EXEC TransposeTablesInformation @targetParmeter = 'row_count' 

Klíčové poznatky

  • Pokud zautomatizujete provádění skriptu, který vyplňuje cílovou tabulku, můžete si okamžitě všimnout, že se s ním nebo s vašimi daty něco pokazilo. Podívejte se na údaje pro tabulku ‚t1‘ a sloupec ‚15‘. Můžete tam vidět NULL, což bylo provedeno záměrně, aby vám ukázalo něco, co se může stát.
  • V tomto druhu zobrazení můžete vidět zvláštní chování pro nejdůležitější/kritické databázové tabulky.
  • V uvedeném příkladu jsem zvolil pole „row_count“ cílové tabulky, ale jako parametr můžete zvolit jakékoli jiné číselné pole a získat stejný formát tabulky, ale s jinými údaji.
  • Nemějte obavy, pokud zadáte neplatný parametr, uložená procedura vás upozorní a zastaví její provádění.

Zde je úplný kód uložené procedury, který transponuje informace cílové tabulky:

*Na úplném začátku skriptu uvidíte výchozí hodnotu, kterou uložená procedura předpokládá, pokud není pro každý parametr předána žádná hodnota.

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE OR ALTER PROCEDURE [dbo].[TransposeTablesInformation] 
	@targetParameter NVARCHAR(15) = 'row_count' 
AS
BEGIN
	SET NOCOUNT ON;

    IF (@targetParameter <> 'row_count' AND @targetParameter <> 'total_space_mb' AND @targetParameter <> 'used_space_mb' AND @targetParameter <> 'unused_space_mb')
	BEGIN
		PRINT 'Please specify a valid parameter!'
		PRINT 'i.e. row_count | total_space_mb | used_space_mb | unused_space_mb'
		RETURN
	END
	ELSE
	BEGIN
		CREATE TABLE #TablesInformation(
			[database] [VARCHAR](255) NOT NULL,
			[schema]   [VARCHAR](64) NOT NULL,
			[table]    [VARCHAR](255) NOT NULL,
			[1]		   [DECIMAL](10,2) NULL,
			[2]		   [DECIMAL](10,2) NULL,
			[3]		   [DECIMAL](10,2) NULL,
			[4]		   [DECIMAL](10,2) NULL,
			[5]		   [DECIMAL](10,2) NULL,
			[6]		   [DECIMAL](10,2) NULL,
			[7]		   [DECIMAL](10,2) NULL,
			[8]		   [DECIMAL](10,2) NULL,
			[9]		   [DECIMAL](10,2) NULL,
			[10]	   [DECIMAL](10,2) NULL,
			[11]	   [DECIMAL](10,2) NULL,
			[12]	   [DECIMAL](10,2) NULL,
			[13]	   [DECIMAL](10,2) NULL,
			[14]	   [DECIMAL](10,2) NULL,
			[15]	   [DECIMAL](10,2) NULL,
			[16]	   [DECIMAL](10,2) NULL,
			[17]	   [DECIMAL](10,2) NULL,
			[18]	   [DECIMAL](10,2) NULL,
			[19]	   [DECIMAL](10,2) NULL,
			[20]	   [DECIMAL](10,2) NULL,
			[21]	   [DECIMAL](10,2) NULL,
			[22]	   [DECIMAL](10,2) NULL,
			[23]	   [DECIMAL](10,2) NULL,
			[24]	   [DECIMAL](10,2) NULL,
			[25]	   [DECIMAL](10,2) NULL,
			[26]	   [DECIMAL](10,2) NULL,
			[27]	   [DECIMAL](10,2) NULL,
			[28]	   [DECIMAL](10,2) NULL,
			[29]	   [DECIMAL](10,2) NULL,
			[30]	   [DECIMAL](10,2) NULL,
			[31]	   [DECIMAL](10,2) NULL
		)

		INSERT INTO #TablesInformation([database],[schema],[table])
		SELECT DISTINCT [database_name],[schema],[table_name]
		FROM DBA_Tables
		ORDER BY [database_name],[schema],table_name

		DECLARE @databaseName  NVARCHAR(255)
		DECLARE @schemaName    NVARCHAR(64)
		DECLARE @tableName     NVARCHAR(255)
		DECLARE @value	       DECIMAL(10,2)
		DECLARE @dataTimestamp DATETIME
		DECLARE @sqlCommand    NVARCHAR(MAX)

		IF(@targetParameter = 'row_count')
		BEGIN
			DECLARE TablesCursor CURSOR FOR
			SELECT 
					[database_name],
					[schema],
					[table_name],
					[row_count],
					[data_collection_timestamp]
			FROM DBA_Tables
			ORDER BY [database_name],[schema],table_name
		END

		IF(@targetParameter = 'total_space_mb')
		BEGIN
			DECLARE TablesCursor CURSOR FOR
			SELECT 
					[database_name],
					[schema],
					[table_name],
					[total_space_mb],
					[data_collection_timestamp]
			FROM DBA_Tables
			ORDER BY [database_name],[schema],table_name
		END

		IF(@targetParameter = 'used_space_mb')
		BEGIN
			DECLARE TablesCursor CURSOR FOR
			SELECT 
					[database_name],
					[schema],
					[table_name],
					[used_space_mb],
					[data_collection_timestamp]
			FROM DBA_Tables
			ORDER BY [database_name],[schema],table_name
		END

		IF(@targetParameter = 'unused_space_mb')
		BEGIN
			DECLARE TablesCursor CURSOR FOR
			SELECT 
					[database_name],
					[schema],
					[table_name],
					[unused_space_mb],
					[data_collection_timestamp]
			FROM DBA_Tables
			ORDER BY [database_name],[schema],table_name
		END

		OPEN TablesCursor

		FETCH NEXT FROM TablesCursor INTO @databaseName,@schemaName,@tableName,@value,@dataTimestamp

		WHILE(@@FETCH_STATUS = 0)
		BEGIN
			SET @sqlCommand = CONCAT('
			UPDATE #TablesInformation
			SET [',DAY(@dataTimestamp),'] = ',@value,'
			WHERE [database] = ',CHAR(39),@databaseName,CHAR(39),'
			  AND [schema] = ',CHAR(39),@schemaName+CHAR(39),'
			  AND [table] = ',CHAR(39),@tableName+CHAR(39),'
			')
			EXEC(@sqlCommand)

			FETCH NEXT FROM TablesCursor INTO @databaseName,@schemaName,@tableName,@value,@dataTimestamp
		END

		CLOSE TablesCursor

		DEALLOCATE TablesCursor

		IF(@targetParameter = 'row_count')
		SELECT [database],
			   [schema],
			   [table],
			   CONVERT(INT,[1])  AS [1],
			   CONVERT(INT,[2])  AS [2],
			   CONVERT(INT,[3])  AS [3],
			   CONVERT(INT,[4])  AS [4],
			   CONVERT(INT,[5])  AS [5],
			   CONVERT(INT,[6])  AS [6],
			   CONVERT(INT,[7])  AS [7],
			   CONVERT(INT,[8])  AS [8],
			   CONVERT(INT,[9])  AS [9],
			   CONVERT(INT,[10]) AS [10],
			   CONVERT(INT,[11]) AS [11],
			   CONVERT(INT,[12]) AS [12],
			   CONVERT(INT,[13]) AS [13],
			   CONVERT(INT,[14]) AS [14],
			   CONVERT(INT,[15]) AS [15],
			   CONVERT(INT,[16]) AS [16],
			   CONVERT(INT,[17]) AS [17],
			   CONVERT(INT,[18]) AS [18],
			   CONVERT(INT,[19]) AS [19],
			   CONVERT(INT,[20]) AS [20],
			   CONVERT(INT,[21]) AS [21],
			   CONVERT(INT,[22]) AS [22],
			   CONVERT(INT,[23]) AS [23],
			   CONVERT(INT,[24]) AS [24],
			   CONVERT(INT,[25]) AS [25],
			   CONVERT(INT,[26]) AS [26],
			   CONVERT(INT,[27]) AS [27],
			   CONVERT(INT,[28]) AS [28],
			   CONVERT(INT,[29]) AS [29],
			   CONVERT(INT,[30]) AS [30],
			   CONVERT(INT,[31]) AS [31]
		FROM #TablesInformation
		ELSE
		SELECT * FROM #TablesInformation
	END
END
GO

Závěr

  • Sběr dat SP můžete nasadit v každé instanci serveru SQL Server pod vaší podporou a implementovat mechanismus upozornění v rámci celého zásobníku podporovaných instancí.
  • Pokud implementujete úlohu agenta, která se dotazuje na tyto informace relativně často, můžete zůstat na vrcholu hry, pokud jde o to, jak se vaše data během měsíce chovají. Samozřejmě můžete jít ještě dále a ukládat měsíční shromážděná data, abyste měli ještě větší obrázek; museli byste v kódu provést nějaké úpravy, ale rozhodně by to stálo za to.
  • Ujistěte se, že jste tento mechanismus řádně otestovali v prostředí izolovaného prostoru, a když plánujete produkční nasazení, vyberte období s nízkou aktivitou.
  • Shromažďování informací tohoto typu může pomoci odlišit DBA od sebe navzájem. Pravděpodobně existují nástroje 3 stran, které dokážou totéž, a dokonce i více, ale ne každý má rozpočet, aby si to mohl dovolit. Doufám, že to může pomoci každému, kdo se rozhodne jej použít ve svém prostředí.

  1. Jak zjistím, jaká znaková sada je databáze / tabulka / sloupec MySQL?

  2. Typy kurzoru SQL Server - Jaký je rozdíl mezi LOKÁLNÍM A GLOBÁLNÍM kurzorem | Kurz SQL Server / Kurz TSQL

  3. Cloud Vendor Deep-Dive:PostgreSQL na DigitalOcean

  4. Před číslo v PostgreSQL přidejte znaménko plus/mínus