27

我一直在试验 PostgreSQL 和 PL/V8,它们将 V8 JavaScript 引擎嵌入到 PostgreSQL 中。使用它,我可以查询到数据库中的 JSON 数据,这非常棒。

基本方法如下:

CREATE or REPLACE FUNCTION 
  json_string(data json, key text) RETURNS TEXT AS $$
  var data = JSON.parse(data); 
  return data[key];
$$ LANGUAGE plv8 IMMUTABLE STRICT;

SELECT id, data FROM things WHERE json_string(data,'name') LIKE 'Z%';

使用 V8,我可以将 JSON 数据解析为 JS,然后返回一个字段,我可以将其用作常规 pg 查询表达式。

在大型数据集上,性能可能是一个问题,因为我需要解析数据的每一行。解析器很快,但它绝对是过程中最慢的部分,而且每次都必须发生。

我想要解决的问题(最终解决一个实际问题)是是否有办法缓存或预处理 JSON ......甚至将 JSON 的二进制表示形式存储在 V8 可以使用的表中自动作为 JS 对象可能是一个胜利。我已经研究过使用诸如 messagepack 或 protobuf 之类的替代格式,但我认为它们在任何情况下都不一定会像本机 JSON 解析器一样快。

想法

PG 有 blob 和二进制类型,所以数据可以以二进制形式存储,然后我们只需要一种方法将其编组到 V8 中。

4

5 回答 5

12

Postgres 支持任意函数调用的索引。以下索引应该可以解决问题:

CREATE INDEX json_idx ON things (json_string(field,'name'));
于 2012-05-26T16:06:25.560 回答
7

简短的版本似乎是在 Pg 的新json支持下,到目前为止,除了序列化的 json 文本之外,没有办法直接以任何形式存储 json。(这看起来可能会在 9.4 中改变)

您似乎想要存储一个预解析的表单,它是 v8 如何在内存中表示 json 的序列化表示,目前不支持。甚至不清楚 v8 是否提供任何类型的 json 结构的二进制序列化/反序列化。如果它本身不这样做,则需要将代码添加到 Pg 以生成这样的表示并将其转换回 v8 json 数据结构。

它也不一定会更快:

  • 如果json以 v8 特定的二进制形式存储,则向客户端返回正常 json 表示的查询必须在每次返回时对其进行格式化,从而产生 CPU 成本。

  • json 的二进制序列化版本与将 v8 json 数据结构直接存储在内存中不同。您不能编写涉及直接指向磁盘的任何类型的指针图的数据结构,它必须被序列化。这种序列化和反序列化是有代价的,它甚至可能不会比解析 json 文本表示快多少。这在很大程度上取决于 v8 如何在内存中表示 JavaScript 对象。

  • 二进制序列化表示很容易变得更大,因为大多数 json 是文本和小数字,您不会从二进制表示中获得任何紧凑性。由于存储大小直接影响表扫描速度、从 TOAST 获取值、TOAST 值所需的解压缩时间、索引大小等,因此您可以轻松地使用较慢的查询和更大的表。

我很想看看像您描述的那样的优化是否可行,以及它是否会成为一种优化。

为了在进行表扫描时获得您想要的好处,我想您真正需要的是一种无需解析即可遍历的格式,并将其转换为可能是 malloc() 的 javascript 对象图。您希望能够为字段提供路径表达式,并直接从序列化表单中将其读取到 Pg 读取缓冲区或 shared_buffers 中。那将是一个非常有趣的设计项目,但如果 v8 中存在类似的东西,我会感到惊讶。

你真正需要做的是研究现有的基于 json 的对象数据库如何快速搜索任意 json 路径以及它们在磁盘上的表示是什么,然后报告 pgsql-hackers。也许从已经解决了这个问题的人那里可以学到一些东西——当然,假设他们已经解决了。

与此同时,我想关注的是这里的其他答案正在做什么:解决慢点并找到其他方法来做你需要的事情。您还可以考虑帮助优化 json 解析器,但取决于使用的是 v8 解析器还是其他某个可能已经远远超过收益递减点的解析器。

我想这是在速度和灵活的数据表示之间进行权衡的领域之一。

于 2012-05-28T23:54:31.467 回答
1

也许不是让检索阶段负责解析数据,而是创建一种可以在输入上预先传播 json 数据的新数据类型可能是一种更好的方法?

http://www.postgresql.org/docs/9.2/static/sql-createtype.html

于 2012-05-20T04:14:31.960 回答
1

我对此没有任何经验,但这让我很好奇,所以我做了一些阅读。

仅 JSON

像下面这样的东西(未经测试,顺便说一句)呢?它没有解决您关于存储 JSON 的二进制表示的问题,它试图为您正在检查的所有行一次解析所有 JSON,希望通过减少处理来产生更高的性能为每一行单独执行此操作的开销。如果它成功了,我认为它可能会导致更高的内存消耗。

这些CREATE TYPE...set_of_records()东西改编自wiki上的示例,其中提到“您还可以返回带有 JSON 数组的记录”。我想它真的意味着“一组对象”。

数据库记录中的id值是否嵌入在 JSON 中?

版本 #1

CREATE TYPE rec AS (id integer, data text, name text);

CREATE FUNCTION set_of_records() RETURNS SETOF rec AS
$$

  var records = plv8.execute( "SELECT id, data FROM things" );

  var data = [];


  // Use for loop instead if better performance

  records.forEach( function ( rec, i, arr ) {

    data.push( rec.data );

  } );

  data = "[" + data.join( "," ) + "]";

  data = JSON.parse( data );


  records.forEach( function ( rec, i, arr ) {

    rec.name = data[ i ].name;

  } );


  return records;

$$
LANGUAGE plv8;


SELECT id, data FROM set_of_records() WHERE name LIKE 'Z%'

版本 #2

这让 Postgres 聚合/连接一些值以减少在 JS 中完成的处理。

CREATE TYPE rec AS (id integer, data text, name text);

CREATE FUNCTION set_of_records() RETURNS SETOF rec AS
$$

  var cols = plv8.execute(

    "SELECT" +

    "array_agg( id ORDER BY id ) AS id," +

    "string_agg( data, ',' ORDER BY id ) AS data" +

    "FROM things"

  )[0];


  cols.data = JSON.parse( "[" + cols.data + "]" );


  var records = cols.id;


  // Use for loop if better performance

  records.forEach( function ( id, i, arr ) {

    arr[ i ] = {

      id : id,

      data : cols.data[ i ],

      name : cols.data[ i ].name

    };

  } );


  return records;

$$
LANGUAGE plv8;


SELECT id, data FROM set_of_records() WHERE name LIKE 'Z%'

hstore

这个比较的性能如何?:在写入时将 JSON 数据复制到 hstore 列中(或者如果性能以某种方式设法足够好,在选择时将 JSON 转换为 hstore)并在您的 中使用 hstore WHERE,例如:

SELECT id, data FROM things WHERE hstore_data -> name LIKE 'Z%'

我从这里听说过 hstore:http: //lwn.net/Articles/497069/

文章还提到了一些其他有趣的事情:

PL/v8 允许您...在特定 JSON 元素上创建表达式索引并保存它们,为您提供存储的搜索索引,就像 CouchDB 的“视图”一样。

它没有详细说明,我真的不知道它指的是什么。

有一条评论被归为“jberkus”,上面写着:

我们也讨论了二进制 JSON 类型,但是没有传输二进制值的协议(BSON 根本不是标准,并且有一些严重的故障),似乎没有任何意义。

如果您有兴趣为 PostgreSQL 提供二进制 JSON 支持,我们很乐意为您提供帮助...

于 2012-05-25T17:08:42.597 回答
0

我不知道它在这里是否有用,但我遇到了这个:pg-to-json-serializer。它提到了以下功能:

解析 JSON 字符串并从中填充 postgreSQL 记录/数组

我不知道它是否会比您迄今为止所做的工作提供任何性能优势,而且我什至不了解他们的示例。

只是觉得值得一提。

于 2012-05-25T22:18:50.887 回答