我可以定期检查当前在线的用户列表。我想把它变成有用的东西,比如每个用户登录/注销时间的条目列表。除了检查当前在线的用户之外,没有其他方法可以确定这些信息
经过一番思考,我想出了这样的东西:
CREATE TABLE onlineActivity (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
name CHAR (32) NOT NULL,
login_time DATETIME NOT NULL,
logout_time DATETIME NOT NULL,
time SMALLINT (3) NOT NULL DEFAULT 0,
online BOOL DEFAULT NULL,
UNIQUE (name, online),
PRIMARY KEY (id)
) ENGINE = MyISAM;
我每隔几分钟运行一次这个查询,以在活动列表中添加/更新名称:
INSERT INTO onlineActivity (name, login_time, logout_time, online)
SELECT name, now(), now(), true FROM onlineList ON DUPLICATE KEY UPDATE logout_time = now()
此查询针对每个已注销的用户运行:
(名称是通过比较两个相邻的在线列表来确定的,即当前列表和上一个列表)
UPDATE onlineActivity SET online = NULL WHERE name = ? AND online = 1
问题:
- 我担心在UNIQUE索引中使用NULL字段(
online
)是个坏主意,会影响性能。我认为MySQL可能必须对每个名称的所有online
进行完全扫描(而不是使用索引),才能找到一个不为NULL的名称。有人能澄清一下这里的情况吗?我找不到任何关于MySQL如何处理这种情况的信息 - 其他数据库系统(PostgreSQL、SQLite)在这方面的表现是否与MySQL不同
- 我是否应该代替第一个查询,为每个名称运行两个查询,以查看指定的用户当前是否在线,并相应地采取行动
- 我之所以想到这个设计,是因为我想尽量减少使用的查询量,这本身就是一个有缺陷的想法吗
- 该表每天将获得约30万至50万张新记录。我还能做些什么来减少性能下降吗
我想存储用户活动的完整历史记录,而不是一个条目。
我不知道为什么你有一个唯一的名字和在线,因为你试图做的是创建一个在线活动列表。按照您指定的方式放置一个唯一的键意味着您只能在其中有一个名称三次,每个状态一次(null、true、false)。
您正在有效地创建一个历史记录表,在这种情况下,要使用当前的填充方法,您应该在表上放置一个唯一的键(name,logout_time),其中null logout_time表示当前登录的用户(因为您只希望有一个注销时间为null)。
类似这样的东西:
CREATE TABLE onlineActivity (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
name CHAR (32) NOT NULL,
login_time DATETIME NOT NULL,
logout_time DATETIME NULL,
time SMALLINT (3) NOT NULL DEFAULT 0,
online BOOL not null DEFAULT false,
UNIQUE (name, logout_time),
PRIMARY KEY (id)
) ENGINE = MyISAM;
然后按计划运行以更新表
INSERT IGNORE INTO onlineActivity (name, login_time, logout_time, online)
SELECT name, now(), null, true FROM onlineList
用户注销时
UPDATE onlineActivity SET online = false, logout_time = now() WHERE name = ? AND logout_time = null