Database
 sql >> Baza danych >  >> RDS >> Database

Przechowywana procedura uzyskiwania informacji z tabel bazy danych

Jako administratorzy baz danych SQL Server zawsze dbamy o jedną z najważniejszych rzeczy dla biznesu, czyli o dane. W niektórych przypadkach aplikacje mogą stać się dość złożone i w rezultacie otrzymujesz mnóstwo tabel baz danych rozsianych po instancjach SQL Server. Może to prowadzić do kilku niedogodności, takich jak:

  • Wiedza, jak Twoje dane zachowują się każdego dnia, pod względem trendów wzrostu (przestrzeń i/lub liczba wierszy).
  • Wiedza, jakie tabele bazy danych wymagają (lub będą wymagać) określonej/innej strategii przechowywania danych, ponieważ rośnie ona zbyt szybko.
  • Wiedza, które z tabel bazy danych zajmują zbyt dużo miejsca, co może prowadzić do ograniczeń pamięci.

Ze względu na wagę tych szczegółów stworzyłem kilka procedur składowanych, które mogą być bardzo pomocne dla każdego administratora baz danych SQL Server, który chciałby śledzić informacje dotyczące tabel bazy danych w swoim środowisku. Zaufaj mi, jeden z nich jest bardzo fajny.

Rozważania wstępne

  • Upewnij się, że konto wykonujące tę procedurę składowaną ma wystarczające uprawnienia. Prawdopodobnie możesz zacząć od sysadmin, a następnie przejść tak szczegółowo, jak to możliwe, aby upewnić się, że użytkownik ma minimalne uprawnienia wymagane do prawidłowego działania SP.
  • Obiekty bazy danych (tabela bazy danych i procedura składowana) zostaną utworzone wewnątrz bazy danych wybranej w czasie wykonywania skryptu, więc wybieraj ostrożnie.
  • Skrypt jest tak skonstruowany, że można go wykonać kilka razy bez wyrzucenia błędu. W przypadku procedury składowanej użyłem instrukcji „CREATE OR ALTER PROCEDURE”, dostępnej od SQL Server 2016 SP1. Dlatego nie zdziw się, jeśli nie działa płynnie we wcześniejszej wersji.
  • Możesz zmienić nazwy utworzonych obiektów bazy danych.
  • Zwróć uwagę na parametry procedury składowanej, która gromadzi nieprzetworzone dane. Mogą mieć kluczowe znaczenie w potężnej strategii gromadzenia danych do wizualizacji trendów.

Jak korzystać z zapisanych procedur?

  1. Skopiuj i wklej kod T-SQL (dostępny w tym artykule).
  2. Pierwszy SP oczekuje 2 parametrów:
    1. @persistData:„Y”, jeśli administrator danych chce zapisać dane wyjściowe w tabeli docelowej, i „N”, jeśli administrator danych chce bezpośrednio wyświetlić dane wyjściowe.
    2. @truncateTable:„Y”, aby najpierw obciąć tabelę przed zapisaniem przechwyconych danych, i „N”, jeśli bieżące dane są przechowywane w tabeli. Pamiętaj, że wartość tego parametru nie ma znaczenia, jeśli wartość parametru @persistData to „N”.
  3. Drugi SP oczekuje 1 parametru:
    1. @targetParameter:nazwa kolumny, która ma być użyta do transpozycji zebranych informacji.

Prezentowane pola i ich znaczenie

  • nazwa_bazy danych: nazwa bazy danych, w której znajduje się tabela.
  • schemat: nazwa schematu, w którym znajduje się tabela.
  • nazwa_tabeli: symbol zastępczy nazwy tabeli.
  • liczba wierszy: liczba wierszy, które aktualnie ma tabela.
  • całkowita_przestrzeń_mb: liczba megabajtów przydzielonych dla tabeli.
  • used_space_mb: liczba megabajtów faktycznie używanych przez tabelę.
  • unused_space_mb: liczba megabajtów, których tabela nie używa.
  • data_utworzenia: data/godzina utworzenia tabeli.
  • data_collection_timestamp: widoczne tylko po przekazaniu „Y” do parametru @persistData. Jest używany, aby wiedzieć, kiedy SP został wykonany i informacje zostały pomyślnie zapisane w tabeli DBA_Tables.

Testy wykonania

Pokażę kilka wykonań procedur składowanych:

/* Wyświetl informacje o tabelach dla wszystkich baz danych użytkowników */

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

/* Zachowaj informacje z tabel bazy danych i wykonaj zapytanie do tabeli docelowej, najpierw obcinając tabelę docelową */

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

Zapytania poboczne

*Zapytanie, aby wyświetlić tabele bazy danych posortowane od największej liczby wierszy do najmniejszej.

SELECT * FROM DBA_Tables ORDER BY row_count DESC;

*Zapytanie, aby wyświetlić tabele bazy danych posortowane od największej całkowitej przestrzeni do najmniejszej.

SELECT * FROM DBA_Tables ORDER BY total_space_mb DESC;

*Zapytanie, aby wyświetlić tabele bazy danych posortowane od największego do najmniejszego miejsca.

SELECT * FROM DBA_Tables ORDER BY used_space_mb DESC;

*Zapytanie, aby wyświetlić tabele bazy danych posortowane od największego niewykorzystanego miejsca do najmniejszego.

SELECT * FROM DBA_Tables ORDER BY unused_space_mb DESC;

*Zapytanie, aby wyświetlić tabele bazy danych posortowane według daty utworzenia, od najnowszych do najstarszych.

SELECT * FROM DBA_Tables ORDER BY created_date DESC;

Oto pełny kod procedury składowanej, który przechwytuje informacje z tabel bazy danych:

*Na samym początku skryptu zobaczysz domyślną wartość, którą przyjmuje procedura składowana, jeśli nie przekazano żadnej wartości dla każdego parametru.

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

Do tego momentu informacje wydają się nieco suche, ale pozwólcie, że zmienię to postrzeganie, prezentując uzupełniającą procedurę przechowywaną. Jego głównym celem jest transpozycja informacji zebranych w tabeli docelowej, która służy jako źródło raportów trendów.

Oto jak możesz wykonać procedurę składowaną:

*W celach demonstracyjnych wstawiłem ręcznie rekordy do tabeli docelowej o nazwie t1, aby zasymulować moje zwykłe wykonanie procedury zapisanej.

*Zestaw wyników jest nieco szeroki, więc zrobię kilka zrzutów ekranu, aby pokazać pełny wynik.

EXEC TransposeTablesInformation @targetParmeter = 'row_count' 

Kluczowe dania na wynos

  • Jeśli zautomatyzujesz wykonanie skryptu, który zapełnia tabelę docelową, możesz natychmiast zauważyć, czy coś poszło nie tak z nim lub z danymi. Spójrz na dane dla tabeli „t1” i kolumny „15”. Możesz tam zobaczyć NULL, który został zrobiony celowo, aby pokazać ci coś, co może się wydarzyć.
  • Dzięki temu widokowi możesz zobaczyć szczególne zachowanie najważniejszych/krytycznych tabel bazy danych.
  • W podanym przykładzie wybrałem pole „row_count” tabeli docelowej, ale możesz wybrać dowolne inne pole numeryczne jako parametr i uzyskać ten sam format tabeli, ale z innymi danymi.
  • Nie martw się, jeśli określisz nieprawidłowy parametr, procedura składowana ostrzeże Cię i zatrzyma jej wykonywanie.

Oto kompletny kod procedury składowanej, która transponuje informacje z tabeli docelowej:

*Na samym początku skryptu zobaczysz domyślną wartość, którą przyjmuje procedura składowana, jeśli nie przekazano żadnej wartości dla każdego parametru.

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

Wniosek

  • Możesz wdrożyć SP do zbierania danych w każdej instancji SQL Server pod twoim wsparciem i zaimplementować mechanizm ostrzegania w całym stosie obsługiwanych instancji.
  • Jeśli zaimplementujesz zadanie agenta, które zadaje te informacje stosunkowo często, możesz być na bieżąco z tym, jak zachowują się Twoje dane w ciągu miesiąca. Oczywiście możesz pójść jeszcze dalej i przechowywać gromadzone co miesiąc dane, aby mieć jeszcze większy obraz; musiałbyś wprowadzić kilka poprawek w kodzie, ale byłoby to całkowicie tego warte.
  • Upewnij się, że prawidłowo przetestowałeś ten mechanizm w środowisku piaskownicy, a planując wdrożenie produkcyjne, wybierz okresy niskiej aktywności.
  • Zbieranie informacji tego typu może pomóc w odróżnieniu DBA od siebie. Prawdopodobnie istnieją narzędzia innych firm, które mogą zrobić to samo, a nawet więcej, ale nie każdy ma na to budżet. Mam nadzieję, że pomoże to każdemu, kto zdecyduje się go używać w swoim środowisku.

  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Eliminowanie powielania wyrażeń Where w aplikacji

  2. Wprowadzenie do SQL

  3. Wskazówki dotyczące wydajności XML

  4. Typowe błędy w diagramie ER

  5. Praca z danymi JDBC w Domo