1

我有这个 SQL 查询,它每 5 秒查询一次数据库,以确定谁当前正在积极使用该软件。活动用户在过去 10 秒内对服务器进行了 ping 操作。(该表会根据用户活动正确更新,并且我有一个线程在会话超时时驱逐条目,一切正常)。

我正在寻找一种更有效/更快的方法来执行此操作,因为它被频繁调用,大约每 5 秒一次。此外,数据库中最多可能有 500 个用户。该语言是Java,但问题确实与任何语言有关。

List<String> r = new ArrayList<String>();
Calendar c =  Calendar.getInstance();
long threshold = c.get(Calendar.SECOND) + c.get(Calendar.MINUTE)*60 + c.get(Calendar.HOUR_OF_DAY)*60*60 - 10;

String tmpSql = "SELECT user_name, EXTRACT(HOUR FROM last_access_ts) as hour, EXTRACT(MINUTE FROM last_access_ts) as minute, EXTRACT(SECOND FROM last_access_ts) as second FROM user_sessions";
DBResult rs = DB.select(tmpSql);
for (int i=0; i<rs.size(); i++)
{
   Map<String, Object> result = rs.get(i);
   long hour = (Long)result.get("hour");
   long minute = (Long)result.get("minute");
   long second = (Long)result.get("second");
   if (hour*60*60 + minute*60 + second > threshold)
      r.add(result.get("user_name").toString());
}

return r;
4

6 回答 6

2

如果您希望它运行得更快,请在 上创建一个索引user_sessions(last_access_ts, user_name),并在查询中执行日期逻辑:

select user_name
from user_sessions
where last_access_ts >= now() - 5/(24*60*60);

这确实有一个缺点。您大概last_access_ts会经常更新该字段。该字段的索引也必须更新。积极的一面是,这是一个覆盖索引,因此索引本身可以满足查询,而无需求助于原始数据页。

于 2013-08-28T13:41:52.057 回答
0

只需让数据库使用以下查询为您进行比较:

    SELECT 
      user_name
    FROM user_sessions
    where TIMESTAMPDIFF(SECOND, last_access_ts, current_timestamp) > 10

完整示例:

List<String> r = new ArrayList<String>();
Calendar c =  Calendar.getInstance();
long threshold = c.get(Calendar.SECOND) + c.get(Calendar.MINUTE)*60 + c.get(Calendar.HOUR_OF_DAY)*60*60 - 10;
// this will return all users that were inactive for longer than 10 seconds
String tmpSql = "SELECT 
      user_name
    FROM user_sessions
    where TIMESTAMPDIFF(SECOND, last_access_ts, current_timestamp) > 10";
DBResult rs = DB.select(tmpSql);
for (int i=0; i<rs.size(); i++)
{
   Map<String, Object> result = rs.get(i);
   r.add(result.get("user_name").toString());
}

return r;

SQLFiddle

于 2013-08-28T13:43:40.197 回答
0

TimeDiff在您的选择中尝试 MySQL功能。这样,您可以只选择活动的结果,而无需进行任何其他计算。

链接:MySQL:如何以秒为单位获取两个时间戳之间的差异

于 2013-08-28T13:36:41.990 回答
0

我会将逻辑从 Java 移到 DB。这意味着您翻译ifwhere,并且只需选择有效结果的名称。

SELECT user_name FROM user_sessions WHERE last_access_ts > ?

在您的示例中,c表示当前时间。结果很可能为空。

因此,您的问题应该更多关于数据库上的日期时间操作。

于 2013-08-28T13:36:57.880 回答
0

解决方案是使用 where 子句从代码中删除逻辑到 sql 查询,以便仅从该选择中获取活动用户。

使用 sql 内置函数可以更快地获取更少的记录并减少代码中的迭代。

将此添加到您的 sql 查询中以仅获取活动用户:

Where TIMESTAMPDIFF(SECOND, last_access_ts, current_timestamp) > 10

这将为您提供日期在 10 秒之前或更早的所有记录。

于 2013-08-28T13:45:48.120 回答
0

如果我猜对了,那么您的user_sessions表中只有 500 个条目。在这种情况下,我什至不会关心索引。把它们丢掉。对于如此低的记录数,数据库引擎可能无论如何都不会使用它们。由于没有在每次记录更新时更新索引而获得的性能提升可能高于查询开销。

如果您关心数据库压力,则将查询/更新间隔延长至 1 分钟或更长(如果您的应用程序允许)。Gordon Linoff 的回答应该会给你最好的查询性能。

作为旁注(因为它以前曾咬过我):如果您不对所有用户回调使用相同的同步时间,那么您的“活跃用户逻辑”在设计上存在缺陷。

于 2013-08-28T14:14:52.353 回答