实现环形缓冲区

时间:2014-03-28 11:31:05

标签: sql sql-server tsql ssms

我们有一个表记录数据。它以每秒15K行的速度记录。

问题:我们如何将表格大小限制在10亿个最新行?

即。一旦达到1bn行,它就变成一个环形缓冲区,在添加最新的行时删除最旧的行。

触发器可能会加载系统太多。 Here's SO上的触发示例。 我们已经在使用一堆调整来保持加速(例如存储过程,表参数等)。

5 个答案:

答案 0 :(得分:2)

除非有大约10亿的魔法,否则我认为你应该考虑其他方法。

首先想到的是对数据进行分区。比如说,将一小时的数据放入每个分区。这将导致分区中大约15,000 * 60 * 60 = 5400万条记录。大约每20个小时,您可以删除一个分区。

分区的一大优势是插入性能应该很好,并且您不必删除单个记录。根据查询负载,索引和其他因素,可能会有额外的开销。但是,由于没有额外的索引和主要是插入的查询负载,它应该比尝试每秒删除15,000条记录以及插入更好地解决您的问题。

答案 1 :(得分:0)

这是我的建议:

  • 使用1,000,000,000行预填充表,包括行号作为主键。
  • 让记录器保留一个每次递增的计数器变量,而不是insert新的行,并根据行号update相应的行。

这实际上是你在其他环境中使用环形缓冲区的方法。你不会继续分配内存和删除;你只是一遍又一遍地覆盖同一个数组。

更新:更新doesn't actually change the data in place,正如我所想的那样。所以这可能效率不高。

答案 2 :(得分:0)

我没有完整的答案,但希望有一些想法可以帮助你开始。

我会在表格中添加某种数字列。此值将增加1,直到达到要保留的行数。此时,该过程将切换到update语句,覆盖前一行而不是插入新行。您显然无法使用此列来确定行的顺序,因此如果您还没有,我还会添加一个时间戳列,以便您可以按时间顺序对它们进行排序。

为了协调跨事务的计数器值,您可以使用序列,然后执行模除法以获得计数器值。

为了处理表中的任何空白(例如有人删除了某些行),您可能需要使用merge语句。如果行丢失则应执行插入,如果存在则执行更新。

希望这有帮助。

答案 3 :(得分:0)

只是想在评论中写一个复杂的想法。

创建一些日志表,例如3,Log1,Log2,Log3

CREATE TABLE Log1 (
    Id int NOT NULL
        CHECK (Id BETWEEN 0 AND 9)
   ,Message varchar(10) NOT NULL
   ,CONSTRAINT [PK_Log1] PRIMARY KEY CLUSTERED ([Id] ASC) ON [PRIMARY]
)
CREATE TABLE Log2 (
    Id int NOT NULL
        CHECK (Id BETWEEN 10 AND 19)
   ,Message varchar(10) NOT NULL
   ,CONSTRAINT [PK_Log2] PRIMARY KEY CLUSTERED ([Id] ASC) ON [PRIMARY]
)
CREATE TABLE Log3 (
    Id int NOT NULL
        CHECK (Id BETWEEN 20 AND 29)
   ,Message varchar(10) NOT NULL
   ,CONSTRAINT [PK_Log3] PRIMARY KEY CLUSTERED ([Id] ASC) ON [PRIMARY]
)

然后创建分区视图

CREATE VIEW LogView AS (
    SELECT * FROM Log1
  UNION ALL
    SELECT * FROM Log2
  UNION ALL
    SELECT * FROM Log3
)

如果您使用的是SQL2012,则可以使用序列

CREATE SEQUENCE LogSequence AS int 
    START WITH 0
    INCREMENT BY 1
    MINVALUE 0
    MAXVALUE 29
    CYCLE
;

然后开始插入值

INSERT INTO LogView (Id, Message)
SELECT NEXT VALUE FOR LogSequence
      ,'SomeMessage'

现在你只需要在某种时间表上截断日志表

如果您没有sql2012,则需要以其他方式创建序列

答案 4 :(得分:0)

我自己正在寻找类似的东西(使用表作为循环缓冲区)但似乎更简单的方法(对我来说)只是定期删除旧条目(例如最低的 ID 或最低的创建/上次修改日期时间或超过一定年龄的条目)。它不是一个循环缓冲区,但对于某些人来说,它可能是一个足够接近的近似值。 ;)