在 timescaleDB postgresql 上的 CAGG 之上进行黑客攻击以实现(连续聚合)CAGG
hacking to achieve (continuous aggregate) CAGG on top of CAGG on timescaleDB postgresql
只是想跟进这个话题https://github.com/timescale/timescaledb/issues/1400,是否可以在另一个连续聚合之上创建一个连续聚合? (通过执行一些黑客攻击?)
我打算将分时数据插入数据库(可能每0.1s),并在1s、1min、1hour、1day、1个月、1年、10年上进行连续聚合。根据我目前对 CAGG 的理解,从时间上看,在 10 年内执行聚合将花费 ~3600* 24* 365* 10 倍于 1 秒的 CAGG,但如果我们在 CAGG 之上执行 CAGG(通过创建新的超表来跟踪变化进行黑客攻击以前的物化视图),我们可能会以指数方式加速......
我的想法有效吗?因为我之前没有在postgresql上写过任何触发函数...
这是一个简单的原型,您可以破解自己来喂养第二个超级table,就像在另一个之上的连续聚合:
-- DROP TABLE ticks CASCADE;
-- DROP TABLE ohlc_1s CASCADE;
CREATE TABLE ticks ( time TIMESTAMP NOT NULL, symbol varchar, price decimal, volume int);
CREATE TABLE ohlc_1s ( time TIMESTAMP NOT NULL, symbol varchar, o decimal, h decimal, l decimal, c decimal, v int);
SELECT create_hypertable('ticks', 'time');
SELECT create_hypertable('ohlc_1s', 'time');
您还可以使用触发器来喂 ohlc_1s table:
CREATE OR REPLACE FUNCTION feed_ohlc_1s() RETURNS trigger AS
$BODY$
DECLARE
last_time timestamp;
BEGIN
SELECT time_bucket('1 second', time) INTO last_time
FROM ticks WHERE symbol = NEW.symbol
ORDER BY time DESC LIMIT 1;
-- When turn next second
IF NEW.time - last_time >= INTERVAL '1 second' THEN
INSERT INTO ohlc_1s (time, symbol, o, h, l, c, v)
SELECT time_bucket('1 second', time) as time,
symbol,
FIRST(price, time) as open,
MAX(price) as high,
MIN(price) as low,
LAST(price, time) as close,
SUM(volume) as volume FROM ticks
GROUP BY 1, 2 ORDER BY 1 DESC LIMIT 1;
END IF;
RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql;
CREATE TRIGGER feed_ohlc_every_new_second
BEFORE INSERT
ON ticks
FOR EACH ROW
EXECUTE PROCEDURE feed_ohlc_1s();
下面是一些插入示例:
INSERT INTO ticks VALUES
('2021-08-26 10:09:00.01'::timestamp, 'SYMBOL', 10.1, 100),
('2021-08-26 10:09:00.08'::timestamp, 'SYMBOL', 10.0, 100),
('2021-08-26 10:09:00.23'::timestamp, 'SYMBOL', 10.2, 100),
('2021-08-26 10:09:00.40'::timestamp, 'SYMBOL', 10.3, 100);
table ticks;
table ohlc_1s;
如您所见,当我们处于同一秒时,它不会生成任何新数据:
┌────────────────────────┬────────┬───────┬────────┐
│ time │ symbol │ price │ volume │
├────────────────────────┼────────┼───────┼────────┤
│ 2021-08-26 10:09:00.01 │ SYMBOL │ 10.1 │ 100 │
│ 2021-08-26 10:09:00.08 │ SYMBOL │ 10.0 │ 100 │
│ 2021-08-26 10:09:00.23 │ SYMBOL │ 10.2 │ 100 │
│ 2021-08-26 10:09:00.4 │ SYMBOL │ 10.3 │ 100 │
└────────────────────────┴────────┴───────┴────────┘
(4 rows)
┌──────┬────────┬───┬───┬───┬───┬───┐
│ time │ symbol │ o │ h │ l │ c │ v │
├──────┼────────┼───┼───┼───┼───┼───┤
└──────┴────────┴───┴───┴───┴───┴───┘
(0 rows)
现在插入更多 2 秒的刻度:
INSERT INTO ticks VALUES
('2021-08-26 10:09:01.02'::timestamp, 'SYMBOL', 10.0, 100),
('2021-08-26 10:09:01.04'::timestamp, 'SYMBOL', 14.0, 200),
('2021-08-26 10:09:01.42'::timestamp, 'SYMBOL', 12.3, 200),
('2021-08-26 10:09:01.62'::timestamp, 'SYMBOL', 8.3, 200),
('2021-08-26 10:09:02.80'::timestamp, 'SYMBOL', 9.0, 500);
table ticks;
table ohlc_1s;
这是输出:
┌────────────────────────┬────────┬───────┬────────┐
│ time │ symbol │ price │ volume │
├────────────────────────┼────────┼───────┼────────┤
│ 2021-08-26 10:09:00.01 │ SYMBOL │ 10.1 │ 100 │
│ 2021-08-26 10:09:00.08 │ SYMBOL │ 10.0 │ 100 │
│ 2021-08-26 10:09:00.23 │ SYMBOL │ 10.2 │ 100 │
│ 2021-08-26 10:09:00.4 │ SYMBOL │ 10.3 │ 100 │
│ 2021-08-26 10:09:01.02 │ SYMBOL │ 10.0 │ 100 │
│ 2021-08-26 10:09:01.04 │ SYMBOL │ 14.0 │ 200 │
│ 2021-08-26 10:09:01.42 │ SYMBOL │ 12.3 │ 200 │
│ 2021-08-26 10:09:01.62 │ SYMBOL │ 8.3 │ 200 │
│ 2021-08-26 10:09:02.8 │ SYMBOL │ 9.0 │ 500 │
└────────────────────────┴────────┴───────┴────────┘
(9 rows)
┌─────────────────────┬────────┬──────┬──────┬──────┬──────┬─────┐
│ time │ symbol │ o │ h │ l │ c │ v │
├─────────────────────┼────────┼──────┼──────┼──────┼──────┼─────┤
│ 2021-08-26 10:09:00 │ SYMBOL │ 10.1 │ 10.3 │ 10.0 │ 10.3 │ 400 │
│ 2021-08-26 10:09:01 │ SYMBOL │ 10.0 │ 14.0 │ 8.3 │ 8.3 │ 700 │
└─────────────────────┴────────┴──────┴──────┴──────┴──────┴─────┘
(2 rows)
可能将其链接到更大的时间范围内也会使其变得非常简单。
只是想跟进这个话题https://github.com/timescale/timescaledb/issues/1400,是否可以在另一个连续聚合之上创建一个连续聚合? (通过执行一些黑客攻击?)
我打算将分时数据插入数据库(可能每0.1s),并在1s、1min、1hour、1day、1个月、1年、10年上进行连续聚合。根据我目前对 CAGG 的理解,从时间上看,在 10 年内执行聚合将花费 ~3600* 24* 365* 10 倍于 1 秒的 CAGG,但如果我们在 CAGG 之上执行 CAGG(通过创建新的超表来跟踪变化进行黑客攻击以前的物化视图),我们可能会以指数方式加速......
我的想法有效吗?因为我之前没有在postgresql上写过任何触发函数...
这是一个简单的原型,您可以破解自己来喂养第二个超级table,就像在另一个之上的连续聚合:
-- DROP TABLE ticks CASCADE;
-- DROP TABLE ohlc_1s CASCADE;
CREATE TABLE ticks ( time TIMESTAMP NOT NULL, symbol varchar, price decimal, volume int);
CREATE TABLE ohlc_1s ( time TIMESTAMP NOT NULL, symbol varchar, o decimal, h decimal, l decimal, c decimal, v int);
SELECT create_hypertable('ticks', 'time');
SELECT create_hypertable('ohlc_1s', 'time');
您还可以使用触发器来喂 ohlc_1s table:
CREATE OR REPLACE FUNCTION feed_ohlc_1s() RETURNS trigger AS
$BODY$
DECLARE
last_time timestamp;
BEGIN
SELECT time_bucket('1 second', time) INTO last_time
FROM ticks WHERE symbol = NEW.symbol
ORDER BY time DESC LIMIT 1;
-- When turn next second
IF NEW.time - last_time >= INTERVAL '1 second' THEN
INSERT INTO ohlc_1s (time, symbol, o, h, l, c, v)
SELECT time_bucket('1 second', time) as time,
symbol,
FIRST(price, time) as open,
MAX(price) as high,
MIN(price) as low,
LAST(price, time) as close,
SUM(volume) as volume FROM ticks
GROUP BY 1, 2 ORDER BY 1 DESC LIMIT 1;
END IF;
RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql;
CREATE TRIGGER feed_ohlc_every_new_second
BEFORE INSERT
ON ticks
FOR EACH ROW
EXECUTE PROCEDURE feed_ohlc_1s();
下面是一些插入示例:
INSERT INTO ticks VALUES
('2021-08-26 10:09:00.01'::timestamp, 'SYMBOL', 10.1, 100),
('2021-08-26 10:09:00.08'::timestamp, 'SYMBOL', 10.0, 100),
('2021-08-26 10:09:00.23'::timestamp, 'SYMBOL', 10.2, 100),
('2021-08-26 10:09:00.40'::timestamp, 'SYMBOL', 10.3, 100);
table ticks;
table ohlc_1s;
如您所见,当我们处于同一秒时,它不会生成任何新数据:
┌────────────────────────┬────────┬───────┬────────┐
│ time │ symbol │ price │ volume │
├────────────────────────┼────────┼───────┼────────┤
│ 2021-08-26 10:09:00.01 │ SYMBOL │ 10.1 │ 100 │
│ 2021-08-26 10:09:00.08 │ SYMBOL │ 10.0 │ 100 │
│ 2021-08-26 10:09:00.23 │ SYMBOL │ 10.2 │ 100 │
│ 2021-08-26 10:09:00.4 │ SYMBOL │ 10.3 │ 100 │
└────────────────────────┴────────┴───────┴────────┘
(4 rows)
┌──────┬────────┬───┬───┬───┬───┬───┐
│ time │ symbol │ o │ h │ l │ c │ v │
├──────┼────────┼───┼───┼───┼───┼───┤
└──────┴────────┴───┴───┴───┴───┴───┘
(0 rows)
现在插入更多 2 秒的刻度:
INSERT INTO ticks VALUES
('2021-08-26 10:09:01.02'::timestamp, 'SYMBOL', 10.0, 100),
('2021-08-26 10:09:01.04'::timestamp, 'SYMBOL', 14.0, 200),
('2021-08-26 10:09:01.42'::timestamp, 'SYMBOL', 12.3, 200),
('2021-08-26 10:09:01.62'::timestamp, 'SYMBOL', 8.3, 200),
('2021-08-26 10:09:02.80'::timestamp, 'SYMBOL', 9.0, 500);
table ticks;
table ohlc_1s;
这是输出:
┌────────────────────────┬────────┬───────┬────────┐
│ time │ symbol │ price │ volume │
├────────────────────────┼────────┼───────┼────────┤
│ 2021-08-26 10:09:00.01 │ SYMBOL │ 10.1 │ 100 │
│ 2021-08-26 10:09:00.08 │ SYMBOL │ 10.0 │ 100 │
│ 2021-08-26 10:09:00.23 │ SYMBOL │ 10.2 │ 100 │
│ 2021-08-26 10:09:00.4 │ SYMBOL │ 10.3 │ 100 │
│ 2021-08-26 10:09:01.02 │ SYMBOL │ 10.0 │ 100 │
│ 2021-08-26 10:09:01.04 │ SYMBOL │ 14.0 │ 200 │
│ 2021-08-26 10:09:01.42 │ SYMBOL │ 12.3 │ 200 │
│ 2021-08-26 10:09:01.62 │ SYMBOL │ 8.3 │ 200 │
│ 2021-08-26 10:09:02.8 │ SYMBOL │ 9.0 │ 500 │
└────────────────────────┴────────┴───────┴────────┘
(9 rows)
┌─────────────────────┬────────┬──────┬──────┬──────┬──────┬─────┐
│ time │ symbol │ o │ h │ l │ c │ v │
├─────────────────────┼────────┼──────┼──────┼──────┼──────┼─────┤
│ 2021-08-26 10:09:00 │ SYMBOL │ 10.1 │ 10.3 │ 10.0 │ 10.3 │ 400 │
│ 2021-08-26 10:09:01 │ SYMBOL │ 10.0 │ 14.0 │ 8.3 │ 8.3 │ 700 │
└─────────────────────┴────────┴──────┴──────┴──────┴──────┴─────┘
(2 rows)
可能将其链接到更大的时间范围内也会使其变得非常简单。