【问题标题】:Most efficient way to sustain a maximum number of entries in SQL Server database table在 SQL Server 数据库表中维持最大条目数的最有效方法
【发布时间】:2015-08-20 04:15:12
【问题描述】:

我想知道,执行以下操作最有效的方法是什么?

我正在尝试实现某种审核系统,其中每次登录到我的页面都将存储在数据库中。我使用 SQL Server 2005 数据库。存储审计数据的表显然不能无上限地增长。因此,比如说,它最多应该有 1000 个条目,然后在插入新条目时必须删除任何旧条目。问题是您如何以最有效的方式执行此操作 - 我是否需要添加任何特殊列,例如,为了更容易清理的序号条目?

编辑: 说,如果我的表的结构是(伪代码):

`id` BIGINT autoincrement
`date` DATETIME
`data1` NVARCHAR(256)
`data2` INT

你会如何编写这个清理程序?

【问题讨论】:

  • 固定数量的记录,每条记录的大小固定,听起来像一个循环队列。在这种情况下,每个“插入”实际上都可能是基于序列模数的更新(如果您预先填充,或者如果不是,则合并/更新插入)。即更新audit_table set date=..., data1=..., data2=... 其中id = sequence%1000。日期索引仍然很忙。也许有点激进而且不是很数据库化。我自己没有这样做。我倾向于对旧数据进行分区和修剪。或者对于使用带有滚动日志文件的操作系统日志记录,可以通过外部表(Oracle 世界)查看的活动。

标签: sql sql-server sql-delete


【解决方案1】:

正如托尼所说,使用日期来识别插入内容。另外,在日期字段上使用聚集索引,使插入始终在表的末尾,并且可以轻松高效地扫描和删除旧行。

如果你使用一个数字,这样的事情应该可以工作:

DELETE FROM myTable WHERE someField < (SELECT MAX(someField) - 1000 FROM myTable)

对于某个日期,删除超过一天的所有内容类似于:

DELETE FROM myTable WHERE someField < DateAdd('d', -1, getdate())

【讨论】:

  • 但是如果我按日期执行,我如何保持固定数量的条目(我的问题是 1000 个)?
  • 您可以使用数字。日期更有效只是因为它们可以在客户端计算,而不是需要增量列的(诚然非常小的)开销
  • 尽管如此,您仍然希望在代表排序的任何列上使用聚集索引
  • 对不起,我不太懂SQL,能详细点吗?我用数据结构编辑了我的原始帖子。
  • 在这种情况下 max 需要一个查询,并且 dateadd 它只被调用一次。后者效率更高。
【解决方案2】:

按日期而不是数字。看看你的统计数据,看看 1000 是多少天/将是多少天。删除任何比这更旧的东西。审计从来都不是特别有效,但如果你有大量的数据对你没有帮助,那就太低效了......

【讨论】:

  • 您的意思是按日期排序可能比按 BIGINT 自动增量字段排序更有效?
  • 排序实际上是无关紧要的,因为你有一个索引。一段损坏的代码和你最后的 1000 条记录可能都属于一个人。最后 1000 个太简单了,除非你很幸运,否则我会更舒服地说每个用户至少 1 次(月?)登录。
【解决方案3】:

如果我了解您的需求,这应该可以。我已经在 SQL 2008R2 上对其进行了测试,但我看不出它不能在 SQL Server 2005 上运行的任何原因。

  1. 使用登录触发器在审计表中插入一行。

  2. 在您的审计表上创建一个 AFTER INSERT 触发器,以删除具有 MIN(ID) 的行。

这里有一些代码可以玩:

/* 创建审计表 */

CREATE TABLE ServerLogonHistory
(SystemUser VARCHAR(512),
ID BIGINT,
DBUser VARCHAR(512),
SPID INT,
LogonTime DATETIME)
GO

/* 创建登录触发器 */

CREATE TRIGGER Tr_ServerLogon
ON ALL SERVER FOR LOGON
AS
BEGIN
INSERT INTO TestDB.dbo.ServerLogonHistory
SELECT SYSTEM_USER, MAX(ID)+1 , USER,@@SPID,GETDATE()
FROM TestDB.dbo.ServerLogonHistory;
END
GO 

/* 创建清理触发器 */

CREATE TRIGGER AfterLogin
ON TestDB.dbo.ServerLogonHistory
AFTER INSERT
AS
DELETE 
FROM TestDB.dbo.ServerLogonHistory 
WHERE ID = 
(SELECT MIN(ID) FROM TestDB.dbo.ServerLogonHistory);
GO;

一句警告。如果您创建了无效的登录触发器,您将无法登录到数据库。但不要惊慌!这都是学习的一部分。您将能够使用“sqlcmd”删除错误的触发器。

我确实尝试在登录触发器中删除具有最小 ID 的行,但我无法让它工作。

【讨论】:

  • 当然,一旦审核表包含您需要/想要的行数,您就可以创建清理触发器。然后到那时,只要插入一行,最旧的行就会被删除。
  • @ahmd0 - 我可能建议了一个比您需要的更复杂的解决方案。我在想你需要记录对数据库本身的登录。现在我看到您可能正在考虑登录您的网站。如果是后者,则无需登录触发器。如果您的审计表正在工作并捕获您需要的内容,则在表上创建“清理”触发器。触发器将为插入的每个新行删除一行。
【解决方案4】:

“ID”列是第 1 步的身份列吗?

插入一行后

删除id

【讨论】:

  • 有趣,谢谢。我假设 IDENTITY_CURRENT 是一些不涉及任何选择的内部变量,对吧?
  • IDENTITY_CURRENT 将返回您的表的标识列的最新值。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-21
  • 2010-12-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多