상태 데이터베이스 질의
이 항목에는 블록체인 원장의 현재 상태 데이터가 저장된 상태 데이터베이스를 쿼리하는 방법을 이해하는 데 도움이 되는 정보가 포함되어 있습니다.
상태 데이터베이스란?
블록체인 원장의 현재 상태 데이터는 상태 데이터베이스에 저장됩니다.
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 테이블을 생성합니다. 이 테이블은 상태 정보 데이터를 저장하며, JSON 형식 데이터를 사용 중인지 여부에 따라 key이라는 키 열과 value 또는 valueJson라는 값 열을 포함합니다.
| 열 이름 | 유형 | 설명 |
|---|---|---|
key |
TEXT | 상태 테이블의 키 열입니다. |
value |
TEXT | 상태 테이블의 값 열입니다. |
valueJson |
TEXT | 상태 테이블의 JSON 형식 값 열입니다. |
valueJson 열과 value 열은 상호 배타적입니다. 따라서 체인코드가 키에 JSON 값을 지정하면 valueJson 열에 해당 값이 포함되고 값 열이 Null로 설정됩니다. 체인코드가 키에 비JSON 값을 지정하면 valueJson 열이 널로 설정되고 값 열에 값이 포함됩니다.
상태 데이터베이스의 예
다음은 자동차 딜러 샘플의 상태 데이터베이스에서 키와 해당 값의 예입니다.
| 키 | value | valueJson |
|---|---|---|
| abg1234 | 널 | {"docType": "vehiclePart", "serialNumber": "abg1234", "어셈블러": "panama-parts", "assemblyDate": 1502688979, "name": "airbag 2020", "소유자": "Detroit Auto", "recall": false, "recallDate": 1502688979} |
| abg1235 | 널 | {"docType": "vehiclePart", "serialNumber": "abg1235", "조립자": "panama-parts", "assemblyDate": 1502688979, "이름": "airbag 4050", "소유자": "Detroit Auto", "recall": false, "recallDate": 1502688979} |
| ser1236 | 널 | {"docType": "vehiclePart", "serialNumber": "ser1236", "조립자": "panama-parts", "assemblyDate": 1502688979, "name": "seatbelt 10020", "소유자": "Detroit Auto", "recall": false, "recallDate": 1502688979} |
| bra1238 | 널 | {"docType": "vehiclePart", "serialNumber": "bra1238", "어셈블러": "bobs-bits", "assemblyDate": 1502688979, "name": "brakepad 4200", "owner": "Detroit Auto", "recall": false, "recallDate": 1502688979} |
| dtrt10001 | 널 | {"docType": "차량", "chassisNumber": "dtrt10001", "제조업자": "Detroit Auto", "모델": "쿠페", "assemblyDate": 1502688979, "airbagSerialNumber": "abg1235", "소유자": "Sam 딜러", "회수": 거짓, "recallDate": 1502688979 |
지원되는 서식 있는 쿼리 구문
Oracle Blockchain Platform은 상태 데이터베이스를 쿼리하는 데 사용할 수 있는 두 가지 유형의 서식 있는 쿼리 구문을 지원합니다. SQL 서식 있는 쿼리와 CouchDB 서식 있는 쿼리입니다.
SQL 서식 있는 질의 구문
Berkeley DB JSON 확장은 SQL 함수 형식입니다.
시작하기 전에
다음 정보에 유의하십시오.
- 질의를 실행 중인 채널 체인코드(<STATE>)에만 액세스할 수 있습니다.
- SELECT 문만 지원됩니다.
- 상태 데이터베이스 테이블을 수정할 수 없습니다.
- 서식 있는 질의 표현식은 하나의 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", "어셈블러": "panama-parts", "assemblyDate": 1502688979, "name": "airbag 2020", "소유자": "Detroit Auto", "recall": false, "recallDate": 1502688979} |
| abg1235 | {"docType": "vehiclePart", "serialNumber": "abg1235", "조립자": "panama-parts", "assemblyDate": 1502688979, "이름": "airbag 4050", "소유자": "Detroit Auto", "recall": false, "recallDate": 1502688979} |
| bra1238 | {"docType": "vehiclePart", "serialNumber": "bra1238", "어셈블러": "bobs-bits", "assemblyDate": 1502688979, "name": "brakepad 4200", "owner": "Detroit Auto", "recall": false, "recallDate": 1502688979} |
| dtrt10001 | {"docType": "차량", "chassisNumber": "dtrt10001", "제조업자": "Detroit Auto", "모델": "쿠페", "assemblyDate": 1502688979, "airbagSerialNumber": "abg1235", "소유자": "Sam 딜러", "회수": 거짓, "recallDate": 1502688979 |
| ser1236 | {"docType": "vehiclePart", "serialNumber": "ser1236", "조립자": "panama-parts", "assemblyDate": 1502688979, "name": "seatbelt 10020", "소유자": "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", "어셈블러": "panama-parts", "assemblyDate": "1502688979", "name": "airbag 2020", "소유자": "Detroit Auto", "recall": "false", "recallDate": "1502688979"} |
| abg1235 | {"docType": "vehiclePart", "serialNumber": "abg1235", "어셈블러": "panama-parts", "assemblyDate": "1502688979", "name": "airbag 4050", "소유자": "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 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 네트워크에 참여하는 Hyperledger Fabric 피어에 설치할 체인코드를 작성해야 하는 경우 이 항목의 정보를 사용합니다.
새 체인코드를 작성하는 경우 Oracle은 SQL 리치 쿼리를 사용하여 Berkeley DB가 제공하는 Oracle Blockchain Platform의 성능 이점을 활용할 것을 권장합니다.
체인코드 작성 및 테스트에 대한 자세한 내용은 체인코드 개발을 참조하십시오.
지원되지 않는 질의 매개변수 및 선택기 구문
Oracle Blockchain Platform은 use_index 매개변수를 지원하지 않습니다. 사용되는 경우 Oracle Blockchain Platform은 이 매개변수를 무시하고 해당 StateDB에 정의된 인덱스를 자동으로 선택합니다.
| 매개변수 | 유형 | 설명 |
|---|---|---|
| use_index | json | 특정 인덱스를 사용하도록 query에 지시합니다. |
자동차의 모든 모델, 제조업체 및 소유자 검색 및 소유자별 주문
다음 식을 사용합니다.
{
"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 문서로 표현되는 복합 인덱스를 지원하는 표현식 배열로 정의됩니다. 파일당 하나의 인덱스가 있습니다. statedb/relationaldb/indexes 디렉토리 구조의 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: 이 예에서는 Example 1에 설명된 인덱스와 Example 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 서식 있는 쿼리가 포함된 표준 Hyperledger Fabric이 다르게 동작합니다.
CouchDB를 사용하는 표준 Hyperledger Fabric에서 질의에 의해 반환된 각 키 및 값 쌍은 트랜잭션의 읽기 세트에 추가되며 질의를 재실행하지 않고 검증 시 검증됩니다. Berkeley DB에서는 반환된 키 및 값 쌍이 읽기 세트에 추가되지 않지만 서식 있는 질의의 결과는 Merkle 트리에서 해시되고 검증 시 질의 재실행에 대해 검증됩니다.
Native Hyperledger Fabric은 리치 쿼리에 대한 데이터 보호를 제공하지 않습니다. 그러나 Berkeley DB에는 Merkle 트리 해시 값을 읽기 세트에 추가하고, 서식 있는 쿼리를 재실행하고, 검증 단계에서 Merkle 트리 값을 재계산하여 서식 있는 쿼리를 보호하고 검증하는 기능이 포함되어 있습니다. 검증이 Berkeley DB를 사용하는 Oracle Blockchain Platform에서 더 정확하기 때문에 체인코드 호출이 더 빈번한 팬텀 읽기에 대해 플래그가 지정되는 경우가 있습니다.