web-dev-qa-db-ja.com

カーソル/ Whileループは、複数のデータベースに管理上の変更を加える唯一の方法ですか?

サーバー上のすべてのデータベースの復旧モデルを変更するためのプログラム可能な方法が特に必要です。このソリューションはすべての「データベースの変更」コマンドに適用できることを知っています。 PowerShellのSMOがこの問題を非常に簡単に解決できることは知っていますが、

Import-Module SQLPS
CD SQL\*ServerName*\*InstanceName*\databases
foreach ($database in (ls -force)){
$database.recoverymodel = 'Full'
$database.update
}

最も効率的なT-SQLソリューションを探しています。カーソルをすべてのコストで回避するために頭の中に根付いていますが、alterステートメントを実行するためのセットベースのソリューションは考えられません。これがカーソルベースのソリューションです。

DECLARE @sql varchar(MAX), @name varchar(50)

DECLARE cur CURSOR FOR
SELECT name 
FROM sys.databases
where name <> 'tempdb';
OPEN cur

FETCH NEXT FROM cur 
INTO @name

WHILE @@FETCH_STATUS = 0
BEGIN
    SET @sql = 'ALTER DATABASE ' + @name + ' SET RECOVERY FULL;'
    exec(@sql)
    FETCH NEXT FROM cur INTO @name
END
CLOSE CUR
DEALLOCATE cur
  1. これは、whileループでも実行できますが、そのソリューションは依然としてループプロセスを通過します... whileループは大幅に優れたパフォーマンスを提供しますか?
  2. パフォーマンスに偏執的ですか?このような管理タスクはそれほど頻繁には行われず、ループする必要のあるオブジェクトの量は一般的には少ないためです。しかし、私は常に「何千ものオブジェクトが存在する大規模な環境で作業するとどうなるか」と考え、最も効率的なソリューションを使用していない可能性があることに罪悪感を感じ始めます。
6
Luke Pafford

ループがこのタイプのことを行う限り、心配する必要はありません。ループとカーソルは、通常はより高速なセットベースのアプローチがよくあるため、評判が悪い。管理関連の場合、ループが唯一の方法である場合があり、この春を念頭に置くセットベースの方法はありませんが、DOS、SSIS、Powershellなどのツールでタスクを並列化できます。

そうは言っても、私はこのタイプのものに [〜#〜] sqlcmd [〜#〜] モードを使用することを好みます。これは、SQL Server Management Studio(SSMS)でメインメニュー> [クエリ]> [SQLCMDモード]を使用して、次のように切り替えることができる特別なモードです。

SQLCMD mode in SSMS

このモードをオンにすると、別のサーバーに接続する:connect、ファイルを読み取る:r、出力をリダイレクトする:out、SQLCMD変数など、あらゆる種類のコマンドにアクセスできます。 DOSコマンドの前に2つの感嘆符を付けることで、たとえば!!dirのようにします。

あなたの例では、次のようなことをすることができます:

:connect .\sql2014
SET NOCOUNT ON
GO

-- Redirect output back to normal
:out d:\temp\temp.sql
GO

SELECT 'ALTER DATABASE ' + name + ' SET RECOVERY FULL;'
FROM sys.databases
WHERE recovery_model_desc != 'FULL'
  AND database_id > 4
  AND name Not In ( 'distribution', 'SSISDB' )
GO

PRINT 'GO'
GO
-- Redirect output back to normal
:out STDOUT

-- Optionally read/run the temp file you have scripted
--:r d:\temp\temp.sql
GO

これにより、「スクリプトをスクリプト化」して、それを確認し、必要に応じて変更することができ、実行された内容の監査証跡があります。 SQLCMDモードをお試しください!

13
wBob

ループ構造を必要としない1つの方法を次に示します。

DECLARE @sql nvarchar(MAX) = N'';

SELECT 
    @sql += N'ALTER DATABASE ' 
    + QUOTENAME(name)
    + N' SET RECOVERY FULL;
'
FROM sys.databases
WHERE database_id > 4
AND name NOT IN ( N'distribution', N'SSISDB' );

PRINT @sql;
--EXEC(@sql);

WBobの answer に同意します。これは、頻繁に実行されない管理スクリプトのパフォーマンスに過度に関与する必要がないという点です。

上記の文字列連結メソッドが this Connect item に従って複数の行に影響を与えるステートメントに対して期待される結果を常に生成することは保証されていません。動作はプランに依存するためです。

カーソル以外のメソッドには、CLRとXMLがあります。以下はXMLメソッドの例です。これは重要な計画に対してより信頼性が高く、ORDER BYが必要です。

DECLARE @sql varchar(MAX) = N'';
SET @sql = (
SELECT N'ALTER DATABASE ' 
    + QUOTENAME(name)
    + N' SET RECOVERY FULL;
'
FROM sys.databases
WHERE
 database_id > 4
AND name NOT IN ( N'distribution', N'SSISDB' )
FOR XML PATH(''), TYPE
).value('.', 'nvarchar(MAX)');

PRINT @sql;
--EXEC(@sql);
5
Dan Guzman