• When I do this (in batches) I wonder if the selection criteria (i.e. "like 'SIC%'" in your case) takes time on each iteration of the loop.

    I get all the clustered index keys into a #temporary table, ordered by those keys, with an IDENTTIY column, and then delete in batches based on ranges of the ID. Something like this:

    SELECT IDENTITY(int, 1, 1) AS MyID, ClustKey1, ClustKey2, ...

    INTO #TEMP

    FROM F_POLICY_TRANSACTION

    WHERE [POLICY_TRANSACTION_BKEY] like 'SIC%'

    ORDER BY ClustKey1, ClustKey2, ...

    DECLARE@intLoop int = 1

    WHILE 1 = 1

    BEGIN

    DELETE D

    FROM #TEMP AS T

    JOIN F_POLICY_TRANSACTION AS D

    ON D.ClustKey1 = T.ClustKey1

    AND D.ClustKey2 = T.ClustKey2

    AND ...

    WHERE T.ID BETWEEN @intLoop AND @intLoop + 50000

    IF @@ROWCOUNT < 50000 BREAK;

    SELECT @intLoop = @intLoop + 50000

    END

    I'd be interested to hear if that is any more efficient for you.