27

私は PostgreSQL と、V8 JavaScript エンジンを PostgreSQL に組み込んだPL/V8 を試してきました。これを使用して、データベース内の 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 をキャッシュまたは前処理する方法があるかどうかです... V8 で使用できるテーブルに JSON のバイナリ表現を格納することさえあります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 データ構造に戻す必要があります。

また、必ずしも高速であるとは限りません。

  • が v8 固有のバイナリ形式で格納されている場合json、通常の json 表現をクライアントに返すクエリは、返されるたびにそれをフォーマットする必要があり、CPU コストが発生します。

  • json のバイナリ シリアル化バージョンは、v8 json データ構造をメモリに直接格納することと同じではありません。あらゆる種類のポインターのグラフを含むデータ構造をディスクに直接書き込むことはできません。シリアル化する必要があります。このシリアライゼーションとデシリアライゼーションにはコストがかかり、json テキスト表現を解析するよりもはるかに高速ではない可能性さえあります。これは、v8 がメモリ内の JavaScript オブジェクトをどのように表現するかに大きく依存します。

  • ほとんどのjsonはテキストと小さな数値であり、バイナリ表現からコンパクトさを得ることができないため、バイナリシリアル化表現は簡単に大きくなる可能性があります。ストレージ サイズは、テーブル スキャンの速度、TOAST からの値のフェッチ、TOAST された値に必要な解凍時間、インデックス サイズなどに直接影響するため、クエリが遅くなり、テーブルが大きくなる可能性があります。

あなたが説明したような最適化が可能かどうか、そしてそれが最適化になるかどうかを知りたいです。

テーブルスキャンを行うときに必要な利点を得るために、本当に必要なのは、解析せずにトラバースできるフォーマットであり、おそらくそれを javascript オブジェクトの malloc() グラフに変換することだと思います。フィールドのパス式を指定し、Pg 読み取りバッファーまたは shared_buffers に読み取られたシリアル化されたフォームから直接取得できるようにする必要があります。それは非常に興味深い設計プロジェクトになるでしょうが、v8 にそのようなものが存在するとしたら、私は驚きます。

本当に必要なのは、既存の json ベースのオブジェクト データベースが任意の json パスを高速に検索する方法と、それらのディスク上の表現が何であるかを調査し、pgsql-hackers に報告することです。たぶん、これをすでに解決した人から学ぶべきことがあるかもしれません-もちろん、彼らが解決したと仮定して。

それまでの間、私が注目したいのは、ここで他の回答が行っていることです。スローポイントを回避し、必要なことを行うための他の方法を見つけることです。json パーサーの最適化を検討することもできますが、v8 パーサーが使用されているか、他のパーサーが使用されているかによっては、利益が減少するポイントをすでにはるかに超えている可能性があります。

これは、速度と柔軟なデータ表現の間にトレードオフがある分野の 1 つだと思います。

于 2012-05-28T23:54:31.467 に答える
1

経験はありませんが、気になったので読んでみました。

JSONのみ

次のようなものはどうですか(未テスト、BTW)?JSONのバイナリ表現の保存に関する質問には対応していません。処理を減らすことでパフォーマンスが向上することを期待して、チェックしているすべての行に対してすべてのJSONを一度に解析しようとしています。行ごとに個別に行うオーバーヘッド。それが成功すると、メモリ消費量が増える可能性があると思います。

この内容は、「JSON の配列でレコードを返すこともできます」と言及されているwikiCREATE TYPE...set_of_records()の例から改作されています。それは本当に「オブジェクトの配列」を意味していると思います。

DB レコードの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%'

hストア

この比較のパフォーマンスはどうなりますか?: 書き込み時に JSON データを hstore 列に複製し (または、パフォーマンスが何とか十分に良好である場合は、選択時に JSON を hstore に変換します)、あなたのWHEREで hstore を使用します。

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 に答える
1

おそらく、データの解析を担当する検索フェーズを作成する代わりに、入力時にjsonデータを事前に配布できる新しいデータ型を作成する方が良い方法でしょうか?

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

于 2012-05-20T04:14:31.960 に答える
0

ここで役立つかどうかはわかりませんが、 pg-to-json-serializerに出くわしました。次の機能について説明します。

JSON文字列を解析し、そこからpostgreSQLレコード/配列を埋めます

それがあなたがこれまでやってきたことよりもパフォーマンス上の利点を提供するかどうかはわかりませんし、彼らの例さえ本当に理解していません。

言及する価値があると思っただけです。

于 2012-05-25T22:18:50.887 に答える