65.9K
CodeProject 正在变化。 阅读更多。
Home

文件管理的 SQL 自动清理基础

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2012 年 7 月 25 日

CPOL

5分钟阅读

viewsIcon

12641

本文将帮助您根据基本的文件管理原则来管理自动数据库清理。

引言

文件管理是所有企业,无论大小,最终都要处理的事情。但文件管理涵盖的范围不仅仅是企业生成的文档。每当企业在 SQL Server 中存储信息时,企业必须提供一种方法来严格遵守其文件管理程序。请注意,我说的是 **IT 必须提供方法,而不是制定规则**。有什么区别?IT 通常不拥有数据!

背景  

过去,DBA 使用各种方法从 SQL Server 中清理数据,但在许多情况下,DBA 只是为了保持数据库大小可管理。在我做自由职业者时,我经常看到一些数据非常陈旧,已经没有保存的意义了。在我为一家财富 500 强公司工作的日常工作中,这不仅仅是不可取的,而是不可接受的。数据最终对用户来说不再有意义,如果保留可能会对企业造成损害。

但是我们应该如何清理数据呢?如果您有一个小的 SQL Server,可能只有十几个数据库,按数据库创建 SQL 作业似乎是合理的。但如果数据所有者需要按表进行不同的清理呢? 这样您就会创建大量 SQL 作业,它们会使您的环境杂乱无章,并且在数据所有者想要更改清理设置时需要大量维护。当创建新数据库或表时又该怎么办? 通常是在编码过程中或临时进行的,并且抱着稍后返回设置清理的良好意愿。

使用代码

这是非常简单的代码,可以扩展到远远超出我目前提出的基本形式。我想保持简单,以便每个独特的环境都可以做自己想做的事情。也许您想添加一个前端网页,以便数据所有者可以更改自己的清理设置,或者添加一些额外的字段等。

第一步是创建两个新表来存储管理数据:

(请注意,我首先创建了一个新数据库“DataPurge”。我喜欢在我的服务器中进行分离)

USE [DataPurge]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

SET ANSI_PADDING ON
GO

CREATE TABLE [dbo].[DataPurgeHistory](
	[DBName] [varchar](50) NOT NULL,
	[TableName] [varchar](50) NOT NULL,
	[DateStamp] [datetime] NULL,
	[PurgeNeeded] [bit] NOT NULL,
	[NewTable] [bit] NOT NULL,
	[YearsToKeep] [int] NULL,
	[PurgeField] [varchar](50) NULL,
 CONSTRAINT [PK_DataPurgeHistory] PRIMARY KEY CLUSTERED 
(
	[DBName] ASC,
	[TableName] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, 
       ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

SET ANSI_PADDING OFF
GO

ALTER TABLE [dbo].[DataPurgeHistory] ADD CONSTRAINT [DF_DataPurgeHistory_PurgeNeeded]  DEFAULT ((0)) FOR [PurgeNeeded]
GO

ALTER TABLE [dbo].[DataPurgeHistory] ADD CONSTRAINT [DF_DataPurgeHistory_NewTable]  DEFAULT ((1)) FOR [NewTable]
GO  

这个表将用于实际存储清理数据。日期戳仅用于让我们知道最后一次清理该表的时间。PurgeNeeded 可以设置为 0,这样作业就不会清理选定的表。NewTable 用于告知我们需要为哪些表设置清理选择。YearsToKeep 是一个非常简单的年份偏移量,用于根据 PurgeField 删除数据。

USE [DataPurge]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

SET ANSI_PADDING ON
GO

CREATE TABLE [dbo].[DBTables](
	[DBName] [varchar](50) NULL,
	[TableName] [varchar](50) NULL
) ON [PRIMARY]

GO

SET ANSI_PADDING OFF
GO 

这个表只是保留了此服务器内所有表的列表。

在实际作业之前,我们还必须在创建的两个表所在的数据库中设置一个视图,它将用于帮助我们向清理列表中添加新表。

USE [DataPurge]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE VIEW [dbo].[vwNewDBTable]
AS
SELECT     TOP (100) PERCENT dbo.DBTables.DBName, dbo.DBTables.TableName, dbo.DataPurgeHistory.DBName AS DBName2, 
                      dbo.DataPurgeHistory.TableName AS TableName2
FROM         dbo.DBTables LEFT OUTER JOIN
                      dbo.DataPurgeHistory ON dbo.DataPurgeHistory.DBName = dbo.DBTables.DBName 
                      AND dbo.DBTables.TableName = dbo.DataPurgeHistory.TableName
WHERE     (dbo.DataPurgeHistory.DBName IS NULL)
ORDER BY dbo.DBTables.DBName, dbo.DBTables.TableName

GO

现在我们已经设置好了一切,我们需要创建两个作业。第一个作业将检查已创建的任何新数据库和/或表。我将其设置为每天运行一次,但您可以根据需要创建任何适合您的计划。这是一个简单的作业,只有一个 T-SQL 步骤。

SET NOCOUNT ON 

Delete from DataPurge.dbo.DBTables

DECLARE @AllTables table (DbName sysname,SchemaName sysname, TableName sysname) 
DECLARE 
     @SearchDb nvarchar(200) 
    ,@SearchSchema nvarchar(200) 
    ,@SearchTable nvarchar(200) 
    ,@SQL nvarchar(4000) 
SET @SearchDb=''%'' 
SET @SearchSchema=''%'' 
SET @SearchTable=''%Account%'' 
SET @SQL=''select ''''?'''' as DbName, t.name as TableName from [?].sys.tables t inner 
    join sys.schemas s on t.schema_id=s.schema_id WHERE ''''?'''' not in 
    (''''master'''',''''tempdb'''',''''model'''',''''msdb'''') AND s.name LIKE ''''''+@SearchSchema+''''''''
 
INSERT INTO DataPurge.dbo.DBTables (DbName, TableName) 
    EXEC sp_msforeachdb @SQL 
    
Insert into DataPurge.dbo.DataPurgeHistory (DBName, TableName)
	Select DBNAme,TableName from DataPurge.dbo.vwNewDBTable

下一个作业将根据我们之前创建的 DataPurgeHistory 表中的设置实际执行清理。同样,我将其设置为每天运行一次,但根据您的环境,您可以根据有意义的任何计划运行它。这个作业也只有一个步骤。

SET NOCOUNT ON 

DECLARE 
     @DbName nvarchar(200) 
    ,@Schema nvarchar(200) 
    ,@TableName nvarchar(200) 
    ,@PurgeField nvarchar(200) 
    ,@YearsToKeep nvarchar(200) 
    ,@SQL nvarchar(4000) 

Declare c Cursor For Select DBName,TableName,PurgeField,YearsToKeep from 
   DataPurge.dbo.DataPurgeHistory where PurgeNeeded = 1 and YearsToKeep is not null and PurgeField is not null
Open c 
 
Fetch next From c into @DBName,@TableName,@PurgeField,@YearsToKeep;
 Set @Schema=''dbo'';
 
While @@Fetch_Status=0 Begin 
      
SET @SQL=''Delete From '' + @DbName + ''.'' + @Schema + ''.'' + @TableName + '' where '' + 
          @PurgeField + '' < dateadd(year, -'' + @YearsToKeep + '', getdate());
			Update DataPurge.dbo.DataPurgeHistory set DateStamp = getdate() where 
			DBName = '''''' + @DBNAme + '''''' and TableName ='''''' + @TableName +'''''';''
 
     EXEC (@SQL )
   
   Fetch next From c into @DBName,@TableName,@PurgeField,@YearsToKeep; 
End 
 
Close c 
Deallocate c

是的,您可以将这些作业设置为一个包含两个步骤的作业,但我将它们分开,以便最终我们可以让它们在不同的计划中运行。

 那么它是如何工作的?  首先,第一个作业运行并获取所有新的数据库和表。这样您就可以为该数据库和表分配一个清理字段。接下来,您输入要保留的年数。最后,您需要将 PurgeNeeded 更改为 1,将 NewTable 更改为 0。这个作业的工作方式是,它只会清理包含所有必需信息且 PurgeNeeded 设置为 1 的行。

 这样,如果需要,您可以出于法律行动等原因暂停某些信息。您还可以简单地不清理包含静态数据的表(例如网页下拉菜单的信息)。

 当您的作业运行时,它将逐行浏览 DataPurgeHistory 表并根据请求清理数据。

兴趣点 

这段代码并不复杂,也易于重现/更改。根据您的环境,您或您的公司应该更改许多内容。一些例子:

  • 我们的一些表不默认为 dbo,对于包含这些表的服务器,我们将 Schema 添加到了 Table Checker 的一部分。
  • 我们添加了一些描述字段,以便数据所有者可以进行注释。
  • 我们有前端网页,允许数据所有者根据预定的文件管理指南选择他们的清理设置。
  • 网页包含一个下拉菜单,其中列出了所有可能的 datetime 字段,这些字段可用作所选表内的清理字段。
  • 我们的一些表需要清理,而不是基于年数,因此我们添加了一个字段来告诉我们“ToKeep”列是基于什么(例如天、周、月或年)。

有很多方法可以扩展这个非常基础的清理框架。

© . All rights reserved.