【发布时间】:2013-01-04 23:02:33
【问题描述】:
基本上,我尝试的结果是:“获取过去一定时间内有 0 个不成功 记录的 成功 记录的数量”。 “成功”和“不成功”只是指列的值。
虽然有点复杂,但这里是我正在处理的表的描述:
`log`
id int PRIMARY KEY AUTO_INCREMENT
fingerprint_id int (foreign key)
status boolean
date timestamp
我们的小系统的工作流程是,当用户刷指纹时,会在这个表中添加一条记录,并根据是否匹配设置status(再次,还有更多,我只是试图简化)。我们会根据用户执行此操作得到fingerprint_id,因此这是用于将记录与人员相关联的标识符。
目前,我们要求他们最多尝试 3 次。因此,他们可以在 3 之 1、3 之 2、3 之 3 或根本不匹配。这意味着他们的“组”中可以有 1、2 或 3 条记录。虽然这不是真的,但我们可以假设用户将继续尝试,直到匹配或达到 3 次失败尝试(我们发现有时人们可能会在失败一两次后不再继续)。
以下是一些数据的示例:
id fp_id status date
----------------------------------------
20 2 0 '2013-01-21 12:30:01'
21 2 0 '2013-01-21 12:30:05'
22 2 0 '2013-01-21 12:30:10'
23 9 1 '2013-01-21 12:31:30'
24 1 0 '2013-01-21 12:35:00'
25 1 1 '2013-01-21 12:35:05'
在数据中,用户 (fingerprint_id) 2 尝试了 3 次,从未匹配。用户 9 第一次尝试匹配。用户 1 尝试一次失败,然后再次尝试匹配。
关键是找出35秒前有多少成功(status=1)的日志记录有0个不成功(status=0)的记录。当然,“连接”它们的唯一方法是通过fingerprint_id。
再一次,我们假设了很多事情,但这没关系。
这是我的尝试:
SELECT COUNT(*)
FROM log AS log_main
WHERE log_main.status=1 AND
(SELECT COUNT(*)
FROM log AS log_inner
WHERE log_inner.fingerprint_id=log_main.fingerprint_id AND
log_inner.status=0 AND
log_inner.date<log_main.date AND log_inner.date>=(log_main.date - INTERVAL 35 SECOND))=0
^ 我希望这个选择所有成功的记录,这些记录在 35 秒前(对于该用户)内发生的不成功记录计数为 0。但我不知道,因为查询需要 600 多秒。我刚刚发现了如何延长 MySQL Workbench 的最大超时时间,但无论哪种方式,都需要很长时间。该表总共有大约 120,000 条记录,所以我不确定这是否足以让这个查询变得如此缓慢。
无论如何,这是另一个尝试:
SELECT COUNT(*)
FROM (SELECT log.fingerprint_id, log.date
FROM log
WHERE log.status=1) successful,
(SELECT log.fingerprint_id, log.date
FROM log
WHERE log.status=0) unsuccessful
WHERE successful.fingerprint_id=unsuccessful.fingerprint_id AND
unsuccessful.date<successful.date AND unsuccessful.date>=(successful.date - INTERVAL 35 SECOND)
^ 我觉得这个更接近,但当然,没有比较过去匹配多少记录的“计数”。这就是我对如何解决感到困惑的部分。我感觉它与GROUP BY 或使用IN 有关,但我所做的似乎不起作用(从某种意义上说,它超过了 600 秒或类似的时间)。这是我用GROUP BY尝试过的一个例子
SELECT successful.id, COUNT(*) cnt
FROM (SELECT log.fingerprint_id, log.date, log.id
FROM log
WHERE log.status=1) successful,
(SELECT log.fingerprint_id, log.date, log.id
FROM log
WHERE log.status=0) unsuccessful
WHERE successful.fingerprint_id=unsuccessful.fingerprint_id AND
unsuccessful.date<successful.date AND unsuccessful.date>=(successful.date - INTERVAL 35 SECOND)
GROUP BY successful.id
^ 但结果仅包含计数不为 0 的行。我猜这是因为WHERE 子句。但我只需要 0 个计数。
我尝试了这么多组合,我觉得我的大脑只是炸了。
【问题讨论】:
-
一点:关于运行了这么长时间的查询,你有没有索引你需要这些查询有机会执行ok?
-
@DWright 我感觉可能是个问题。不幸的是,我们没有。巧合的是,我是不久前加入团队时决定开始清理数据库的人,并且已经准备好添加索引的查询。问题是我正在生产服务器(数据真正重要的地方)上测试这些查询,并且宁愿等到今晚的一些停机时间来修改表。对我来说,索引在
fingerprint_id和date列上很有意义。那可能是对的吗?