Indexing JSON Data in Oracle Database 12c Release 1 (12.1.0.2)
This article provides an overview of how to index JSON data in Oracle Database 12c Release 1 (12.1.0.2).
oracle 12cconfigurationintermediate
by OracleDba
16 views
This article provides an overview of how to index JSON data in Oracle Database 12c Release 1 (12.1.0.2).
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
DROP TABLE json_documents PURGE;
CREATE TABLE json_documents (
id RAW(16) NOT NULL,
data CLOB,
CONSTRAINT json_documents_pk PRIMARY KEY (id),
CONSTRAINT json_documents_json_chk CHECK (data IS JSON)
);
INSERT INTO json_documents (id, data)
VALUES (SYS_GUID(),
'{
"FirstName" : "John",
"LastName" : "Doe",
"Job" : "Clerk",
"Address" : {
"Street" : "99 My Street",
"City" : "My City",
"Country" : "UK",
"Postcode" : "A12 34B"
},
"ContactDetails" : {
"Email" : "[email protected]",
"Phone" : "44 123 123456",
"Twitter" : "@johndoe"
},
"DateOfBirth" : "01-JAN-1980",
"Active" : true
}');
INSERT INTO json_documents (id, data)
VALUES (SYS_GUID(),
'{
"FirstName" : "Jayne",
"LastName" : "Doe",
"Job" : "Manager",
"Address" : {
"Street" : "100 My Street",
"City" : "My City",
"Country" : "UK",
"Postcode" : "A12 34B"
},
"ContactDetails" : {
"Email" : "[email protected]",
"Phone" : ""
},
"DateOfBirth" : "01-JAN-1982",
"Active" : false
}');
COMMIT;123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
CREATE INDEX json_docs_email_idx
ON json_documents (JSON_VALUE(data, '$.ContactDetails.Email' RETURNING VARCHAR2 ERROR ON ERROR));
SET AUTOTRACE TRACE EXPLAIN
SELECT a.data.FirstName,
a.data.LastName,
a.data.ContactDetails.Email AS Email
FROM json_documents a
WHERE JSON_VALUE(data, '$.ContactDetails.Email' RETURNING VARCHAR2 ERROR ON ERROR) = '[email protected]';
-----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 1499 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID BATCHED| JSON_DOCUMENTS | 1 | 1499 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | JSON_DOCS_EMAIL_IDX | 1 | | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access(JSON_VALUE("DATA" FORMAT JSON , '$.ContactDetails.Email' RETURNING VARCHAR2(4000)
ERROR ON ERROR)='[email protected]')
SET AUTOTRACE TRACE EXPLAIN
SELECT a.data.FirstName,
a.data.LastName,
a.data.ContactDetails.Email AS Email
FROM json_documents a
WHERE a.data.ContactDetails.Email = '[email protected]';
-----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 1499 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID BATCHED| JSON_DOCUMENTS | 1 | 1499 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | JSON_DOCS_EMAIL_IDX | 1 | | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access(JSON_VALUE("DATA" FORMAT JSON , '$.ContactDetails.Email' RETURNING VARCHAR2(4000)
ERROR ON ERROR)='[email protected]')
DROP INDEX json_docs_email_idx;
CREATE INDEX json_docs_email_idx
ON json_documents a (a.data.ContactDetails.Email);
SET AUTOTRACE TRACE EXPLAIN
SELECT a.data.FirstName,
a.data.LastName,
a.data.ContactDetails.Email AS Email
FROM json_documents a
WHERE a.data.ContactDetails.Email = '[email protected]';
-----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 1499 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID BATCHED| JSON_DOCUMENTS | 1 | 1499 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | JSON_DOCS_EMAIL_IDX | 1 | | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access(JSON_QUERY("DATA" FORMAT JSON , '$.ContactDetails.Email' RETURNING VARCHAR2(4000)
ASIS WITHOUT ARRAY WRAPPER NULL ON ERROR)='[email protected]')
SET AUTOTRACE TRACE EXPLAIN
SELECT a.data.FirstName,
a.data.LastName,
a.data.ContactDetails.Email AS Email
FROM json_documents a
WHERE JSON_VALUE(data, '$.ContactDetails.Email' RETURNING VARCHAR2 ERROR ON ERROR) = '[email protected]';
------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 1499 | 4 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| JSON_DOCUMENTS | 1 | 1499 | 4 (0)| 00:00:01 |
------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(JSON_VALUE("DATA" FORMAT JSON , '$.ContactDetails.Email'
RETURNING VARCHAR2(4000) ERROR ON ERROR)='[email protected]')
SET AUTOTRACE TRACE EXPLAIN
SELECT a.data.FirstName,
a.data.LastName,
a.data.ContactDetails.Email AS Email
FROM json_documents a
WHERE JSON_QUERY("DATA" FORMAT JSON , '$.ContactDetails.Email' RETURNING VARCHAR2(4000)
ASIS WITHOUT ARRAY WRAPPER NULL ON ERROR) = '[email protected]';
-----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 1499 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID BATCHED| JSON_DOCUMENTS | 1 | 1499 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | JSON_DOCS_EMAIL_IDX | 1 | | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access(JSON_QUERY("DATA" FORMAT JSON , '$.ContactDetails.Email' RETURNING VARCHAR2(4000)
ASIS WITHOUT ARRAY WRAPPER NULL ON ERROR)='[email protected]')
SET AUTOTRACE TRACE EXPLAIN
SELECT a.data.FirstName,
a.data.LastName,
a.data.ContactDetails.Email AS Email
FROM json_documents a
WHERE JSON_QUERY("DATA" FORMAT JSON , '$.ContactDetails.Email') = '[email protected]';
------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 1499 | 4 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| JSON_DOCUMENTS | 1 | 1499 | 4 (0)| 00:00:01 |
------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(JSON_QUERY("DATA" FORMAT JSON , '$.ContactDetails.Email'
RETURNING VARCHAR2(4000) WITHOUT ARRAY WRAPPER NULL ON
ERROR)='[email protected]')
DROP INDEX json_docs_name_idx;
CREATE INDEX json_docs_name_idx ON json_documents (
JSON_QUERY(data, '$.FirstName')
);
DROP INDEX json_docs_name_idx;
CREATE INDEX json_docs_name_idx ON json_documents (
JSON_EXISTS(data, '$.FirstName')
);12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
-- Create the virtual columns and index.
ALTER TABLE json_documents ADD (first_name VARCHAR2(50)
GENERATED ALWAYS AS (JSON_VALUE(data, '$.FirstName' RETURNING VARCHAR2(50))));
ALTER TABLE json_documents ADD (last_name VARCHAR2(50)
GENERATED ALWAYS AS (JSON_VALUE(data, '$.LastName' RETURNING VARCHAR2(50))));
CREATE INDEX json_docs_name_idx ON json_documents (first_name, last_name);
-- Test a query against the virtual columns,
SET AUTOTRACE TRACE EXPLAIN
SELECT COUNT(*)
FROM json_documents
WHERE first_name = 'John'
AND last_name = 'Doe';
----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 54 | 1 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 54 | | |
|* 2 | INDEX RANGE SCAN| JSON_DOCS_NAME_IDX | 1 | 54 | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("FIRST_NAME"='John' AND "LAST_NAME"='Doe')
-- Test a query using direct JSON_VALUE calls.
SET AUTOTRACE TRACE EXPLAIN
SELECT COUNT(*)
FROM json_documents
WHERE JSON_VALUE(data, '$.FirstName' RETURNING VARCHAR2(50)) = 'John'
AND JSON_VALUE(data, '$.LastName' RETURNING VARCHAR2(50)) = 'Doe';
----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 54 | 1 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 54 | | |
|* 2 | INDEX RANGE SCAN| JSON_DOCS_NAME_IDX | 1 | 54 | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("JSON_DOCUMENTS"."FIRST_NAME"='John' AND
"JSON_DOCUMENTS"."LAST_NAME"='Doe')
-- Remove the previous index and virtual columns.
DROP INDEX json_docs_name_idx;
ALTER TABLE json_documents DROP COLUMN first_name;
ALTER TABLE json_documents DROP COLUMN last_name;
-- Create the composite index directly.
CREATE INDEX json_docs_name_idx ON json_documents (
JSON_VALUE(data, '$.FirstName' RETURNING VARCHAR2(50)),
JSON_VALUE(data, '$.LastName' RETURNING VARCHAR2(50))
);
-- Test a query using direct JSON_VALUE calls.
SET AUTOTRACE TRACE EXPLAIN
SELECT COUNT(*)
FROM json_documents
WHERE JSON_VALUE(data, '$.FirstName' RETURNING VARCHAR2(50)) = 'John'
AND JSON_VALUE(data, '$.LastName' RETURNING VARCHAR2(50)) = 'Doe';
----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 54 | 1 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 54 | | |
|* 2 | INDEX RANGE SCAN| JSON_DOCS_NAME_IDX | 1 | 54 | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access(JSON_VALUE("DATA" FORMAT JSON , '$.FirstName' RETURNING
VARCHAR2(50) NULL ON ERROR)='John' AND JSON_VALUE("DATA" FORMAT JSON ,
'$.LastName' RETURNING VARCHAR2(50) NULL ON ERROR)='Doe')1234567891011121314
DROP INDEX json_docs_name_idx;
CREATE BITMAP INDEX json_docs_name_idx ON json_documents (
JSON_VALUE(data, '$.FirstName')
);
DROP INDEX json_docs_name_idx;
CREATE BITMAP INDEX json_docs_name_idx ON json_documents (
JSON_QUERY(data, '$.FirstName')
);
DROP INDEX json_docs_name_idx;
CREATE BITMAP INDEX json_docs_name_idx ON json_documents (
JSON_EXISTS(data, '$.FirstName')
);12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
-- 12.1 Syntax
CREATE INDEX json_docs_search_idx ON json_documents (data)
INDEXTYPE IS CTXSYS.CONTEXT
PARAMETERS ('section group CTXSYS.JSON_SECTION_GROUP SYNC (ON COMMIT)');
-- 12.2 Syntax
CREATE
SEARCH
INDEX json_docs_search_idx ON json_documents (data)
FOR JSON
;
EXEC DBMS_STATS.gather_table_stats(USER, 'JSON_DOCUMENTS');
SET AUTOTRACE TRACE EXPLAIN
SELECT COUNT(*)
FROM json_documents
WHERE JSON_TEXTCONTAINS(data, '$.ContactDetails.Email', '[email protected]');
-----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 2014 | 4 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 2014 | | |
|* 2 | DOMAIN INDEX | JSON_DOCS_SEARCH_IDX | 1 | 2014 | 4 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("CTXSYS"."CONTAINS"("JSON_DOCUMENTS"."DATA",'{[email protected]}
INPATH(/ContactDetails/Email)')>0)
SELECT COUNT(*)
FROM json_documents
WHERE JSON_EXISTS(data, '$.ContactDetails');
-----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 1494 | 4 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 1494 | | |
|* 2 | DOMAIN INDEX | JSON_DOCS_SEARCH_IDX | 1 | 1494 | 4 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("CTXSYS"."CONTAINS"("JSON_DOCUMENTS"."DATA",'HASPATH(/ContactDetail
s)')>0)
SELECT COUNT(*)
FROM json_documents
WHERE JSON_VALUE(data, '$.ContactDetails.Email') = '[email protected]';
-----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 1494 | 4 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 1494 | | |
|* 2 | TABLE ACCESS BY INDEX ROWID| JSON_DOCUMENTS | 1 | 1494 | 4 (0)| 00:00:01 |
|* 3 | DOMAIN INDEX | JSON_DOCS_SEARCH_IDX | | | 4 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter(JSON_VALUE("DATA" FORMAT JSON , '$.ContactDetails.Email' RETURNING
VARCHAR2(4000) NULL ON ERROR)='[email protected]')
3 - access("CTXSYS"."CONTAINS"("JSON_DOCUMENTS"."DATA",'{[email protected]}
INPATH(/ContactDetails/Email)')>0)Please to add comments
No comments yet. Be the first to comment!