JSON 双数组列
JSON column for array of double
我正在为分析应用程序设计数据库。我的数据是从 CSV 文件加载的。此文件包含名为 'feed'.
的对象的一系列双精度值(可能超过 100k 个值)
我想将这些双精度数组存储到 PostgreSQL 的 JSON 列和 "partition" 数据中。我将选择一个因子数(例如:1000),这意味着对于每个 JSON,它最多包含 1000 个值。因此,如果您在 CSV 中有 3000 个值,那么您将有 3 行,每行将包含一个 JSON 的 1000 个值,如下所示:
Table feed
----------------------------------------
| id | data |
| 1 | { data: [1,2,3,4...1000]}
| 2 | { data: [1001,1002,...,2000]}
| 3 | { data: [2001,2002,...,3000]}
如果您想更新任何值,那么我将使用新值复制每个 JSON 中的数组,其他值将为 -1。
例如,如果要将值 2002(位于索引 1)更改为 4500,则 table 将为:
Table feed
----------------------------------------
| id | data |
| 1 | { data: [1,2,3,4...1000]}
| 2 | { data: [1001,1002,...,2000]}
| 3 | { data: [2001,2002,...,3000], new_data: [-1,4500,-1,-1...]}
也许我会添加一些额外的元数据列来描述 JSON 数据,例如 array_length、is_modifed...以便于处理。
我不知道这个设计是否可以轻松地进行 CRUD 操作?它对实时渲染和更新图表有好处吗?因为读、写、更新……这个数组数据太频繁了。任何人都可以给我一些建议吗?
谢谢
在您描述的场景中使用 JSON 数据是一个非常糟糕的主意。
JSON is a lightweight data-interchange format 因此作为 数据存储 和 [=38= 效率不是特别高]数据操作格式和PostgreSQL作为关系数据存储模型不是特别suitable 用于 JSON 操作(JSON 具有分层数据结构)或大型数组。
您的想法效率不高的几个更具体的原因:
- 将 1,000 个双精度值放入一个数组中会产生超过 8,000 字节的数据结构(假设
jsonb
数据类型:双精度为 8,000 字节,结构本身及其描述符有一些开销;常规 json
很可能会更大,因为每个值至少有 8 个字符来准确描述每个值的大小)。这意味着 table 将被 TOASTed,这会导致性能下降。
- 更新数组中的单个值需要重写整个记录(在主 table 和 TOAST table 中),效率极低。
最好在 PostgreSQL 中使用一个简单的关系结构,并使用触发器来实现您的逻辑。如果您的图表客户端需要 JSON 文档作为输入,那么 PostgreSQL 可以生成该 on-the-fly。例如:
CREATE TABLE feed (
"index" integer,
value double precision
);
CREATE FUNCTION trf_upd_feed RETURNS trigger AS $$
BEGIN
-- This DELETE statement throws out unwanted data (the -1 values in your example)
-- Usually there will be very few rows (just 1?) that get deleted
DELETE FROM feed
WHERE ("index" - 1) / 1000 = (NEW."index" - 1) / 1000; -- integer division!
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER tr_feed_update
BEFORE UPDATE ON feed
FOR EACH ROW EXECUTE PROCEDURE trf_upd_feed();
当您需要图表数据时,您可以 运行 一个简单的查询来获取值切片的数据作为 JSON 对象:
SELECT json_build_object('data', arr) AS json_data
FROM (
SELECT json_agg(coalesce(feed.value, -1)) AS arr
FROM generate_series(1001, 2000) i(x)
LEFT JOIN feed ON feed."index" = i.x) sub;
这总体上效率更高,因为您不需要 TOAST tables 并且您不存储没有任何意义的数据(所有 -1 值)。
备选
根据您的描述,我了解到您的图表客户端维护自己的值缓存,然后定期轮询数据库中的新数据。如果是这样的话,你应该改变你的逻辑。您不应在更新时更改值(删除记录),而应在图表应用程序读取数据时这样做;为此,您需要一个函数而不是更新触发器(如果您已经创建了它,请删除它):
CREATE FUNCTION chart_data (start_idx integer, end_idx integer) RETURNS json AS $$
DECLARE
json_data json;
BEGIN
SELECT json_build_object('data', arr) INTO json_data
FROM (
SELECT json_agg(coalesce(feed.value, -1)) AS arr
FROM generate_series(start_idx, end_idx) i(x)
LEFT JOIN feed ON feed."index" = i.x) sub;
-- Data has been read, so now it can be deleted
DELETE FROM feed
WHERE "index" BETWEEN start_idx AND end_idx;
RETURN json_data;
END;
$ LANGUAGE plpgsql VOLATILE STRICT;
然后简单地调用`SELECT chart_data (1001, 2000);
我正在为分析应用程序设计数据库。我的数据是从 CSV 文件加载的。此文件包含名为 'feed'.
的对象的一系列双精度值(可能超过 100k 个值)我想将这些双精度数组存储到 PostgreSQL 的 JSON 列和 "partition" 数据中。我将选择一个因子数(例如:1000),这意味着对于每个 JSON,它最多包含 1000 个值。因此,如果您在 CSV 中有 3000 个值,那么您将有 3 行,每行将包含一个 JSON 的 1000 个值,如下所示:
Table feed
----------------------------------------
| id | data |
| 1 | { data: [1,2,3,4...1000]}
| 2 | { data: [1001,1002,...,2000]}
| 3 | { data: [2001,2002,...,3000]}
如果您想更新任何值,那么我将使用新值复制每个 JSON 中的数组,其他值将为 -1。
例如,如果要将值 2002(位于索引 1)更改为 4500,则 table 将为:
Table feed
----------------------------------------
| id | data |
| 1 | { data: [1,2,3,4...1000]}
| 2 | { data: [1001,1002,...,2000]}
| 3 | { data: [2001,2002,...,3000], new_data: [-1,4500,-1,-1...]}
也许我会添加一些额外的元数据列来描述 JSON 数据,例如 array_length、is_modifed...以便于处理。
我不知道这个设计是否可以轻松地进行 CRUD 操作?它对实时渲染和更新图表有好处吗?因为读、写、更新……这个数组数据太频繁了。任何人都可以给我一些建议吗?
谢谢
在您描述的场景中使用 JSON 数据是一个非常糟糕的主意。
JSON is a lightweight data-interchange format 因此作为 数据存储 和 [=38= 效率不是特别高]数据操作格式和PostgreSQL作为关系数据存储模型不是特别suitable 用于 JSON 操作(JSON 具有分层数据结构)或大型数组。
您的想法效率不高的几个更具体的原因:
- 将 1,000 个双精度值放入一个数组中会产生超过 8,000 字节的数据结构(假设
jsonb
数据类型:双精度为 8,000 字节,结构本身及其描述符有一些开销;常规json
很可能会更大,因为每个值至少有 8 个字符来准确描述每个值的大小)。这意味着 table 将被 TOASTed,这会导致性能下降。 - 更新数组中的单个值需要重写整个记录(在主 table 和 TOAST table 中),效率极低。
最好在 PostgreSQL 中使用一个简单的关系结构,并使用触发器来实现您的逻辑。如果您的图表客户端需要 JSON 文档作为输入,那么 PostgreSQL 可以生成该 on-the-fly。例如:
CREATE TABLE feed (
"index" integer,
value double precision
);
CREATE FUNCTION trf_upd_feed RETURNS trigger AS $$
BEGIN
-- This DELETE statement throws out unwanted data (the -1 values in your example)
-- Usually there will be very few rows (just 1?) that get deleted
DELETE FROM feed
WHERE ("index" - 1) / 1000 = (NEW."index" - 1) / 1000; -- integer division!
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER tr_feed_update
BEFORE UPDATE ON feed
FOR EACH ROW EXECUTE PROCEDURE trf_upd_feed();
当您需要图表数据时,您可以 运行 一个简单的查询来获取值切片的数据作为 JSON 对象:
SELECT json_build_object('data', arr) AS json_data
FROM (
SELECT json_agg(coalesce(feed.value, -1)) AS arr
FROM generate_series(1001, 2000) i(x)
LEFT JOIN feed ON feed."index" = i.x) sub;
这总体上效率更高,因为您不需要 TOAST tables 并且您不存储没有任何意义的数据(所有 -1 值)。
备选
根据您的描述,我了解到您的图表客户端维护自己的值缓存,然后定期轮询数据库中的新数据。如果是这样的话,你应该改变你的逻辑。您不应在更新时更改值(删除记录),而应在图表应用程序读取数据时这样做;为此,您需要一个函数而不是更新触发器(如果您已经创建了它,请删除它):
CREATE FUNCTION chart_data (start_idx integer, end_idx integer) RETURNS json AS $$
DECLARE
json_data json;
BEGIN
SELECT json_build_object('data', arr) INTO json_data
FROM (
SELECT json_agg(coalesce(feed.value, -1)) AS arr
FROM generate_series(start_idx, end_idx) i(x)
LEFT JOIN feed ON feed."index" = i.x) sub;
-- Data has been read, so now it can be deleted
DELETE FROM feed
WHERE "index" BETWEEN start_idx AND end_idx;
RETURN json_data;
END;
$ LANGUAGE plpgsql VOLATILE STRICT;
然后简单地调用`SELECT chart_data (1001, 2000);