2017-11-21 7 views
4

この質問の環境は、AWS RDSのPostgreSQL 9.6.5です。インデックス付きビットセットへの大規模な一括更新の最適なアプローチ

質問は、次の論理データ・モデルを含む3億行を持つ表のための最適なスキーマ設計とバッチ更新戦略についてです:

  • id:主キー、40までの文字列を文字
  • code
  • year
  • 整数1〜999:整数年
  • フラグ:可変数(1000+)名に関連付けられたそれぞれは、新しいフラグは、時間をかけて添加しました。理想的には、フラグは、(null)、オン(true/1)、オフ(false/0)の3つの値を持つと考えるべきです。追加の更新(以下を参照)を犠牲にして、フラグを単純なビット(オンまたはオフ、欠落なし)として扱うことは可能です。 「オン」の値は、通常、非常に疎です:< 1/1000です。

クエリは、一般的にcodeyear時折も関与して(名前で)一の以上のフラグの存在下または非存在下での論理式を伴います。

Apache Sparkを介してデータが一括して更新されます。つまり、更新は、COPY形式やSQL操作などのフラットファイルとして表すことができます。一度にアクティブな更新は1つだけです。 codeyearへの更新は非常にまれです。フラグの更新は、1更新あたり1〜5%の行(3〜15百万行)に影響します。更新行には、すべてのフラグとその値、更新される "オン"フラグ、または値が変更されたフラグだけを含めることができます。前者の場合、Sparkはフラグの現在の値を取得するためにデータを照会する必要があります。

更新中に読み込み負荷が小さくなります。

質問は説明されているようにクエリ&の更新をサポートするための最適なスキーマと関連する更新戦略に関するものです。これまでの研究から

いくつかのコメント:

  • 1000 + boolean型の列を使用しては非常に効率的な行表現を作成することになりますが、いくつかのDDLの複雑さに加えて、1000 +インデックスを必要とします。

  • 個々のビットにインデックスを付ける方法があれば、ビット列は素晴らしいでしょう。また、不在フラグを表すための良い方法も提供していません。このアプローチを使用するには、フラグ名とビットIDの間にルックアップテーブルを維持する必要があります。ただし、PostgreSQLのMVCCでは、行全体を置き換えるのではなく、フラグだけを更新するほうがはるかに役立たないようです。

  • JSONBフィールドは、インデックスを提供します。彼らはまたnull表現を提供しますが、それはコストがかかります: "オフ"のすべてのフラグを明示的に設定する必要があり、フィールドがかなり大きくなります。 null表現を無視すると、JSONBフィールドは比較的小さくなります。さらに縮小するために、ルックアップテーブルに短い1〜3文字のフィールド名を使用できます。同じコメントがビットストリングと同じようにマージされます。

  • tsvector/tsquery:このデータ型での経験はありませんが、理論的には、名前で "オン"フラグのセットを正確に表しているようです。トークンにフラグ名をマッピングするルックアップテーブルを使用する必要があります。これは、ステミングによる衝突がないことを保証するための追加要件です。

答えて

1

フラグをメインテーブルに格納しないでください。メインテーブルは、dataと呼ばれ、次のようなものを定義されているとすると

:新しいフラグが作成された場合

CREATE TABLE flag_names (
    id smallint PRIMARY KEY, 
    name text NOT NULL 
); 

CREATE TABLE flag (
    flagname_id smallint NOT NULL REFERENCES flag_names(id), 
    data_id text NOT NULL REFERENCES data(id), 
    value boolean NOT NULL, 
    PRIMARY KEY (flagname_id, data_id) 
); 

は、flag_namesに新しい行を挿入します。

フラグがTRUEまたはFALSEに設定されている場合は、flagテーブルに行を挿入または更新します。

dataflagを結合して、特定のフラグが設定されているかどうかをテストします。

+0

これを行うためのパフォーマンス上の理由もあることを追加する必要があります。大きな行の更新は遅いです。 – AlexanderMP

+0

1人につき1000以上のフラグを使用すると、毎回最大9〜45億行が更新され、3,000億行のテーブルを提案していますか?それを示唆していない場合、つまり「オン」に設定されているフラグのみを保持する場合は、値の列はなぜですか? 1つの大きな行を更新するよりも高速にするために、1,000行までの小さな行を更新すると思いますか? – Sim

+0

また、私はフラグ 'Aまたは(BとC)ではなく、(DとE)ではない'のクエリがスキーマのように見えるのは不思議です。フラグ情報を複数の行に分割するには、同じアカウントのフラグの依存関係を評価するための余分な作業が必要です。 – Sim

関連する問題