[英]Efficient SQL query to find gap in consecutive numeric data (MySQL)
我有一个包含“时间”列(INT 无符号)的表,每一行代表一秒钟,我需要及时找到间隔(丢失的秒数)。
我试过这个查询(在差距之前找到第一次):
SELECT t1.time
FROM `table` AS t1
LEFT JOIN `table` AS t2 ON t2.time=(t1.time+1)
WHERE t2.time IS NULL
ORDER BY TIME ASC
LIMIT 1
它有效,但对于大表(近 100M 行)来说太慢了
有没有更快的解决方案?
显示创建:
CREATE TABLE `candles` (
`time` int(10) unsigned NOT NULL,
`open` float unsigned NOT NULL,
`high` float unsigned NOT NULL,
`low` float unsigned NOT NULL,
`close` float unsigned NOT NULL,
`vb` int(10) unsigned NOT NULL,
`vs` int(10) unsigned NOT NULL,
`trades` int(10) unsigned NOT NULL,
PRIMARY KEY (`time`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
如果数据库版本为8.0
,则可以使用递归公用表表达式,例如
WITH RECURSIVE cte AS
(
SELECT 1 AS n
UNION ALL
SELECT n + 1 AS value
FROM cte
WHERE cte.n < (SELECT MAX(time) FROM tab )
)
SELECT n AS gaps
FROM cte
LEFT JOIN tab
ON n=time
WHERE cte.n > (SELECT MIN(time) FROM tab )
AND time IS NULL
在 MySQL 5.7 中,这是一个用户变量可能有用的用例:
select max(time)
from (
select t.time, @rn := @rn + 1 as rn
from (select time from mytable order by time) t
cross join (select @rn := 0) r
) t
group by time - rn
这将问题作为一个间隙和孤岛问题来解决。 这个想法是识别时间增量没有间隙(岛屿)的记录组。 为此,我们为每一行分配一个递增的 id,按时间排序; 每当time
和自动增量之间的差异发生变化时,您就会知道存在差距。
对于 mysql 8,您可以使用 LEAD():
select time from (
select time, lead(time, 1) over (order by time) next_time
from `table`
) t
where time+1 != next_time
在早期版本中,我可能会这样做:
select prev_time as time from (
select @prev_time+0 as prev_time,if(@prev_time:=time,time,time) as time
from (select @prev_time:=null) initvars
cross join (select time from `table` order by time) t
) t
where time != prev_time+1
两者都不会包括您的原始查询所包含的最长时间。
我认为 group by 需要将其视为严格的差距和岛屿问题,因为有那么多记录,代价太大了。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.