1

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

通过失败测试查看这个历史性问题。示例:j->'x'是一个表示数字和j->'y'布尔值的 JSONb。从 JSONb 的第一个版本(2014 年发布 9.4)到今天(6 年!),使用 PostgreSQL v12... 似乎我们需要强制执行双重转换:

  1. 丢弃j->'x'“二进制 JSONb 数字”信息,并将其转换为可打印字符串 j->>'x'
    丢弃j->'y'“二进制 JSONb 布尔”信息并将其转换为可打印字符串 j->>'y'

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

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

我在指南中没有看到 ......或者它从未实施过:它是否存在技术障碍?


关于我们需要它的典型场景的注释

(回应评论)

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

  1. 元数据(带有模式描述符)和数组数组中的所有数据集;
  2. 分离两个表中的元数据和表行。

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

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

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 字符串......我们可以通过简单的格式化规则重现上述“稳定模式转换”,从元数据中提取:

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、... 10 亿个不同的数据集在同一张表上)。

回到问题上来:想象一个有大约 50 列或更多列的数据集,如果 PostgreSQL 提供“bynary to bynary cast”,SQL VIEW 会更快。

4

1 回答 1

4

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

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

JSON 数字恰好在numeric内部存储为 PostgreSQL,因此无论如何“直接”都不会工作。但是没有主要原因为什么不能有一种更有效的方法来提取这样的值numeric

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

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

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

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

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

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

于 2020-06-24T15:13:20.857 回答