web-dev-qa-db-ja.com

DBCC SHRINKFILEの結果をテーブルに保存するにはどうすればよいですか?

次のスクリプトがあります。

-- available space in each of the database files

PRINT @@SERVERNAME
--SQLDWDEV01
USE [BodenStage]
GO
SELECT name 
,(CAST(ROUND((size/128.0 - CAST(FILEPROPERTY(name, 'SpaceUsed') AS int)/128.0),2) AS NUMERIC(18,2))) AS AvailableSpaceInMB  
,(CAST(ROUND((size/128.0 - FILEPROPERTY(name, 'SpaceUsed')/128.0)/1024.00,2) AS NUMERIC(18,2))) AS AvailableSpaceInGB 
FROM sys.database_files;  
GO

データやログファイルを縮小したくないので、必要な場合もあります。私のせいじゃない。

説明されているように、断片化を発生させずにデータファイルを圧縮する方法があります here

切り捨て

ファイルの末尾にあるすべての空き領域をオペレーティングシステムに解放しますが、ファイル内のページ移動は実行しません。データファイルは、最後に割り当てられたエクステントにのみ縮小されます。

DBCC SHRINKFILE の結果をテーブルに保存するにはどうすればよいですか?

以下を参照してください DBCC SQLPERF の結果をテーブルに保存する1つの方法です。

select @@servername as [Server]
       ,db_name() as [database]
go

SET NOCOUNT ON

begin try
  drop table #radhe
end try
begin catch
end catch


create table #radhe (
  DatabaseName varchar(100)
  , LOGSIZE_MB NUMERIC(18, 9)
  , LOGSPACE_USED NUMERIC(18, 9)
  , LOGSTATUS NUMERIC(18, 9)) 


INSERT #Radhe(DatabaseName, LOGSIZE_MB, LOGSPACE_USED, LOGSTATUS) 
EXEC('DBCC SQLPERF(LOGSPACE);')


select  DatabaseName, 
     LOGSIZE_GB=CONVERT(NUMERIC(18,2) ,ISNULL( ROUND(LOGSIZE_MB/1024.00,2),0)),
     PERC_USED =CONVERT(NUMERIC(4,2) ,ISNULL( ROUND(LOGSPACE_USED,2),0))
from #radhe
order by logsize_mb desc

これで、DBCC SHRINKFILEコマンドが生成されました。

DECLARE @db VARCHAR(108)
DECLARE @dbid INT
DECLARE @amount INT

SELECT @db = 'MY_DATABASSEStage'
SELECT @dbid = DB_ID(@DB) 
SELECT @amount = 0

SELECT SHRINKFILE_SCRIPT = 'USE ' + QUOTENAME( DB_NAME(smf.database_id)) + CHAR(10) 
                         + 'GO' + CHAR(10)  
                         + 'DBCC SHRINKFILE(''' + smf.name + '''' + ',' + CAST(@amount AS VARCHAR) + ', TRUNCATEONLY) WITH NO_INFOMSGS' + CHAR(10) 
                         + 'GO' + CHAR(10)  
, * 
FROM  sys.master_files smf
WHERE smf.database_id = @dbid

上記のスクリプトにより、次の結果が生成されました。

USE [MY_DATABASSEStage]
GO
DBCC SHRINKFILE('MY_DATABASSEStageStockLedger',0, TRUNCATEONLY) WITH NO_INFOMSGS
GO

USE [MY_DATABASSEStage]
GO
DBCC SHRINKFILE('MY_DATABASSEStageStockLedgerArchive',0, TRUNCATEONLY) WITH NO_INFOMSGS
GO


USE [MY_DATABASSEStage]
GO
DBCC SHRINKFILE('MY_DATABASSEStageProduct',0, TRUNCATEONLY) WITH NO_INFOMSGS
GO

これはスクリプトの1つの結果です-with no_infomsgsを削除した後 enter image description here

同様の質問がありますが、私のケースに当てはまる答えはありません:

SQL Serverのユーザートランザクション間でログを縮小

DBCC ShrinkFileの結果を保存

結論

私の答えは問題なく機能しますが、srutzkyによって使用される方法ははるかに単純であり、機能します。リンクサーバーが必要です。

テストサーバーでは、次のスクリプトを使用してリンクサーバーを作成しています。

USE [master]
GO

IF NOT EXISTS (SELECT srv.name FROM sys.servers srv WHERE srv.server_id != 0 AND srv.name = N'TESTDBCC')
BEGIN
        EXEC master.dbo.sp_addlinkedserver 
                                            @server = N'TESTDBCC', 
                                            @srvproduct=N'', 
                                            @provider=N'SQLNCLI11', 
                                            @datasrc=N'JPB01275\SQL2014', 
                                            @catalog=N'radhe'


        EXEC master.dbo.sp_addlinkedsrvlogin 
                                            @rmtsrvname=N'TESTDBCC',
                                            @useself=N'True',
                                            @locallogin=NULL,
                                            @rmtuser=NULL,
                                            @rmtpassword=NULL
END
GO

EXEC master.dbo.sp_serveroption 
                                @server=N'TESTDBCC', 
                                @optname=N'collation compatible', 
                                @optvalue=N'false'
GO

EXEC master.dbo.sp_serveroption @server=N'TESTDBCC', 
                                @optname=N'data access', 
                                @optvalue=N'true'
GO

EXEC master.dbo.sp_serveroption @server=N'TESTDBCC', 
                                @optname=N'dist', 
                                @optvalue=N'false'
GO

EXEC master.dbo.sp_serveroption @server=N'TESTDBCC', 
                                @optname=N'pub', 
                                @optvalue=N'false'
GO

EXEC master.dbo.sp_serveroption @server=N'TESTDBCC', 
                                @optname=N'rpc', 
                                @optvalue=N'true'
GO

EXEC master.dbo.sp_serveroption @server=N'TESTDBCC', 
                                @optname=N'rpc out', 
                                @optvalue=N'true'
GO

EXEC master.dbo.sp_serveroption @server=N'TESTDBCC', 
                                @optname=N'sub', 
                                @optvalue=N'false'
GO

EXEC master.dbo.sp_serveroption @server=N'TESTDBCC', 
                                @optname=N'connect timeout', 
                                @optvalue=N'0'
GO

EXEC master.dbo.sp_serveroption @server=N'TESTDBCC', 
                                @optname=N'collation name', 
                                @optvalue=null
GO

EXEC master.dbo.sp_serveroption @server=N'TESTDBCC', 
                                @optname=N'lazy schema validation', 
                                @optvalue=N'false'
GO

EXEC master.dbo.sp_serveroption @server=N'TESTDBCC', 
                                @optname=N'query timeout', 
                                @optvalue=N'0'
GO

EXEC master.dbo.sp_serveroption @server=N'TESTDBCC', 
                                @optname=N'use remote collation', 
                                @optvalue=N'true'
GO

EXEC master.dbo.sp_serveroption @server=N'TESTDBCC', 
                                @optname=N'remote proc transaction promotion', 
                                @optvalue=N'false'
GO

上記のリンクサーバーを使用すると、次のようにデータを収集できます。

--Use the Linked Server via EXEC() AT

CREATE TABLE #ShrinkFileResults
(
    [DBID] SMALLINT,
    [FileID] INT,
    [CurrentSize] INT,
    [MinimumSize] INT,
    [UsedPages] INT,
    [EstimatedPages] INT
);

INSERT INTO #ShrinkFileResults
  ([DBID], [FileID], [CurrentSize], [MinimumSize], [UsedPages], [EstimatedPages])
  EXEC(N'
     USE [tempdb];
     DBCC SHRINKFILE(N''tempdev'', 0, TRUNCATEONLY);
  ') AT [TestDBCC];


INSERT INTO #ShrinkFileResults
  ([DBID], [FileID], [CurrentSize], [MinimumSize], [UsedPages], [EstimatedPages])
  EXEC(N'
     USE [radhe];
     DBCC SHRINKFILE(N''radhe_log'', 0, TRUNCATEONLY);
  ') AT [TestDBCC];

INSERT INTO #ShrinkFileResults
  ([DBID], [FileID], [CurrentSize], [MinimumSize], [UsedPages], [EstimatedPages])
  EXEC(N'
     USE [US16HSMMProduct_AFTER_CHANGES];
     DBCC SHRINKFILE(N''US16HSMMProduct_AFTER_CHANGES_log'', 0, TRUNCATEONLY);
  ') AT [TestDBCC];

INSERT INTO #ShrinkFileResults
  ([DBID], [FileID], [CurrentSize], [MinimumSize], [UsedPages], [EstimatedPages])
  EXEC(N'
     USE [US16HSMMProduct_AFTER_CHANGES];
     DBCC SHRINKFILE(N''US16HSMMProduct_AFTER_CHANGES_log'', 0, TRUNCATEONLY);
  ') AT [TestDBCC];

SELECT * FROM #ShrinkFileResults;

enter image description here

5

これは、_'remote proc transaction promotion'_プロパティがfalseに設定された「ループバック」リンクサーバーを使用することにより、いくらか簡単に実現できます。これにより、圧縮ファイル操作を実行できません_INSERT...EXEC_オペレーションによって開始された暗黙のトランザクションをサイドステップすることによるユーザートランザクションエラーの内部。それ以外の場合、リンクサーバーでは、_'rpc out'_プロパティをtrueに設定するだけで済みます。 _'data access'_および_'rpc'_プロパティを有効にする必要はありません(少なくとも私にとっては)。

リンクサーバーを作成します

_USE [master];

DECLARE @LinkedServerName sysname;
SET @LinkedServerName = N'TestDBCC';

IF (NOT EXISTS (SELECT srv.name
                FROM   sys.servers srv
                WHERE  srv.server_id <> 0
                AND    srv.name = @LinkedServerName))
BEGIN
  EXEC [master].dbo.sp_addlinkedserver
    @server = @LinkedServerName, @srvproduct=N'', @provider=N'SQLNCLI11', @datasrc=N'DALI';
  EXEC [master].dbo.sp_addlinkedsrvlogin
    @rmtsrvname=@LinkedServerName,@useself=N'True',@locallogin=NULL,
    @rmtuser=NULL,@rmtpassword=NULL;
END;

--EXEC [master].dbo.sp_serveroption @server=@LinkedServerName,
--  @optname=N'data access', @optvalue=N'true';
--EXEC [master].dbo.sp_serveroption @server=@LinkedServerName,
--  @optname=N'rpc', @optvalue=N'true'; -- is_remote_login_enabled
EXEC [master].dbo.sp_serveroption @server=@LinkedServerName,
  @optname=N'rpc out', @optvalue=N'true';
EXEC [master].dbo.sp_serveroption @server=@LinkedServerName,
  @optname=N'remote proc transaction promotion', @optvalue=N'false';
GO
_

EXEC() ATを介してリンクサーバーを使用する

_CREATE TABLE #ShrinkFileResults
(
    [DBID] SMALLINT,
    [FileID] INT,
    [CurrentSize] INT,
    [MinimumSize] INT,
    [UsedPages] INT,
    [EstimatedPages] INT
);

INSERT INTO #ShrinkFileResults
  ([DBID], [FileID], [CurrentSize], [MinimumSize], [UsedPages], [EstimatedPages])
  EXEC(N'
     USE [tempdb];
     DBCC SHRINKFILE(N''tempdev'', 0, TRUNCATEONLY);
  ') AT [TestDBCC];

SELECT * FROM #ShrinkFileResults;
_

これは、SQL Server 2012 SP3とSQL Server 2016 RTMの両方で機能しました。

[〜#〜]メモ[〜#〜]

  • OPENQUERYを使用しても機能しません。最初に「メタデータ検出」エラーが発生します。これは、DBCC呼び出しを、_WITH RESULT SETS_オプションを使用する別のEXECでラップすることで解決できます。しかし、「OPENQUERYはオブジェクトが存在しないか、オブジェクトへのアクセス権がないため、オブジェクトを処理できません」というエラーを受け取ります。ただし、ファイルの論理名を圧縮に変更すると、DBCCからその名前のファイルが見つからないというエラーと、OPENQUERYからの2次エラーが発生します。呼び出しは結果セットを返しませんでした。これらはすべて、正しいファイル名でさらに遠くにあることを示しています。

  • この操作は、SQLCLRを介して簡単に実行することもできます。実際には、外部接続(コンテキスト接続ではない)を使用してUDF /スカラー関数を作成できます。これにより、SELECTリストのセットベースの操作で呼び出すことができます。また、数行のコードしか必要とせず、_xp_cmdshell_を有効にするか、リンクサーバーを作成する場合と比較して、セキュリティリスクを最小限に抑えることができます。

3
Solomon Rutzky

以下のプロセスは、dbcc shrinkfileの結果をテーブルに保存する方法です

  • xp_cmdshellの使用を有効にする
  • スクリプトを実行するためのログインまたはプロキシを取得する

したがって、次のスクリプトが必要です。

-- To allow advanced options to be changed.
EXEC sp_configure 'show advanced options', 1
GO

    -- To update the currently configured value for advanced options.
    RECONFIGURE
    GO

    -- To enable the feature.
    EXEC sp_configure 'xp_cmdshell', 1
    GO

    -- To update the currently configured value for this feature.
    RECONFIGURE
    GO

USE master
GO
-- Create the SQL login which will use xp_cmdshell.
CREATE LOGIN [SQL_User_Impresonated] WITH PASSWORD='Sql_P@ssword'
-- Create a proxy credential for xp_cmdshell assigned to a Domain/Windows account.

EXEC sp_xp_cmdshell_proxy_account 'DOMAIN\LOGINNAME', 'LOGINNAME_PASSWORD';
-- Grant database access to the SQL Server login account that you want to provide access.

EXEC sp_grantdbaccess 'SQL_User_Impresonated'
-- Grant execute permission on xp_cmdshell to the SQL Server login account.
GRANT exec ON sys.xp_cmdshell TO [SQL_User_Impresonated]
GO

--Configuration option 'show advanced options' changed from 1 to 1. Run the RECONFIGURE statement to install.
--Configuration option 'xp_cmdshell' changed from 0 to 1. Run the RECONFIGURE statement to install.

----------------------------------------------------------------
-- GRANT THE REQUIRED PERMISSIONS TO LOGIN SQL_User_Impresonated
----------------------------------------------------------------





--=======================================================================================================
-- before schrinking the log, lets see how much space we are currently using
--=======================================================================================================
declare @Radhe table(
  DatabaseName varchar(100)
  , LOGSIZE_MB decimal(18, 9)
  , LOGSPACE_USED decimal(18, 9)
  ,  LOGSTATUS decimal(18, 9)) 


insert @Radhe(DatabaseName, LOGSIZE_MB, LOGSPACE_USED, LOGSTATUS) 
EXEC('DBCC SQLPERF(LOGSPACE);')

select DatabaseName, 
     LOGSIZE_MB =CAST (ROUND(LOGSIZE_MB,2) AS NUMERIC(10,2)),
     LOGSIZE_GB =CAST (ROUND(LOGSIZE_MB/1024.00,2)AS NUMERIC(10,2)),
     LOGSPACE_USED =CAST(ROUND(LOGSPACE_USED,2)AS NUMERIC(10,2))
     FROM @Radhe
order by logsize_mb desc
--=======================================================================================================

enter image description here

--=======================================================================================================
-- process to shrink the log file and show the outcome
--=======================================================================================================
DECLARE       @sqlCommand   VARCHAR(1000)
DECLARE       @filePath     VARCHAR(100)
DECLARE       @fileName     VARCHAR(100)

SET    @filePath = 'C:\sqlBackup\'

SET    @fileName = 'Shrink_' +
       + CONVERT(VARCHAR, GETDATE(), 112) + '_' +
         RIGHT('00'+CAST(DATEPART(HOUR, GETDATE()) AS VARCHAR),2) + '_' +
         RIGHT('00'+CAST(DATEPART(MINUTE,GETDATE()) AS VARCHAR),2) + '.txt'

PRINT @filePath + @filename

       --SET    @sqlCommand = 'sqlcmd -S "JPB01275\SQL2014" -U SQL_User_Impresonated -P Sql_P@ssword -N -C -d "Radhe" -o "C:\sqlBackup\shrink.txt" -Q "DBCC SHRINKFILE(''Radhe_log'',0, TRUNCATEONLY)"'

       SET    @sqlCommand = 'sqlcmd -S "JPB01275\SQL2014" -U SQL_User_Impresonated -P Sql_P@ssword -N -C -d "Radhe" -o ' + '"' + @FILEPATH + @fileName + '"' + ' -Q "DBCC SHRINKFILE(''Radhe_log'',0, TRUNCATEONLY)"'


--PRINT       @sqlCommand

EXEC   master..xp_cmdshell @sqlCommand

--select QUOTENAME(@@servername)

BEGIN TRY
   DROP TABLE #RADHE
END TRY
BEGIN CATCH 
END CATCH


CREATE TABLE #RADHE
(THE_LINE VARCHAR(500) NULL)

select @sqlCommand=
'BULK INSERT #RADHE ' + CHAR(10) +
'FROM ' + '''' + @FILEPATH + @fileName + '''' + CHAR(10) +
   'WITH 
      (
         ROWTERMINATOR =''\n''
      )'

exec (@sqlCommand)


--querying an specific line of a heap
ALTER TABLE #RADHE
ADD ID INT NOT NULL IDENTITY(1,1) PRIMARY KEY CLUSTERED

BEGIN TRY
   DROP TABLE #X
END TRY
BEGIN CATCH 
END CATCH

BEGIN TRY
   DROP TABLE #Y
END TRY
BEGIN CATCH 
END CATCH
--=========================================================================================
-- CTE to extract all numbers from string: niikola
--=========================================================================================
Declare @txt varchar(4000) 
Declare @num varchar(10) = '%[0-9.,]%'
Declare @oth varchar(10) = '%[^0-9.,]%'


SELECT @txt =THE_LINE
FROM #RADHE
WHERE ID = 3

Set @txt+='X'

;With a as (
Select 1 as i,
Substring(@txt,Patindex(@num,@txt),patindex(@oth,Substring(@txt,Patindex(@num,@txt),4000))-1) as num, 
substring(@txt,Patindex(@num,@txt)+patindex(@oth,Substring(@txt,Patindex(@num,@txt),4000))-1,4000) as txt
Union All
Select i+1,
Substring(txt,Patindex(@num,txt),patindex(@oth,Substring(txt,Patindex(@num,txt),4000))-1), 
substring(txt,Patindex(@num,txt)+patindex(@oth,Substring(txt,Patindex(@num,txt),4000))-1,4000)
from a
Where txt like '%[0-9]%'
)
Select IND=i, NUM=CAST( num  AS INT)
INTO #Y
from a
Where num like '%[0-9]%'


CREATE TABLE #x
(
    [DBID] int,
    FileID int,
    CurrentSize int,
    MinimumSize int,
    UsedPages int,
    EstimatedPages int
)


-- Problems with the Insert
-- The select list for the INSERT statement contains fewer items than the insert list. The number of SELECT values must match the number of INSERT columns.
-- Column name or number of supplied values does not match table definition.


-- select * from #y

INSERT INTO #x 
(
    [DBID],
    FileID,
    CurrentSize,
    MinimumSize,
    UsedPages,
    EstimatedPages
)

SELECT *
FROM 
(
  SELECT IND,NUM
  FROM #Y
) RADHE
PIVOT
(
  SUM(NUM)
  FOR IND IN ([1], [2], [3],[4], [5], [6])
) PIV;


--==============================================================================
-- the outpout of DBCC Shrinkfile

-- https://msdn.Microsoft.com/en-GB/library/ms189493.aspx

--Column name   Description
--DbId  Database identification number of the file the Database Engine tried to shrink.
--FileId    The file identification number of the file the Database Engine tried to shrink.
--CurrentSize   Number of 8-KB pages the file currently occupies.
--MinimumSize   Number of 8-KB pages the file could occupy, at minimum. This corresponds to the minimum size or originally created size of a file.
--UsedPages Number of 8-KB pages currently used by the file.
--EstimatedPages    Number of 8-KB pages that the Database Engine estimates the file could be shrunk down to.
--==============================================================================

use radhe

SELECT name ,size/128.0 - CAST(FILEPROPERTY(name, 'SpaceUsed') AS int)/128.0 AS AvailableSpaceInMB  
FROM sys.database_files;  

--SELECT SUM(user_object_reserved_page_count) AS [user object pages used],  
--(SUM(user_object_reserved_page_count)*1.0/128) AS [user object space in MB]  
--FROM sys.dm_db_file_space_usage;  


select *
FROM sys.dm_db_log_space_usage;  


SELECT 
the_database_name=db_name(dbid),
FileID,
CurrentSize,
MinimumSize,
UsedPages,
EstimatedPages
FROM #X

enter image description here

2