T-SQLを介したプログラムによるデータベースの参照


11

データベース名を引数として取り、そのデータベースのインデックスとその断片化レベルのテーブルを返すストアドプロシージャを書いています。このストアドプロシージャは、DBAデータベース(DBAが監視および最適化に使用するテーブルを含むDB)に存在します。問題のシステムはすべて、SQL Server 2008 R2です。

基本的なクエリは解決しましたが、インデックスの実際の名前を提供しようとしています。私の知る限りでは、その情報は各個人のsys.indexesビューに含まれています。私の特定の問題は、別のデータベースのストアドプロシージャからプログラムによってそのビューを参照しようとしていることです。

説明のために、これは問題となっているクエリの一部です。

FROM sys.dm_db_index_physical_stats(@db_id,NULL,NULL,NULL,NULL) p
INNER JOIN sys.indexes b ON p.[object_id] = b.[object_id] 
    AND p.index_id = b.index_id 
    AND b.index_id != 0

クエリは、適切なsys.indexesビューを使用しているため、@ db_idで識別されるデータベースから実行すると正常に機能します。ただし、これをDBAデータベースから呼び出そうとすると、sys.indexesビューが間違ったデータベース用であるため、すべてnullになります。

より一般的に言えば、私は次のようなことができるようにする必要があります:

DECLARE @db_name NVARCHAR(255) = 'my_database';
SELECT * FROM @db_name + '.sys.indexes';

または

USE @db_name;

文字列連結とOBJECT_NAME / OBJECT_ID / DB_ID関数の組み合わせを使用して、データベースの切り替えや他のデータベースの参照を試みましたが、何も機能しないようです。コミュニティのアイデアがあれば教えていただければ幸いですが、このストアドプロシージャを個別のデータベースに配置するために、ツールを変更する必要があると思います。

提案を事前に感謝します。


1
これには動的SQLを使用する必要があると思います...
JNK

回答:


10

動的SQLは、これらのタイプの管理タスクに役立ちます。以下は、私が作成したストアドプロシージャの抜粋で、最適化レベルを取得するだけでなく、最適化を実行するコードも生成します。

select @SQL = 
'
select getdate(),
       ''' + @@ServerName + ''',
       ''' + @DatabaseName + ''',
       so.Name,
       si.Name,
       db_id(''' + @DatabaseName + '''),
       ips.object_id,
       ips.index_id,
       ips.index_type_desc,
       ips.alloc_unit_type_desc,
       ips.index_depth,
       ips.avg_fragmentation_in_percent,
       ips.fragment_count,
       avg_fragment_size_in_pages,
       ips.page_count,
       ips.record_count,
       case
         when ips.index_id = 0 then ''alter table [' + @DatabaseName + '].'' + ss.name + ''.['' + so.name + ''] rebuild with (online = on)''
         else ''alter index '' + si.name + '' on [' + @DatabaseName + '].'' + ss.name + ''.['' + so.name + ''] rebuild with (online = on)''
       end
  from sys.dm_db_index_physical_stats(db_id(''' + @DatabaseName + '''),null,null,null, ''' + @SampleMode + ''') ips
  join [' + @DatabaseName + '].sys.objects so  on so.object_id = ips.object_id
  join [' + @DatabaseName + '].sys.schemas ss  on ss.schema_id = so.schema_id
  join [' + @DatabaseName + '].sys.indexes si  on si.object_id = ips.object_id
                      and si.index_id  = ips.index_id
order by so.Name, ips.index_id
'

exec (@SQL)

JNKのコメントに基づいて、動的SQLを使用するようにクエリを変更しました。もちろん動作します。デフラグコードを生成する別のクエリがあります。これを試してみて、どのように見えるかを説明します。しかし、これを答えとして受け入れます。
mdoyle

注意点の1つは、これはSQL Server 2008R2 Enterprise Editionで実行されることです。「再構築(オンライン=オン)」は、標準版ではサポートされていません。
datagod 2012

1
いいですね、あなたの回答に賛成投票するのに十分な担当者がいます。:-)これは洗練されたクエリですが、コード生成クエリを個別に持つのが好きです。結果をテキストに変換して、ジョブにカットアンドペーストできることが好きです。非常にエレガントなソリューションであることに感謝します。
mdoyle

8

動的SQLの代替はSQLCMDで、コマンドライン、エージェントジョブステップ、Invoke-Sqlcmd Powershellコマンドレットから呼び出すか、SSMSで有効にすることができます。SQLCMD構文の例は次のようになります。

:SETVAR DatabaseName MyDatabase

SELECT * FROM $(DatabaseName).sys.indexes;

SQLCMDモードは、私が以前に知っていたかった機能の1つです。多くの状況で重宝します。


1
これは、PowerShellを使用して実現するのにも非常にシンプルでエレガントです。私はあなたのアプローチが好きです、マーク。+1
トーマス・ストリンガー

@Shark良い点、私はでPowerShellコマンドレットを編集します。
マーク・ストーリー・スミス

これも良い解決策です。これについても検討します。
mdoyle

これはいいですが、これがTSQLでサポートされていない理由はありますか?
tbone 2016年

0

通常、別のDBに含まれるプロシージャから1つのテーブルセットを参照することは困難です。マスターにプロシージャをシステムプロシージャとしてインストールすると、それ自体を参照することなく他のDBコンテキストで使用できます。

プロシージャが「sp_」で始まる場合、それは普遍的に見えるようになり、「sys.sp_%」スキーマで定義すると、他のDBコンテキストで使用できます。

これは、DB_nameを動的にプラグインする必要なしに、複数のDBで動作する代替方法を提供します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.