2012-02-08 5 views
3

サーバー上のすべてのデータベースを更新し、それぞれのデータベースで同じロジックを実行する必要があります。問題のデータベースはすべて、CorpDB1、CorpDB2などの共通の命名体系に従います。問題のデータベース(50を超える)ごとにSQL Agent Jobを作成するのではなく、カーソルを使用してデータベースのリストを反復することを考えましたそれぞれにいくつかの動的SQLを実行します。カーソルは最後の手段でなければならないという共通の考え方に照らして、これは、文書化されていないsp_MSforeachdb stored procedureを使用して、パフォーマンスを上げるために書き直すことも、別の方法で書き直すこともできますか?最適なパフォーマンスを得るために、このカーソルを最適化または再書き込みできますか?

DECLARE @db VARCHAR(100) --current database name 
DECLARE @sql VARCHAR(1000) --t-sql used for processing on each database 

DECLARE db_cursor CURSOR FAST_FORWARD FOR 
    SELECT name 
    FROM MASTER.dbo.sysdatabases 
    WHERE name LIKE 'CorpDB%' 
OPEN db_cursor 
FETCH NEXT FROM db_cursor INTO @db 
WHILE @@FETCH_STATUS = 0 
BEGIN 
    SET @sql = 'USE ' + @db + 
    ' DELETE FROM db_table --more t-sql processing' 
    EXEC(@sql) 
    FETCH NEXT FROM db_cursor INTO @db 
END 
CLOSE db_cursor 
DEALLOCATE db_cursor 
+1

'sp_msforeachdb'と' sp_msforeachtable'はどちらもカーソルのためのラッパーであり、パフォーマンスの違いはほとんどありません。 – JNK

+0

Heh go figure ...私は彼らが何をしたかを見て開けたことはありませんでしたが、それは私を驚かせません。 – CheckRaise

+2

私はあなたがそのようなカーソルを使ってSQL-Godsを動揺させるとは思わない。カーソルの正確さはサーバを停止させることはありません。それはあなたがそれをどのようにして何回行うかです。この場合、50行をループします。私はこれが私が把握できる任意の選択肢よりも優れていると思う。 –

答えて

5

プロシージャコードでセットに基づく問題に対処するためにカーソルを使用すると、カーソルが正しくありません。私はカーソルがあなたのシナリオでは必ずしも悪い考えではないと思います。

複数のデータベース(バックアップ、整合性チェック、インデックス保守など)に対して操作を実行する必要がある場合は、カーソルの使用に問題はありません。確かに、データベース名を含む一時テーブルを作成してループすることもできますが、これは手続き的アプローチです。

具体的には、WHERE句の条件に基づいてこれらのテーブルの行を削除しない場合は、DELETE FROMの代わりにTRUNCATE TABLEを使用することを検討してください。 2つの操作の違いはhereです。 TRUNCATE TABLEを実行しているユーザーは、影響を受けるオブジェクトに対するアクセス許可がALTERである必要があります。

+0

それは私が将来の使用のために間違いなく心に留めておくべき素晴らしい情報です。この特定のインスタンスでは、deleteステートメントにはwhere句があります。私は簡潔にするためにそれを残しました。 – CheckRaise

2

これは、削除ステートメントのセットを収集し、それらをすべて1つのシーケンスで実行します。これは必ずしもパフォーマンス面で優れているとは限りませんが、猫を肌に触れる別の方法です。

DECLARE @sql NVARCHAR(MAX); -- if SQL Server 2000, use NVARCHAR(4000) 

SET @sql = N''; 

SELECT @sql = @sql + N';DELETE ' + name + '..db_table -- more t-sql' 
    FROM master.sys.databases 
    WHERE name LIKE N'CorpDB%'; 

SET @sql = STUFF(@sql, 1, 1, ''); 

EXEC sp_executesql @sql; 

あなたは、カーソル内の同様の方法で文字列を構築する代わりに、コマンドごとにEXEC()内部を実行することを検討することがあります。

DECLARE db_cursor CURSOR 
    LOCAL STATIC FORWARD_ONLY READ_ONLY 
    FOR 

これは少なくともロックと不要なtempdbの使用方法があります:あなたは、カーソルを引き続き使用するつもりなら、次の宣言を使用します。

+0

私はあなたの代わりのアプローチに感謝します。私は可能な答えとして両方をマークすることができたらいいと思う! – CheckRaise

+0

また、文書化されていない/サポートされていない場合は、 'sp_msforeachdb'を使用しないようにするには不十分です。http://sqlblog.com/blogs/aaron_bertrand/archive/2010/12/29/a-more-reliable-and -more-flexible-sp-msforeachdb.aspxおよびhttp://www.mssqltips.com/sqlservertip/2201/making-a-more-reliable-and-flexible-spmsforeachdb/ –

関連する問題