SlideShare a Scribd company logo
1 of 112
Download to read offline
1
Agile Database Development
with JSON
Chris Saxon
Developer Advocate, @ChrisRSaxon & @SQLDaily
blogs.oracle.com/sql
youtube.com/c/TheMagicofSQL
asktom.oracle.com
Image by Semevent from Pixabay
We're creating a new online store
Selling boxes of brick models
Photo by Jon Tyson on Unsplash
We need to respond to customer feedback…
Photo by Johannes Plenio on Unsplash
…and evolve the application rapidly
Photo by Brannon Naito on Unsplash
working in short sprints and releasing often
So we need to be
Agile
{ JSON }
To support this we'll store data as
7
Agile Database Development
with JSON
Chris Saxon
Developer Advocate, @ChrisRSaxon & @SQLDaily
blogs.oracle.com/sql
youtube.com/c/TheMagicofSQL
asktom.oracle.com
The following is intended to outline our general product direction. It is intended for information purposes
only, and may not be incorporated into any contract. It is not a commitment to deliver any material, code,
or functionality, and should not be relied upon in making purchasing decisions. The development,
release, timing, and pricing of any features or functionality described for Oracle’s products may change
and remains at the sole discretion of Oracle Corporation.
Statements in this presentation relating to Oracle’s future plans, expectations, beliefs, intentions and
prospects are “forward-looking statements” and are subject to material risks and uncertainties. A detailed
discussion of these factors and other risks that affect our business is contained in Oracle’s Securities and
Exchange Commission (SEC) filings, including our most recent reports on Form 10-K and Form 10-Q
under the heading “Risk Factors.” These filings are available on the SEC’s website or on Oracle’s website
at http://www.oracle.com/investor. All information in this presentation is current as of September 2019
and Oracle undertakes no duty to update any statement in light of new information or future events.
Safe Harbor
User Story #1
We must be able to store
product & order details
So we need to create the tables
and define CRUD operations on them
create table products (
product_id integer
not null
primary key,
product_json ##TODO##
not null,
check (
json_data is json
)
);
create table orders (
order_id integer
not null
primary key,
order_json ##TODO##
not null,
check (
json_data is json
)
);
The tables are just a
primary key, JSON column,
& is json constraint
create table products (
product_id integer
not null
primary key,
product_json ##TODO##
not null,
check (
json_data is json
)
);
create table orders (
order_id integer
not null
primary key,
order_json ##TODO##
not null,
check (
json_data is json
)
);
But which data type
to use for JSON?!
Which data type should you use for JSON?
"Small" documents varchar2
"Large" documents ???
<= 4,000 bytes / 32k
"Small" documents varchar2
"Large" documents blob
JSON data type
coming in 20c
Avoids character set conversions
Less storage than clob
create table products (
product_id integer
not null
primary key,
product_json blob
not null,
check (
json_data is json
)
);
create table orders (
order_id integer
not null
primary key,
order_json blob
not null,
check (
json_data is json
)
);
insert into products ( product_json )
values ( utl_raw.cast_to_raw ( '{
"productName": "..."
}' ) );
BLOBs need extra processing on insert
select product_json from products;
PRODUCT_JSON
7B202274686973223A20227468617422207D
and select to make them human readable
select json_serialize (
product_json
returning clob
pretty
) jdata
from products;
JDATA
{
"productName": "..."
}
Added in 19c
json_serialize
converts JSON data to
text; which you can
pretty print for
readability
select json_query (
product_json,
'$' returning clob
pretty
) jdata
from products;
JDATA
{
"productName": "..."
}
In earlier releases use
json_query
The clob return type
was added in 18c
User Story #2
Customers must be able to
search by price
So we need to query the products table for JSON
where the unitPrice is in the specified range
{
"productName": "GEEKWAGON",
"descripion": "Ut commodo in …",
"unitPrice": 35.97,
"bricks": [ {
"colour": "red", "shape": "cube",
"quantity": 13
}, {
"colour": "green", "shape": "cube",
"quantity": 17
}, …
]
}
We need to search for this
value in the documents
select * from products p
where p.product_json.unitPrice <= :max_price;
But remember it returns
varchar2
=> implicit conversion!
Use simple dot-notation to access the value
select * from products p
where json_value (
product_json,
'$.unitPrice' returning number
) <= :max_price;
json_value gives you more control
So this returns number
=> no implicit conversion! :)
select * from products p
where p.product_json.unitPrice.number()
<= :max_price;
From 19c you can state
the return type with
simple dot-notation
User Story #3
Customers must be able to view their
orders
Showing order details and a list of what they bought
So we need to join the order productIds to products
{
"customerId" : 2,
"orderDatetime" : "2019-01-01T03:25:43",
"products" : [ {
"productId" : 1,
"unitPrice" : 74.95
}, {
"productId" : 10,
"unitPrice" : 35.97
}, …
]
}
We need to extract these
from the product array
select o.order_json.products[*].productId
from orders o;
PRODUCTS
[2,8,5]
[3,9,6]
[1,10,7,4]
...
With simple dot-notation,
you can get an array of
the values…
select json_query (
order_json, '$.products[*].productId'
with array wrapper
)
from orders o;
PRODUCTS
[2,8,5]
[3,9,6]
[1,10,7,4]
...
But to join these to
products, we need to
convert them to rows…
…or with json_query
json_table
With json_table you can convert JSON…
…to relational rows-and-columns
with order_items as (
select order_id, t.*
from orders o, json_table (
order_json
columns (
customerId,
nested products[*] columns (
productId,
unitPrice
) )
) t
)
Simplified syntax 18c
with order_items as (
select order_id, t.*
from orders o, json_table (
order_json
columns (
customerId,
nested products[*] columns (
productId,
unitPrice
) )
) t
)
This tells the database to
return a row for each
element in the products
array…
select order_id,
p.product_json.productName product,
unitPrice
from order_items oi
join products p
on oi.productId = p.product_id
where customerId = :cust_var
order by oi.order_id desc, p.product_id
…So you can join output to the products table!
Minimum viable product complete!
Ship it!
Copyright © 2019 Oracle and/or its affiliates.
Soooo…
How many
orders today?
…people have lots of questions
As always, post release…
Ryan McGuire / Gratisography
User Story #4
Sales must be able to view
today's orders
We need to create a dashboard counting orders
So we need to search for orders placed today
{
"customerId" : 2,
"orderDatetime" : "2019-01-01T03:25:43",
"products" : [ {
"productId" : 1,
"unitPrice" : 74.95
}, {
"productId" : 10,
"unitPrice" : 35.97
}, …
]
}
We need to search
for this value in the
documents
select * from orders o
where o.order_json.orderDatetime >=
trunc ( sysdate );
ORA-01861: literal does
not match format string
Remember the
implicit conversions?
It fails for dates!
Use simple dot-notation to access the value
select * from orders o
where json_value (
order_json,
'$.orderDatetime' returning date
) >= trunc ( sysdate )
So you need to define the
return type; JSON dates
conform to ISO 8601 date
2019-01-01
ISO 8601 date
Which is YYYY-MM-DD for dates
There is no time component in an ISO date!
2019-01-01T03:25:43
ISO 8601 timestamp
Use ISO timestamps to include times
Note the "T" between the date and time!
select * from orders o
where json_value (
order_json,
'$.orderDatetime' returning date
) >= trunc ( sysdate )
But the query is very slow…
select * from orders o
where json_value (
order_json,
'$.orderDatetime' returning date
) >= trunc ( sysdate )
{ "customerId": 1, … }
{ "customerId": 2, … }
…
User Story #4b
… and make it fast!
currently the query does a full table scan
To speed it up we need to create an index!
create index orders_date_i
on orders ( order_json );
ORA-02327: cannot create index on
expression with datatype LOB
You can't index LOB data
create search index orders_json_i
on orders ( order_json )
for json
parameters ( 'sync (on commit)' );
Added in 12.2, a json search
index enables JSON queries
to use an index
JSON Search Indexes
select * from orders o
where json_value (
order_json,
'$.orderDatetime' returning date
) >= trunc ( sysdate )
{ "customerId": 1, … }
{ "customerId": 2, … }
…
-----------------------------------------------------
| Id | Operation | Name |
-----------------------------------------------------
| 0 | SELECT STATEMENT | |
|* 1 | TABLE ACCESS BY INDEX ROWID| ORDERS |
|* 2 | DOMAIN INDEX | ORDERS_JSON_I |
-----------------------------------------------------
With the search index in place,
the optimizer can use it
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(JSON_VALUE("ORDER_JSON" FORMAT JSON ,
'$.orderDatetime' RETURNING TIMESTAMP NULL
ON ERROR) >= TIMESTAMP' 2019-01-15 00:00:00')
2 - access("CTXSYS"."CONTAINS"("O"."ORDER_JSON",
'sdatap(TMS_orderDatetime >=
"2019-01-15T00:00:00+00:00" /orderDatetime)')>0)
Under the covers, this uses Oracle Text
create index order_date_i
on orders (
json_value (
order_json,
'$.orderDatetime'
returning date
error on error
null on empty
)
);
It's more efficient to
create a function-
based index,
matching the search
you'll do
This has some other
benefits…
create index order_date_i
on orders (
json_value (
order_json,
'$.orderDatetime'
returning date
error on error
null on empty
)
);
Data validation!
If the value is not
a JSON date;
inserts will raise
an exception
create index order_date_i
on orders (
json_value (
order_json,
'$.orderDatetime'
returning date
error on error
null on empty
)
);
From 12.2 you can
also raise an error
if the attribute is
not present
------------------------------------------------------------
| Id | Operation | Name |
------------------------------------------------------------
| 0 | SELECT STATEMENT | |
| 1 | TABLE ACCESS BY INDEX ROWID BATCHED| ORDERS |
|* 2 | INDEX RANGE SCAN | ORDER_DATE_I |
------------------------------------------------------------
The function-based index is more
efficient, so the optimizer will choose
this over the search index
Search vs. Function-Based Indexes
JSON Search Index Function-based Index
Applicability Any JSON query Matching function
Performance Slower Faster
Use Ad-hoc queries Application queries
0
5
10
15
20
25
With the dashboard in place, it's clear
sales are levelling off
We need a way to increase sales!
We need to offer
discounts!
…discount promotion codes
Marketing have a brilliant plan…
Ryan McGuire / Gratisography
User Story #5
Customers may be able to
enter a promotion code
This will give a discount
We need to store the code and discount value
{
…,
"promotion": {
"code": "20OFF",
"discountAmount": 20
}
}
The order JSON will include the an
promotion object…
…so there are no changes
needed in the database!
Nothing to do in the database!
relax!
So you can sit back and count the money!
Ryan McGuire / Gratisography
0
20
40
60
80
100
120
Customers love the promotion
Sales are going through the roof!
Cake for everyone!
The promotion is a success!
Ryan McGuire / Gratisography
Where's the
$$$?!
…the $$$ tells a different story
But finance are unhappy…
Ryan McGuire / Gratisography
-250
-200
-150
-100
-50
0
50
100
150
Red bars = sales
Yellow line = profits
The discount is too big!
We're losing money!
Finance need to view order profitability
They need to understand where we're losing money
User Story #6
Store unit cost for each brick
We need to update the product JSON;
adding unitCost to every object in the bricks arrays
{ …,
"bricks": [ {
"colour": "red",
"shape": "cube",
"quantity": 13
}, {
"colour": "green",
"shape": "cuboid",
"quantity": 17
}, …
]
}
Add unitCost
"Luckily" we have the costs in a spreadsheet!
"bricks": [ {
"colour": "red",
"shape": "cube",
"quantity": 13
}, {
"colour": "green",
"shape": "cuboid",
"quantity": 17
}, …
] join on
colour, shape
We need to combine the spreadsheet
data with the stored JSON
Step 1: transform JSON
to rows-and-columns
Step 3: convert
back to JSON
Step 2: join
the costs
Photo by Gus Ruballo on Unsplash
Buckle up!
This will be a bumpy ride!
select * from external ( (
colour varchar2(30),
shape varchar2(30),
unit_cost number
)
default directory tmp
location ( 'costs.csv' )
)
From 18c you can query files "on the
fly" with an inline external table
select product_id, j.*
from products, json_table (
product_json columns (
nested bricks[*] columns (
pos for ordinality,
colour path '$.colour',
shape path '$.shape',
brick format json path '$'
)
)
) j
Using JSON_table to
extract the bricks as rows
select product_id, j.*
from products, json_table (
product_json columns (
nested bricks[*] columns (
pos for ordinality,
colour path '$.colour',
shape path '$.shape',
brick format json path '$'
)
)
) j
select product_id, j.*
from products, json_table (
product_json columns (
nested bricks[*] columns (
pos for ordinality,
colour path '$.colour',
shape path '$.shape',
brick format json path '$'
)
)
) j
with costs as (
select * from external …
), bricks as (
select product_id, j.*
from products, json_table (
…
)
)
select …
from bricks join costs
on …
We've joined the data, but how do
we convert it back to JSON?
json_object
json_objectagg
json_array
json_arrayagg
(12.2)
JSON Generation Functions
select json_object (
'colour' value b.colour,
'shape' value b.shape,
'quantity' value b.quantity,
'unitCost' value c.cost
)
from bricks b
join costs c
on b.colour = c.colour
and b.shape = c.shape;
So you can create a brick
object with json_object…
select json_mergepatch (
brick,
'{ "unitCost": ' || c.cost || '}'
)
from bricks b
join costs c
on b.colour = c.colour
and b.shape = c.shape;
Add/replace this…
…to this document
… or use
json_mergepatch (19c)
to add it to the brick object
{
"colour": "red",
"shape": "cube",
"quantity": 13,
"unitCost": 0.59
}
{
"colour": "green",
"shape": "cuboid",
"quantity": 17,
"unitCost": 0.39
}
This returns a row
for each brick
To combine them
into an array for
each product, use
json_arrayagg
json_arrayagg (
json_mergepatch (
brick,
'{ "unitCost": ' || cost || '}'
) order by pos
)
[ {
"colour": "red",
"shape": "cube",
"quantity": 13,
"unitCost": 0.59
}, {
"colour": "green",
"shape": "cuboid",
"quantity": 17,
"unitCost": 0.39
}, …
]
Make the array into
an object with
json_object
json_object (
'bricks' value
json_arrayagg (
json_mergepatch (
brick,
'{ "unitCost": ' || cost || '}'
) order by pos
)
)
"bricks": [ {
"colour": "red",
"shape": "cube",
"quantity": 13,
"unitCost": 0.59
}, {
"colour": "green",
"shape": "cuboid",
"quantity": 17,
"unitCost": 0.39
}, …
]
And replace this
array in the product
JSON with
json_mergepatch
json_mergepatch (
product,
json_object (
'bricks' value
json_arrayagg (
json_mergepatch (
brick,
'{ "unitCost": ' || cost || '}'
) order by pos
)
)
)
{
"productName": "GEEKWAGON",
"descripion": "Ut commodo in …",
"unitPrice": 35.97,
"bricks": [ {
…, "unitCost": 0.59
}, {
…, "unitCost": 0.39
}, …
]
}
Finally!
We've added
unitCost to every
element in the array
We just need to
update the table…
update products
set product_json = (
with costs as (
select * from external …
), bricks as (
select …
)
select json_mergepatch …
)
…at least we can view order profitability now
That was hard work
Ryan McGuire / Gratisography
User Story #7
Create report
prices - discount – total cost
We've got the data;
but want an easier way to query it…
dbms_json.add_virtual_columns (
'orders', 'order_json'
);
JSON Data Guide
Added in 12.2, the JSON Data Guide
enables you to expose attributes as virtual
columns in the table. To do this, the column
must have a json search index
desc orders
Name Null? Type
ORDER_ID NOT NULL NUMBER(38)
ORDER_JSON NOT NULL BLOB
ORDER_JSON$customerId NUMBER
ORDER_JSON$orderDatetime VARCHAR2(32)
ORDER_JSON$code VARCHAR2(8)
ORDER_JSON$discountAmount NUMBER
Sadly it only exposes
scalar (non-array) values
dbms_json.create_view_on_path (
'product_bricks_vw', 'products',
'product_json', '$'
);
…using json_table
on this!
Create this view…
Luckily you can create
a view instead!
select product_id,
"PRODUCT_JSON$shape" shape,
"PRODUCT_JSON$colour" colour
from product_bricks_vw
order by product_id, shape, colour
You can now query the
view to see JSON as
rows-and-columns
PRODUCT_ID SHAPE COLOUR
1 cube green
1 cube red
1 cylinder blue
1 cylinder blue
1 cylinder green
1 cylinder green
… … …
The unique key
for a brick is
(colour, shape)
Some products have
duplicate entries
in the bricks array!
We're shipping too
many bricks!
User Story #8
FIX ALL THE DATAZ!
We need to remove all the duplicate entries
from the product brick arrays
{ ..., "bricks" : [
{
"colour" : "red",
"shape" : "cylinder",
"quantity" : 20,
"unitCost" : 0.39
}, {
"colour" : "red",
"shape" : "cylinder",
"quantity" : 20,
"unitCost" : 0.39
}
{ ..., "bricks" : [
{
"colour" : "red",
"shape" : "cylinder",
"quantity" : 8,
"unitCost" : 0.39
}, {
"colour" : "blue",
"shape" : "cylinder",
"quantity" : 10,
"unitCost" : 0.98
}
Comparing the brick arrays
for two products shows
unitCost is duplicated
{ ..., "bricks" : [
{
"colour" : "red",
"shape" : "cylinder",
"quantity" : 20,
"unitCost" : 0.39
}, {
"colour" : "red",
"shape" : "cylinder",
"quantity" : 20,
"unitCost" : 0.39
}
{ ..., "bricks" : [
{
"colour" : "red",
"shape" : "cylinder",
"quantity" : 8,
"unitCost" : 0.39
}, {
"colour" : "blue",
"shape" : "cylinder",
"quantity" : 10,
"unitCost" : 0.98
}
And the brick itself is
duplicated within an array
Wrong Data Model
PRODUCTS BRICKS
The JSON models the relationship between
products and bricks as 1:M
This is the wrong data model
the relationship is M:M
Fixed It!
PRODUCTS BRICKSPRODUCT_BRICKS
unique (
product_id,
brick_id
)
{ JSON } { JSON }{ JSON }
You need a junction table
between products and bricks
This avoids duplication &
enables constraints
You still need to model { JSON } data!
Copyright © 2019 Oracle and/or its affiliates.
"The more I work with existing NoSQL
deployments however, the more I believe that their
schemaless nature has become an excuse for
sloppiness and unwillingness to dwell
on a project’s data model beforehand"
- Florents Tselai
https://tselai.com/modern-data-practice-and-the-sql-tradition.html
select distinct "PRODUCT_JSON$shape" shape,
"PRODUCT_JSON$colour" colour,
"PRODUCT_JSON$unitCost" unit_cost
from product_bricks_vw
Moving from 1:M to M:M
Using the JSON Data Guide
view, you can find all the
unique brick types…
with vals as (
select distinct "PRODUCT_JSON$shape" shape,
"PRODUCT_JSON$colour" colour,
"PRODUCT_JSON$unitCost" unit_cost
from product_bricks_vw
)
select rownum brick_id,
v.*
from vals v;
…assign a unique ID to each
( colour, shape ) …
create table bricks as
with vals as (
select distinct "PRODUCT_JSON$shape" shape,
"PRODUCT_JSON$colour" colour,
"PRODUCT_JSON$unitCost" unit_cost
from product_bricks_vw
)
select rownum brick_id,
v.*
from vals v;
…and create a table
from the results!
create table bricks as
with vals as (
select distinct "PRODUCT_JSON$shape" "shape",
"PRODUCT_JSON$colour" "colour",
"PRODUCT_JSON$unitCost" "unitCost"
from product_bricks_vw
)
select rownum brick_id,
json_object ( v.* ) brick_json
from vals v;
19c simplification
(Storing the values as
JSON if you want)
create table product_bricks as
select distinct product_id, brick_id
from product_bricks_vw
join bricks
on ...
Create the Join Table
json_mergepatch (
product_json,
'{ "bricks": null }'
)
If you pass a null value for an
attribute to JSON_mergepatch,
it's removed from the source
Removing the bricks array from products
When should I store { JSON }?
Storing JSON can be the right choice for…
JSON responses
- 3rd party APIs
- IoT devices
Schema extensions
- flex fields
- sparse columns
1 2
Further Reading
How to Store, Query, and Create JSON
Documents in Oracle Database Blog Post
http://bit.ly/json-in-oracle-db
Presentation Live SQL Scripts
http://bit.ly/agile-json-livesql
Copyright © 2019 Oracle and/or its affiliates.
Copyright © 2019 Oracle and/or its affiliates.
VS
Some people suggest JSON and
relational are fundamentally different
Copyright © 2019 Oracle and/or its affiliates.
VS
This is not the case!
However you store data,
you still need to normalize it
to avoid duplication and errors
Copyright © 2019 Oracle and/or its affiliates.
How you store the data is a spectrum
from just rows-and-columns to wholly
JSON and everything in-between
Copyright © 2019 Oracle and/or its affiliates.
Oracle Database
supports it all!
However you store
your data
asktom.oracle.com
#MakeDataGreatAgain
Ryan McGuire / Gratisography

More Related Content

What's hot

Data guard architecture
Data guard architectureData guard architecture
Data guard architectureVimlendu Kumar
 
Oracle Real Application Clusters (RAC) 12c Rel. 2 - Operational Best Practices
Oracle Real Application Clusters (RAC) 12c Rel. 2 - Operational Best PracticesOracle Real Application Clusters (RAC) 12c Rel. 2 - Operational Best Practices
Oracle Real Application Clusters (RAC) 12c Rel. 2 - Operational Best PracticesMarkus Michalewicz
 
Best Practices for the Most Impactful Oracle Database 18c and 19c Features
Best Practices for the Most Impactful Oracle Database 18c and 19c FeaturesBest Practices for the Most Impactful Oracle Database 18c and 19c Features
Best Practices for the Most Impactful Oracle Database 18c and 19c FeaturesMarkus Michalewicz
 
"It can always get worse!" – Lessons Learned in over 20 years working with Or...
"It can always get worse!" – Lessons Learned in over 20 years working with Or..."It can always get worse!" – Lessons Learned in over 20 years working with Or...
"It can always get worse!" – Lessons Learned in over 20 years working with Or...Markus Michalewicz
 
Oracle 10g Performance: chapter 02 aas
Oracle 10g Performance: chapter 02 aasOracle 10g Performance: chapter 02 aas
Oracle 10g Performance: chapter 02 aasKyle Hailey
 
Oracle GoldenGate 18c - REST API Examples
Oracle GoldenGate 18c - REST API ExamplesOracle GoldenGate 18c - REST API Examples
Oracle GoldenGate 18c - REST API ExamplesBobby Curtis
 
Harnessing the Power of Optimizer Hints
Harnessing the Power of Optimizer HintsHarnessing the Power of Optimizer Hints
Harnessing the Power of Optimizer HintsMaria Colgan
 
Kafka Summit NYC 2017 - Singe Message Transforms are not the Transformations ...
Kafka Summit NYC 2017 - Singe Message Transforms are not the Transformations ...Kafka Summit NYC 2017 - Singe Message Transforms are not the Transformations ...
Kafka Summit NYC 2017 - Singe Message Transforms are not the Transformations ...confluent
 
InfluxDB IOx Tech Talks: The Impossible Dream: Easy-to-Use, Super Fast Softw...
InfluxDB IOx Tech Talks: The Impossible Dream:  Easy-to-Use, Super Fast Softw...InfluxDB IOx Tech Talks: The Impossible Dream:  Easy-to-Use, Super Fast Softw...
InfluxDB IOx Tech Talks: The Impossible Dream: Easy-to-Use, Super Fast Softw...InfluxData
 
Oracle AHF Insights 23c - Deeper Diagnostic Insights for your Oracle Database...
Oracle AHF Insights 23c - Deeper Diagnostic Insights for your Oracle Database...Oracle AHF Insights 23c - Deeper Diagnostic Insights for your Oracle Database...
Oracle AHF Insights 23c - Deeper Diagnostic Insights for your Oracle Database...Sandesh Rao
 
Part1 of SQL Tuning Workshop - Understanding the Optimizer
Part1 of SQL Tuning Workshop - Understanding the OptimizerPart1 of SQL Tuning Workshop - Understanding the Optimizer
Part1 of SQL Tuning Workshop - Understanding the OptimizerMaria Colgan
 
Oracle sql high performance tuning
Oracle sql high performance tuningOracle sql high performance tuning
Oracle sql high performance tuningGuy Harrison
 
Evening out the uneven: dealing with skew in Flink
Evening out the uneven: dealing with skew in FlinkEvening out the uneven: dealing with skew in Flink
Evening out the uneven: dealing with skew in FlinkFlink Forward
 
Oracle GoldenGate 21c New Features and Best Practices
Oracle GoldenGate 21c New Features and Best PracticesOracle GoldenGate 21c New Features and Best Practices
Oracle GoldenGate 21c New Features and Best PracticesBobby Curtis
 
New Generation Oracle RAC Performance
New Generation Oracle RAC PerformanceNew Generation Oracle RAC Performance
New Generation Oracle RAC PerformanceAnil Nair
 
Oracle Database: Checklist Connection Issues
Oracle Database: Checklist Connection IssuesOracle Database: Checklist Connection Issues
Oracle Database: Checklist Connection IssuesMarkus Flechtner
 
Amazon Aurora Storage Demystified: How It All Works (DAT363) - AWS re:Invent ...
Amazon Aurora Storage Demystified: How It All Works (DAT363) - AWS re:Invent ...Amazon Aurora Storage Demystified: How It All Works (DAT363) - AWS re:Invent ...
Amazon Aurora Storage Demystified: How It All Works (DAT363) - AWS re:Invent ...Amazon Web Services
 

What's hot (20)

Data guard architecture
Data guard architectureData guard architecture
Data guard architecture
 
Oracle Real Application Clusters (RAC) 12c Rel. 2 - Operational Best Practices
Oracle Real Application Clusters (RAC) 12c Rel. 2 - Operational Best PracticesOracle Real Application Clusters (RAC) 12c Rel. 2 - Operational Best Practices
Oracle Real Application Clusters (RAC) 12c Rel. 2 - Operational Best Practices
 
Best Practices for the Most Impactful Oracle Database 18c and 19c Features
Best Practices for the Most Impactful Oracle Database 18c and 19c FeaturesBest Practices for the Most Impactful Oracle Database 18c and 19c Features
Best Practices for the Most Impactful Oracle Database 18c and 19c Features
 
"It can always get worse!" – Lessons Learned in over 20 years working with Or...
"It can always get worse!" – Lessons Learned in over 20 years working with Or..."It can always get worse!" – Lessons Learned in over 20 years working with Or...
"It can always get worse!" – Lessons Learned in over 20 years working with Or...
 
Oracle 10g Performance: chapter 02 aas
Oracle 10g Performance: chapter 02 aasOracle 10g Performance: chapter 02 aas
Oracle 10g Performance: chapter 02 aas
 
Oracle GoldenGate 18c - REST API Examples
Oracle GoldenGate 18c - REST API ExamplesOracle GoldenGate 18c - REST API Examples
Oracle GoldenGate 18c - REST API Examples
 
Harnessing the Power of Optimizer Hints
Harnessing the Power of Optimizer HintsHarnessing the Power of Optimizer Hints
Harnessing the Power of Optimizer Hints
 
Kafka Summit NYC 2017 - Singe Message Transforms are not the Transformations ...
Kafka Summit NYC 2017 - Singe Message Transforms are not the Transformations ...Kafka Summit NYC 2017 - Singe Message Transforms are not the Transformations ...
Kafka Summit NYC 2017 - Singe Message Transforms are not the Transformations ...
 
Rac questions
Rac questionsRac questions
Rac questions
 
InfluxDB IOx Tech Talks: The Impossible Dream: Easy-to-Use, Super Fast Softw...
InfluxDB IOx Tech Talks: The Impossible Dream:  Easy-to-Use, Super Fast Softw...InfluxDB IOx Tech Talks: The Impossible Dream:  Easy-to-Use, Super Fast Softw...
InfluxDB IOx Tech Talks: The Impossible Dream: Easy-to-Use, Super Fast Softw...
 
Oracle AHF Insights 23c - Deeper Diagnostic Insights for your Oracle Database...
Oracle AHF Insights 23c - Deeper Diagnostic Insights for your Oracle Database...Oracle AHF Insights 23c - Deeper Diagnostic Insights for your Oracle Database...
Oracle AHF Insights 23c - Deeper Diagnostic Insights for your Oracle Database...
 
Data guard oracle
Data guard oracleData guard oracle
Data guard oracle
 
Part1 of SQL Tuning Workshop - Understanding the Optimizer
Part1 of SQL Tuning Workshop - Understanding the OptimizerPart1 of SQL Tuning Workshop - Understanding the Optimizer
Part1 of SQL Tuning Workshop - Understanding the Optimizer
 
Oracle sql high performance tuning
Oracle sql high performance tuningOracle sql high performance tuning
Oracle sql high performance tuning
 
Evening out the uneven: dealing with skew in Flink
Evening out the uneven: dealing with skew in FlinkEvening out the uneven: dealing with skew in Flink
Evening out the uneven: dealing with skew in Flink
 
Oracle GoldenGate 21c New Features and Best Practices
Oracle GoldenGate 21c New Features and Best PracticesOracle GoldenGate 21c New Features and Best Practices
Oracle GoldenGate 21c New Features and Best Practices
 
Oracle GoldenGate
Oracle GoldenGate Oracle GoldenGate
Oracle GoldenGate
 
New Generation Oracle RAC Performance
New Generation Oracle RAC PerformanceNew Generation Oracle RAC Performance
New Generation Oracle RAC Performance
 
Oracle Database: Checklist Connection Issues
Oracle Database: Checklist Connection IssuesOracle Database: Checklist Connection Issues
Oracle Database: Checklist Connection Issues
 
Amazon Aurora Storage Demystified: How It All Works (DAT363) - AWS re:Invent ...
Amazon Aurora Storage Demystified: How It All Works (DAT363) - AWS re:Invent ...Amazon Aurora Storage Demystified: How It All Works (DAT363) - AWS re:Invent ...
Amazon Aurora Storage Demystified: How It All Works (DAT363) - AWS re:Invent ...
 

Similar to Agile Database Development with JSON

Going Native: Leveraging the New JSON Native Datatype in Oracle 21c
Going Native: Leveraging the New JSON Native Datatype in Oracle 21cGoing Native: Leveraging the New JSON Native Datatype in Oracle 21c
Going Native: Leveraging the New JSON Native Datatype in Oracle 21cJim Czuprynski
 
IBM Db2 JSON 11.5
IBM  Db2 JSON 11.5IBM  Db2 JSON 11.5
IBM Db2 JSON 11.5Phil Downey
 
ADBMS ASSIGNMENT
ADBMS ASSIGNMENTADBMS ASSIGNMENT
ADBMS ASSIGNMENTLori Moore
 
MongoDB World 2018: Keynote
MongoDB World 2018: KeynoteMongoDB World 2018: Keynote
MongoDB World 2018: KeynoteMongoDB
 
DN 2017 | Reducing pain in data engineering | Martin Loetzsch | Project A
DN 2017 | Reducing pain in data engineering | Martin Loetzsch | Project ADN 2017 | Reducing pain in data engineering | Martin Loetzsch | Project A
DN 2017 | Reducing pain in data engineering | Martin Loetzsch | Project ADataconomy Media
 
MongoDB .local Chicago 2019: Still Haven't Found What You Are Looking For? Us...
MongoDB .local Chicago 2019: Still Haven't Found What You Are Looking For? Us...MongoDB .local Chicago 2019: Still Haven't Found What You Are Looking For? Us...
MongoDB .local Chicago 2019: Still Haven't Found What You Are Looking For? Us...MongoDB
 
[MongoDB.local Bengaluru 2018] Keynote
[MongoDB.local Bengaluru 2018] Keynote[MongoDB.local Bengaluru 2018] Keynote
[MongoDB.local Bengaluru 2018] KeynoteMongoDB
 
Connecting Teradata and MongoDB with QueryGrid
Connecting Teradata and MongoDB with QueryGridConnecting Teradata and MongoDB with QueryGrid
Connecting Teradata and MongoDB with QueryGridMongoDB
 
MongoDB .local Munich 2019: Still Haven't Found What You Are Looking For? Use...
MongoDB .local Munich 2019: Still Haven't Found What You Are Looking For? Use...MongoDB .local Munich 2019: Still Haven't Found What You Are Looking For? Use...
MongoDB .local Munich 2019: Still Haven't Found What You Are Looking For? Use...MongoDB
 
Relevance trilogy may dream be with you! (dec17)
Relevance trilogy  may dream be with you! (dec17)Relevance trilogy  may dream be with you! (dec17)
Relevance trilogy may dream be with you! (dec17)Woonsan Ko
 
Elixir, GraphQL and Vue.js
Elixir, GraphQL and Vue.jsElixir, GraphQL and Vue.js
Elixir, GraphQL and Vue.jsJeroen Visser
 
Application Development & Database Choices: Postgres Support for non Relation...
Application Development & Database Choices: Postgres Support for non Relation...Application Development & Database Choices: Postgres Support for non Relation...
Application Development & Database Choices: Postgres Support for non Relation...EDB
 
JSON Support in DB2 for z/OS
JSON Support in DB2 for z/OSJSON Support in DB2 for z/OS
JSON Support in DB2 for z/OSJane Man
 
Geek Sync | Rewriting Bad SQL Code 101
Geek Sync | Rewriting Bad SQL Code 101Geek Sync | Rewriting Bad SQL Code 101
Geek Sync | Rewriting Bad SQL Code 101IDERA Software
 
Beyond PHP - It's not (just) about the code
Beyond PHP - It's not (just) about the codeBeyond PHP - It's not (just) about the code
Beyond PHP - It's not (just) about the codeWim Godden
 
SenchaCon 2016: Handle Real-World Data with Confidence - Fredric Berling
SenchaCon 2016: Handle Real-World Data with Confidence - Fredric Berling SenchaCon 2016: Handle Real-World Data with Confidence - Fredric Berling
SenchaCon 2016: Handle Real-World Data with Confidence - Fredric Berling Sencha
 
Big Objects in Salesforce
Big Objects in SalesforceBig Objects in Salesforce
Big Objects in SalesforceAmit Chaudhary
 

Similar to Agile Database Development with JSON (20)

Going Native: Leveraging the New JSON Native Datatype in Oracle 21c
Going Native: Leveraging the New JSON Native Datatype in Oracle 21cGoing Native: Leveraging the New JSON Native Datatype in Oracle 21c
Going Native: Leveraging the New JSON Native Datatype in Oracle 21c
 
IBM Db2 JSON 11.5
IBM  Db2 JSON 11.5IBM  Db2 JSON 11.5
IBM Db2 JSON 11.5
 
KPMG - TASK 1.pdf
KPMG - TASK 1.pdfKPMG - TASK 1.pdf
KPMG - TASK 1.pdf
 
ADBMS ASSIGNMENT
ADBMS ASSIGNMENTADBMS ASSIGNMENT
ADBMS ASSIGNMENT
 
MongoDB World 2018: Keynote
MongoDB World 2018: KeynoteMongoDB World 2018: Keynote
MongoDB World 2018: Keynote
 
MongoDB Meetup
MongoDB MeetupMongoDB Meetup
MongoDB Meetup
 
DN 2017 | Reducing pain in data engineering | Martin Loetzsch | Project A
DN 2017 | Reducing pain in data engineering | Martin Loetzsch | Project ADN 2017 | Reducing pain in data engineering | Martin Loetzsch | Project A
DN 2017 | Reducing pain in data engineering | Martin Loetzsch | Project A
 
MongoDB .local Chicago 2019: Still Haven't Found What You Are Looking For? Us...
MongoDB .local Chicago 2019: Still Haven't Found What You Are Looking For? Us...MongoDB .local Chicago 2019: Still Haven't Found What You Are Looking For? Us...
MongoDB .local Chicago 2019: Still Haven't Found What You Are Looking For? Us...
 
Test data article
Test data articleTest data article
Test data article
 
[MongoDB.local Bengaluru 2018] Keynote
[MongoDB.local Bengaluru 2018] Keynote[MongoDB.local Bengaluru 2018] Keynote
[MongoDB.local Bengaluru 2018] Keynote
 
Connecting Teradata and MongoDB with QueryGrid
Connecting Teradata and MongoDB with QueryGridConnecting Teradata and MongoDB with QueryGrid
Connecting Teradata and MongoDB with QueryGrid
 
MongoDB .local Munich 2019: Still Haven't Found What You Are Looking For? Use...
MongoDB .local Munich 2019: Still Haven't Found What You Are Looking For? Use...MongoDB .local Munich 2019: Still Haven't Found What You Are Looking For? Use...
MongoDB .local Munich 2019: Still Haven't Found What You Are Looking For? Use...
 
Relevance trilogy may dream be with you! (dec17)
Relevance trilogy  may dream be with you! (dec17)Relevance trilogy  may dream be with you! (dec17)
Relevance trilogy may dream be with you! (dec17)
 
Elixir, GraphQL and Vue.js
Elixir, GraphQL and Vue.jsElixir, GraphQL and Vue.js
Elixir, GraphQL and Vue.js
 
Application Development & Database Choices: Postgres Support for non Relation...
Application Development & Database Choices: Postgres Support for non Relation...Application Development & Database Choices: Postgres Support for non Relation...
Application Development & Database Choices: Postgres Support for non Relation...
 
JSON Support in DB2 for z/OS
JSON Support in DB2 for z/OSJSON Support in DB2 for z/OS
JSON Support in DB2 for z/OS
 
Geek Sync | Rewriting Bad SQL Code 101
Geek Sync | Rewriting Bad SQL Code 101Geek Sync | Rewriting Bad SQL Code 101
Geek Sync | Rewriting Bad SQL Code 101
 
Beyond PHP - It's not (just) about the code
Beyond PHP - It's not (just) about the codeBeyond PHP - It's not (just) about the code
Beyond PHP - It's not (just) about the code
 
SenchaCon 2016: Handle Real-World Data with Confidence - Fredric Berling
SenchaCon 2016: Handle Real-World Data with Confidence - Fredric Berling SenchaCon 2016: Handle Real-World Data with Confidence - Fredric Berling
SenchaCon 2016: Handle Real-World Data with Confidence - Fredric Berling
 
Big Objects in Salesforce
Big Objects in SalesforceBig Objects in Salesforce
Big Objects in Salesforce
 

More from Chris Saxon

Game of Fraud Detection with SQL and Machine Learning
Game of Fraud Detection with SQL and Machine LearningGame of Fraud Detection with SQL and Machine Learning
Game of Fraud Detection with SQL and Machine LearningChris Saxon
 
Polymorphic Table Functions in SQL
Polymorphic Table Functions in SQLPolymorphic Table Functions in SQL
Polymorphic Table Functions in SQLChris Saxon
 
Using Edition-Based Redefinition for Zero Downtime PL/SQL Changes
Using Edition-Based Redefinition for Zero Downtime PL/SQL ChangesUsing Edition-Based Redefinition for Zero Downtime PL/SQL Changes
Using Edition-Based Redefinition for Zero Downtime PL/SQL ChangesChris Saxon
 
Why Isn't My Query Using an Index? An Introduction to SQL Performance
Why Isn't My Query Using an Index? An Introduction to SQL PerformanceWhy Isn't My Query Using an Index? An Introduction to SQL Performance
Why Isn't My Query Using an Index? An Introduction to SQL PerformanceChris Saxon
 
12 Things Developers Will Love About Oracle Database 12c Release 2
12 Things Developers Will Love About Oracle Database 12c Release 212 Things Developers Will Love About Oracle Database 12c Release 2
12 Things Developers Will Love About Oracle Database 12c Release 2Chris Saxon
 
How to Hack Your App Using SQL Injection
How to Hack Your App Using SQL InjectionHow to Hack Your App Using SQL Injection
How to Hack Your App Using SQL InjectionChris Saxon
 
18(ish) Things You'll Love About Oracle Database 18c
18(ish) Things You'll Love About Oracle Database 18c18(ish) Things You'll Love About Oracle Database 18c
18(ish) Things You'll Love About Oracle Database 18cChris Saxon
 
How to Find Patterns in Your Data with SQL
How to Find Patterns in Your Data with SQLHow to Find Patterns in Your Data with SQL
How to Find Patterns in Your Data with SQLChris Saxon
 

More from Chris Saxon (8)

Game of Fraud Detection with SQL and Machine Learning
Game of Fraud Detection with SQL and Machine LearningGame of Fraud Detection with SQL and Machine Learning
Game of Fraud Detection with SQL and Machine Learning
 
Polymorphic Table Functions in SQL
Polymorphic Table Functions in SQLPolymorphic Table Functions in SQL
Polymorphic Table Functions in SQL
 
Using Edition-Based Redefinition for Zero Downtime PL/SQL Changes
Using Edition-Based Redefinition for Zero Downtime PL/SQL ChangesUsing Edition-Based Redefinition for Zero Downtime PL/SQL Changes
Using Edition-Based Redefinition for Zero Downtime PL/SQL Changes
 
Why Isn't My Query Using an Index? An Introduction to SQL Performance
Why Isn't My Query Using an Index? An Introduction to SQL PerformanceWhy Isn't My Query Using an Index? An Introduction to SQL Performance
Why Isn't My Query Using an Index? An Introduction to SQL Performance
 
12 Things Developers Will Love About Oracle Database 12c Release 2
12 Things Developers Will Love About Oracle Database 12c Release 212 Things Developers Will Love About Oracle Database 12c Release 2
12 Things Developers Will Love About Oracle Database 12c Release 2
 
How to Hack Your App Using SQL Injection
How to Hack Your App Using SQL InjectionHow to Hack Your App Using SQL Injection
How to Hack Your App Using SQL Injection
 
18(ish) Things You'll Love About Oracle Database 18c
18(ish) Things You'll Love About Oracle Database 18c18(ish) Things You'll Love About Oracle Database 18c
18(ish) Things You'll Love About Oracle Database 18c
 
How to Find Patterns in Your Data with SQL
How to Find Patterns in Your Data with SQLHow to Find Patterns in Your Data with SQL
How to Find Patterns in Your Data with SQL
 

Recently uploaded

Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?Igalia
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MIND CTI
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CVKhem
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FMESafe Software
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024The Digital Insurer
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Principled Technologies
 
Top 10 Most Downloaded Games on Play Store in 2024
Top 10 Most Downloaded Games on Play Store in 2024Top 10 Most Downloaded Games on Play Store in 2024
Top 10 Most Downloaded Games on Play Store in 2024SynarionITSolutions
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...apidays
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businesspanagenda
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)wesley chun
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...apidays
 

Recently uploaded (20)

Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
 
Top 10 Most Downloaded Games on Play Store in 2024
Top 10 Most Downloaded Games on Play Store in 2024Top 10 Most Downloaded Games on Play Store in 2024
Top 10 Most Downloaded Games on Play Store in 2024
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 

Agile Database Development with JSON

  • 1. 1 Agile Database Development with JSON Chris Saxon Developer Advocate, @ChrisRSaxon & @SQLDaily blogs.oracle.com/sql youtube.com/c/TheMagicofSQL asktom.oracle.com
  • 2. Image by Semevent from Pixabay We're creating a new online store Selling boxes of brick models
  • 3. Photo by Jon Tyson on Unsplash We need to respond to customer feedback…
  • 4. Photo by Johannes Plenio on Unsplash …and evolve the application rapidly
  • 5. Photo by Brannon Naito on Unsplash working in short sprints and releasing often So we need to be Agile
  • 6. { JSON } To support this we'll store data as
  • 7. 7 Agile Database Development with JSON Chris Saxon Developer Advocate, @ChrisRSaxon & @SQLDaily blogs.oracle.com/sql youtube.com/c/TheMagicofSQL asktom.oracle.com
  • 8. The following is intended to outline our general product direction. It is intended for information purposes only, and may not be incorporated into any contract. It is not a commitment to deliver any material, code, or functionality, and should not be relied upon in making purchasing decisions. The development, release, timing, and pricing of any features or functionality described for Oracle’s products may change and remains at the sole discretion of Oracle Corporation. Statements in this presentation relating to Oracle’s future plans, expectations, beliefs, intentions and prospects are “forward-looking statements” and are subject to material risks and uncertainties. A detailed discussion of these factors and other risks that affect our business is contained in Oracle’s Securities and Exchange Commission (SEC) filings, including our most recent reports on Form 10-K and Form 10-Q under the heading “Risk Factors.” These filings are available on the SEC’s website or on Oracle’s website at http://www.oracle.com/investor. All information in this presentation is current as of September 2019 and Oracle undertakes no duty to update any statement in light of new information or future events. Safe Harbor
  • 9. User Story #1 We must be able to store product & order details So we need to create the tables and define CRUD operations on them
  • 10. create table products ( product_id integer not null primary key, product_json ##TODO## not null, check ( json_data is json ) ); create table orders ( order_id integer not null primary key, order_json ##TODO## not null, check ( json_data is json ) ); The tables are just a primary key, JSON column, & is json constraint
  • 11. create table products ( product_id integer not null primary key, product_json ##TODO## not null, check ( json_data is json ) ); create table orders ( order_id integer not null primary key, order_json ##TODO## not null, check ( json_data is json ) ); But which data type to use for JSON?!
  • 12. Which data type should you use for JSON? "Small" documents varchar2 "Large" documents ??? <= 4,000 bytes / 32k
  • 13. "Small" documents varchar2 "Large" documents blob JSON data type coming in 20c Avoids character set conversions Less storage than clob
  • 14. create table products ( product_id integer not null primary key, product_json blob not null, check ( json_data is json ) ); create table orders ( order_id integer not null primary key, order_json blob not null, check ( json_data is json ) );
  • 15. insert into products ( product_json ) values ( utl_raw.cast_to_raw ( '{ "productName": "..." }' ) ); BLOBs need extra processing on insert
  • 16. select product_json from products; PRODUCT_JSON 7B202274686973223A20227468617422207D and select to make them human readable
  • 17. select json_serialize ( product_json returning clob pretty ) jdata from products; JDATA { "productName": "..." } Added in 19c json_serialize converts JSON data to text; which you can pretty print for readability
  • 18. select json_query ( product_json, '$' returning clob pretty ) jdata from products; JDATA { "productName": "..." } In earlier releases use json_query The clob return type was added in 18c
  • 19. User Story #2 Customers must be able to search by price So we need to query the products table for JSON where the unitPrice is in the specified range
  • 20. { "productName": "GEEKWAGON", "descripion": "Ut commodo in …", "unitPrice": 35.97, "bricks": [ { "colour": "red", "shape": "cube", "quantity": 13 }, { "colour": "green", "shape": "cube", "quantity": 17 }, … ] } We need to search for this value in the documents
  • 21. select * from products p where p.product_json.unitPrice <= :max_price; But remember it returns varchar2 => implicit conversion! Use simple dot-notation to access the value
  • 22. select * from products p where json_value ( product_json, '$.unitPrice' returning number ) <= :max_price; json_value gives you more control So this returns number => no implicit conversion! :)
  • 23. select * from products p where p.product_json.unitPrice.number() <= :max_price; From 19c you can state the return type with simple dot-notation
  • 24. User Story #3 Customers must be able to view their orders Showing order details and a list of what they bought So we need to join the order productIds to products
  • 25. { "customerId" : 2, "orderDatetime" : "2019-01-01T03:25:43", "products" : [ { "productId" : 1, "unitPrice" : 74.95 }, { "productId" : 10, "unitPrice" : 35.97 }, … ] } We need to extract these from the product array
  • 26. select o.order_json.products[*].productId from orders o; PRODUCTS [2,8,5] [3,9,6] [1,10,7,4] ... With simple dot-notation, you can get an array of the values…
  • 27. select json_query ( order_json, '$.products[*].productId' with array wrapper ) from orders o; PRODUCTS [2,8,5] [3,9,6] [1,10,7,4] ... But to join these to products, we need to convert them to rows… …or with json_query
  • 28. json_table With json_table you can convert JSON… …to relational rows-and-columns
  • 29. with order_items as ( select order_id, t.* from orders o, json_table ( order_json columns ( customerId, nested products[*] columns ( productId, unitPrice ) ) ) t ) Simplified syntax 18c
  • 30. with order_items as ( select order_id, t.* from orders o, json_table ( order_json columns ( customerId, nested products[*] columns ( productId, unitPrice ) ) ) t ) This tells the database to return a row for each element in the products array…
  • 31. select order_id, p.product_json.productName product, unitPrice from order_items oi join products p on oi.productId = p.product_id where customerId = :cust_var order by oi.order_id desc, p.product_id …So you can join output to the products table!
  • 32. Minimum viable product complete! Ship it!
  • 33. Copyright © 2019 Oracle and/or its affiliates. Soooo… How many orders today? …people have lots of questions As always, post release… Ryan McGuire / Gratisography
  • 34. User Story #4 Sales must be able to view today's orders We need to create a dashboard counting orders So we need to search for orders placed today
  • 35. { "customerId" : 2, "orderDatetime" : "2019-01-01T03:25:43", "products" : [ { "productId" : 1, "unitPrice" : 74.95 }, { "productId" : 10, "unitPrice" : 35.97 }, … ] } We need to search for this value in the documents
  • 36. select * from orders o where o.order_json.orderDatetime >= trunc ( sysdate ); ORA-01861: literal does not match format string Remember the implicit conversions? It fails for dates! Use simple dot-notation to access the value
  • 37. select * from orders o where json_value ( order_json, '$.orderDatetime' returning date ) >= trunc ( sysdate ) So you need to define the return type; JSON dates conform to ISO 8601 date
  • 38. 2019-01-01 ISO 8601 date Which is YYYY-MM-DD for dates There is no time component in an ISO date!
  • 39. 2019-01-01T03:25:43 ISO 8601 timestamp Use ISO timestamps to include times Note the "T" between the date and time!
  • 40. select * from orders o where json_value ( order_json, '$.orderDatetime' returning date ) >= trunc ( sysdate ) But the query is very slow…
  • 41. select * from orders o where json_value ( order_json, '$.orderDatetime' returning date ) >= trunc ( sysdate ) { "customerId": 1, … } { "customerId": 2, … } …
  • 42. User Story #4b … and make it fast! currently the query does a full table scan To speed it up we need to create an index!
  • 43. create index orders_date_i on orders ( order_json ); ORA-02327: cannot create index on expression with datatype LOB You can't index LOB data
  • 44. create search index orders_json_i on orders ( order_json ) for json parameters ( 'sync (on commit)' ); Added in 12.2, a json search index enables JSON queries to use an index JSON Search Indexes
  • 45. select * from orders o where json_value ( order_json, '$.orderDatetime' returning date ) >= trunc ( sysdate ) { "customerId": 1, … } { "customerId": 2, … } …
  • 46. ----------------------------------------------------- | Id | Operation | Name | ----------------------------------------------------- | 0 | SELECT STATEMENT | | |* 1 | TABLE ACCESS BY INDEX ROWID| ORDERS | |* 2 | DOMAIN INDEX | ORDERS_JSON_I | ----------------------------------------------------- With the search index in place, the optimizer can use it
  • 47. Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter(JSON_VALUE("ORDER_JSON" FORMAT JSON , '$.orderDatetime' RETURNING TIMESTAMP NULL ON ERROR) >= TIMESTAMP' 2019-01-15 00:00:00') 2 - access("CTXSYS"."CONTAINS"("O"."ORDER_JSON", 'sdatap(TMS_orderDatetime >= "2019-01-15T00:00:00+00:00" /orderDatetime)')>0) Under the covers, this uses Oracle Text
  • 48. create index order_date_i on orders ( json_value ( order_json, '$.orderDatetime' returning date error on error null on empty ) ); It's more efficient to create a function- based index, matching the search you'll do This has some other benefits…
  • 49. create index order_date_i on orders ( json_value ( order_json, '$.orderDatetime' returning date error on error null on empty ) ); Data validation! If the value is not a JSON date; inserts will raise an exception
  • 50. create index order_date_i on orders ( json_value ( order_json, '$.orderDatetime' returning date error on error null on empty ) ); From 12.2 you can also raise an error if the attribute is not present
  • 51. ------------------------------------------------------------ | Id | Operation | Name | ------------------------------------------------------------ | 0 | SELECT STATEMENT | | | 1 | TABLE ACCESS BY INDEX ROWID BATCHED| ORDERS | |* 2 | INDEX RANGE SCAN | ORDER_DATE_I | ------------------------------------------------------------ The function-based index is more efficient, so the optimizer will choose this over the search index
  • 52. Search vs. Function-Based Indexes JSON Search Index Function-based Index Applicability Any JSON query Matching function Performance Slower Faster Use Ad-hoc queries Application queries
  • 53. 0 5 10 15 20 25 With the dashboard in place, it's clear sales are levelling off We need a way to increase sales!
  • 54. We need to offer discounts! …discount promotion codes Marketing have a brilliant plan… Ryan McGuire / Gratisography
  • 55. User Story #5 Customers may be able to enter a promotion code This will give a discount We need to store the code and discount value
  • 56. { …, "promotion": { "code": "20OFF", "discountAmount": 20 } } The order JSON will include the an promotion object… …so there are no changes needed in the database!
  • 57. Nothing to do in the database! relax! So you can sit back and count the money! Ryan McGuire / Gratisography
  • 58. 0 20 40 60 80 100 120 Customers love the promotion Sales are going through the roof!
  • 59. Cake for everyone! The promotion is a success! Ryan McGuire / Gratisography
  • 60. Where's the $$$?! …the $$$ tells a different story But finance are unhappy… Ryan McGuire / Gratisography
  • 61. -250 -200 -150 -100 -50 0 50 100 150 Red bars = sales Yellow line = profits The discount is too big! We're losing money!
  • 62. Finance need to view order profitability They need to understand where we're losing money
  • 63. User Story #6 Store unit cost for each brick We need to update the product JSON; adding unitCost to every object in the bricks arrays
  • 64. { …, "bricks": [ { "colour": "red", "shape": "cube", "quantity": 13 }, { "colour": "green", "shape": "cuboid", "quantity": 17 }, … ] } Add unitCost
  • 65. "Luckily" we have the costs in a spreadsheet!
  • 66. "bricks": [ { "colour": "red", "shape": "cube", "quantity": 13 }, { "colour": "green", "shape": "cuboid", "quantity": 17 }, … ] join on colour, shape We need to combine the spreadsheet data with the stored JSON
  • 67. Step 1: transform JSON to rows-and-columns Step 3: convert back to JSON Step 2: join the costs
  • 68. Photo by Gus Ruballo on Unsplash Buckle up! This will be a bumpy ride!
  • 69. select * from external ( ( colour varchar2(30), shape varchar2(30), unit_cost number ) default directory tmp location ( 'costs.csv' ) ) From 18c you can query files "on the fly" with an inline external table
  • 70. select product_id, j.* from products, json_table ( product_json columns ( nested bricks[*] columns ( pos for ordinality, colour path '$.colour', shape path '$.shape', brick format json path '$' ) ) ) j Using JSON_table to extract the bricks as rows
  • 71. select product_id, j.* from products, json_table ( product_json columns ( nested bricks[*] columns ( pos for ordinality, colour path '$.colour', shape path '$.shape', brick format json path '$' ) ) ) j
  • 72. select product_id, j.* from products, json_table ( product_json columns ( nested bricks[*] columns ( pos for ordinality, colour path '$.colour', shape path '$.shape', brick format json path '$' ) ) ) j
  • 73. with costs as ( select * from external … ), bricks as ( select product_id, j.* from products, json_table ( … ) ) select … from bricks join costs on … We've joined the data, but how do we convert it back to JSON?
  • 75. select json_object ( 'colour' value b.colour, 'shape' value b.shape, 'quantity' value b.quantity, 'unitCost' value c.cost ) from bricks b join costs c on b.colour = c.colour and b.shape = c.shape; So you can create a brick object with json_object…
  • 76. select json_mergepatch ( brick, '{ "unitCost": ' || c.cost || '}' ) from bricks b join costs c on b.colour = c.colour and b.shape = c.shape; Add/replace this… …to this document … or use json_mergepatch (19c) to add it to the brick object
  • 77. { "colour": "red", "shape": "cube", "quantity": 13, "unitCost": 0.59 } { "colour": "green", "shape": "cuboid", "quantity": 17, "unitCost": 0.39 } This returns a row for each brick To combine them into an array for each product, use json_arrayagg
  • 78. json_arrayagg ( json_mergepatch ( brick, '{ "unitCost": ' || cost || '}' ) order by pos )
  • 79. [ { "colour": "red", "shape": "cube", "quantity": 13, "unitCost": 0.59 }, { "colour": "green", "shape": "cuboid", "quantity": 17, "unitCost": 0.39 }, … ] Make the array into an object with json_object
  • 80. json_object ( 'bricks' value json_arrayagg ( json_mergepatch ( brick, '{ "unitCost": ' || cost || '}' ) order by pos ) )
  • 81. "bricks": [ { "colour": "red", "shape": "cube", "quantity": 13, "unitCost": 0.59 }, { "colour": "green", "shape": "cuboid", "quantity": 17, "unitCost": 0.39 }, … ] And replace this array in the product JSON with json_mergepatch
  • 82. json_mergepatch ( product, json_object ( 'bricks' value json_arrayagg ( json_mergepatch ( brick, '{ "unitCost": ' || cost || '}' ) order by pos ) ) )
  • 83. { "productName": "GEEKWAGON", "descripion": "Ut commodo in …", "unitPrice": 35.97, "bricks": [ { …, "unitCost": 0.59 }, { …, "unitCost": 0.39 }, … ] } Finally! We've added unitCost to every element in the array We just need to update the table…
  • 84. update products set product_json = ( with costs as ( select * from external … ), bricks as ( select … ) select json_mergepatch … )
  • 85. …at least we can view order profitability now That was hard work Ryan McGuire / Gratisography
  • 86. User Story #7 Create report prices - discount – total cost We've got the data; but want an easier way to query it…
  • 87. dbms_json.add_virtual_columns ( 'orders', 'order_json' ); JSON Data Guide Added in 12.2, the JSON Data Guide enables you to expose attributes as virtual columns in the table. To do this, the column must have a json search index
  • 88. desc orders Name Null? Type ORDER_ID NOT NULL NUMBER(38) ORDER_JSON NOT NULL BLOB ORDER_JSON$customerId NUMBER ORDER_JSON$orderDatetime VARCHAR2(32) ORDER_JSON$code VARCHAR2(8) ORDER_JSON$discountAmount NUMBER Sadly it only exposes scalar (non-array) values
  • 89. dbms_json.create_view_on_path ( 'product_bricks_vw', 'products', 'product_json', '$' ); …using json_table on this! Create this view… Luckily you can create a view instead!
  • 90. select product_id, "PRODUCT_JSON$shape" shape, "PRODUCT_JSON$colour" colour from product_bricks_vw order by product_id, shape, colour You can now query the view to see JSON as rows-and-columns
  • 91. PRODUCT_ID SHAPE COLOUR 1 cube green 1 cube red 1 cylinder blue 1 cylinder blue 1 cylinder green 1 cylinder green … … … The unique key for a brick is (colour, shape) Some products have duplicate entries in the bricks array! We're shipping too many bricks!
  • 92. User Story #8 FIX ALL THE DATAZ! We need to remove all the duplicate entries from the product brick arrays
  • 93. { ..., "bricks" : [ { "colour" : "red", "shape" : "cylinder", "quantity" : 20, "unitCost" : 0.39 }, { "colour" : "red", "shape" : "cylinder", "quantity" : 20, "unitCost" : 0.39 } { ..., "bricks" : [ { "colour" : "red", "shape" : "cylinder", "quantity" : 8, "unitCost" : 0.39 }, { "colour" : "blue", "shape" : "cylinder", "quantity" : 10, "unitCost" : 0.98 } Comparing the brick arrays for two products shows unitCost is duplicated
  • 94. { ..., "bricks" : [ { "colour" : "red", "shape" : "cylinder", "quantity" : 20, "unitCost" : 0.39 }, { "colour" : "red", "shape" : "cylinder", "quantity" : 20, "unitCost" : 0.39 } { ..., "bricks" : [ { "colour" : "red", "shape" : "cylinder", "quantity" : 8, "unitCost" : 0.39 }, { "colour" : "blue", "shape" : "cylinder", "quantity" : 10, "unitCost" : 0.98 } And the brick itself is duplicated within an array
  • 95. Wrong Data Model PRODUCTS BRICKS The JSON models the relationship between products and bricks as 1:M This is the wrong data model the relationship is M:M
  • 96. Fixed It! PRODUCTS BRICKSPRODUCT_BRICKS unique ( product_id, brick_id ) { JSON } { JSON }{ JSON } You need a junction table between products and bricks This avoids duplication & enables constraints
  • 97. You still need to model { JSON } data!
  • 98. Copyright © 2019 Oracle and/or its affiliates. "The more I work with existing NoSQL deployments however, the more I believe that their schemaless nature has become an excuse for sloppiness and unwillingness to dwell on a project’s data model beforehand" - Florents Tselai https://tselai.com/modern-data-practice-and-the-sql-tradition.html
  • 99. select distinct "PRODUCT_JSON$shape" shape, "PRODUCT_JSON$colour" colour, "PRODUCT_JSON$unitCost" unit_cost from product_bricks_vw Moving from 1:M to M:M Using the JSON Data Guide view, you can find all the unique brick types…
  • 100. with vals as ( select distinct "PRODUCT_JSON$shape" shape, "PRODUCT_JSON$colour" colour, "PRODUCT_JSON$unitCost" unit_cost from product_bricks_vw ) select rownum brick_id, v.* from vals v; …assign a unique ID to each ( colour, shape ) …
  • 101. create table bricks as with vals as ( select distinct "PRODUCT_JSON$shape" shape, "PRODUCT_JSON$colour" colour, "PRODUCT_JSON$unitCost" unit_cost from product_bricks_vw ) select rownum brick_id, v.* from vals v; …and create a table from the results!
  • 102. create table bricks as with vals as ( select distinct "PRODUCT_JSON$shape" "shape", "PRODUCT_JSON$colour" "colour", "PRODUCT_JSON$unitCost" "unitCost" from product_bricks_vw ) select rownum brick_id, json_object ( v.* ) brick_json from vals v; 19c simplification (Storing the values as JSON if you want)
  • 103. create table product_bricks as select distinct product_id, brick_id from product_bricks_vw join bricks on ... Create the Join Table
  • 104. json_mergepatch ( product_json, '{ "bricks": null }' ) If you pass a null value for an attribute to JSON_mergepatch, it's removed from the source Removing the bricks array from products
  • 105. When should I store { JSON }?
  • 106. Storing JSON can be the right choice for… JSON responses - 3rd party APIs - IoT devices Schema extensions - flex fields - sparse columns 1 2
  • 107. Further Reading How to Store, Query, and Create JSON Documents in Oracle Database Blog Post http://bit.ly/json-in-oracle-db Presentation Live SQL Scripts http://bit.ly/agile-json-livesql Copyright © 2019 Oracle and/or its affiliates.
  • 108. Copyright © 2019 Oracle and/or its affiliates. VS Some people suggest JSON and relational are fundamentally different
  • 109. Copyright © 2019 Oracle and/or its affiliates. VS This is not the case! However you store data, you still need to normalize it to avoid duplication and errors
  • 110. Copyright © 2019 Oracle and/or its affiliates. How you store the data is a spectrum from just rows-and-columns to wholly JSON and everything in-between
  • 111. Copyright © 2019 Oracle and/or its affiliates. Oracle Database supports it all! However you store your data