web-dev-qa-db-ja.com

ALTER VIEWはビューからインデックスを削除します

ヘッダー行が示すように:インデックスが付いているVIEWでALTER VIEWステートメントを使用すると、警告なしにVIEWからこの(すべて?)インデックスが削除されます。最初にインデックスを削除するように通知して、ALTER VIEWステートメントを失敗させたいと思います。

SQL SERVERにこの動作を変更する設定はありますか?それともSQL 2012(SP3)以降のバージョンで変更されますか?

11
Ralf

DDLトリガーを使用して、インデックス付きビューの変更を防ぐことができます。しかし、DDLトリガーが実行されるため、実装は少し複雑です変更後ビューが変更されてインデックスが削除されましたが、変更がコミットされる前であり、以前にビューを直接検出することはできませんインデックスがありました。

したがって、インデックスが作成されるたびにビューに拡張プロパティを配置して、拡張プロパティを持ついくつかの不正解を取得する必要があります。

例えば:

create or alter trigger ddl_trig_prevent_alter_indexed_view   
on database  
for drop_index, create_index, alter_view
as   
begin
    --select eventdata().value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]','nvarchar(max)')  , eventdata()

    declare @schemaName sysname, @objectName sysname, @eventType varchar(50), @targetObjectType varchar(50)
           ,@targetObjectName sysname, @targetObjectSchemaName sysname

    declare @e xml = eventdata();

    select @eventType = @e.value('(/EVENT_INSTANCE/EventType)[1]','varchar(50)'),
           @targetObjectType = @e.value('(/EVENT_INSTANCE/TargetObjectType)[1]','varchar(50)'),
           @targetObjectName = @e.value('(/EVENT_INSTANCE/TargetObjectName)[1]','sysname'),
           @schemaName = @e.value('(/EVENT_INSTANCE/SchemaName)[1]','sysname'),
           @objectName = @e.value('(/EVENT_INSTANCE/ObjectName)[1]','sysname')

    if @eventType = 'DROP_INDEX' and @targetObjectType = 'VIEW'
    begin
        --print @eventType
        set @targetObjectSchemaName = (select schema_name(schema_id) from sys.views where name = @targetObjectName)
        if exists( select * from fn_listextendedproperty ('HasIndex', 'SCHEMA', @targetObjectSchemaName, 'VIEW', @targetObjectName, NULL, NULL) )
           and not exists( select * from sys.indexes where object_id = object_id( concat(quotename(@targetObjectSchemaName),'.',quotename(@targetObjectName))) )
        begin
            exec sp_dropextendedproperty
                 @name = N'HasIndex' 
                ,@level0type = N'Schema', @level0name = @targetObjectSchemaName
                ,@level1type = N'View', @level1name = @targetObjectName
            print 'Extended property HasIndex on view dropped.'
        end

    end
    else if @eventType = 'CREATE_INDEX' and @targetObjectType = 'VIEW'
    begin
        --print @eventType
        set @targetObjectSchemaName = (select schema_name(schema_id) from sys.views where name = @targetObjectName)
        if exists( select * from fn_listextendedproperty ('HasIndex', 'SCHEMA', @targetObjectSchemaName, 'VIEW', @targetObjectName, NULL, NULL) )
        begin
            exec sp_updateextendedproperty  
                 @name = N'HasIndex' 
                ,@value = N'1' 
                ,@level0type = N'Schema', @level0name = @targetObjectSchemaName
                ,@level1type = N'View', @level1name = @targetObjectName
           print 'Extended property HasIndex on view updated.'
        end
        else
        begin
            exec sp_addextendedproperty  
                 @name = N'HasIndex' 
                ,@value = N'1' 
                ,@level0type = N'Schema', @level0name = @targetObjectSchemaName
                ,@level1type = N'View', @level1name = @targetObjectName
           print 'Extended property HasIndex on view added.'
        end

    end
    else if @eventType = 'ALTER_VIEW'
    begin
      --print @eventType
      if exists( select * from fn_listextendedproperty ('HasIndex', 'SCHEMA', @schemaName, 'VIEW', @objectName, NULL, NULL) where value = '1' )
      begin
         ;throw 50001,'Cannot alter view with an index.  Drop the index first.', 1;
         rollback;
         return;
      end
    end
    else
    begin 
      ;throw 50001,'Unexpected event type in ddl trigger.', 1
    end
end

この動作を変更する設定はありません。また、新しいバージョンのSQL Serverでも変更されていません。 SQL Server 2019およびAzure SQLデータベースの 現在のドキュメントの注釈セクション からの抜粋:

ALTER VIEWは、インデックス付きビューに適用できます。ただし、ALTER VIEWは無条件でビューのすべてのインデックスを削除します

20
Dan Guzman