【问题标题】:Binary to binary cast with JSONb使用 JSONb 进行二进制到二进制转换
【发布时间】:2020-10-14 15:00:05
【问题描述】:

如何避免不必要的 CPU 开销?

this historic question with failure tests。示例:j->'x' 是表示数字的 JSONb,j->'y' 是布尔值。从 JSONb 的第一个版本(2014 年发布 9.4)到今天(6 年!),随着 PostgreSQL v12... 似乎我们需要强制双重转换:

  1. 丢弃j->'x'“binary JSONb number”信息,转换成可打印字符串j->>'x'
    丢弃j->'y'“binary JSONb boolean”信息,转换成可打印字符串j->>'y'

  2. 通过转换字符串(j->>'x')::float AS x来解析字符串以获得“二进制SQL浮点数”;
    通过转换字符串(j->>'y')::boolean AS y解析字符串以获得“二进制SQL布尔值”。

程序员是否没有语法或优化函数强制执行直接转换?

我没有看到 in the guide... 或者它从未实现过:是否存在技术障碍?


关于我们需要它的典型场景的说明

(响应 cmets)

想象一个场景,您的系统需要存储许多小数据集 (real example!)使用最少的磁盘,并通过集中控制/元数据/等进行管理。 JSONb 是一个很好的解决方案,并且提供了至少 2 个很好的替代方案来存储在数据库中:

  1. 元数据(带有架构描述符)和array of arrays 中的所有数据集;
  2. 在两个表中分隔元数据和表行。

(以及将元数据转换为text[] 等缓存的变体)
Alternative-1,单片,最适合“最小磁盘使用”要求,完整信息速度更快检索。当表 Alt2_DatasetLine 也有多个列(如 time)用于时间序列时,Alternative-2 可以是随机访问或部分检索的选择。

例如,您可以在单独的架构中创建所有 SQL VIEWS

CREATE mydatasets.t1234 AS 
  SELECT (j->>'d')::date AS d,  j->>'t' AS t,  (j->>'b')::boolean AS b,
         (j->>'i')::int AS i,  (j->>'f')::float AS f
  FROM (
   select jsonb_array_elements(j_alldata) j FROM Alt1_AllDataset
   where dataset_id=1234
  ) t
  -- or FROM alt2...
;

CREATE VIEW 可以自动运行 SQL 字符串 dynamically ...我们可以通过简单的格式化规则重现上述“稳定模式转换”,从元数据中提取:

SELECT string_agg( CASE 
   WHEN x[2]!='text' THEN format(E'(j->>\'%s\')::%s AS %s',x[1],x[2],x[1])
   ELSE  format(E'j->>\'%s\' AS %s',x[1],x[1])
  END, ',' ) as x2
FROM (
 SELECT  regexp_split_to_array(trim(x),'\s+') x
 FROM regexp_split_to_table('d date, t text, b boolean, i int, f float', ',') t1(x)
) t2;

...这是一个“现实生活场景”,这种(显然丑陋的)模型对于小流量应用程序来说速度惊人。除了减少磁盘使用量之外,还有其他优点:灵活性(您可以更改数据集模式而无需更改 SQL 模式)和可扩展性(2、3、... 1十亿个不同的数据集在同一张表上)。

回到问题:想象a dataset with ~50 or more columns,如果 PostgreSQL 提供“bynary to bynary cast”,SQL VIEW 会更快。

【问题讨论】:

  • 你的问题到底是什么?
  • 嗨@a_horse_with_no_name,我正在编辑...现在是粗体字
  • 好吧,我猜这就是你为去规范化付出的代价
  • 如果您可以在 JSONB 模式上创建关系视图,这意味着(至少对我而言)实际上不需要去规范化的步骤,您可以完全摆脱 JSON 部分。
  • This answer 建议 jsonb_populate_record[set] 可能会跳过文本转换。

标签: postgresql casting compiler-optimization


【解决方案1】:

简答:不,没有比(例如)更好的方法将jsonb 数字提取为 PostgreSQL

CAST(j ->> 'attr' AS double precision)

一个 JSON 数字恰好在内部存储为 PostgreSQL numeric,因此无论如何这都不能“直接”工作。但是,没有任何主要原因可以更有效地提取 numeric 这样的值。

那么,为什么我们没有那个?

  1. 没有人实现它。这通常表明没有人认为值得付出努力。我个人认为这将是一种微优化——如果您想获得最大效率,您可以从 JSON 中提取该列并将其直接存储为表中的列。

    无需修改 PostgreSQL 源即可执行此操作。可以编写自己的 C 函数来完全按照您的设想进行操作。如果很多人认为这是有益的,我希望有人已经编写了这样的函数。

  2. PostgreSQL 具有即时编译 (JIT)。因此,如果像这样的表达式被评估为很多行,PostgreSQL 将即时为它构建可执行代码。这样可以减轻效率低下的情况,并减少出于效率原因而设置特殊情况的必要性。

  3. 对于许多数据类型来说,这可能不像看起来那么容易。 JSON 标准类型不一定在所有情况下都对应于 PostgreSQL 类型。这似乎有些做作,但请查看 Hackers 邮件列表中的 this recent thread,它处理 JSON 和 PostgreSQL 之间数字类型之间的差异。

以上所有都不是这样一个功能永远不会存在的原因,我只是想说明我们没有它的原因。

【讨论】:

  • 关于JIT 的好消息(实际上是好的LLVM Compiler Infrastructure)和自动use-JIT decision! ...是的,只有很少的“二进制到二进制”优化是可能的,因此微优化演员表的平均增益可能很低并且难以估计...也许没有办法投资的“收益-成本分析”(在 C 实现中),仅在实现后通过基准测试过程。也感谢您找到有关最近线程讨论的链接。
  • 我对“二进制 JSONb → 二进制 SQL” 转换的小收获的猜测:适用于 boolean→booleannumber→numeric、null→null::type, number→int, number→bigint;对 number→floatnumber→double 不利。
  • numeric 转换为任何整数类型并不便宜,因为它们完全不同。
  • 嗯...这不容易理解jbvType...如果我们假设 jbvNumeric 是 JSON 数字的“JSON 二进制值”,似乎不一样internal SQL numeric;而且,是的,似乎不提供直接转换为int4。您是否与内存中的表示有可靠的联系?
  • 另一个问题,测试 PostgreSQL v12。现在我们可以直接进行 JSONb 到 SqlType 的转换(!),但它只是字符串转换的语法糖? (我的解释分析说那是糖)。示例:SELECT (j->'i')::int,(j->>'i')::int, (j->'f')::float,(j->>'f')::float FROM (SELECT '{"i":123,"f":12.34}'::jsonb) t(j); 工作正常。奇怪的是 NULL-to-SqlType 不起作用,“错误:无法将 jsonb null 转换为整数类型”.
猜你喜欢
  • 1970-01-01
  • 2023-04-11
  • 2018-08-11
  • 2021-07-29
  • 2021-08-10
  • 2011-09-14
  • 2016-02-09
  • 2016-08-26
相关资源
最近更新 更多