状態データベースの問合せ

このトピックでは、状態データベースの問合せ方法を理解するのに役立つ情報を示します。

状態データベースとは

ブロックチェーン台帳の現在の状態データは、状態データベースに格納されます。

Oracle Blockchain Platformチェーンコードを開発する場合、リッチ問合せを実行することで、状態データベースからデータを抽出できます。Oracle Blockchain Platformでは、SQLのリッチ問合せ構文およびCouchDBの検索式を使用し、リッチ問合せをサポートしています。「SQLリッチ問合せ構文」および「CouchDBリッチ問合せ構文」を参照してください。

Hyperledger Fabricでは、SQLリッチ問合せはサポートされません。Oracle Blockchain PlatformネットワークにHyperledger Fabric参加者が含まれる場合は、次のことを確認する必要があります:

  • チェーンコードにSQLリッチ問合せ構文が含まれている場合、それらのチェーンコードはOracle Blockchain Platformを使用するメンバー・ピアにのみインストールします。

  • チェーンコードをOracle Blockchain PlatformおよびHyperledger Fabricピアにインストールする必要がある場合、チェーンコードにCouchDB構文を使用し、Hyperledger FabricピアがCouchDBを状態データベース・リポジトリとして使用するように設定されていることを確認します。Oracle Blockchain PlatformはCouchDBを処理できます。

Oracle Blockchain PlatformはBerkeley DBとどのように連携しますか。

Oracle Blockchain Platformは、状態データベースとしてOracle Berkeley DBを使用します。Oracle Blockchain Platformは、SQLite拡張に基づいてBerkeley DBにリレーショナル表を作成します。このアーキテクチャは、SQLリッチ問合せを検証するための堅牢でパフォーマンスの高い方法を提供します。

チャネル・チェーンコードごとに、Oracle Blockchain PlatformによってBerkeley DB表が作成されます。この表には、状態情報データが格納され、少なくともkeyという名前のキー列と(JSON形式データを使用しているかどうかによって)valueまたはvalueJsonという名前の値列が含まれます。

列名 タイプ 説明
key TEXT 状態表のキー列。
value TEXT 状態表の値列。
valueJson TEXT 状態表のJSON形式の値列。

valueJsonおよびvalue列は、相互に排他的であることに注意してください。したがって、チェーンコードがキーにJSON値を割り当てた場合、valueJson列にその値が保持され、value列はnullに設定されます。チェーンコードがキーに非JSON値を割り当てた場合、valueJson列はnullに設定され、value列に値が保持されます。

状態データベースの例

Car Dealerサンプルの状態データベースのキーとその値の例を次に示します:

key value valueJson
abg1234 null {"docType": "vehiclePart", "serialNumber": "abg1234", "assembler": "panama-parts", "assemblyDate": 1502688979, "name": "airbag 2020", "owner": "Detroit Auto", "recall": false, "recallDate": 1502688979}
abg1235 null {"docType": "vehiclePart", "serialNumber": "abg1235", "assembler": "panama-parts", "assemblyDate": 1502688979, "name": "airbag 4050", "owner": "Detroit Auto", "recall": false, "recallDate": 1502688979}
ser1236 null {"docType": "vehiclePart", "serialNumber": "ser1236", "assembler": "panama-parts", "assemblyDate": 1502688979, "name": "seatbelt 10020", "owner": "Detroit Auto", "recall": false, "recallDate": 1502688979}
bra1238 null {"docType": "vehiclePart", "serialNumber": "bra1238", "assembler": "bobs-bits", "assemblyDate": 1502688979, "name": "brakepad 4200", "owner": "Detroit Auto", "recall": false, "recallDate": 1502688979}
dtrt10001 null {"docType": "vehicle", "chassisNumber": "dtrt10001", "manufacturer": "Detroit Auto", "model": "a coupe", "assemblyDate": 1502688979, "airbagSerialNumber": "abg1235", "owner": "Sam Dealer", "recall": false, "recallDate": 1502688979

状態データベースの索引

状態データベースには、大量のデータを格納できます。このような場合、Oracle Blockchain Platformでは索引を使用してデータ・アクセスを向上させます。

デフォルトの索引

チェーンコードがデプロイされると、Oracle Blockchain Platformによって2つの索引が作成されます。

  • キー索引 - キー列に作成されます。

  • 値索引 - 値列に作成されます。

カスタム索引

カスタム索引の作成が必要になる場合があります。これらの索引は、状態表のコンテキストで解決される任意の式を使用して定義します。Berkeley DBに対して作成されたカスタム索引は、SQLite構文に依存しますが、それ以外の場合は、Hyperledger Fabricが提供するのと同じCouchDB実装に従います。

大規模データ・セットに対するWHERE文とORDER BY文のパフォーマンスを大幅に向上させるために、カスタム索引を使用できることに注意してください。カスタム索引を使用するとデータ挿入が遅くなるため、その使用には適切な判断が必要です。

各カスタム索引は、複合索引をサポートする式の配列として定義され、1つのファイル内でJSONドキュメントとして表されます(ファイルごとに1つの索引があることに注意してください)。このファイルは、statedb/relationaldb/indexesというディレクトリ構造の"indexes"という名前のフォルダに、チェーンコードとともにパッケージ化する必要があります。『How to add CouchDB indexes during chaincode installation』を参照してください。

カスタム索引の例

この項のカスタム索引の例では、Car Dealerサンプルを使用します。

例1 - この例では、WHERE式とORDER BY式のコンテキストでjson_extract式の使用を索引付けしています。

{"indexExpressions": ["json_extract(valueJson, '$.owner')"]}

例:

SELECT … FROM … ORDER BY json_extract(valueJson, '$.owner')

例2 - この例では、WHERE式とORDER BY式のコンテキストで2つのjson_extract式の複合使用を索引付けしています。

{"indexExpressions": ["json_extract(valueJson, '$.docType')", "json_extract(valueJson, '$.owner')"]}

例:

SELECT … FROM … WHERE json_extract(valueJson, '$.docType') = 'vehiclePart' AND json_extract(valueJson, '$.owner') = 'Detroit Auto'

例3 - この例では、例1で説明した索引と例2で説明した索引の、2つの索引を作成します。各JSON構造は個別のファイルに含める必要があることに注意してください。各ファイルには、単一の索引(例1のような単純な索引、または例2のような複合索引)を記述します。

索引1: {"indexExpressions": ["json_extract(valueJson, '$.owner')"]}

索引2: {"indexExpressions": ["json_extract(valueJson, '$owner')", "json_extract(valueJson, '$.docType')"]}

次の例では、問合せのWHERE部分のAND式に索引2が適用され、ORDER BY式に索引1が適用されます:

SELECT … FROM … WHERE json_extract(valueJson, '$.docType') = 'vehiclePart' AND json_extract(valueJson, '$.owner') = 'Detroit Auto' ORDER BY json_extract(valueJson, '$.owner')

JSONドキュメントの形式

JSONドキュメントは次の形式である必要があります:

{"indexExpressions": [expr1, ..., exprN]}

例:

{"indexExpressions": ["json_extract(valueJson, '$.owner')"]}

リッチ問合せの検証の相違点

標準的なHyperledger Fabric with CouchDBのリッチ問合せとOracle Berkeley DBのリッチ問合せの動作が異なる場合があります。

標準的なHyperledger Fabric with CouchDBでは、問合せによって返されたキーと値の各ペアはトランザクションの読取りセットに追加され、検証時に問合せを再実行することなく検証されます。Berkeley DBでは、返されたキーと値のペアは読取りセットに追加されませんが、リッチ問合せの結果がMerkleツリーにハッシュされ、検証時に問合せの再実行に対して検証されます。

ネイティブHyperledger Fabricでは、リッチ問合せに対するデータ保護は提供されていません。ただし、Berkeley DBには、Merkleツリー・ハッシュ値を読取りセットに追加し、リッチ問合せを再実行し、検証段階でMerkleツリー値を再計算することでリッチ問合せを保護および検証する機能が含まれています。Berkeley DBを使用するOracle Blockchain Platformでは検証がより正確であるため、チェーンコードの呼出しに頻繁なファントム読取りのフラグが設定されることがあります。