SQL存档存储过程的最佳实践

时间:2009-12-09 20:04:19

标签: sql sql-server optimization stored-procedures archive

我有一个非常大的数据库(~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

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

谢谢!

这是SQL Server 2000。

编辑:在大型表上,ActionDate字段上有一个聚簇索引。还有另外两个索引,但在任何查询中都没有引用。 Archive表没有索引。在我的测试服务器上,这是唯一一个命中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

6 个答案:

答案 0 :(得分: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字段等)

答案 1 :(得分:4)

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

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

在大批量生产中你也可能会更好。一次只有一百个,查询的开销最终将主导成本/时间。

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

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

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

编辑: 您是否检查了代码块的查询计划?我遇到了像这样的表变量的问题,其中查询优化器无法弄清楚表变量的大小很小,所以它总是试图在基表上进行全表扫描。

就我而言,它最终成了一个没有实际意义的点,所以我不确定最终解决方案是什么。您当然可以在actionDate上为所有选择查询添加条件,这至少可以最大限度地减少这种情况的影响。

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

答案 2 :(得分:1)

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

答案 3 :(得分:1)

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

花费的时间最多? INSERT还是删除?

答案 4 :(得分:1)

INSERT和DELETE语句正在加入

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

如果此处没有索引,并且您指示没有,则表示您正在进行两次表扫描。这可能是缓慢的原因,b / c SQL Server表扫描将整个表读入临时表,在临时表中搜索匹配的行,然后删除临时表。

我认为您需要在UniqueID上添加索引。维护它的性能损失必须小于表扫描。您可以在归档完成后删除它。

答案 5 :(得分: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

您也可以在单个查询中执行此操作,方法是将“output into”直接导入到归档表中(无需使用表变量)