查詢狀態資料庫

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

狀態資料庫是什麼?

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

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

Hyperledger Fabric 不支援 SQL 豐富查詢。如果您的 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 DB 搭配運作?

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

Oracle Blockchain Platform 會為每個通路鏈碼建立 Berkeley 資料庫表格。此表格儲存狀態資訊資料,並至少包含一個名為 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", "manufacturer": "Detroit Auto", "model": "a coupe", "assemblyDate": 1502688979, "airbagSerialNumber": "abg1235", "owner": "Sam Dealer", "recall": false, "recallDate": 1502688979

主控台中的豐富查詢

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

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

支援的 RTF 查詢語法

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

SQL RTF 查詢語法

Berkeley DB JSON 擴充為 SQL 函數的形式。

Before You Begin - 開始之前

請注意下列資訊:

  • 您只能存取執行查詢的來源通道鏈碼 (<STATE>)。
  • 只支援 SELECT 敘述句。
  • 您無法修改狀態資料庫表格。
  • Rich Query 表示式只能有一個 SELECT 敘述句。
  • 本主題中的範例只是一些您可以撰寫豐富查詢的方式。您可以存取一般完整 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", "manufacturer": "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 經銷商」所有汽車的型號與製造商

使用此語法:

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 經銷商」所有汽車的型號和製造商:

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 Rich Query 語法

如果您將包含 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 經銷商」所有汽車的型號與製造商

使用此表示式:

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

狀態資料庫索引

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

預設索引

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

  • 索引鍵索引 - 在索引鍵資料欄上建立。

  • 值索引 - 在值資料欄上建立。

自訂索引

在某些情況下,您可能需要建立自訂索引。您可以使用可以在狀態表格的相關資訊環境中解析的任何表示式來定義這些索引。針對 Berkeley DB 建立的自訂索引使用 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')"]}

驗證 RTF 查詢的差異

在某些情況下,具有 CouchDB 豐富查詢的標準 Hyperledger Fabric 和 Oracle Berkeley DB 豐富查詢的運作方式會有所不同。

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

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