更有效的SQL查询方式?时间比较查询?

时间:2013-08-28 13:32:26

标签: java mysql sql

我有这个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;

6 个答案:

答案 0 :(得分: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字段。该字段的索引也必须更新。从积极的方面来说,这是一个覆盖索引,因此索引本身可以满足查询而无需求助于原始数据页。

答案 1 :(得分:0)

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

链接:MySQL: how to get the difference between two timestamps in seconds

答案 2 :(得分:0)

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

SELECT user_name FROM user_sessions WHERE last_access_ts > ?

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

所以你的问题应该是关于数据库的日期时间操作。

答案 3 :(得分: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

答案 4 :(得分:0)

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

使用sql内置函数获取更少的记录并在代码中迭代次数更快。

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

Where TIMESTAMPDIFF(SECOND, last_access_ts, current_timestamp) > 10

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

答案 5 :(得分:0)

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

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

作为旁注(因为它之前曾经咬过我):如果你没有对所有用户回调使用相同的同步时间,那么你的“活跃用户逻辑”就会因设计而有缺陷。