4

我有一个非常大的数据库(~100Gb),主要由两个我想减小大小的表组成(这两个表都有大约 5000 万条记录)。我在这两个表的同一台服务器上设置了一个存档数据库,使用相同的模式。我正在尝试确定从实时数据库中删除行并将它们插入存档数据库的最佳概念方法。在伪代码中,这就是我现在正在做的事情:

Declare @NextIDs Table(UniqueID)
Declare @twoYearsAgo = two years from today's date

Insert into @NextIDs 
     SELECT top 100 from myLargeTable Where myLargeTable.actionDate < twoYearsAgo

Insert into myArchiveTable
<fields>
SELECT <fields> 
FROM myLargeTable INNER JOIN @NextIDs on myLargeTable.UniqueID = @NextIDs.UniqueID

DELETE MyLargeTable
FROM MyLargeTable INNER JOIN @NextIDs on myLargeTable.UniqueID = @NextIDs.UniqueID

现在,完成 1000 条记录需要非常慢的 7 分钟。我已经测试了删除和插入,两者都需要大约。3.5 分钟完成,所以它不一定比另一个效率低得多。谁能指出一些优化的想法?

谢谢!

这是 SQL Server 2000。

编辑:在大表上,ActionDate 字段上有一个聚集索引。还有另外两个索引,但在任何查询中都没有引用。存档表没有索引。在我的测试服务器上,这是访问 SQL Server 的唯一查询,因此它应该具有足够的处理能力。

代码(一次循环 1000 条记录):

 DECLARE @NextIDs TABLE(UniqueID int primary key)
DECLARE @TwoYearsAgo datetime
SELECT @TwoYearsAgo = DATEADD(d, (-2 * 365), GetDate())

WHILE EXISTS(SELECT TOP 1 UserName FROM [ISAdminDB].[dbo].[UserUnitAudit] WHERE [ActionDateTime] < @TwoYearsAgo)
BEGIN

BEGIN TRAN

--get all records to be archived
INSERT INTO @NextIDs(UniqueID)
        SELECT TOP 1000 UniqueID FROM [ISAdminDB].[dbo].[UserUnitAudit] WHERE [UserUnitAudit].[ActionDateTime] < @TwoYearsAgo

--insert into archive table
INSERT INTO [ISArchive].[dbo].[userunitaudit] 
(<Fields>)
SELECT  <Fields>
FROM  [ISAdminDB].[dbo].[UserUnitAudit] AS a
        INNER JOIN @NextIDs AS b ON a.UniqueID = b.UniqueID

--remove from Admin DB
DELETE [ISAdminDB].[dbo].[UserUnitAudit] 
FROM  [ISAdminDB].[dbo].[UserUnitAudit] AS a
INNER JOIN @NextIDs AS b ON a.UniqueID = b.UniqueID 

DELETE FROM @NextIDs

COMMIT

END
4

6 回答 6

4

在执行插入/删除命令之前,您实际上需要运行三个选择:

对于第一个插入:

SELECT top 100 from myLargeTable Where myLargeTable.actionDate < twoYearsAgo

对于第二个插入:

SELECT <fields> FROM myLargeTable INNER JOIN NextIDs 
on myLargeTable.UniqueID = NextIDs.UniqueID

对于删除:

(select *)
FROM MyLargeTable INNER JOIN NextIDs on myLargeTable.UniqueID = NextIDs.UniqueID

我会尝试优化这些,如果它们都很快,那么索引可能会减慢你的写入速度。一些建议:

  1. 启动分析器并查看读/写等发生了什么。

  2. 检查所有三个语句的索引使用情况。

  3. 尝试运行SELECTs仅返回的 PK,查看延迟是查询执行还是获取数据(确实有例如任何全文索引字段、TEXT字段等)

于 2009-12-09T20:15:23.560 回答
4

您在源表上是否有用于过滤结果的列的索引?在这种情况下,这将是 actionDate。

此外,在进行大量插入之前,它通常有助于从目标表中删除所有索引,但在这种情况下,您一次只能执行 100 个。

大批量执行此操作也可能会更好。一次有一百个查询的开销最终将主导成本/时间。

在此期间服务器上是否有任何其他活动?是否有任何阻塞发生?

希望这可以为您提供一个起点。

如果您可以提供您正在使用的确切代码(如果存在隐私问题,可能没有列名),那么也许有人可以发现其他优化方法。

编辑:你检查过你的代码块的查询计划吗?我遇到了这样的表变量问题,其中查询优化器无法确定表变量的大小会很小,因此它总是尝试对基表进行全表扫描。

就我而言,它最终成为一个有争议的问题,所以我不确定最终的解决方案是什么。您当然可以在所有选择查询中添加关于 actionDate 的条件,这至少可以最大限度地减少这种影响。

另一种选择是使用普通表来保存 ID。

于 2009-12-09T20:17:56.570 回答
1

myLargeTable.actionDate 和 .UniqueID 上是否有任何索引?

于 2009-12-09T20:14:10.553 回答
1

您是否尝试过大于 100 的批量大小?

什么东西花的时间最多?插入还是删除?

于 2009-12-09T20:15:18.133 回答
1

INSERT 和 DELETE 语句正在加入

[ISAdminDB].[dbo].[UserUnitAudit].UniqueID

如果这没有索引,并且您指出没有,那么您正在执行两次表扫描。这可能是速度慢的原因,b/ca SQL Server 表扫描将整个表读取到临时表中,在临时表中搜索匹配的行,然后删除临时表。

我认为您需要在UniqueID. 维护它的性能损失必须小于表扫描。您可以在存档完成后将其删除。

于 2009-12-09T20:40:31.437 回答
0

您可以尝试使用输出子句执行此操作:

declare @items table (
  <field list just like source table> )

delete top 100 source_table
  output deleted.first_field, deleted.second_field, etc
  into @items
  where <conditions>

insert archive_table (<fields>)
  select (<fields>) from @items

您也可以在单个查询中执行此操作,方法是直接将“输出到”到存档表中(消除对表 var 的需要)

于 2009-12-09T20:39:08.797 回答