2016-06-29 44 views
1

私は本当に複数のインデックスを再構築するためのカーソルが必要なので、私の質問は種類の他のものとは異なります。しかし、私はすでにカーソルにいて更新をしているという事実を利用したい。ここで さらに "カーソルは読み取り専用です。"

は、SQLコードです:

USE [MyDB] 
DECLARE @TableName NVARCHAR(128) 
DECLARE @IndexName NVARCHAR(128) 
DECLARE @Sql NVARCHAR(MAX) 

BEGIN TRY 
    DECLARE c CURSOR LOCAL FORWARD_ONLY KEYSET SCROLL_LOCKS FOR 
    SELECT TableName,IndexName 
    FROM _NonClusteredIndices_ i 
    JOIN _Candidates_ c ON i.ObjectId = c.ObjectId 
    WHERE State = 1 
    ORDER BY TableName,IndexName 
    FOR UPDATE OF i.State 
    OPEN c 
    FETCH NEXT FROM c INTO @TableName,@IndexName 
    WHILE @@FETCH_STATUS = 0 
    BEGIN 
     SET @Sql = 'ALTER INDEX [' + @IndexName + '] ON [' + @TableName + '] REBUILD' 
     EXEC(@Sql) 
     UPDATE _NonClusteredIndices_ SET State = 2 WHERE CURRENT OF c 
     FETCH NEXT FROM c INTO @TableName,@IndexName 
    END 
    CLOSE c 
    DEALLOCATE c 
END TRY 
BEGIN CATCH 
    SELECT 
     ERROR_NUMBER() AS ErrorNumber, 
     ERROR_SEVERITY() AS ErrorSeverity, 
     ERROR_STATE() as ErrorState, 
     ERROR_PROCEDURE() as ErrorProcedure, 
     ERROR_LINE() as ErrorLine, 
     ERROR_MESSAGE() as ErrorMessage; 
END CATCH 

ああ、私は取得カーソルが読み込まれONLY

なぜ?どうすれば修正できますか?

EDIT

二つのテーブルのDDLである:表の

USE [MyDB] 
GO 
SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 
CREATE TABLE [dbo].[_Candidates_](
    [ObjectId] [int] NOT NULL, 
    [ClientIdColumnId] [int] NOT NULL, 
    [TableName] [nvarchar](128) NOT NULL, 
    [ClientIdColumnName] [nvarchar](128) NOT NULL, 
    [RowCount] [bigint] NOT NULL 
) ON [PRIMARY] 

CREATE TABLE [dbo].[_NonClusteredIndices_](
    [ObjectId] [int] NOT NULL, 
    [IndexName] [nvarchar](128) NOT NULL, 
    [State] [int] NOT NULL DEFAULT ((0)) 
) ON [PRIMARY] 

(おっと、間違ったテーブルに記載されている)

なしを除いて、任意のインデックスまたは制約を持ちません_NonClusteredIndices_.Stateカラムのデフォルト制約

+0

あなたは、両方のテーブルのDDLを提供することができます。別の方法として

は、私はあなたが完全にCURSORを取り除くとセットベースのクエリを使用してこれを行う示唆しますか? –

+0

私はその投稿を読んで、 'LOCAL FORWARD_ONLY KEYSET SCROLL_LOCKS'を追加するように指示しましたが、ダイスはまだありません。それ以外は、私が間違っていることを理解していません。あなたがそれを見れば、私は何かを逃しているかもしれない - 共有してください。 – mark

+0

DDLを追加しました... – mark

答えて

1

で参照されるテーブルの1つにユニークインデックスがない場合、CURSORSTATICに変換されます。 STATICのカーソルはREAD-ONLYです。詳細については、Using Implicit Cursor Conversionsを参照してください。

DECLARE @sql NVARCHAR(MAX) = ''; 

BEGIN TRY 
    BEGIN TRANSACTION 
     SELECT 
      @sql = @sql + 'ALTER INDEX ' + QUOTENAME(IndexName) + ' ON ' + QUOTENAME(TableName) + ' REBUILD;' + CHAR(10) 
     FROM _NonClusteredIndices_ i 
     JOIN _Candidates_ c 
      ON i.ObjectId = c.ObjectId 
     WHERE State = 1; 

     EXEC(@sql); 

     UPDATE i 
      SET i.State = 2 
     FROM _NonClusteredIndices_ i 
     JOIN _Candidates_ c 
      ON i.ObjectId = c.ObjectId 
     WHERE State = 1; 

    COMMIT TRANSACTION 
END TRY 
BEGIN CATCH 
    IF @@TRANCOUNT > 0 BEGIN 
     ROLLBACK TRANSACTION 
    END 
    DECLARE 
     @ErrorNumber INT, 
     @ErrorMessage NVARCHAR(4000), 
     @ErrorState  INT, 
     @ErrorSeverity INT, 
     @ErrorLine  INT; 

    SELECT 
     @ErrorNumber = ERROR_NUMBER(), 
     @ErrorSeverity = ERROR_SEVERITY(), 
     @ErrorState  = ERROR_STATE(), 
     @ErrorLine  = ERROR_LINE(), 
     @ErrorMessage = ERROR_MESSAGE(); 

    RAISERROR(@ErrorMessage, @ErrorSeverity, @ErrorState); 
END CATCH 
+0

私はこのアプローチに気付いていますが、問題があります。途中で止めることはできません。インデックスの一部が非常に大きい場合、オペレータはセッションチェックを何か停止してから再開することがあります。私は同じトランザクション内のすべてのインデックスを再構築することはできません。さらに、実際のクエリは 'RAISERROR ... NO WAIT'を使って進捗メッセージを出力します。 – mark

+0

@mark次に' _NonClusteredIndices_'に一意のインデックスを入れます。 –

+0

私は、簡単に言うことができますが、そのようにすると 'CURSOR'が' STATIC'、つまり 'READONLY'に変換されると言っただけではありませんか? – mark

関連する問題