我的表中有数十亿行 4k 可变参数,我需要获取其中 500 个参数的最后一个值 我的表按天分区并按参数 id 排序,所以我只需要找到具有所需 id 的最后一条记录
SELECT max(time)
FROM obj_ntgres.param_values_history
PREWHERE param_id = 4171
Run Code Online (Sandbox Code Playgroud)
工作慢:经过:0.437 秒。处理 256 万行,5.21 MB(587 万行/秒,11.92 MB/秒)
SELECT *
FROM obj_ntgres.param_values_history
PREWHERE param_id = 4171
ORDER BY time DESC
LIMIT 1
Run Code Online (Sandbox Code Playgroud)
较慢:集合中有 1 行。经过:3.413 秒。处理 256 万行,5.45 MB(75121 万行/秒,1.60 MB/秒)
桌子
CREATE TABLE obj_ntgres.param_values_history (
time DateTime,
param_id UInt16,
param_value Float32,
param_value_quality Decimal(1, 0),
msec Decimal(3, 0)
) ENGINE = MergeTree PARTITION BY toStartOfDay(time)
ORDER BY
param_id SETTINGS index_granularity = 8192
Run Code Online (Sandbox Code Playgroud)
也许您有一些想法如何让它更快?
我的意思是:在所有表上不使用 max() 找到最后一个元素
实际上,它仍然需要使用相同的方法扫描相当多的数据param_id。
可能的方法很少。在所有情况下,一开始您都需要将time列添加到表排序键:
CREATE TABLE param_values_history (
time DateTime,
param_id UInt16,
param_value Float32,
param_value_quality Decimal(1, 0),
msec Decimal(3, 0)
) ENGINE = MergeTree PARTITION BY toStartOfDay(time)
ORDER BY
(param_id,time) SETTINGS index_granularity = 8192
Run Code Online (Sandbox Code Playgroud)
之后 - 如果您的数据是时间对齐的,即如果您确切地知道所有 500 个参数在过去几秒/分钟内都有一些值,您可以添加一个像 之类的过滤器,它AND time > now() - INTERVAL 10 MINUTES会工作得非常快(不需要扫描很多行)。
如果您的某些参数没有定期活动,情况会更糟。
在这种情况下,最快的方法是通过物化视图缓存每个参数的最后一次,甚至整个最后一行。像这样的东西:
CREATE MATERIALIZED VIEW last_positions
Engine=ReplacingMergeTree(max_time)
ORDER BY param_id
PARTITION BY tuple()
AS SELECT param_id, max(time) as max_time
FROM param_values_history
GROUP BY param_id;
SELECT * FROM param_values_history PREWHERE (param_id,time) IN (SELECT param_id, max(max_time) FROM last_positions GROUP BY param_id);
Run Code Online (Sandbox Code Playgroud)
或者:MV中最后一行全部收集
CREATE MATERIALIZED VIEW last_positions
Engine=ReplacingMergeTree(max_time)
ORDER BY param_id
PARTITION BY tuple()
AS SELECT param_id,
argMax(param_value, time) as _param_value,
argMax(param_value_quality, time) as _param_value_quality,
argMax(param_value, msec) as _msec,
max(time) as max_time
FROM param_values_history
GROUP BY param_id;
SELECT * FROM last_positions FINAL;
Run Code Online (Sandbox Code Playgroud)