-1

私は、2つのテーブル(ユーザーのテーブル(3700人)とユーザーが作成した見積もりの​​テーブル(280000人))を参照する本番データベースでスクリプトを実行しています。Quoteは、アプリケーションのメインオブジェクトであり、非常に大きなオブジェクトであり、多くのデータテーブルが作成されて入力されます。私の目標は、少数のユーザーグループで作成されたものを除くすべての引用からデータベースをクリーンアップすることです。

最初にそれらのユーザーのIDを含む一時テーブルを作成し(スクリプトでも他の方法で使用されます)、次にメインテーブルを実行するカーソルで引用符が一覧表示されます。ユーザーグループから作成された引用符については、必要なクレンジング。

このスクリプトは約26時間実行されることがわかります。これは、データベースの復元に一般に約15分かかるため、独特だと思います。最も重いSQLがそこで実行されると思います。ただし、dbの重量は100GBを超えます。

私が作成しているスクリプトの一部がひどく最適ではないか、またはこれをはるかに短い実行で実行する方法についての提案がありますか?

SQL Server2008R2を実行しています。

これがスクリプトのスケッチです。

CREATE table #UsersIdsToStay(user_id int)
INSERT INTO #UsersIdsToStay
select user_id 
from users 
where user_name like '%SOMESTRING '
-----
declare @QuoteId int
declare @UserId int

declare QuoteCursor cursor for 
select DISTINCT QuoteId, UserId
from QuotesTable
where UserId not in 
    (
        select * from #UsersIdsToStay
    )

open QuoteCursor
while 1=1
begin
    fetch QuoteCursor into @QuoteId, @UserId
    if @@fetch_status != 0 break

    -- all the deletions from related tables are executed here using @QuoteId and @UserId
    exec('delete from QuoteHistory where QuoteId = ' + @QuoteId + ' and UserId = ' + @UserId )
    exec('delete from QuoteRevisions where QuoteId = ' + @QuoteId + ' and UserId = ' + @UserId )
    exec('delete from QuoteItems where QuoteId = ' + @QuoteId + ' and UserId = ' + @UserId )
    ....

end
close QuoteCursor;
deallocate QuoteCursor
4

2 に答える 2

1

カーソルは、関連する各テーブルで一度に1つのUser_Id/Quote_Idの組み合わせのみを削除するように制限します。結合を使用することにより、一括で削除することができます。

Common Table Expression(CTE)を使用して一時テーブルを切り替えることもできます。これが1回限りのスクリプトの場合、一時テーブルは問題ないはずですが、本番コードの場合はCTEを作成します。

    if OBJECT_ID('tempdb..#quotesToDelete') is not null
            drop table #quotesToDelete


    select distinct 
                ut.user_id, 
                qt.quote_id
        into #quotesToDelete
    from    dbo.QuotesTable qt (nolock)
        inner join dbo.UsersTable ut (nolock)
            on qt.user_id = ut.user_id
    where ut.user_name not like '%SOMESTRING '

    -- all the deletions from related tables are executed here using @QuoteId and @UserId

    -- relatedtableA
    delete a
    from relatedtableA a
        inner join #quotesToDelete b
        on a.user_id = b.user_id
        and a.quote_id = b.quote_id

    -- relatedtableB
    ...
于 2013-01-24T21:05:19.747 に答える
0

削除を表示しないため、カーソルを回避する方法を表示できません。

しかし、かなり簡単な臨時雇用者なしでこれを行うことができます

select DISTINCT QuoteId, UserId
from QuotesTable
where UserId not in 
    (
        select user_id 
        from users 
        where user_name like '%SOMESTRING '
    )

また

select DISTINCT QuoteId, UserId
from QuotesTable 
left join UserId 
  on UserId.user_id = QuotesTable.UserId 
 and user_name like '%SOMESTRING '
where UserId.user_id is null 

問題はカーソルであり、あなたはそれを必要としません

CREATE table #QuotesToDelete(QuoteId int, UserID int)
insert into #QuotesToDelete
select DISTINCT QuoteId, UserId
    from QuotesTable 
    left join UserId 
      on UserId.user_id = QuotesTable.UserId 
     and user_name like '%SOMESTRING '
    where UserId.user_id is null 
delete  QH
from QuoteHistory QH 
join #QuotesToDelete 
  on #QuotesToDelete.QuoteId = QH.QuoteId 
 and #QuotesToDelete.UserID  = QH.UserID
delete  QR
from QuoteRevisions QR 
join #QuotesToDelete 
  on #QuotesToDelete.QuoteId = QR.QuoteId 
 and #QuotesToDelete.UserID  = QR.UserID
于 2013-01-24T21:04:16.140 に答える