查詢狀態資料庫

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

什麼是狀態資料庫?

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

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

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

  • 如果您的鏈碼包含 SQL RTF 查詢語法,則這些鏈碼僅會安裝在使用 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 豐富查詢。

對於每個通路鏈碼,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 專賣店」,"recall":false,"recallDate":1502688979

主控台中的豐富查詢

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

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

支援的 Rich Query 語法

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

SQL RTF 查詢語法

Berkeley 資料庫 JSON 擴充功能的格式為 SQL 函數。

Before You Begin - 開始之前

請注意下列資訊:

  • 您只能存取執行查詢的來源通路鏈碼 (<STATE>)。
  • 只支援 SELECT 敘述句。
  • 您無法修改狀態資料庫表格。
  • RTF 查詢運算式只能有一個 SELECT 陳述式。
  • 本主題中的範例只是幾種可以撰寫豐富查詢的方式。您可以存取一般的完整 SQL 語法來查詢 SQL 資料庫。
  • 您可以存取 JSON1 擴充功能 (SQLite 擴充功能)。請參閱 JSON1 擴充功能SQL 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 專賣店」,"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

擷取「垃圾車經銷商」擁有之所有汽車的型號與製造商

使用此語法:

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 RTF 查詢語法

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

如果您要撰寫新的鏈碼,Oracle 建議您使用 SQL 豐富查詢,以利用 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" 
   ]
}

擷取「垃圾車經銷商」擁有之所有汽車的型號與製造商

使用此表示式:

{ 
  "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 豐富查詢的運作方式不同。

在含有 CouchDB 的標準 Hyperledger Fabric 中,查詢所傳回的每個索引鍵與值組都會新增至交易的讀取集,並在驗證時進行驗證,且不會重新執行查詢。在 Berkeley 資料庫中,傳回的索引鍵與值組未新增至讀取集,但 Rich Query 的結果會雜湊在 Merkle 樹狀結構中,並驗證在驗證時重新執行查詢。

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