-1

我在我们的生产数据库上运行一个脚本,引用两个表:我们的用户表(其中 3700 个)和他们所做的报价表(其中 280000 个)。Quote 是我们应用程序中的主要对象,一个非常大的对象,为其创建和填充了许多数据表。我的目标是从所有报价中清除数据库,但由一小部分用户组成的报价除外。

我首先创建一个临时表,其中包含这些用户的 id(它也在脚本中使用),然后创建一个游标,该游标在主表中运行,用于列出引号以及从用户组创建的那些引号必要的清洁。

我看到这个脚本将执行大约 26 小时,我认为这很奇怪,因为我需要大约 15 分钟来恢复数据库,我猜最重的 sql 在那里执行。但是,数据库的重量超过 100GB。

是否有脚本的某些部分是我非常不理想的,或者您有一些建议如何通过更短的执行来完成。

我们正在运行 SQL Server 2008 R2。

这是脚本的草图。

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

游标限制您一次只能删除每个相关表上的单个 User_Id/Quote_Id 组合。通过使用连接,您将能够批量删除。

您还可以使用公用表表达式 (CTE) 切换临时表。如果这是一个一次性脚本,那么临时表应该没问题,但对于生产代码,我会创建一个 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 回答