Database
 sql >> база данни >  >> RDS >> Database

Съхранена процедура за получаване на информация за таблици на базата данни

Като администратори на база данни на SQL Server, ние винаги се грижим за едно от най-важните неща за бизнеса, данните. В някои случаи приложенията могат да станат доста сложни и в крайна сметка ще получите много таблици на база данни, разпръснати около вашия SQL Server екземпляр(и). Това може да доведе до някои неудобства, като например:

  • Да знаете как се държат данните ви всеки ден по отношение на тенденциите на растеж (пространство и/или количество редове).
  • Да знаете какви таблици на базата данни изискват (или ще изискват) конкретна/различна стратегия за съхраняване на данните, защото расте твърде бързо.
  • Да знаете кои от вашите таблици на база данни заемат твърде много място, което вероятно води до ограничения за съхранение.

Поради важността на тези подробности създадох няколко съхранени процедури, които могат да бъдат от голяма помощ на всеки SQL Server DBA, който би искал да следи информация относно таблиците на базата данни в неговата/нейната среда. Повярвайте ми, един от тях е много готин.

Първоначални съображения

  • Уверете се, че акаунтът, изпълняващ тази съхранена процедура, има достатъчно привилегии. Вероятно бихте могли да започнете със sysadmin и след това да преминете възможно най-подробно, за да сте сигурни, че потребителят има минималните привилегии, необходими за правилното функциониране на SP.
  • Обектите на базата данни (таблица на базата данни и съхранена процедура) ще бъдат създадени в базата данни, избрана в момента на изпълнение на скрипта, така че избирайте внимателно.
  • Скриптът е изработен по начин, по който може да бъде изпълнен няколко пъти, без да ви бъде изведена грешка. За съхранената процедура използвах израз „CREATE OR ALTER PROCEDURE“, наличен от SQL Server 2016 SP1. Ето защо не се учудвайте, ако не работи гладко в по-ранна версия.
  • Чувствайте се свободни да промените имената на създадените обекти на базата данни.
  • Обърнете внимание на параметрите на съхранената процедура, която събира необработените данни. Те могат да бъдат от решаващо значение в мощна стратегия за събиране на данни за визуализиране на тенденциите.

Как да използвам съхранените процедури?

  1. Копирайте и поставете T-SQL кода (наличен в тази статия).
  2. Първият SP очаква 2 параметъра:
    1. @persistData:„Y“, ако DBA иска да запише изхода в целева таблица, и „N“, ако DBA иска да види изхода директно.
    2. @truncateTable:„Y“, за да се съкрати първо таблицата, преди да се съхранят заснетите данни, и „N“, ако текущите данни се съхраняват в таблицата. Имайте предвид, че стойността на този параметър е без значение, ако стойността на параметъра @persistData е „N“.
  3. Вторият SP очаква 1 параметър:
    1. @targetParameter:Името на колоната, която ще се използва за транспониране на събраната информация.

Представени полета и тяхното значение

  • име на база_данни: името на базата данни, където се намира таблицата.
  • схема: името на схемата, където се намира таблицата.
  • име_на таблица: заместителя за името на таблицата.
  • брой_редове: броя на редовете, които таблицата има в момента.
  • total_space_mb: броят мегабайтове, разпределени за таблицата.
  • used_space_mb: броят мегабайтове, които действително се използват от таблицата.
  • unused_space_mb: броят мегабайтове, които таблицата не използва.
  • created_date: датата/часа, когато е създадена таблицата.
  • data_collection_timestamp: видимо само ако „Y“ се предава на параметъра @persistData. Използва се, за да се знае кога SP е бил изпълнен и информацията е била успешно запазена в таблицата DBA_Tables.

Тестове за изпълнение

Ще демонстрирам няколко изпълнения на съхранените процедури:

/* Показва информацията за таблиците за всички потребителски бази данни */

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

/* Запазете информацията от таблиците на базата данни и поискайте целевата таблица, като първо съкратите целевата таблица */

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

Странични заявки

*Запитване за преглед на таблиците на базата данни, сортирани от най-големия брой редове до най-ниския.

SELECT * FROM DBA_Tables ORDER BY row_count DESC;

*Запитване за преглед на таблиците на базата данни, сортирани от най-голямото общо пространство до най-ниското.

SELECT * FROM DBA_Tables ORDER BY total_space_mb DESC;

*Запитване за преглед на таблиците на базата данни, сортирани от най-голямото използвано пространство до най-ниското.

SELECT * FROM DBA_Tables ORDER BY used_space_mb DESC;

*Запитване за преглед на таблиците на базата данни, сортирани от най-голямото неизползвано пространство до най-ниското.

SELECT * FROM DBA_Tables ORDER BY unused_space_mb DESC;

*Запитване за преглед на таблиците на базата данни, сортирани по дата на създаване, от най-новите до най-старите.

SELECT * FROM DBA_Tables ORDER BY created_date DESC;

Ето пълен код на Съхранената процедура, която улавя информацията от таблиците на базата данни:

*В самото начало на скрипта ще видите стойността по подразбиране, която запаметената процедура приема, ако не се подаде стойност за всеки параметър.

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

До този момент информацията изглежда малко суха, но нека променя това възприятие с представянето на допълнителна Съхранена процедура. Основната му цел е да транспонира информацията, събрана в целевата таблица, която служи като източник за отчети за тенденциите.

Ето как можете да изпълните съхранената процедура:

*За демонстрационни цели вмъкнах ръчни записи в целевата таблица с име t1, за да симулирам обичайното ми изпълнение на Съхранена процедура.

*Наборът от резултати е малко широк, така че ще направя няколко екранни снимки, за да покажа пълния резултат.

EXEC TransposeTablesInformation @targetParmeter = 'row_count' 

Основни изводи

  • Ако автоматизирате изпълнението на скрипта, който попълва целевата таблица, можете веднага да забележите дали нещо се обърка с него или с вашите данни. Разгледайте данните за таблицата „t1“ и колоната „15“. Можете да видите NULL там, което е направено нарочно, за да ви покаже нещо, което може да се случи.
  • С този вид изглед можете да видите особено поведение за най-важните/критични таблици на база данни.
  • В дадения пример избрах полето „row_count“ на целевата таблица, но можете да изберете всяко друго числово поле като параметър и да получите същия формат на таблицата, но с различни данни.
  • Не се притеснявайте, ако посочите невалиден параметър, съхранената процедура ще ви предупреди и ще спре изпълнението й.

Ето пълен код на Съхранената процедура, който транспонира информацията от целевата таблица:

*В самото начало на скрипта ще видите стойността по подразбиране, която запаметената процедура приема, ако не се подаде стойност за всеки параметър.

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

Заключение

  • Можете да разгърнете SP за събиране на данни във всеки екземпляр на SQL Server под вашата поддръжка и да внедрите механизъм за предупреждение в целия си пакет от поддържани екземпляри.
  • Ако внедрите задача на агент, която прави заявки за тази информация относително често, можете да останете на върха на играта по отношение на това как да знаете как се държат данните ви през месеца. Разбира се, можете да отидете още по-далеч и да съхранявате месечните събирани данни, за да имате още по-голяма картина; ще трябва да направите някои промени в кода, но би си струвало напълно.
  • Уверете се, че сте тествали правилно този механизъм в среда на пясъчна среда и когато планирате внедряване в производство, не забравяйте да изберете периоди с ниска активност.
  • Събирането на информация от този тип може да помогне за разграничаването на DBA един от друг. Вероятно има 3 партии инструмента, които могат да направят едно и също нещо, и дори повече, но не всеки има бюджет да си го позволи. Надявам се, че това може да помогне на всеки, който реши да го използва в своята среда.

  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Как да добавя дни към дата в T-SQL

  2. Проблемна група 2 – Идентифициране на обекти и атрибути

  3. Топ 10 причини защо трябва да научите SQL

  4. Изявление на SQL DROP TABLE и различни случаи на употреба

  5. Преброяване на препратки към запис в таблица чрез външни ключове