0

比較的単純なストアドプロシージャがありますが、transactionsテーブルのデータ量が原因で、実行に永遠に時間がかかります。クエリを最適化するか、カーソルを使用しないように変換する方法についての提案をいただければ幸いです。

BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;

DECLARE @ItemID uniqueidentifier 

SET @CurrentCount = 0;

DECLARE @TempTransTable TABLE
(
    ID uniqueidentifier
)

-- Insert statements for procedure here
DECLARE curs_GetAllItems CURSOR LOCAL STATIC FORWARD_ONLY READ_ONLY FOR
    select 
        ID
    from 
        item
    where 
        locationid in 
            (
                -- gets corona locations
                select 
                    Locations.ID
                from Locations
                    left outer join unit
                        on unit.locationid = locations.id
                where unit.unittype = '4'
            )
        and stat not in (1,10,11,13) -- only items not in stock

    OPEN curs_GetAllItems

    FETCH NEXT FROM curs_GetAllItems INTO @ItemID
        WHILE (@@FETCH_STATUS =0)
        BEGIN
            -- Clear table to ensure accurate data
            DELETE FROM @TempTransTable

            -- Insert transaction records to delete
            -- Every transaction except the first two and the last
            INSERT INTO @TempTransTable
            select 
                ID 
            from 
                transactions 
            where 
                transactions.id not in
                    (select ID from (select top 2 * from transactions where itemid = @ItemID order by transdate asc) as t1
                    union 
                    select ID from (select top 1 * from transactions where itemid = @ItemID order by transdate desc) as t2)
                and itemid = @ItemID

            -- Delete trans records
            DELETE FROM 
                dbo.transactions 
            WHERE 
                transactions.ID in (select ID from @TempTransTable);

        -- Get next item.id
        FETCH NEXT FROM curs_GetAllItems INTO @ItemID
        END
    CLOSE curs_GetAllItems
    DEALLOCATE curs_GetAllItems
END
4

2 に答える 2

1
;with tmp as (
    select *,
           rn_asc = ROW_NUMBER() over (partition by t.itemid order by transdate asc),
           rn_desc = ROW_NUMBER() over (partition by t.itemid order by transdate desc)
      from transactions t
     where exists (
          select *
          from item i
          join Locations l on i.locationid = l.ID
          join unit u on u.locationid = l.id and u.unittype = '4'
         where i.id = t.itemid)
       and stat not in (1,10,11,13) -- only items not in stock
)
    delete tmp
     where rn_asc > 2 and rn_desc > 1;
于 2012-12-13T20:01:26.223 に答える
0

やり方を見直したほうがいいと思います。カーソルとループをまったく使用せずに管理できるはずです。中間一時テーブルを使用する必要があるかもしれません (それにインデックスを追加することを検討してください)。

その他のポイント: これらのクエリが困難であり、同時変更を伴うデータベースで動作している場合、ロック、タイムアウト、データの不整合などの問題に簡単に陥る可能性があります。

于 2012-12-13T20:28:31.777 に答える