5

MSSQL 2008 R2 を使用しています。更新可能なビューの便利な機能があります。たとえば、id を名前にマッピングする 1 つのテーブル t があるとします。

create table t (id int not null primary key, name varchar(100) not null unique)

次に、いくつかの ID とその他の情報を示す別のテーブル:

create table u (id int not null primary key references t, info varchar(100) not null)

便宜上、名前列で拡張された u からの行を表示できるビューを示します。

create view v as select u.*, t.name from u u join t t on u.id = t.id

次に、ID ではなく名前で更新できるようになりました。

update v set info = 'foo' where name = 'fred'

最も便利です。しかし、「fred」の行を削除したい場合はどうなりますか?

delete v where name = 'fred' -- Fails

エラーが発生します

変更は複数のベース テーブルに影響するため、ビューまたは関数 'v' は更新できません。

結合されたテーブルを使用した SQL 更新可能ビュー(Oracle を指しますが、MSSQL の場合も状況は同じように見えます)で説明されているように、キー保存テーブルが 1 つしかない限り、複数のベース テーブルに対して更新可能なビューを作成できます。大まかに言えば、これは、テーブルの行がビューに最大 1 回表示される場所です。上記のビューでは、t と u の両方がキー保存テーブルであることがわかります。しかし、ビューの定義を微調整することでごまかすことができます。

create view v as
select u.*, (select t.name from t t where t.id = u.id) as name
from u u

これにより、以前と同じ行が得られますが、更新が可能になりました。

update v set info = 'foo' where name = 'fred'

意味的には、t からのすべての行がビューに最大 1 回しか表示されないことは変わりませんが、通常の方法で t に結合していないため、更新制限に該当しません。さらに、このビューから削除することもできます:

delete from v where name = 'fred'

これは正しいことを行い、基になるテーブル u から削除しますが、t からは削除しません。明らかに、単純な結合として表された以前のビューでは、「削除」操作が行を u または t (または両方) から削除する必要があるかどうかを判断する方法はありません。

多くの「選択」クエリでは、書き換えられたビューを使用した実行計画が少し異なるため、場合によっては実行が少し遅くなることが予想されます。オプティマイザーが (この特定のケースでは、一意のインデックスが存在するため) 2 つのビューに同じデータがあることを確認できないのは残念です。

関数を使用して更新可能なビューを作成することもできます。

create function dbo.get_name(@id int) returns varchar(100) as begin
  declare @r varchar(100)
  select @r = name from t where id = @id
  return @r
end

create view v as select *, dbo.get_name(id) as name from u

これにより、さらに異なる (多くの場合、より複雑な) クエリ プランが得られる可能性があるため、さらに遅くなる可能性があります。

したがって、更新可能なビューを作成する方法は 2 つありますが、完全に満足できるものではありません。更新操作と削除操作が機能するのは良いことですが、選択クエリでビューが 2 つのテーブルの単純な結合よりもパフォーマンスが低下しないことを確認してください。おそらく、クエリ エンジンに与えることができるヒントがいくつかあります。誰でも何か提案できますか?

4

1 に答える 1

2

これ(select t.name from t t where t.id = u.id)は非常に Macgyver のトリックです。削除可能なテーブルを 1 つだけにするという制限を回避します。

私が提案できる解決策の 1 つは、トリガーの代わりに使用することです。これにより、ビューに対する delete ステートメントの動作をカスタマイズできます。

カスタマイズされたトリガーは、ビューの自動最適化に影響しない場合があります。

いくつかの例を使用して、それについてさらに詳しく説明しているサイト: http://blogs.msdn.com/b/anthonybloesch/archive/2009/02/16/insteadoftriggerspart1.aspx および http://www.mssqltips.com/sqlservertip /1804/using-instead-of-triggers-in-sql-server-for-dml-operations/

于 2014-04-06T06:50:18.593 に答える