SlideShare a Scribd company logo
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

Oracle sql high performance tuning
Oracle sql high performance tuningOracle sql high performance tuning
Oracle sql high performance tuning
Guy Harrison
 
The Top 5 Reasons to Deploy Your Applications on Oracle RAC
The Top 5 Reasons to Deploy Your Applications on Oracle RACThe Top 5 Reasons to Deploy Your Applications on Oracle RAC
The Top 5 Reasons to Deploy Your Applications on Oracle RAC
Markus Michalewicz
 
Oracle db performance tuning
Oracle db performance tuningOracle db performance tuning
Oracle db performance tuningSimon Huang
 
Oracle Performance Tuning Fundamentals
Oracle Performance Tuning FundamentalsOracle Performance Tuning Fundamentals
Oracle Performance Tuning Fundamentals
Enkitec
 
Tanel Poder - Scripts and Tools short
Tanel Poder - Scripts and Tools shortTanel Poder - Scripts and Tools short
Tanel Poder - Scripts and Tools short
Tanel Poder
 
Exploring Oracle Database Performance Tuning Best Practices for DBAs and Deve...
Exploring Oracle Database Performance Tuning Best Practices for DBAs and Deve...Exploring Oracle Database Performance Tuning Best Practices for DBAs and Deve...
Exploring Oracle Database Performance Tuning Best Practices for DBAs and Deve...Aaron Shilo
 
Catalyst optimizer
Catalyst optimizerCatalyst optimizer
Catalyst optimizer
Ayub Mohammad
 
Oracle Transparent Data Encryption (TDE) 12c
Oracle Transparent Data Encryption (TDE) 12cOracle Transparent Data Encryption (TDE) 12c
Oracle Transparent Data Encryption (TDE) 12c
Nabeel Yoosuf
 
Oracle 12c PDB insights
Oracle 12c PDB insightsOracle 12c PDB insights
Oracle 12c PDB insights
Kirill Loifman
 
DOAG Oracle Unified Audit in Multitenant Environments
DOAG Oracle Unified Audit in Multitenant EnvironmentsDOAG Oracle Unified Audit in Multitenant Environments
DOAG Oracle Unified Audit in Multitenant Environments
Stefan Oehrli
 
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
Markus Michalewicz
 
The Oracle RAC Family of Solutions - Presentation
The Oracle RAC Family of Solutions - PresentationThe Oracle RAC Family of Solutions - Presentation
The Oracle RAC Family of Solutions - Presentation
Markus Michalewicz
 
Apache Calcite (a tutorial given at BOSS '21)
Apache Calcite (a tutorial given at BOSS '21)Apache Calcite (a tutorial given at BOSS '21)
Apache Calcite (a tutorial given at BOSS '21)
Julian Hyde
 
1 - Introduction to PL/SQL
1 - Introduction to PL/SQL1 - Introduction to PL/SQL
1 - Introduction to PL/SQL
rehaniltifat
 
Oracle Latch and Mutex Contention Troubleshooting
Oracle Latch and Mutex Contention TroubleshootingOracle Latch and Mutex Contention Troubleshooting
Oracle Latch and Mutex Contention Troubleshooting
Tanel Poder
 
Explain the explain_plan
Explain the explain_planExplain the explain_plan
Explain the explain_plan
Maria Colgan
 
Mysql security 5.7
Mysql security 5.7 Mysql security 5.7
Mysql security 5.7
Mark Swarbrick
 
Apache Spark Notes
Apache Spark NotesApache Spark Notes
Apache Spark Notes
Venkateswaran Kandasamy
 
Best Practices with ODI : Flexibility
Best Practices with ODI : FlexibilityBest Practices with ODI : Flexibility
Best Practices with ODI : Flexibility
Gurcan Orhan
 

What's hot (20)

Oracle sql high performance tuning
Oracle sql high performance tuningOracle sql high performance tuning
Oracle sql high performance tuning
 
The Top 5 Reasons to Deploy Your Applications on Oracle RAC
The Top 5 Reasons to Deploy Your Applications on Oracle RACThe Top 5 Reasons to Deploy Your Applications on Oracle RAC
The Top 5 Reasons to Deploy Your Applications on Oracle RAC
 
Oracle db performance tuning
Oracle db performance tuningOracle db performance tuning
Oracle db performance tuning
 
Oracle Performance Tuning Fundamentals
Oracle Performance Tuning FundamentalsOracle Performance Tuning Fundamentals
Oracle Performance Tuning Fundamentals
 
Tanel Poder - Scripts and Tools short
Tanel Poder - Scripts and Tools shortTanel Poder - Scripts and Tools short
Tanel Poder - Scripts and Tools short
 
Exploring Oracle Database Performance Tuning Best Practices for DBAs and Deve...
Exploring Oracle Database Performance Tuning Best Practices for DBAs and Deve...Exploring Oracle Database Performance Tuning Best Practices for DBAs and Deve...
Exploring Oracle Database Performance Tuning Best Practices for DBAs and Deve...
 
AWR reports-Measuring CPU
AWR reports-Measuring CPUAWR reports-Measuring CPU
AWR reports-Measuring CPU
 
Catalyst optimizer
Catalyst optimizerCatalyst optimizer
Catalyst optimizer
 
Oracle Transparent Data Encryption (TDE) 12c
Oracle Transparent Data Encryption (TDE) 12cOracle Transparent Data Encryption (TDE) 12c
Oracle Transparent Data Encryption (TDE) 12c
 
Oracle 12c PDB insights
Oracle 12c PDB insightsOracle 12c PDB insights
Oracle 12c PDB insights
 
DOAG Oracle Unified Audit in Multitenant Environments
DOAG Oracle Unified Audit in Multitenant EnvironmentsDOAG Oracle Unified Audit in Multitenant Environments
DOAG Oracle Unified Audit in Multitenant Environments
 
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
 
The Oracle RAC Family of Solutions - Presentation
The Oracle RAC Family of Solutions - PresentationThe Oracle RAC Family of Solutions - Presentation
The Oracle RAC Family of Solutions - Presentation
 
Apache Calcite (a tutorial given at BOSS '21)
Apache Calcite (a tutorial given at BOSS '21)Apache Calcite (a tutorial given at BOSS '21)
Apache Calcite (a tutorial given at BOSS '21)
 
1 - Introduction to PL/SQL
1 - Introduction to PL/SQL1 - Introduction to PL/SQL
1 - Introduction to PL/SQL
 
Oracle Latch and Mutex Contention Troubleshooting
Oracle Latch and Mutex Contention TroubleshootingOracle Latch and Mutex Contention Troubleshooting
Oracle Latch and Mutex Contention Troubleshooting
 
Explain the explain_plan
Explain the explain_planExplain the explain_plan
Explain the explain_plan
 
Mysql security 5.7
Mysql security 5.7 Mysql security 5.7
Mysql security 5.7
 
Apache Spark Notes
Apache Spark NotesApache Spark Notes
Apache Spark Notes
 
Best Practices with ODI : Flexibility
Best Practices with ODI : FlexibilityBest Practices with ODI : Flexibility
Best Practices with ODI : Flexibility
 

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 21c
Jim Czuprynski
 
IBM Db2 JSON 11.5
IBM  Db2 JSON 11.5IBM  Db2 JSON 11.5
IBM Db2 JSON 11.5
Phil Downey
 
KPMG - TASK 1.pdf
KPMG - TASK 1.pdfKPMG - TASK 1.pdf
KPMG - TASK 1.pdf
Darshana6228
 
ADBMS ASSIGNMENT
ADBMS ASSIGNMENTADBMS ASSIGNMENT
ADBMS ASSIGNMENT
Lori Moore
 
MongoDB World 2018: Keynote
MongoDB World 2018: KeynoteMongoDB World 2018: Keynote
MongoDB World 2018: Keynote
MongoDB
 
MongoDB Meetup
MongoDB MeetupMongoDB Meetup
MongoDB Meetup
Maxime Beugnet
 
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
Dataconomy 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
 
Test data article
Test data articleTest data article
Test data article
David Harrison
 
[MongoDB.local Bengaluru 2018] Keynote
[MongoDB.local Bengaluru 2018] Keynote[MongoDB.local Bengaluru 2018] Keynote
[MongoDB.local Bengaluru 2018] Keynote
MongoDB
 
Connecting Teradata and MongoDB with QueryGrid
Connecting Teradata and MongoDB with QueryGridConnecting Teradata and MongoDB with QueryGrid
Connecting Teradata and MongoDB with QueryGrid
MongoDB
 
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.js
Jeroen 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/OS
Jane 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 101
IDERA 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 code
Wim 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 Salesforce
Amit 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 Learning
Chris Saxon
 
Polymorphic Table Functions in SQL
Polymorphic Table Functions in SQLPolymorphic Table Functions in SQL
Polymorphic Table Functions in SQL
Chris 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 Changes
Chris 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 Performance
Chris 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 2
Chris 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 Injection
Chris 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 18c
Chris 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 SQL
Chris 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

Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdfSmart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
91mobiles
 
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
Product School
 
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdfFIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance
 
The Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and SalesThe Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and Sales
Laura Byrne
 
Essentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with ParametersEssentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with Parameters
Safe Software
 
ODC, Data Fabric and Architecture User Group
ODC, Data Fabric and Architecture User GroupODC, Data Fabric and Architecture User Group
ODC, Data Fabric and Architecture User Group
CatarinaPereira64715
 
UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4
DianaGray10
 
GraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge GraphGraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge Graph
Guy Korland
 
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMsTo Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
Paul Groth
 
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdfFIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance
 
"Impact of front-end architecture on development cost", Viktor Turskyi
"Impact of front-end architecture on development cost", Viktor Turskyi"Impact of front-end architecture on development cost", Viktor Turskyi
"Impact of front-end architecture on development cost", Viktor Turskyi
Fwdays
 
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
James Anderson
 
PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)
Ralf Eggert
 
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
Product School
 
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 previewState of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
Prayukth K V
 
Accelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish CachingAccelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish Caching
Thijs Feryn
 
JMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and GrafanaJMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and Grafana
RTTS
 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
Kari Kakkonen
 
How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...
Product School
 
Connector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a buttonConnector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a button
DianaGray10
 

Recently uploaded (20)

Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdfSmart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
 
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
 
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdfFIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
 
The Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and SalesThe Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and Sales
 
Essentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with ParametersEssentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with Parameters
 
ODC, Data Fabric and Architecture User Group
ODC, Data Fabric and Architecture User GroupODC, Data Fabric and Architecture User Group
ODC, Data Fabric and Architecture User Group
 
UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4
 
GraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge GraphGraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge Graph
 
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMsTo Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
 
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdfFIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdf
 
"Impact of front-end architecture on development cost", Viktor Turskyi
"Impact of front-end architecture on development cost", Viktor Turskyi"Impact of front-end architecture on development cost", Viktor Turskyi
"Impact of front-end architecture on development cost", Viktor Turskyi
 
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
 
PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)
 
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
 
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 previewState of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
 
Accelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish CachingAccelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish Caching
 
JMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and GrafanaJMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and Grafana
 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
 
How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...
 
Connector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a buttonConnector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a button
 

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