如何使用自定义规则 select 多个数据库行?
How to select many database rows using custom rule?
我目前有一个很大的 table(数百万行),其中包含两列:时间戳(毫秒)和值。
我希望能够以固定时间增量使用仪器的最新值在 PHP 中生成 CSV 文件。举个例子:
Table: data
timestamp value
50 1
700 2
1500 3
2100 4
3100 5
3900 6
假设固定时间增量为 1 秒(1000 毫秒),输出应如下所示:
timestamp value
1000 2
2000 3
3000 4
4000 6
我目前正在发出以下形式的许多查询:
SELECT * FROM `data` WHERE timestamp<=2000 ORDER BY `timestamp` DESC LIMIT 1
然后我将每一行输出到 php://output,用户的浏览器会在文件创建时下载它。然而,考虑到所有查询,这种首先生成数据的方法被证明过于缓慢。
我怎样才能加快这个过程?我想我可能应该将大部分处理移动到 MySQL 以减少进程间通信,但我不确定该怎么做。
我不知道这会有多高效,因为数学和没有索引,但您可以使用这样的查询:
select q1.nearest, q1.value
from
(select t,
if(mod(t, 1000), (floor(t/1000) + 1) * 1000, t) nearest,
if(mod(t, 1000), (floor(t/1000) + 1) * 1000, t) -t as diff,
value
from data
) q1
left join
(select t,
if(mod(t, 1000), (floor(t/1000) + 1) * 1000, t) nearest,
if(mod(t, 1000), (floor(t/1000) + 1) * 1000, t) -t as diff,
value
from data
) q2
on q1.nearest = q2.nearest
and q1.diff > q2.diff
where q2.diff is null
这里有演示 fiddle:http://sqlfiddle.com/#!9/5a199/13
请注意,这假设没有两个时间戳相同。
您希望最大时间戳的值等于或小于增量 1000 的倍数。您可以自动化您的过程:
select 1000 * ceil(lt.timestamp / 1000) as timestamp, value
from data lt
where not exists (select 1
from data lt2
where lt2.timestamp > lt.timestamp and
lt2.timestamp <= 1000 * ceil(lt.timestamp / 1000)
);
data(timestamp)
上的索引应该会有帮助。
您不能完全按照 MySQL 进行表述,因为 MySQL 在这些类型的子查询中不支持 limit
。
您也可以将每个时间戳四舍五入,然后得到每个四舍五入结果的最大时间戳。
SELECT
a.RoundedTimeStamp,
t.Value
FROM(SELECT
CEIL(TimeStamp/1000)*1000 as RoundedTimeStamp,
MAX(TimeStamp) as TimeStamp
FROM tablename
GROUP BY CEIL(TimeStamp/1000)*1000
) a
JOIN tablename t
ON t.TimeStamp = a.TimeStamp
我目前有一个很大的 table(数百万行),其中包含两列:时间戳(毫秒)和值。
我希望能够以固定时间增量使用仪器的最新值在 PHP 中生成 CSV 文件。举个例子:
Table: data
timestamp value
50 1
700 2
1500 3
2100 4
3100 5
3900 6
假设固定时间增量为 1 秒(1000 毫秒),输出应如下所示:
timestamp value
1000 2
2000 3
3000 4
4000 6
我目前正在发出以下形式的许多查询:
SELECT * FROM `data` WHERE timestamp<=2000 ORDER BY `timestamp` DESC LIMIT 1
然后我将每一行输出到 php://output,用户的浏览器会在文件创建时下载它。然而,考虑到所有查询,这种首先生成数据的方法被证明过于缓慢。
我怎样才能加快这个过程?我想我可能应该将大部分处理移动到 MySQL 以减少进程间通信,但我不确定该怎么做。
我不知道这会有多高效,因为数学和没有索引,但您可以使用这样的查询:
select q1.nearest, q1.value
from
(select t,
if(mod(t, 1000), (floor(t/1000) + 1) * 1000, t) nearest,
if(mod(t, 1000), (floor(t/1000) + 1) * 1000, t) -t as diff,
value
from data
) q1
left join
(select t,
if(mod(t, 1000), (floor(t/1000) + 1) * 1000, t) nearest,
if(mod(t, 1000), (floor(t/1000) + 1) * 1000, t) -t as diff,
value
from data
) q2
on q1.nearest = q2.nearest
and q1.diff > q2.diff
where q2.diff is null
这里有演示 fiddle:http://sqlfiddle.com/#!9/5a199/13
请注意,这假设没有两个时间戳相同。
您希望最大时间戳的值等于或小于增量 1000 的倍数。您可以自动化您的过程:
select 1000 * ceil(lt.timestamp / 1000) as timestamp, value
from data lt
where not exists (select 1
from data lt2
where lt2.timestamp > lt.timestamp and
lt2.timestamp <= 1000 * ceil(lt.timestamp / 1000)
);
data(timestamp)
上的索引应该会有帮助。
您不能完全按照 MySQL 进行表述,因为 MySQL 在这些类型的子查询中不支持 limit
。
您也可以将每个时间戳四舍五入,然后得到每个四舍五入结果的最大时间戳。
SELECT
a.RoundedTimeStamp,
t.Value
FROM(SELECT
CEIL(TimeStamp/1000)*1000 as RoundedTimeStamp,
MAX(TimeStamp) as TimeStamp
FROM tablename
GROUP BY CEIL(TimeStamp/1000)*1000
) a
JOIN tablename t
ON t.TimeStamp = a.TimeStamp