查詢狀態資料庫

本主題包含的資訊可協助您瞭解如何查詢儲存區塊鏈分類帳目前狀態資料的狀態資料庫。

什麼是狀態資料庫?

區塊鏈分類帳目前的狀態資料儲存在狀態資料庫中。

當您開發 Oracle Blockchain Platform 鏈碼時,可以執行豐富的查詢,從狀態資料庫擷取資料。Oracle Blockchain Platform 使用 SQL Rich Query 語法和 CouchDB find 表示式支援豐富的查詢。請參閱 SQL Rich Query SyntaxCouchDB Rich Query Syntax

Hyperledger Fabric 不支援 SQL Rich Query。如果您的 Oracle Blockchain Platform 網路包含 Hyperledger Fabric 參與者,則您必須確定執行下列作業:

  • 如果您的鏈碼包含 SQL Rich Query 語法,則這些鏈碼僅會安裝在使用 Oracle Blockchain Platform 的成員對等上。

  • 如果需要在 Oracle Blockchain Platform 和 Hyperledger Fabric 對等上安裝鏈碼,請在鏈碼中使用 CouchDB 語法,並確認 Hyperledger Fabric 對等體已設定為使用 CouchDB 作為其狀態資料庫儲存區域。Oracle Blockchain Platform 可以處理 CouchDB。

Oracle Blockchain Platform 如何處理 Berkeley 資料庫?

Oracle Blockchain Platform 使用 Oracle Berkeley DB 作為狀態資料庫。Oracle Blockchain Platform 會根據 SQLite 擴充功能,在 Berkeley 資料庫中建立關聯式表格。此架構提供健全且高效能的方式來驗證 SQL Rich Query。

對於每個通路鏈碼,Oracle Blockchain Platform 會建立一個 Berkeley DB 表格。此表格會儲存狀態資訊資料,並包含至少一個名為 key 的索引鍵資料欄,以及一個名為 valuevalueJson 的值資料欄 (視您是否使用 JSON 格式資料而定)。

資料欄名稱 Type 描述
key TEXT 狀態表格的索引鍵資料欄。
value TEXT 狀態表格的值資料欄。
valueJson TEXT 狀態表格的 JSON 格式值資料欄。

請注意,valueJsonvalue 資料欄是互斥的。因此,如果鏈碼將 JSON 值指派給索引鍵,則 valueJson 資料欄將保留該值,並將值資料欄設為空值。如果鏈碼將非 JSON 值指派給索引鍵,則 valueJson 資料欄將設為空值,值資料欄將保留該值。

狀態資料庫範例

以下是「汽車經銷商」範例狀態資料庫的關鍵碼及其值範例:

索引鍵 value valueJson
abg1234 空值 {"docType": "vehiclePart", "serialNumber": "abg1234", "assembler": "panama-parts", "assemblyDate": 1502688979, "name": "airbag 2020", "owner": "Detroit Auto", "recall": false, "recallDate": 1502688979}
abg1235 空值 {"docType": "vehiclePart", "serialNumber": "abg1235", "assembler": "panama-parts", "assemblyDate": 1502688979, "name": "airbag 4050", "owner": "Detroit Auto", "recall": false, "recallDate": 1502688979}
ser1236 空值 {"docType": "vehiclePart", "serialNumber": "ser1236", "assembler": "panama-parts", "assemblyDate": 1502688979, "name": "seatbelt 10020", "owner": "Detroit Auto", "recall": false, "recallDate": 1502688979}
bra1238 空值 {"docType": "vehiclePart", "serialNumber": "bra1238", "assembler": "bobs-bits", "assemblyDate": 1502688979, "name": "brakepad 4200", "owner": "Detroit Auto", "recall": false, "recallDate": 1502688979}
dtrt10001 空值 {"docType":"vehicle","chassisNumber":"dtrt10001",「製造商」:"Detroit Auto","model":"a coupe","assemblyDate":1502688979,"airbagSerialNumber":"abg1235","owner":"Sam Dealer","recall":false,"recallDate":1502688979

主控台中的 Rich Queries

管理員可以從主控台執行及分析豐富的查詢。

  1. 前往主控台並選取通道頁籤。
  2. 在通道表格中,找出要執行查詢的通道,按一下通道其他動作按鈕,然後按一下分析 Rich Queries 。便會顯示分析 Rich Queries 對話方塊。
  3. 若要針對狀態資料庫執行 Rich Query,請選取查詢執行
    1. 對於鏈碼,請選取部署到您要查詢之通道的鏈碼。
    2. 對於對等,請選取要查詢的對等。
      只提供目前組織中執行所選鏈碼的對等。
    3. Rich Query 中,輸入要執行與分析的 Rich Query。
      查詢格式必須遵循 Rich Query 語法。如需豐富查詢語法的詳細資訊,請參閱支援的 Rich Query Syntax
    4. 如果是結果資料列限制 (Result Rows Limit) ,請將滑動軸移至要擷取的結果資料列數目上限。您最多可以擷取 50 個資料列的結果。
  4. 若要取得查詢的執行計畫,請選取查詢計畫說明。查詢執行計畫是執行查詢的作業序列。
    1. 對於鏈碼,請選取部署到您要查詢之通道的鏈碼。
    2. 對於對等,請選取要查詢的對等。
    3. 對於收集,請選取狀態資料庫或專用資料收集。
    4. 對於 Rich Query ,請輸入 Rich Query。
      此查詢不需要 explain 關鍵字。
      例如:select * from <state>
  5. 按一下「執行」結果欄位顯示查詢結果表格或執行計畫。若要將結果表格匯出為 .csv 檔案,請按一下匯出
    結果表格大小限制為 1 MB。您可能需要縮小查詢範圍,以避免超過此限制。

支援的 Rich Query 語法

Oracle Blockchain Platform 支援兩種豐富的查詢語法,可用來查詢狀態資料庫:SQL Rich query 和 CouchDB Rich Query。

SQL Rich Query 語法

Berkeley DB JSON 擴充是以 SQL 函數的形式提供。

Before You Begin - 開始之前

請注意下列資訊:

  • 您只能存取執行查詢的通道鏈碼 (<STATE>)。
  • 只支援 SELECT 敘述句。
  • 您無法修改狀態資料庫表格。
  • Rich Query 表示式只能有一個 SELECT 敘述句。
  • 本主題中的範例只是一些您可以撰寫 Rich Query 的方式。您可以存取一般的完整 SQL 語法來查詢 SQL 資料庫。
  • 您可以存取 JSON1 擴充功能 (SQLite 擴充功能)。請參閱 JSON1 ExtensionSQL As Understood by SQLite

如果您需要有關撰寫與測試鏈碼的詳細資訊,請參閱開發鏈碼

如何參照查詢中的狀態資料庫

狀態資料庫表格名稱是由 Oracle Blockchain Platform 內部管理,因此在撰寫鏈碼時,您不需要知道狀態資料庫的實體名稱。

您必須改用 <STATE> 別名來參考表格名稱。例如:select key, value from <STATE>

請注意,<STATE> 別名區分大小寫,因此您可以使用 <state><STATE> 或類似 <StAtE> 的別名。

擷取所有索引鍵

使用此語法:

SELECT key FROM <STATE>

例如,如果您使用此語法來查詢「汽車經銷商」範例,就會得到下列索引鍵清單:

金鑰

abg1234

abg1235

ser1236

bra1238

dtrt10001

依索引鍵依字母順序擷取所有索引鍵與值

使用此語法:

SELECT key AS serialNumber, valueJson AS details FROM  <state> ORDER BY key

例如,如果您使用此語法來查詢「汽車經銷商」範例,就會得到下列結果:

serialNumber 詳細資訊
abg1234 {"docType": "vehiclePart", "serialNumber": "abg1234", "assembler": "panama-parts", "assemblyDate": 1502688979, "name": "airbag 2020", "owner": "Detroit Auto", "recall": false, "recallDate": 1502688979}
abg1235 {"docType": "vehiclePart", "serialNumber": "abg1235", "assembler": "panama-parts", "assemblyDate": 1502688979, "name": "airbag 4050", "owner": "Detroit Auto", "recall": false, "recallDate": 1502688979}
bra1238 {"docType": "vehiclePart", "serialNumber": "bra1238", "assembler": "bobs-bits", "assemblyDate": 1502688979, "name": "brakepad 4200", "owner": "Detroit Auto", "recall": false, "recallDate": 1502688979}
dtrt10001 {"docType":"vehicle","chassisNumber":"dtrt10001",「製造商」:"Detroit Auto","model":"a coupe","assemblyDate":1502688979,"airbagSerialNumber":"abg1235","owner":"Sam Dealer","recall":false,"recallDate":1502688979
ser1236 {"docType": "vehiclePart", "serialNumber": "ser1236", "assembler": "panama-parts", "assemblyDate": 1502688979, "name": "seatbelt 10020", "owner": "Detroit Auto", "recall": false, "recallDate": 1502688979}

擷取開頭為 "abg" 的所有索引鍵和值

使用此語法:

SELECT key AS serialNumber, valueJson AS details FROM <state> WHERE key LIKE 'abg%'SELECT key, value FROM <STATE>

例如,如果您使用此語法來查詢「汽車經銷商」範例,就會得到下列結果:

serialNumber 詳細資訊
abg1234 {"docType": "vehiclePart", "serialNumber": "abg1234", "assembler": "panama-parts", "assemblyDate": "1502688979", "name": "airbag 2020", "owner": "Detroit Auto", "recall": "false", "recallDate": "1502688979"}
abg1235 {"docType": "vehiclePart", "serialNumber": "abg1235", "assembler": "panama-parts", "assemblyDate": "1502688979", "name": "airbag 4050", "owner": "Detroit Auto", "recall": "false", "recallDate": "1502688979"}

擷取包含 "Detroit Auto" 所擁有之車輛零件值的所有機碼

使用此語法:

SELECT key FROM <state> WHERE json_extract(valueJson, '$.docType') = 'vehiclePart' AND json_extract(valueJson, '$.owner') = 'Detroit Auto'

例如,如果您使用此語法來查詢「汽車經銷商」範例,就會得到下列索引鍵清單:

金鑰

abg1234

abg1235

ser1236

bra1238

擷取「Sam Dealer」擁有之所有汽車的型號和製造商

使用此語法:

SELECT json_extract(valueJson, '$.model') AS model, json_extract(valueJson, '$.manufacturer') AS manufacturer FROM <state> WHERE json_extract(valueJson, '$.docType') = 'vehicle' AND json_extract(valueJson, '$.owner') = 'Sam Dealer'

例如,如果您使用此語法來查詢「汽車經銷商」範例,就會得到下列結果:

模型 製造商
一個優惠券 自動偵測

如果州值是 JSON 陣列,您可以使用此語法擷取「Sam Dealer」擁有之所有汽車的型號和製造商:

SELECT json_extract(j.value, '$.model') AS model, json_extract(j.value, '$.manufacturer') AS manufacturer FROM <state> s, json_each(json_extract(s.valueJson,'$')) j WHERE json_valid(j.value) AND json_extract(j.value, '$.owner') = 'Sam Dealer'

CouchDB RTF 查詢語法

如果您要將包含 CouchDB 語法的鏈碼移轉至 Oracle Blockchain Platform ,或需要撰寫鏈碼以安裝在參與 Oracle Blockchain Platform 網路的 Hyperledger Fabric 對等體上,請使用此主題中的資訊。

如果您撰寫新的鏈碼,Oracle 建議您使用 SQL Rich Query,以利用 Oracle Blockchain Platform 與 Berkeley DB 提供的效能優勢。

如果您需要有關撰寫與測試鏈碼的詳細資訊,請參閱開發鏈碼

不支援的查詢參數和選取器語法

Oracle Blockchain Platform 不支援 use_index 參數。如果使用,Oracle Blockchain Platform 會忽略此參數,它會自動挑選 StateDB 上所定義的索引。

Parameter - 參數 Type 描述
use_index json 指示使用特定索引的查詢。

依所有者擷取汽車的所有型號、製造商及所有者,以及訂購他們

使用此表示式:

{ 
  "fields": ["model", "manufacturer", "owner"], 
  "sort": [   
    "owner" 
   ]
}

擷取「Sam Dealer」擁有之所有汽車的型號和製造商

使用此表示式:

{ 
  "fields": ["model", "manufacturer"], 
  "selector": {   
    "docType"  : "vehicle",
     "owner" : "Sam Dealer" 
  }
}

狀態資料庫索引

狀態資料庫可包含大量資料。在這種情況下,Oracle Blockchain Platform 使用索引來改善資料存取。

預設索引

部署鏈碼時,Oracle Blockchain Platform 會建立兩個索引。

  • 索引鍵索引 — 建立於索引鍵資料欄。

  • 值索引 — 在值欄上建立。

自訂索引

在某些情況下,您可能需要建立自訂索引。您可以使用任何可在狀態表格相關資訊環境中解析的表示式來定義這些索引。針對 Berkeley 資料庫建立的自訂索引使用 SQLite 語法,但它們會遵循 Hyperledger Fabric 提供的相同 CouchDB 實行。

請注意,您可以使用自訂索引,大幅提升 WHERE 和 ORDER BY 陳述式對大型資料集的效能。因為使用自訂索引會減緩資料插入的速度,所以您應該謹慎使用它們。

每個自訂索引都會定義為支援複合索引的表示式陣列,以一個檔案內的 JSON 文件表示 (請注意,每個檔案都有一個索引)。您必須在下列目錄結構中名為 "indexes" 的資料夾中,以鏈碼封裝此檔案:statedb/relationaldb/indexes。請參閱如何在安裝鏈碼時新增 CouchDB 索引

自訂索引範例

本節中的自訂索引範例使用「汽車經銷商」範例。

範例 1 — 此範例會編製 WHERE 和 ORDER BY 表示式相關資訊環境中使用 json_extract 表示式的索引。

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

舉例而言:

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

範例 2 — 此範例會編製 WHERE 和 ORDER BY 表示式相關資訊環境中兩個 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 中說明的索引。請注意,每個 JSON 結構都必須包含在單獨的檔案中。每個檔案均描述單一索引:簡單的索引 (例如範例 1),或複合索引 (例如範例 2)。

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

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

在下列範例中,「索引 2」會套用至查詢之 WHERE 部分的 AND 表示式,而「索引 1」會套用至 ORDER BY 表示式:

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 搭配 CouchDB 豐富查詢,以及 Oracle Berkeley DB 豐富查詢的行為會有所不同。

在標準 Hyperledger Fabric 中搭配 CouchDB,查詢傳回的每個索引鍵和值組都會新增至交易的讀取集,並在驗證時驗證,而且不會重新執行查詢。在 Berkeley DB 中,傳回的索引鍵與值組不會新增至讀取集,但 Rich Query 的結果會在 Merkle 樹狀結構中雜湊,並在驗證時依據重新執行查詢進行驗證。

原生 Hyperledger Fabric 不提供豐富查詢的資料保護。不過,Berkeley DB 包含的功能可藉由將 Merkle 樹狀結構雜湊值加入讀取集、重新執行 Rich 查詢,以及在驗證階段重新計算 Merkle 樹狀結構值,來保護和驗證 Rich Query。請注意,由於使用 Berkeley DB 的 Oracle Blockchain Platform 驗證更準確,因此有時會標記鏈碼呼叫以進行更頻繁的虛擬在製品讀取。