将大表复制到存档表 SQL Server 2012

Ant*_*nio 7 sql-server sql-server-2012

我有一个包含我的应用程序日志的表,它有 161.626.718 行(并且还在增长),并且在其上进行插入非常慢。我的想法是只保留表中 6 个月的日志和所有我想复制到应用程序无法访问的存档表上的旧记录,如果有人需要一些信息,只需直接在表上进行选择。因此,我们的想法是创建这样的日常工作:

SELECT * INTO audlog_backup FROM audlog WHERE XDATE <= DATEADD(day,-185,GETDATE())

DELETE FROM audlog WHERE XDATE <= DATEADD(day,-185,GETDATE())
Run Code Online (Sandbox Code Playgroud)

但是由于表的大小,这将花费很长时间,并且在第一次运行时会减慢甚至锁定数据库一段时间,毕竟大多数行将超过 6 个月。

第一次尽可能安全和快速地做这件事的建议是什么?

更多信息:

SQL Server 2012 标准版

创建表的脚本:

CREATE TABLE [dbo].[audlog_backup](
    [PVKEY] [float] NULL,
    [DKEY] [varchar](14) NULL,
    [XDATE] [datetime] NULL,
    [XTIME] [varchar](8) NULL,
    [XFROM] [varchar](50) NULL,
    [XTO] [varchar](50) NULL,
    [DETAILS] [text] NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
SET ANSI_PADDING ON
ALTER TABLE [dbo].[audlog_backup] ADD [XUSER] [varchar](50) NULL
ALTER TABLE [dbo].[audlog_backup] ADD [PEOPLEKEY] [int] NULL
ALTER TABLE [dbo].[audlog_backup] ADD [ADDRESSKEY] [int] NULL
ALTER TABLE [dbo].[audlog_backup] ADD [XFILEKEY] [varchar](50) NULL
ALTER TABLE [dbo].[audlog_backup] ADD [XLOGNO] [int] IDENTITY(1,1) NOT NULL
ALTER TABLE [dbo].[audlog_backup] ADD [XTABLE] [varchar](50) NULL
ALTER TABLE [dbo].[audlog_backup] ADD [XFIELD] [varchar](50) NULL
 CONSTRAINT [PK_AUDLOG_backup] PRIMARY KEY NONCLUSTERED 
(
    [XLOGNO] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
Run Code Online (Sandbox Code Playgroud)

Sol*_*zky 9

您可以使用以下通过 SQL Server 代理作业调度的存储过程来持续存档记录。您无需担心“超过 6 个月的所有内容”的初始移动,因为此过程会自然处理它,因为它可以比您插入记录的速度更快地存档记录。当然,如果您想立即存档这些行的大部分,您可以手动运行此存储过程(当作业未运行时),只需为@BatchSize和传入稍高的参数值@SecondsToRun

重要笔记:

  • 安排它通过 SQL Server 代理运行,可能每小时一次
  • 设置默认值@BatchSize@SecondsToRun匹配数据进入表的速度
  • 创建非聚集索引 dbo.AudLog ([XDATE] ASC)
  • 假设它XLOGNO在主AudLog表中,从XLOGNO此处 (in AudLog_Backup)的列中删除 IDENTITY 规范,因为该值来自主AudLog
  • DETAILS列的数据类型更改为VARCHAR(MAX):text自 SQL Server 2005 发布以来已被弃用,并且更难使用。

小注:

  • 运行此存储过程,通过SQL Server代理作业至少如果不还手动首先获得大吸盘行搬了过来,应该是较少的工作比交换表出来,没有一段时间,当AudLog表空的。
  • 如果没有要存档的内容,存储过程将简单地退出,因此每小时运行一次或每 2-3 小时运行一次(取决于新行进入的速度)不会有什么坏处。
  • 存储过程被限制在特定秒数后退出,因此如果它在主AudLog表上引起争用,它只会持续很短的时间。
  • OUTPUT子句将DELETEfrom 主AudLog表绑定INSERTAudLog_Backup事务中的表中,因此您无需担心这两个操作之间的进程失败或系统关闭/崩溃。
CREATE PROCEDURE dbo.AudLog_Archive
(
  @BatchSize INT = 2000, -- don't go above 3000 to avoid lock escalation
  @SecondsToRun INT = 180, -- run for 3 minutes
  @DaysToKeep INT = 185 -- archive rows older than 6 months
)
AS
SET NOCOUNT ON;

DECLARE @EndTime DATETIME = DATEADD(SECOND, @SecondsToRun, GETDATE()),
        @ArchiveDate DATETIME = DATEADD(DAY, @DaysToKeep * -1, GETDATE()),
        @RowsArchived INT = @BatchSize; -- initialize to be able to enter the loop


WHILE (@EndTime > GETDATE() AND @RowsArchived = @BatchSize)
BEGIN

    IF (EXISTS(
                 SELECT 1
                 FROM   dbo.AudLog al
                 WHERE  al.[XDATE] < @ArchiveDate
              )
        )
    BEGIN
        ;WITH batch AS
        (
            -- Keep this as SELECT * as it will alert you, via job failure, if
            -- you add columns to AudLog but forget to add them to AudLog_Backup
            SELECT  TOP (@BatchSize) al.*
            FROM    dbo.AudLog al
            WHERE   al.[XDATE] < @ArchiveDate
            ORDER BY al.[XDATE] ASC
        )
        DELETE b
        OUTPUT DELETED.* -- keep as * for same reason as noted above
        INTO   dbo.AudLog_Backup ([PVKEY], [DKEY], ...) -- specify all columns
        FROM   batch b

        SET @RowsArchived = @@ROWCOUNT;

        WAITFOR DELAY '00:00:01.000'; -- one second delay for breathing room
    END;
    ELSE
    BEGIN
        BREAK;
    END;
END;
Run Code Online (Sandbox Code Playgroud)