我有一个表,其中包含我正在编写的程序的日志条目。我正在寻找关于SQL查询的想法(我正在使用SQL Server Express 2005),它将保留最新的X数量的记录,并删除其余的。我有一个datetime列,它是日志条目的时间戳。
我认为以下内容可行,但我不确定IN子句对大量记录的性能。性能并不重要,但我可能会在第一时间做到最好。
DELETE FROM MyTable WHERE PrimaryKey NOT IN
(SELECT TOP 10,000 PrimaryKey FROM MyTable ORDER BY TimeStamp DESC)
我应该提一下,这个查询每天会运行3-4次(作为另一个进程的一部分),因此每个查询将删除的记录数量与将要记录的记录数量相比将会很小保持。
答案 0 :(得分:3)
试试这个:
DECLARE @X int
SELECT @X=COUNT(*) FROM MyTable
SET @X=@X-10000
DELETE MyTable
WHERE PrimaryKey IN (SELECT TOP(@x) PrimaryKey
FROM MyTable
ORDER BY TimeStamp ASC
)
取决于你是否删除少于10,000行,如果是这样,这可能会运行得更快,因为它标识要删除的行,而不是要保留的行。
答案 1 :(得分:2)
尝试此操作,使用CTE获取行序号,然后一次只删除X行数。您可以更改此变量以适合您的服务器。
添加ReadPast表提示应防止锁定。
DECLARE @numberToDelete INT;
DECLARE @ROWSTOKEEP INT;
SET @ROWSTOKEEP = 50000;
SET @numberToDelete =1000;
WHILE 1=1
BEGIN
WITH ROWSTODELETE AS
(
SELECT ROW_NUMBER() OVER(ORDER BY dtsTimeStamp DESC) rn,
*
FROM MyTable
)
DELETE TOP (@numberToDelete) FROM ROWSTODELETE WITH(READPAST)
WHERE rn>@ROWSTOKEEP;
IF @@ROWCOUNT=0
BREAK;
END;
答案 2 :(得分:1)
您拥有的查询效率高得多,并且可读。
NOT IN
和NOT EXISTS
比LEFT JOIN/IS NULL
更有效,但仅因为两列都不能为空。你可以read this link for a more in-depth comparison。
答案 3 :(得分:1)
DELETE FROM MyTable
WHERE TimeStamp < (SELECT min(TimeStamp)
FROM (SELECT TOP 10,000 TimeStamp
FROM MyTable
ORDER BY TimeStamp DESC))
或
DELETE FROM MyTable
WHERE TimeStamp < (SELECT min(TimeStamp)
FROM MyTable
WHERE PrimaryKey IN (SELECT TOP 10,000 TimeStamp
FROM MyTable
ORDER BY TimeStamp DESC))
不确定这些是否有效提升。
答案 4 :(得分:1)
这取决于你的场景(对你来说是否可行)以及你有多少行,但有一种可能更加优化的方法。
这显然需要更多考虑而不仅仅是删除行(例如,如果表有IDENTITY列,则需要在新表上设置等)。但是如果你有一个大表,那么将10,000行复制到一个新表然后删除原始表会更有效,而不是试图删除数百万行而只留下10,000个。