sql >> データベース >  >> RDS >> Database

データベーステーブル情報を取得するためのストアドプロシージャ

    SQL Server DBAとして、私たちは常にビジネスにとって最も重要なことの1つであるデータを処理します。場合によっては、アプリケーションが非常に複雑になり、SQLServerインスタンスに大量のデータベーステーブルが散在することになります。これにより、次のようないくつかの不便が生じる可能性があります。

    • 成長傾向(行のスペースや量)の観点から、データが毎日どのように動作するかを知る。
    • データの増大が速すぎるため、データを格納するために特定の/異なる戦略が必要な(または必要になる)データベーステーブルを把握する。
    • どのデータベーステーブルがスペースを取りすぎているかを知ると、ストレージの制約につながる可能性があります。

    これらの詳細が重要であるため、環境内のデータベーステーブルに関する情報を追跡したいSQLServerDBAに非常に役立つストアドプロシージャをいくつか作成しました。私を信じてください、そのうちの1つはとてもクールです。

    最初の考慮事項

    • このストアドプロシージャを実行するアカウントに十分な権限があることを確認してください。おそらく、sysadminから始めて、SPが正しく機能するために必要な最小限の特権をユーザーが持っていることを確認するために、可能な限り細かく調整することができます。
    • データベースオブジェクト(データベーステーブルとストアドプロシージャ)は、スクリプトの実行時に選択されたデータベース内に作成されるため、慎重に選択してください。
    • スクリプトは、エラーが発生することなく数回実行できるように作成されています。ストアドプロシージャには、SQL Server2016SP1以降で使用可能な「CREATEORALTERPROCEDURE」ステートメントを使用しました。そのため、以前のバージョンでスムーズに機能しなくても驚かないでください。
    • 作成したデータベースオブジェクトの名前は自由に変更してください。
    • 生データを収集するストアドプロシージャのパラメータに注意してください。これらは、傾向を視覚化するための強力なデータ収集戦略において重要になる可能性があります。

    ストアドプロシージャの使用方法

    1. T-SQLコード(この記事内で利用可能)をコピーして貼り付けます。
    2. 最初のSPは2つのパラメーターを想定しています。
      1. @ persistData:DBAが出力をターゲットテーブルに保存する場合は「Y」、DBAが出力を直接表示する場合は「N」。
      2. @truncateTable:「Y」はキャプチャされたデータを保存する前に最初にテーブルを切り捨てます。「N」は現在のデータがテーブルに保持されている場合です。 @persistDataパラメータの値が「N」の場合、このパラメータの値は関係ないことに注意してください。
    3. 2番目のSPは1つのパラメーターを想定しています。
      1. @targetParameter:収集された情報を転置するために使用される列の名前。

    提示されたフィールドとその意味

    • database_name: テーブルが存在するデータベースの名前。
    • スキーマ: テーブルが存在するスキーマの名前。
    • table_name: テーブル名のプレースホルダー。
    • row_count: テーブルに現在ある行数。
    • 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 unused_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

    結論

    • サポート下のすべてのSQLServerインスタンスにデータ収集SPを展開し、サポートされているインスタンスのスタック全体にアラートメカニズムを実装できます。
    • この情報を比較的頻繁に照会するエージェントジョブを実装する場合、その月のデータの動作を把握するという点で、ゲームのトップを維持できます。もちろん、さらに進んで、毎月収集されたデータを保存して、さらに全体像を把握することもできます。コードを微調整する必要がありますが、それだけの価値はあります。
    • サンドボックス環境でこのメカニズムを適切にテストし、本番環境への展開を計画している場合は、アクティビティの少ない期間を選択してください。
    • このタイプの情報を収集すると、DBAを互いに区別するのに役立ちます。同じことを実行できるサードパーティのツールはおそらく3つあり、それ以上のツールがありますが、誰もがそれを購入できる予算があるわけではありません。これが、自分の環境で使用することを決定した人の助けになることを願っています。

    1. スクリプトが機能する場合、Postgres now()のタイムスタンプは変更されません

    2. SQL Server 2016:ビューを作成する

    3. AWSEC2からAWSRDSへのOracleデータベースの移行、パート3

    4. Oracleのミリ秒単位のタイムスタンプの違い