查询状态数据库
本主题包含的信息可帮助您了解如何查询存储区块链账本当前状态数据的状态数据库。
什么是状态数据库?
区块链账本的当前状态数据存储在状态数据库中。
开发 Oracle Blockchain Platform 链代码时,您可以通过执行富查询从状态数据库中提取数据。Oracle Blockchain Platform 使用 SQL 富查询语法和 CouchDB 查找表达式来支持富查询。请参阅 SQL Rich Query Syntax 和 CouchDB Rich Query Syntax 。
Hyperledger Fabric 不支持 SQL 丰富的查询。如果您的 Oracle Blockchain Platform 网络包含超级账本架构参与者,则您需要确保执行以下操作:
-
如果链代码包含 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 在 Berkeley DB 中基于 SQLite 扩展创建关系表。此体系结构提供了一种强大的高性能方法来验证 SQL 富查询。
对于每个渠道链代码,Oracle Blockchain Platform 将创建一个 Berkeley DB 表。此表存储状态信息数据,并至少包含一个名为 key
的键列和一个名为 value
或 valueJson
的值列,具体取决于您是否使用 JSON 格式数据。
Column Name(列名) | 类型 | 说明 |
---|---|---|
key |
TEXT | 状态表的关键字列。 |
value |
TEXT | State 表的值列。 |
valueJson |
TEXT | 状态表的 JSON 格式值列。 |
请注意,valueJson
和 value
列是互斥的。因此,如果链代码为键分配了 JSON 值,则 valueJson
列将存储该值,并且值列将设置为 null。如果链代码为键分配了非 JSON 值,则 valueJson
列将设置为 null,并且值列将保存该值。
状态数据库示例
以下是 Car Dealer 示例状态数据库中的键及其值的示例:
键 | 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 支持两种类型的富查询语法,可用于查询状态数据库:SQL 富查询和 CouchDB 富查询。
SQL 富查询语法
Berkeley DB JSON 扩展以 SQL 函数的形式提供。
使用须知
请注意以下信息:
- 您只能访问正在从中执行查询的渠道链代码 (<STATE>)。
- 仅支持 SELECT 语句。
- 无法修改状态数据库表。
- 富查询表达式只能有一个 SELECT 语句。
- 本主题中的示例只是编写富查询的几种方式。您可以访问查询 SQL 数据库时常用的完整 SQL 语法。
- 您有权访问 JSON1 扩展(SQLite 扩展)。请参阅 JSON1 扩展和 SQL As Understanding by SQLite 。
如果您需要有关编写和测试链代码的更多信息,请参阅开发链代码。
如何在查询中引用状态数据库
状态数据库表名称由 Oracle Blockchain Platform 内部管理,因此在编写链代码时无需知道状态数据库的物理名称。
而必须使用 <STATE>
别名来引用表名。例如:select key, value from <STATE>
。
请注意,<STATE>
别名不区分大小写,因此您可以使用 <state>
、<STATE>
或类似 <StAtE>
的名称。
检索所有键
使用以下语法:
SELECT key FROM <STATE>
例如,如果使用此语法查询 Car Dealer 示例,则将获得以下密钥列表:
关键字
abg1234
abg1235
ser1236
bra1238
dtrt10001
检索按键按字母顺序排序的所有键和值
使用以下语法:
SELECT key AS serialNumber, valueJson AS details FROM <state> ORDER BY key
例如,如果使用此语法查询 Car Dealer 示例,则将获得以下结果:
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>
例如,如果使用此语法查询 Car Dealer 示例,则将获得以下结果:
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'
例如,如果使用此语法查询 Car Dealer 示例,则将获得以下密钥列表:
关键字
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'
例如,如果使用此语法查询 Car 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 富查询语法
如果要将包含 CouchDB 语法的链代码迁移到 Oracle Blockchain Platform ,或者需要编写链代码以安装在参与 Oracle Blockchain Platform 网络的超级账本架构对等节点上,请使用本主题中的信息。
如果您正在编写新的链代码,Oracle 建议您使用 SQL 丰富的查询来利用 Oracle Blockchain Platform with Berkeley DB 提供的性能优势。
如果您需要有关编写和测试链代码的更多信息,请参阅开发链代码。
不支持的查询参数和选择器语法
Oracle Blockchain Platform 不支持 use_index
参数。如果使用,Oracle Blockchain Platform 将忽略此参数,并自动选取在相关 StateDB 上定义的索引。
Parameter (参数) | 类型 | 说明 |
---|---|---|
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
。请参见 How to add CouchDB indexes during chaincode installation 。
定制索引示例
本节中的自定义索引示例使用汽车经销商示例。
示例 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')"]}
富查询验证的差异
在某些情况下,具有 CouchDB 富查询的标准超级账本架构和 Oracle Berkeley DB 富查询的行为方式不同。
在带有 CouchDB 的标准超级账本架构中,查询返回的每个键和值对将添加到事务处理的读集,并在验证时进行验证,而无需重新执行查询。在 Berkeley DB 中,返回的键和值对不会添加到读取集中,但富查询的结果会散列在 Merkle 树中,并在验证时针对重新执行查询进行验证。
本机超级账本架构不为富查询提供数据保护。但是,Berkeley DB 包含通过将 Merkle 树散列值添加到读取集中、重新执行富查询以及在验证阶段重新计算 Merkle 树值来保护和验证富查询的功能。请注意,由于 Berkeley DB 的 Oracle Blockchain Platform 中的验证更准确,因此链代码调用有时会被标记为更频繁的虚拟件读取。