使用 UPDATE 或 INSERT INTO 时自动增加 Firebird 字段值

Auto-incrementing a Firebird field value when using UPDATE OR INSERT INTO

我已经成为 Delphi 程序员 25 年了,但直到现在才设法避免 SQL。当时我是一名 dBase 专家。我在 Windows 服务器 2012 机器上使用 Firebird 3.0 SuperServer 作为服务。我 运行 在 Delphi 2007 年编写的 UDP 侦听器服务,用于从我们发布的软件产品接收状态信息。

FB 数据库相当简单。我使用用户的 IP 地址作为主键并在他们进来时记录报告。我目前每天收到大约 150,000 份报告,他们记录在一个文本文件中。

我不想将每个报告都插入到 table 中,而是想在单个记录中增加一个整数值,每个 IP 地址收到的报告总数为“运行ning”。它将节省大量数据。

table 包含 IP 地址(主键)、LastSeen(时间戳)和 Hits(整数)字段。还有一些其他字段,但它们并不重要。

我在收到报告时使用 UPDATE OR INSERT INTO。如果 IP 地址不存在,则插入一个新行。如果确实存在,则更新记录。

我希望它在我每次收到报告时将“点击”字段增加 +1。换句话说,如果“Hits”已经 = 1,那么我想将更新时的 inc(Hits) 增加到 2。依此类推。基本上,“点击”字段将是一个 IP 地址发送报告的总次数 运行。

每月添加 300 万行只是为了获得特定 IP 地址的 COUNT 似乎根本没有效率!

有办法吗?

UPDATE OR INSERT statement is not suitable for this, as you need to specify the values to update or insert, so you will end up with the same value for both the insert and the update. You could address this by creating a before insert trigger that will always assign 1 to the field that holds the count (ignoring the value provided by the statement for the insert), but it is probably better to use MERGE,因为它可以让您更好地控制结果操作。

例如:

merge into user_stats
  using (
    select '127.0.0.1' as ipaddress, timestamp '2021-05-30 17:38' as lastseen 
    from rdb$database
  ) as src
  on user_stats.ipaddress = src.ipaddress
when matched then 
  update set 
    user_stats.hits = user_stats.hits + 1, 
    user_stats.lastseen = max_value(user_stats.lastseen , src.lastseen)
when not matched then
  insert (ipaddress, hits, lastseen) values (src.ipaddress, 1, src.lastseen)

但是,如果您为同一个 IP 地址获得大量更新,并且这些更新是同时处理的,则由于更新冲突,这很容易出错。您可以通过插入单独的命中来解决这个问题,然后有一个后台进程将这些记录汇总到一个记录中(例如每天)。

另请记住,只有一条记录会消除执行更多分析的可能性(例如命中分布、第 X 天或某个时间 HH:mm 等的命中数)。