插入触发器后的 postgres 高 CPU 使用率
postgres high CPU usage on after insert trigger
我有一个应用程序,我在其中接收报价(商品的买入或卖出)流,并试图生成一个 table 详细的 OHLC(开盘价、最高价、最低价、收盘价)列数据。我在 table 中创建这些而不是从报价 table 中派生它们的原因是因为我得到了大量的报价(每天 10000000)。使用此策略,我可以按计划从数据库中删除所有报价,以保持我的数据库大小可管理。
我的模式与此大致相同(为简洁起见,删除了不必要的列)。
CREATE TABLE tick (
executed TIMESTAMP WITH TIME ZONE NOT NULL,
price NUMERIC
);
CREATE TABLE ohlc_minute (
created TIMESTAMP WITH TIME ZONE NOT NULL PRIMARY KEY,
open NUMERIC,
high NUMERIC,
low NUMERIC,
close NUMERIC,
);
我的想法是在 tick
上创建一个插入后触发器,它计算 OHLC 的最后一分钟,然后 upserts 将其插入 ohlc_minute
table 但启用此触发器后,cpu 数据库的使用率几乎立即跃升至 100%。
CREATE OR REPLACE FUNCTION update_ohlc()
RETURNS trigger AS
$BODY$
BEGIN
INSERT INTO ohlc_minute (created, open, high, low, close)
SELECT
date_trunc('minute', NEW.executed) executed,
(array_agg(price ORDER BY executed ASC))[1] as open,
MAX(price) as high,
MIN(price) as low,
(array_agg(price ORDER BY executed DESC))[1] as close
FROM tick
WHERE executed BETWEEN date_trunc('minute', NEW.executed) AND date_trunc('minute', NEW.executed) + interval '1 Min'
ON CONFLICT (created)
DO UPDATE
SET open = EXCLUDED.open, high=EXCLUDED.high, low=EXCLUDED.low, close=EXCLUDED.close;
RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql;
CREATE TRIGGER tick_insert
AFTER INSERT
ON tick
FOR EACH ROW
EXECUTE PROCEDURE update_ohlc();
我有的一个可能的替代方法是 运行 手动按计划更新所有 ohlc 柱的等效函数,但我喜欢始终拥有最新部分(例如,当前柱不到一分钟)的想法) 可用的 ohlc 信息。我可以做任何简单的优化来降低触发函数的 CPU 使用率吗?
我解决了我自己的问题,答案很明显没有索引,我创建了一个索引
CREATE INDEX IF NOT EXISTS execute_index ON tick (executed);
和CPU使用率已经下降到可接受的水平,但是我仍然有兴趣看到优化的解决方案。
报价能保证按顺序到达吗?如果插入成功,那么您的聚合只在一行上完成,因此所有聚合的答案就是价格。如果插入冲突,那么您应该能够根据现有的和排除的值计算每个值。
CREATE OR REPLACE FUNCTION update_ohlc()
RETURNS trigger AS
$BODY$
BEGIN
INSERT INTO ohlc_minute (created, open, high, low, close)
values (
date_trunc('minute', NEW.executed),
NEW.price,
NEW.price,
NEW.price,
NEW.price
)
ON CONFLICT (created)
DO UPDATE
SET high=greatest(ohlc_minute.high,EXCLUDED.high),
low=least(ohlc_minute.low,EXCLUDED.low),
close=EXCLUDED.close;
RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql;
如果不能保证它们按顺序到达,那么我认为如果您坚持在累积的分钟内提供部分结果,那么您当前的解决方案将是最佳的。
我有一个应用程序,我在其中接收报价(商品的买入或卖出)流,并试图生成一个 table 详细的 OHLC(开盘价、最高价、最低价、收盘价)列数据。我在 table 中创建这些而不是从报价 table 中派生它们的原因是因为我得到了大量的报价(每天 10000000)。使用此策略,我可以按计划从数据库中删除所有报价,以保持我的数据库大小可管理。
我的模式与此大致相同(为简洁起见,删除了不必要的列)。
CREATE TABLE tick (
executed TIMESTAMP WITH TIME ZONE NOT NULL,
price NUMERIC
);
CREATE TABLE ohlc_minute (
created TIMESTAMP WITH TIME ZONE NOT NULL PRIMARY KEY,
open NUMERIC,
high NUMERIC,
low NUMERIC,
close NUMERIC,
);
我的想法是在 tick
上创建一个插入后触发器,它计算 OHLC 的最后一分钟,然后 upserts 将其插入 ohlc_minute
table 但启用此触发器后,cpu 数据库的使用率几乎立即跃升至 100%。
CREATE OR REPLACE FUNCTION update_ohlc()
RETURNS trigger AS
$BODY$
BEGIN
INSERT INTO ohlc_minute (created, open, high, low, close)
SELECT
date_trunc('minute', NEW.executed) executed,
(array_agg(price ORDER BY executed ASC))[1] as open,
MAX(price) as high,
MIN(price) as low,
(array_agg(price ORDER BY executed DESC))[1] as close
FROM tick
WHERE executed BETWEEN date_trunc('minute', NEW.executed) AND date_trunc('minute', NEW.executed) + interval '1 Min'
ON CONFLICT (created)
DO UPDATE
SET open = EXCLUDED.open, high=EXCLUDED.high, low=EXCLUDED.low, close=EXCLUDED.close;
RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql;
CREATE TRIGGER tick_insert
AFTER INSERT
ON tick
FOR EACH ROW
EXECUTE PROCEDURE update_ohlc();
我有的一个可能的替代方法是 运行 手动按计划更新所有 ohlc 柱的等效函数,但我喜欢始终拥有最新部分(例如,当前柱不到一分钟)的想法) 可用的 ohlc 信息。我可以做任何简单的优化来降低触发函数的 CPU 使用率吗?
我解决了我自己的问题,答案很明显没有索引,我创建了一个索引
CREATE INDEX IF NOT EXISTS execute_index ON tick (executed);
和CPU使用率已经下降到可接受的水平,但是我仍然有兴趣看到优化的解决方案。
报价能保证按顺序到达吗?如果插入成功,那么您的聚合只在一行上完成,因此所有聚合的答案就是价格。如果插入冲突,那么您应该能够根据现有的和排除的值计算每个值。
CREATE OR REPLACE FUNCTION update_ohlc()
RETURNS trigger AS
$BODY$
BEGIN
INSERT INTO ohlc_minute (created, open, high, low, close)
values (
date_trunc('minute', NEW.executed),
NEW.price,
NEW.price,
NEW.price,
NEW.price
)
ON CONFLICT (created)
DO UPDATE
SET high=greatest(ohlc_minute.high,EXCLUDED.high),
low=least(ohlc_minute.low,EXCLUDED.low),
close=EXCLUDED.close;
RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql;
如果不能保证它们按顺序到达,那么我认为如果您坚持在累积的分钟内提供部分结果,那么您当前的解决方案将是最佳的。