我有一个用于记录实验室访问数据的表。表结构如下:
create table accesslog
(
userid int not null,
direction int not null,
accesstime datetime not null
);
这个实验室只有一个处于访问控制之下的大门。所以用户必须先“进入”实验室,才能“离开”。在我的原始设计中,我将“方向”字段设置为 1(用于进入实验室)或 -1(用于离开实验室)的标志。这样我就可以使用如下查询:
SELECT SUM(direction) FROM accesslog;
获得实验室内的总用户数。从理论上讲,它有效;因为对于任何给定的用户 ID,“方向”将始终采用 1 => -1 => 1 => -1 的模式。
但是很快我发现日志消息会在从实验室门到服务器的传输路径中丢失,要么是由于网络繁忙,要么是硬件故障。当然我可以用序列号、ACK、重传、硬件冗余等来强制传输路径,但最后我可能还是会得到这样的东西:
userid direction accesstime
-------------------------------------
1 1 2013/01/03 08:30
1 -1 2013/01/03 09:20
1 1 2013/01/03 10:10
1 -1 2013/01/03 10:50
1 -1 2013/01/03 13:40
1 1 2013/01/03 18:00
这是用户“1”的最新日志。很明显,我丢失了该用户在 10:50 到 13:40 之间进入实验室的一条日志消息。我查询这个数据的时候,他还在实验室,所以2013/01/03 18:00之后还没有退出日志;这是肯定的。
我的问题是:有没有办法“发现”这些数据与 SQL 命令不一致?我的系统内总共有 5000 名用户,实验室 24 小时运行,没有这样的“神奇时间”可以清除实验室。如果我必须逐行、逐个地编写代码来检查“方向”字段的连续性,那我会很糟糕。
我知道不可能用正确的数据“修复”日志。我只想知道“哦,我有一个 userid=1 的数据不一致问题”,这样我就可以添加一个标记的修改数据来纠正最终的统计数据。
任何建议都将不胜感激,即使更改表结构也可以。
谢谢。
编辑:对不起,我没有提到细节。
目前我正在使用混合 SQL 解决方案。上表是 MySQL,它只包含 24 小时内的日志,作为快速浏览的“实时”状态。
每天凌晨 03:00 将启动在 POSIX 上用 C++ 编写的预先安排的进程。此过程将计算统计数据,并通过专有协议 TCP 套接字将每日统计数据添加到 Oracle DB,然后从 MySQL 中删除旧数据。
Oracle 部分不是我处理的,我对此无能为力。我只是想确保每一天的最终统计数据是正确的。
数据量约为每天 200,000 条记录——我知道这听起来很疯狂,但这是真的。