如何限制我的SQL数据库中的行数,然后在达到限制时覆盖一行?

问题描述 投票:2回答:3

我正在使用带有C#的SQL数据库来存储事件。我的名字是TabOfEvents;它包含事件的代码以及此事件的日期和时间。

CREATE TABLE [dbo].[TabOfEvents] (
    [Id] INT IDENTITY (1, 1) NOT NULL,
    [cta] NCHAR (10) NOT NULL,
    [code] NVARCHAR (MAX) NOT NULL,
    [date] DATETIME2 (7) NULL,
    PRIMARY KEY CLUSTERED ([Id] ASC)
)

每次事件发生时,我都会将它保存在我的表中,按日期排序(从最新到最旧)。

我想限制我的数据库中的行数说100.000行,(或者我的数据库的大小说300Mo,例如,但如果可能的话,我不确定这一行)当达到限制数时,我想要覆盖最旧的事件并用新事件替换它们。

我怎么能用C#做到这一点?

c# sql sql-server database limit
3个回答
0
投票

你可以使用sequenceCYCLE选项作为用作ring buffer的表中的指针。这会在数据库中创建一个序列对象:

CREATE SEQUENCE BufferPtr  
    START WITH 1
    MINVALUE 1
    MAXVALUE 100000
    CYCLE;

以不同方式创建表以允许空条目并允许输入ID

CREATE TABLE dbo.TabOfEvents (
    [Id] INT NOT NULL,
    [cta] NCHAR (10) NULL,
    [code] NVARCHAR (MAX) NULL,
    [date] DATETIME2 (7) NULL,
    PRIMARY KEY CLUSTERED ([Id] ASC)
)

然后用100000个空记录和Ids 1 ... 100000填充表格。我们这样做是为了事先知道记录的数量并保存自己的查询。即,我们不必查询SELECT COUNT (*) FROM TabOfEvents的记录数量,以了解我们是否必须进行插入或更新。序列在UPDATE命令本身中用于确定我们更新的记录。每次生成一个新的序列号,在达到极限100,000后,序列从1开始。

-- This creates 100000 empty records with an Id. The code is quite tricky and I won't explain
-- the details here. If you prefer, create a stored procedure with a FOR-loop or do it in an
-- external application (e.g. C# Console app). Performance is not important, since we are
-- doing it only once.

;WITH e1(n) AS
(
    SELECT 1 FROM (VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(0)) t(n)
)
INSERT INTO dbo.TabOfEvents (Id)
SELECT ROW_NUMBER() OVER (ORDER BY n10.n) AS n
FROM
e1 n10
CROSS JOIN e1 n100
CROSS JOIN e1 n1000
CROSS JOIN e1 n10000
CROSS JOIN e1 n100000

现在设置表和序列,您可以使用更新记录

UPDATE TabOfEvents
SET cta = 'test', code = 'xxx', [date] = SYSDATETIME()
FROM
    TabOfEvents
    INNER JOIN
    (SELECT
        NEXT VALUE FOR BufferPtr AS Ptr
        FROM (VALUES (1)) t(n)
    ) a
    ON TabOfEvents.Id = a.Ptr;

你可以在这里看到一个测试(http://sqlfiddle.com/#!6/2679e/5/2)只使用4条记录。单击“重复运行SQL”,您将看到如何在循环中添加事件。

注意:我的第一次尝试是使用UPDATE TabOfEvents SET cta = 'test', code = 'xxx', [date] = SYSDATETIME() WHERE Id = NEXT VALUE FOR BufferPtr,但SQL-Server拒绝查询WHERE子句中的序列。我的UPDATE语句可以简化吗?


2
投票

不要这样做。你可以这样做:

  • 为您的数据和事件制定保留政策和/或存档政策。例如,您可以存档或删除超过x个月或几天的事件。您可以将它们存档在不同的表/或不同的数据库中。要么,
  • 您可以在应用程序的业务层上放置规则,以了解允许的事件数量。这样,您可以按照自己喜欢的方式控制和限制事件和数据。

因此对于第二个选项,最大事件计数可以存储在数据库中的配置表或配置文件(在app.config或web.config)中。如果你在网上搜索,你可以找到how to read and write in config file

然后在执行插入之前的应用程序中,从数据库中获取事件的计数,如:

SELECT COUNT(*) FROM events;

然后将此结果与web.config中的值进行比较。如果值> =最大值,则拒绝带有错误消息的插入,否则执行插入操作。


0
投票

您可以使用触发器执行此操作。但是,它可能没有必要。

删除表中的行不会自动回收空间。数据库表的工作方式与文件的工作方式不同。由于日志记录,锁定和索引重组,删除行也可能是(相对)耗时的操作。

从性能角度来看,设计良好的数据库应该可以轻松处理数百万行数据 - 对于许多常见类型的查询。

如果您确实想限制表的大小,我建议使用分区方案。然后使用预定作业删除旧分区。删除分区比删除单个行更有效。而且,从丢弃的分区中恢复空间是微不足道的。

© www.soinside.com 2019 - 2024. All rights reserved.