SlideShare a Scribd company logo
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
MySQL 8.0 Optimizer Guide
Morgan Tocker
MySQL Product Manager (Server)
Copyright © 2017, Oracle and/or its affiliates. All rights reserved.
MySQL 8.0 Optimizer Guide
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Safe Harbor Statement
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,
and timing of any features or functionality described for Oracle’s products
remains at the sole discretion of Oracle.
3
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Agenda
1. Introduction
2. Server Architecture
3. B+trees
4. EXPLAIN
5. Optimizer Trace
6. Logical
Transformations
7. Cost Based
Optimization
8. Hints and Switches
9. Comparing Plans
10.Composite Indexes
11.Covering Indexes
12.Visual Explain
13.Transient Plans
14.Subqueries
15.CTEs and Views
16.Joins
17.Aggregation
18.Descending Indexes
19.Sorting
20.Partitioning
21.Query Rewrite
22.Invisible Indexes
23.Profiling
24.JSON
25.Character Sets
4
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Introduction
• SQL is declarative
• You state “what you want” not “how you want”
• Can’t usually sight check queries to understand execution
efficiency
• Database management system is like a GPS navigation system. It
finds the “best”route.
5
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 6
GPS…
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 7
MySQL Optimizer
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Diagnostic Commands
• EXPLAIN (all versions)
• EXPLAIN FORMAT=JSON (5.6+)
– Supported by Workbench in Visual format
• Optimizer Trace (5.6+)
8
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Examples from “The World Schema”
• Contains Cities, Countries, Language statistics
• Download from:
– https://dev.mysql.com/doc/index-other.html
• Very small data set
– Good for learning
– Not good for explaining performance differences
9
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Primary Table we are using
CREATE TABLE `Country` (
`Code` char(3) NOT NULL DEFAULT '',
`Name` char(52) NOT NULL DEFAULT '',
`Continent` enum('Asia','Europe','North America','Africa','Oceania','Antarctica','South America') NOT NULL DEFAULT
'Asia',
`Region` char(26) NOT NULL DEFAULT '',
`SurfaceArea` float(10,2) NOT NULL DEFAULT '0.00',
`IndepYear` smallint(6) DEFAULT NULL,
`Population` int(11) NOT NULL DEFAULT '0',
`LifeExpectancy` float(3,1) DEFAULT NULL,
`GNP` float(10,2) DEFAULT NULL,
`GNPOld` float(10,2) DEFAULT NULL,
`LocalName` char(45) NOT NULL DEFAULT '',
`GovernmentForm` char(45) NOT NULL DEFAULT '',
`HeadOfState` char(60) DEFAULT NULL,
`Capital` int(11) DEFAULT NULL,
`Code2` char(2) NOT NULL DEFAULT '',
PRIMARY KEY (`Code`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
10
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Companion Website
• Content from “The Unofficial MySQL 8.0 Optimizer Guide”
• http://www.unofficialmysqlguide.com/
• More detailed text for many of the examples here…
• Most still applies to 5.6+
• EXPLAIN FORMAT=JSON in 5.6 does not show cost
• Costs will be different
• Output from Optimizer Trace may differ
• Some features will be missing
11
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Danger: Code on slides!
• Some examples may appear small
• Please feel free to download this deck from:
• https://www.slideshare.net/morgo/mysql-80-optimizer-guide
• Follow along on your laptop
12
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Agenda
1. Introduction
2. Server Architecture
3. B+trees
4. EXPLAIN
5. Optimizer Trace
6. Logical
Transformations
7. Cost Based
Optimization
8. Hints and Switches
9. Comparing Plans
10.Composite Indexes
11.Covering Indexes
12.Visual Explain
13.Transient Plans
14.Subqueries
15.CTEs and Views
16.Joins
17.Aggregation
18.Descending Indexes
19.Sorting
20.Partitioning
21.Query Rewrite
22.Invisible Indexes
23.Profiling
24.JSON
25.Character Sets
13
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 14
Server Architecture
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Just the Important Parts
• Comprised of the Server and Storage Engines
• Query Optimization happens at the Server Level
• Semantically there are four stages of Query Optimization
• Followed by Query Execution
15
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Agenda
1. Introduction
2. Server Architecture
3. B+trees
4. EXPLAIN
5. Optimizer Trace
6. Logical
Transformations
7. Cost Based
Optimization
8. Hints and Switches
9. Comparing Plans
10.Composite Indexes
11.Covering Indexes
12.Visual Explain
13.Transient Plans
14.Subqueries
15.CTEs and Views
16.Joins
17.Aggregation
18.Descending Indexes
19.Sorting
20.Partitioning
21.Query Rewrite
22.Invisible Indexes
23.Profiling
24.JSON
25.Character Sets
16
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
B+trees
• When we mean “add an index” we usually mean “add a B+tree
index”:
– Includes PRIMARY, UNIQUE, INDEX type indexes.
• Understanding the basic structure of B+trees helps with
optimization
17
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Binary Tree
• Not the same as a B+tree
• Understand Binary Tree first then compare and contrast
18
Locate 829813 in a
(balanced) binary tree of
1MM ~= 20 hops.
is this good?
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
B+tree
• Amortizes disk accesses by clustering into pages:
• Can achieve same outcome in two hops:
19
CREATE TABLE users (

id INT NOT NULL auto_increment,

username VARCHAR(32) NOT NULL,

payload TEXT,

PRIMARY KEY (id)

);
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
B+tree
• Amortizes disk 

accesses by clustering

into pages
• Can achieve same 

outcome in two hops:
20
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
B-trees are wide not deep
• From the root page: values >= 800788 but < 829908 are on page
16386.
• From page 16386: values >= 829804 but < 829830 are on leaf page
32012.
• Large fan out factor; 1000+ keys/page which point to another index
page with 1000+ keys/page
21
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
InnoDB uses a Clustered Index
• In InnoDB the data rows are also stored in a B+tree, organized by
the primary key
• Secondary key indexes always include the value of the primary key
22
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Agenda
1. Introduction
2. Server Architecture
3. B+trees
4. EXPLAIN
5. Optimizer Trace
6. Logical
Transformations
7. Cost Based
Optimization
8. Hints and Switches
9. Comparing Plans
10.Composite Indexes
11.Covering Indexes
12.Visual Explain
13.Transient Plans
14.Subqueries
15.CTEs and Views
16.Joins
17.Aggregation
18.Descending Indexes
19.Sorting
20.Partitioning
21.Query Rewrite
22.Invisible Indexes
23.Profiling
24.JSON
25.Character Sets
23
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
EXPLAIN
• Pre-execution view of how MySQL intends to execute a query
• Prints what MySQL considers the best plan after a process of
considering potentially thousands of choices
24
EXPLAIN FORMAT=JSON
SELECT * FROM Country WHERE continent='Asia' and population > 5000000;
{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "25.40"
},
"table": {
"table_name": "country",
"access_type": "ALL",
"rows_examined_per_scan": 239,
"rows_produced_per_join": 11,
"filtered": "6.46",
..
"attached_condition": "((`world`.`country`.`Continent` = 'Asia')
and (`world`.`country`.`Population` > 5000000))"
}
}
}
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
What indexes will make this query faster?
• Some Suggestions:
– Index on p (population)
– Index on c (continent)
– Index on p_c (population, continent)
– Index on c_p (continent, population)
26
ALTER TABLE Country ADD INDEX p (population);
EXPLAIN FORMAT=JSON
SELECT * FROM Country WHERE continent='Asia' and population > 5000000;
{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "25.40"
},
"table": {
"table_name": "Country",
"access_type": "ALL",
"possible_keys": [
"p"
],
"rows_examined_per_scan": 239,
"rows_produced_per_join": 15,
"filtered": "6.46",
..
"attached_condition": "((`world`.`country`.`Continent` = 'Asia') and
(`world`.`country`.`Population` > 5000000))"
..
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 28
Why would an index not be used?
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Agenda
1. Introduction
2. Server Architecture
3. B+trees
4. EXPLAIN
5. Optimizer Trace
6. Logical
Transformations
7. Cost Based
Optimization
8. Hints and Switches
9. Comparing Plans
10.Composite Indexes
11.Covering Indexes
12.Visual Explain
13.Transient Plans
14.Subqueries
15.CTEs and Views
16.Joins
17.Aggregation
18.Descending Indexes
19.Sorting
20.Partitioning
21.Query Rewrite
22.Invisible Indexes
23.Profiling
24.JSON
25.Character Sets
29
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Optimizer Trace
• What other choices did EXPLAIN not show?
• Why was that choice made?
• Output is quite verbose
30
ALTER TABLE Country ADD INDEX p (population);
EXPLAIN FORMAT=JSON
SELECT * FROM Country WHERE continent='Asia' and population > 5000000;
{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "25.40"
},
"table": {
"table_name": "Country",
"access_type": "ALL",
"possible_keys": [
"p"
],
"rows_examined_per_scan": 239,
"rows_produced_per_join": 15,
"filtered": "6.46",
"cost_info": {
"read_cost": "23.86",
"eval_cost": "1.54",
"prefix_cost": "25.40",
"data_read_per_join": "3K"
},
..
"attached_condition": "((`world`.`country`.`Continent` = 'Asia') and
(`world`.`country`.`Population` > 5000000))"
..
It’s available but not
used. Why?
SET optimizer_trace="enabled=on";
SELECT * FROM Country WHERE continent='Asia' and population > 5000000;
SELECT * FROM information_schema.optimizer_trace;
{
"steps": [
{
"join_preparation": {
"select#": 1,
"steps": [
{
"expanded_query": "/* select#1 */ select `country`.`Code` AS `Code`,`country`.`Name` AS
`Name`,`country`.`Continent` AS `Continent`,`country`.`Region` AS `Region`,`country`.`SurfaceArea` AS
`SurfaceArea`,`country`.`IndepYear` AS `IndepYear`,`country`.`Population` AS
`Population`,`country`.`LifeExpectancy` AS `LifeExpectancy`,`country`.`GNP` AS
`GNP`,`country`.`GNPOld` AS `GNPOld`,`country`.`LocalName` AS `LocalName`,`country`.`GovernmentForm`
AS `GovernmentForm`,`country`.`HeadOfState` AS `HeadOfState`,`country`.`Capital` AS
`Capital`,`country`.`Code2` AS `Code2` from `country` where ((`country`.`Continent` = 'Asia') and
(`country`.`Population` > 5000000))"
}
]
}
},
{
"join_optimization": {
"select#": 1,
"steps": [
{
"condition_processing": {
"condition": "WHERE",
Page 1 of 6
"original_condition": "((`country`.`Continent` = 'Asia') and (`country`.`Population` > 5000000))",
"steps": [
{
"transformation": "equality_propagation",
"resulting_condition": "((`country`.`Population` > 5000000) and multiple equal('Asia',
`country`.`Continent`))"
},
{
"transformation": "constant_propagation",
"resulting_condition": "((`country`.`Population` > 5000000) and multiple equal('Asia',
`country`.`Continent`))"
},
{
"transformation": "trivial_condition_removal",
"resulting_condition": "((`country`.`Population` > 5000000) and multiple equal('Asia',
`country`.`Continent`))"
}
]
}
},
{
"substitute_generated_columns": {
}
},
{
"table_dependencies": [
{
"table": "`country`",
"row_may_be_null": false,
"map_bit": 0,
Page 2 of 6
"depends_on_map_bits": [
]
}
]
},
{
"ref_optimizer_key_uses": [
]
},
{
"rows_estimation": [
{
"table": "`country`",
"range_analysis": {
"table_scan": {
"rows": 239,
"cost": 27.5
},
"potential_range_indexes": [
{
"index": "PRIMARY",
"usable": false,
"cause": "not_applicable"
},
{
"index": "p",
"usable": true,
"key_parts": [
"Population",
"Code"
]
Page 3 of 6
}
],
"setup_range_conditions": [
],
"group_index_range": {
"chosen": false,
"cause": "not_group_by_or_distinct"
},
"analyzing_range_alternatives": {
"range_scan_alternatives": [
{
"index": "p",
"ranges": [
"5000000 < Population"
],
"index_dives_for_eq_ranges": true,
"rowid_ordered": false,
"using_mrr": false,
"index_only": false,
"rows": 108,
"cost": 38.06,
"chosen": false,
"cause": "cost"
}
],
"analyzing_roworder_intersect": {
"usable": false,
"cause": "too_few_roworder_scans"
}
}
}
Aha! It was too
expensive.
Page 4 of 6
}
]
},
{
"considered_execution_plans": [
{
"plan_prefix": [
],
"table": "`country`",
"best_access_path": {
"considered_access_paths": [
{
"rows_to_scan": 239,
"access_type": "scan",
"resulting_rows": 239,
"cost": 25.4,
"chosen": true
}
]
},
"condition_filtering_pct": 100,
"rows_for_plan": 239,
"cost_for_plan": 25.4,
"chosen": true
}
]
},
{
"attaching_conditions_to_tables": {
"original_condition": "((`country`.`Continent` = 

'Asia') and (`country`.`Population` > 5000000))",
Prefer to table scan
instead
Page 5 of 6
"attached_conditions_computation": [
],
"attached_conditions_summary": [
{
"table": "`country`",
"attached": "((`country`.`Continent` = 'Asia') and (`country`.`Population` > 5000000))"
}
]
}
},
{
"refine_plan": [
{
"table": "`country`"
}
]
}
]
}
},
{
"join_execution": {
"select#": 1,
"steps": [
]
}
}
]
}
Page 6 of 6
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 38
Why would an index not be used?
"analyzing_range_alternatives": {
"range_scan_alternatives": [
{
"index": "p",
"ranges": [
"5000000 < Population"
],
"index_dives_for_eq_ranges": true,
"rowid_ordered": false,
"using_mrr": false,
"index_only": false,
"rows": 108,
"cost": 38.06,
"chosen": false,
"cause": "cost"
}
],
OPTIMIZER TRACE:
..
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "48.86"
},
"table": {
"table_name": "Country",
"access_type": "range",
"possible_keys": [
"p"
],
"key": "p",
..
FORCE INDEX (p):
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 39
Reason again…
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Agenda
1. Introduction
2. Server Architecture
3. B+trees
4. EXPLAIN
5. Optimizer Trace
6. Logical
Transformations
7. Cost Based
Optimization
8. Hints and Switches
9. Comparing Plans
10.Composite Indexes
11.Covering Indexes
12.Visual Explain
13.Transient Plans
14.Subqueries
15.CTEs and Views
16.Joins
17.Aggregation
18.Descending Indexes
19.Sorting
20.Partitioning
21.Query Rewrite
22.Invisible Indexes
23.Profiling
24.JSON
25.Character Sets
40
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Logical Transformations
• First part of optimization

is eliminating 

unnecessary work
41
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Why eliminate unnecessary work?
• Short-cut/reduce number of execution plans that need to be
evaluated
• Transform parts of queries to take advantage of better execution
strategies
• Think of a how a compiler transforms code to be more efficient
• MySQL does similar at runtime
42
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Example:
SELECT * FROM Country

WHERE population > 5000000 AND continent='Asia' 

AND 1=1;
43
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
SHOW WARNINGS says:
EXPLAIN FORMAT=JSON SELECT * FROM Country WHERE population > 5000000 AND 1=1;
SHOW WARNINGS;
/* select#1 */ select

`world`.`Country`.`Code` AS `Code`,

`world`.`Country`.`Name` AS `Name`,

`world`.`Country`.`Continent` AS `Continent`,

`world`.`Country`.`Region` AS `Region`,

`world`.`Country`.`SurfaceArea` AS `SurfaceArea`,

`world`.`Country`.`IndepYear` AS `IndepYear`,

`world`.`Country`.`Population` AS `Population`,

`world`.`Country`.`LifeExpectancy` AS `LifeExpectancy`,

`world`.`Country`.`GNP` AS `GNP`,

`world`.`Country`.`GNPOld` AS `GNPOld`,

`world`.`Country`.`LocalName` AS `LocalName`,

`world`.`Country`.`GovernmentForm` AS `GovernmentForm`,

`world`.`Country`.`HeadOfState` AS `HeadOfState`,

`world`.`Country`.`Capital` AS `Capital`,

`world`.`Country`.`Code2` AS `Code2`

from `world`.`Country`

where (`world`.`Country`.`Population` > 5000000)
44
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
..
"steps": [
{
"condition_processing": {
"condition": "WHERE",
"original_condition": "((`Country`.`Population` > 5000000) and (1 = 1))",
"steps": [
{
"transformation": "equality_propagation",
"resulting_condition": "((`Country`.`Population` > 5000000) and (1 = 1))"
},
{
"transformation": "constant_propagation",
"resulting_condition": "((`Country`.`Population` > 5000000) and (1 = 1))"
},
{
"transformation": "trivial_condition_removal",
"resulting_condition": "(`Country`.`Population` > 5000000)"
..
OPTIMIZER TRACE says:
45
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
What sort of transformations can occur?
• Merging views back with definition of base tables
• Derived table in FROM clause merged back into base tables
• Unique subqueries converted directly to INNER JOIN statements
• Primary key lookup converted to constant values.
– Shortcut plans that will need to be evaluated.
46
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Primary Key Lookup
SELECT * FROM Country WHERE code='CAN'
/* select#1 */ select
'CAN' AS `Code`,
'Canada' AS `Name`,
'North America' AS `Continent`,
'North America' AS `Region`,
'9970610.00' AS `SurfaceArea`,
'1867' AS `IndepYear`,
'31147000' AS `Population`,
'79.4' AS `LifeExpectancy`,
'598862.00' AS `GNP`,
'625626.00' AS `GNPOld`,
'Canada' AS `LocalName`,
'Constitutional Monarchy, Federation' AS `GovernmentForm`,
'Elisabeth II' AS `HeadOfState`,
'1822' AS `Capital`,
'CA' AS `Code2`
from `world`.`Country` where 1
47
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Primary key does not exist
SELECT * FROM Country WHERE code='XYZ'
/* select#1 */ select NULL AS `Code`,NULL AS
`Name`,NULL AS `Continent`,NULL AS `Region`, NULL AS
`SurfaceArea`,NULL AS `IndepYear`,NULL AS
`Population`,NULL AS `LifeExpectancy`,NULL AS `GNP`,
NULL AS `GNPOld`,NULL AS `LocalName`,NULL AS
`GovernmentForm`,NULL AS `HeadOfState`,NULL AS
`Capital`, NULL AS `Code2` from `world`.`Country`
where multiple equal('XYZ', NULL)
48
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Impossible WHERE
SELECT * FROM Country WHERE code='CAN' AND 1=0
/* select#1 */ select `world`.`Country`.`Code` AS
`Code`,`world`.`Country`.`Name` AS `Name`,
`world`.`Country`.`Continent` AS `Continent`,`world`.`Country`.`Region`
AS `Region`, `world`.`Country`.`SurfaceArea` AS
`SurfaceArea`,`world`.`Country`.`IndepYear` AS `IndepYear`,
`world`.`Country`.`Population` AS
`Population`,`world`.`Country`.`LifeExpectancy` AS `LifeExpectancy`,
`world`.`Country`.`GNP` AS `GNP`,`world`.`Country`.`GNPOld` AS
`GNPOld`, `world`.`Country`.`LocalName` AS
`LocalName`,`world`.`Country`.`GovernmentForm` AS `GovernmentForm`,
`world`.`Country`.`HeadOfState` AS
`HeadOfState`,`world`.`Country`.`Capital` AS `Capital`,
`world`.`Country`.`Code2` AS `Code2` from `world`.`Country` where 0
49
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Are transformations always safe?
• Yes they should be
• New transformations (and execution strategies) may return non
deterministic queries in a different order
• Some illegal statements as a result of derived_merge
transformation
50
MySQL 8.0 Optimizer Guide
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Agenda
1. Introduction
2. Server Architecture
3. B+trees
4. EXPLAIN
5. Optimizer Trace
6. Logical
Transformations
7. Cost Based
Optimization
8. Hints and Switches
9. Comparing Plans
10.Composite Indexes
11.Covering Indexes
12.Visual Explain
13.Transient Plans
14.Subqueries
15.CTEs and Views
16.Joins
17.Aggregation
18.Descending Indexes
19.Sorting
20.Partitioning
21.Query Rewrite
22.Invisible Indexes
23.Profiling
24.JSON
25.Character Sets
52
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Query Optimizer Strategy
• Model each of the possible execution plans (using support from
statistics and meta data)
• Pick the plan with the lowest cost
53
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Model you say?
1. Assign a cost to each operation
2. Evaluate how many operations each possible plan would take
3. Sum up the total
4. Choose the plan with the lowest overall cost
54
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
How are statistics calculated?
• Dictionary Information
• Cardinality Statistics
• Records In Range Dynamic Sampling
• Table Size
55
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 56
Example Model: Table Scan
SELECT * FROM Country WHERE continent='Asia' and population > 5000000;
IO Cost:
# pages in table * (IO_BLOCK_READ_COST | MEMORY_BLOCK_READ_COST)
CPU Cost:
# records * ROW_EVALUATE_COST
Defaults:

IO_BLOCK_READ_COST = 1

MEMORY_BLOCK_READ_COST = 0.25

ROW_EVALUATE_COST=0.1
Values:
# pages in table = 6
# records = 239
100% on Disk: 

= (6 * 1) + (0.1 * 239)
= 29.9
EXPLAIN said
cost was 25.40
New! MySQL 8.0 estimates how
many of the pages will be in
memory.
SELECT clust_index_size from
INNODB_SYS_TABLESTATS WHERE
name='world/country'
100% in Memory:

= (6 * 0.25) + (0.1 * 239)
= 25.4
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 57
Example Model: Range Scan
SELECT * FROM Country WHERE continent='Asia' and population > 5000000;
IO Cost:
# records_in_range * (IO_BLOCK_READ_COST | MEMORY_BLOCK_READ_COST)

CPU Cost:

# records_in_range * ROW_EVALUATE_COST

+ # records_in_range * ROW_EVALUATE_COST 









= (108 * 0.25) + ( (108 * 0.1) + (108 * 0.1) )
= 48.6
Evaluate range condition
Evaluate WHERE condition
Compares to "query_cost":
“48.86" in EXPLAIN.
100% in memory.
On disk = 129.6
{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "25.40"
},
"table": {
"table_name": "country",
"access_type": "ALL",
"possible_keys": [
"p"
],
..
"cost_info": {
"read_cost": "23.86",
"eval_cost": "1.54",
"prefix_cost": "25.40",
"data_read_per_join": "3K"
},
..
CPU Cost
IO Cost
Total Cost
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Cost Constant Refinement
select * from mysql.server_cost;
+------------------------------+------------+---------------------+---------+---------------+
| cost_name | cost_value | last_update | comment | default_value |
+------------------------------+------------+---------------------+---------+---------------+
| disk_temptable_create_cost | NULL | 2017-04-14 16:01:42 | NULL | 20 |
| disk_temptable_row_cost | NULL | 2017-04-14 16:01:42 | NULL | 0.5 |
| key_compare_cost | NULL | 2017-04-14 16:01:42 | NULL | 0.05 |
| memory_temptable_create_cost | NULL | 2017-04-14 16:01:42 | NULL | 1 |
| memory_temptable_row_cost | NULL | 2017-04-14 16:01:42 | NULL | 0.1 |
| row_evaluate_cost | NULL | 2017-04-14 16:01:42 | NULL | 0.1 |
+------------------------------+------------+---------------------+---------+---------------+
6 rows in set (0.00 sec)
select * from mysql.engine_costG
*************************** 1. row ***************************
engine_name: default
device_type: 0
cost_name: io_block_read_cost
cost_value: NULL
last_update: 2017-04-14 16:01:42
comment: NULL
default_value: 1
59
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Cost Constant Refinement
UPDATE mysql.server_cost SET cost_value=1 WHERE cost_name=‘row_evaluate_cost';
UPDATE mysql.engine_cost set cost_value = 1;
FLUSH OPTIMIZER_COSTS;
EXPLAIN FORMAT=JSON SELECT * FROM Country WHERE continent='Asia' and population > 5000000;
{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "245.00"
},
"table": {
"table_name": "Country",
"access_type": "ALL",
..
60
Increase row evaluate cost from
0.1 to 1. Make memory and IO
block read cost the same.
New Table Scan Cost:
= (6 * 1) + (1 * 239)
= 245
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Are plans exhaustively evaluated?
• Short cuts are taken to not spend too much time in planning:
– Some parts of queries may be transformed to limit plans
evaluated
– The optimizer will by default limit the search depth of bad plans:

optimizer_search_depth=64

optimizer_prune_level=1
61
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Agenda
1. Introduction
2. Server Architecture
3. B+trees
4. EXPLAIN
5. Optimizer Trace
6. Logical
Transformations
7. Cost Based
Optimization
8. Hints and Switches
9. Comparing Plans
10.Composite Indexes
11.Covering Indexes
12.Visual Explain
13.Transient Plans
14.Subqueries
15.CTEs and Views
16.Joins
17.Aggregation
18.Descending Indexes
19.Sorting
20.Partitioning
21.Query Rewrite
22.Invisible Indexes
23.Profiling
24.JSON
25.Character Sets
62
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
How often is the query optimizer wrong?
• Yes it happens
• Similar to GPS; you may not have traffic data available for all
streets
• The model may be incomplete or imperfect
• There exist method(s) to overwrite it
63
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Hints and Switches
• Typically a better level of override to modifying cost constants
• Come in three varieties:
– Old Style Hints
– New Comment-Style Hints
– Switches
64
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Old Style Hints
• Have SQL and Hint intermingled
• Cause errors when indexes don’t exist
65
SELECT * FROM Country FORCE INDEX (p) WHERE population >
5000000;
SELECT * FROM Country IGNORE INDEX (p) WHERE population >
5000000;
SELECT * FROM Country USE INDEX (p) WHERE population > 5000000;
SELECT STRAIGHT_JOIN ..;
SELECT * FROM Country STRAIGHT_JOIN ..;
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
New Comment-Style Hints
• Can be added by a system that doesn’t understand SQL
• Clearer defined semantics as a hint not a directive
• Fine granularity
66
SELECT
/*+ NO_RANGE_OPTIMIZATION (Country) */
* FROM Country
WHERE Population > 1000000000 AND Continent=‘Asia';
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Switches
• As new optimizations are added, some cause regressions
• Allow the specific optimization to be disabled (SESSION or GLOBAL)
67
SELECT @@optimizer_switch;


index_merge=on,index_merge_union=on,index_merge_sort_union=on,

index_merge_intersection=on,engine_condition_pushdown=on,

index_condition_pushdown=on,mrr=on,mrr_cost_based=on,

block_nested_loop=on,batched_key_access=off,materialization=on,

semijoin=on,loosescan=on,firstmatch=on,duplicateweedout=on,

subquery_materialization_cost_based=on,use_index_extensions=on,

condition_fanout_filter=on,derived_merge=on
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
How to consider hints and switches
• They provide immediate pain relief to production problems at the
cost of maintenance
• They add technical debt to your applications
68
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Agenda
1. Introduction
2. Server Architecture
3. B+trees
4. EXPLAIN
5. Optimizer Trace
6. Logical
Transformations
7. Cost Based
Optimization
8. Hints and Switches
9. Comparing Plans
10.Composite Indexes
11.Covering Indexes
12.Visual Explain
13.Transient Plans
14.Subqueries
15.CTEs and Views
16.Joins
17.Aggregation
18.Descending Indexes
19.Sorting
20.Partitioning
21.Query Rewrite
22.Invisible Indexes
23.Profiling
24.JSON
25.Character Sets
69
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Our simple query with n candidate indexes
• Indexes exist on p(population) and c(continent):
70
SELECT * FROM Country

WHERE population > 50000000 AND continent=‘Asia';
>50M, how many
are less?
How many countries in
Asia vs total world?
Does order of
predicates matter? No.
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Role of the Optimizer
• Given these many choices, which is the best choice?
• A good GPS navigator finds the fastest route!
• We can expect a good query optimizer to do similar
71
ALTER TABLE Country ADD INDEX c (continent);
EXPLAIN FORMAT=JSON # 50M

SELECT * FROM Country WHERE population > 50000000 AND continent=‘Asia';
{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "9.60"
},
"table": {
"table_name": "Country",
"access_type": "ref",
"possible_keys": [
"p",
"c"
],
"key": "c",
"used_key_parts": [
"Continent"
],
"key_length": "1",
"ref": [
"const"
],
..
"attached_condition": "(`world`.`country`.`Population` > 50000000)"
..
Continent is
determined to be lower
cost.
EXPLAIN FORMAT=JSON # 500M
SELECT * FROM Country WHERE continent='Asia' and population > 500000000;
{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "1.16"
},
"table": {
"table_name": "Country",
"access_type": "range",
"possible_keys": [
"p",
"c"
],
"key": "p",
"used_key_parts": [
"Population"
],
"key_length": "4",
..
"attached_condition": "(`world`.`country`.`Continent` = ‘Asia')"
..
Change the predicate,
the query plan changes.
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Query Plan Evaluation
• Evaluated for each query, and thus each set of predicates
• Currently not cached*
• For prepared statements, permanent transformations are cached
74
* Cardinality statistics are cached. Don’t get confused.
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 75
Cost Estimates
p>5M c=’Asia’ p>50M, c=’Asia’ p>500M, c=’Asia’
p 48.86 11.06 1.16
c 9.60 9.60 9.60
ALL 25.40 25.40 25.40
p
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Agenda
1. Introduction
2. Server Architecture
3. B+trees
4. EXPLAIN
5. Optimizer Trace
6. Logical
Transformations
7. Cost Based
Optimization
8. Hints and Switches
9. Comparing Plans
10.Composite Indexes
11.Covering Indexes
12.Visual Explain
13.Transient Plans
14.Subqueries
15.CTEs and Views
16.Joins
17.Aggregation
18.Descending Indexes
19.Sorting
20.Partitioning
21.Query Rewrite
22.Invisible Indexes
23.Profiling
24.JSON
25.Character Sets
76
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
The role of composite indexes
• Useful when two or more predicates combined improves filtering
effect. i.e.



Not all countries with a population > 5M are in Asia
77
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Composite Indexes
• p_c (population, continent)
• c_p (continent, population)
78
ALTER TABLE Country ADD INDEX p_c (Population, Continent);
EXPLAIN FORMAT=JSON
SELECT * FROM Country FORCE INDEX (p_c) WHERE continent='Asia' and population >
5000000;
{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "48.86"
},
"table": {
"table_name": "Country",
"access_type": "range",
"possible_keys": [
"p_c"
],
"key": "p_c",
"used_key_parts": [
"Population"
],
"key_length": "4",
..
Only part of the key is
used!
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Rule of Thumb
• Index on (const, range) instead of (range, const)
• Applies to all databases
80
ALTER TABLE Country ADD INDEX c_p (Continent, Population);

EXPLAIN FORMAT=JSON

SELECT * FROM Country WHERE continent='Asia' and population > 5000000;

{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "7.91"
},
"table": {
"table_name": "Country",
"access_type": "range",
"possible_keys": [
"p",
"c",
"p_c",
"c_p"
],
"key": "c_p",
"used_key_parts": [
"Continent",
"Population"
],
"key_length": “5”,

..
All of the key is
used
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Composite Left-most Rule
• An index on (Continent, Population) can also be used as an index on
(Continent)
• It can not be used as an index on (Population)
82
EXPLAIN FORMAT=JSON 

SELECT * FROM Country FORCE INDEX (c_p) WHERE population >
500000000;
{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "83.90"
},
"table": {
"table_name": "Country",
"access_type": "ALL",
"rows_examined_per_scan": 239,
"rows_produced_per_join": 79,
"filtered": "33.33",
..
"attached_condition": "(`world`.`country`.`Population` >
500000000)"
..
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Agenda
1. Introduction
2. Server Architecture
3. B+trees
4. EXPLAIN
5. Optimizer Trace
6. Logical
Transformations
7. Cost Based
Optimization
8. Hints and Switches
9. Comparing Plans
10.Composite Indexes
11.Covering Indexes
12.Visual Explain
13.Transient Plans
14.Subqueries
15.CTEs and Views
16.Joins
17.Aggregation
18.Descending Indexes
19.Sorting
20.Partitioning
21.Query Rewrite
22.Invisible Indexes
23.Profiling
24.JSON
25.Character Sets
84
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Covering Indexes
• A special kind of composite index
• All information returned just by accessing the index
85
ALTER TABLE Country ADD INDEX c_p_n (Continent,Population,Name);
EXPLAIN FORMAT=JSON
SELECT Name FROM Country WHERE continent='Asia' and population > 5000000;
{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "3.72"
},
"table": {
"table_name": "Country",
"access_type": "range",
"possible_keys": [
..
"c_p_n"
],
"key": "c_p_n",
"used_key_parts": [
"Continent",
"Population"
],
"key_length": "5",
..
"filtered": "100.00",
"using_index": true,
..
Cost is reduced by
53%
Using index means
"covering index"
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Use cases
• Can be used as in this example
• Also beneficial in join conditions (join through covering index on
intermediate table)
• Useful in aggregate queries
87
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Agenda
1. Introduction
2. Server Architecture
3. B+trees
4. EXPLAIN
5. Optimizer Trace
6. Logical
Transformations
7. Cost Based
Optimization
8. Hints and Switches
9. Comparing Plans
10.Composite Indexes
11.Covering Indexes
12.Visual Explain
13.Transient Plans
14.Subqueries
15.CTEs and Views
16.Joins
17.Aggregation
18.Descending Indexes
19.Sorting
20.Partitioning
21.Query Rewrite
22.Invisible Indexes
23.Profiling
24.JSON
25.Character Sets
88
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Visual Explain
• For complex queries, it is useful to see visual representation
• Visualizations in this deck are produced by MySQL Workbench.
89
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Agenda
1. Introduction
2. Server Architecture
3. B+trees
4. EXPLAIN
5. Optimizer Trace
6. Logical
Transformations
7. Cost Based
Optimization
8. Hints and Switches
9. Comparing Plans
10.Composite Indexes
11.Covering Indexes
12.Visual Explain
13.Transient Plans
14.Subqueries
15.CTEs and Views
16.Joins
17.Aggregation
18.Descending Indexes
19.Sorting
20.Partitioning
21.Query Rewrite
22.Invisible Indexes
23.Profiling
24.JSON
25.Character Sets
90
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
A quick recap:
• So far we’ve talked about 4 candidate indexes:
– p (population)
– c (continent)
– p_c (population, continent)
– c_p (continent, population)
• We’ve always used c=‘Asia’ and p > 5M
91
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 92
Cost Estimates
p>5M c=’Asia’ p>5M c=’Antarctica’ p>50M, c=’Asia’
p>50M
c=’Antarctica’
p>500M, c=’Asia’
p>500M
c=’Antarctica’
p 48.86 48.86 11.06 11.06 1.16 1.16
c 9.60 1.75 9.60 1.75 9.60 1.75
c_p 7.91 0.71 5.21 0.71 1.16 0.71
p_c 48.86 48.86 11.06 11.06 1.16 1.16
ALL 25.40 25.40 25.40 25.40 25.40 25.40
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 93
Cost Estimates
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 94
Actual Execution Time
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Agenda
1. Introduction
2. Server Architecture
3. B+trees
4. EXPLAIN
5. Optimizer Trace
6. Logical
Transformations
7. Cost Based
Optimization
8. Hints and Switches
9. Comparing Plans
10.Composite Indexes
11.Covering Indexes
12.Visual Explain
13.Transient Plans
14.Subqueries
15.CTEs and Views
16.Joins
17.Aggregation
18.Descending Indexes
19.Sorting
20.Partitioning
21.Query Rewrite
22.Invisible Indexes
23.Profiling
24.JSON
25.Character Sets
95
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Subquery (Scalar)
• Can optimize away the inner part first and then cache it.
• This avoids re-executing the inner part for-each-row
96
SELECT * FROM Country WHERE

Code = (SELECT CountryCode FROM City WHERE
name=‘Toronto’);
EXPLAIN FORMAT=JSON
SELECT * FROM Country WHERE Code = (SELECT CountryCode FROM City WHERE name=‘Toronto’);
{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "1.00"
},
"table": {
"table_name": "Country",
"access_type": "const",
..
"key": "PRIMARY",
..
},
"optimized_away_subqueries": [
{
"dependent": false,
"cacheable": true,
"query_block": {
"select_id": 2,
"cost_info": {
"query_cost": "425.05"
},
"table": {
"table_name": "City",
"access_type": "ALL",
..
(misleading
visualization)
First query + its
cost
Second query +
its cost
ALTER TABLE city ADD INDEX n (name);
EXPLAIN FORMAT=JSON
SELECT * FROM Country WHERE Code = (SELECT CountryCode FROM City WHERE name=‘Toronto’);
{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "1.00"
},
"table": {
"table_name": "Country",
"access_type": "const",
..
"key": "PRIMARY",
..
},
"optimized_away_subqueries": [
{
"dependent": false,
"cacheable": true,
"query_block": {
"select_id": 2,
"cost_info": {
"query_cost": "0.35"
},
"table": {
"table_name": "City",
"access_type": "ref",
"possible_keys": [
"n"
],
"key": “n",
..
First query + its
cost
Second query +
its cost
(misleading
visualization)
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Subquery (IN list)
• When the result inner subquery returns unique results it can safely
be transformed to an inner join:
99
EXPLAIN FORMAT=JSON SELECT * FROM City WHERE CountryCode IN

(SELECT Code FROM Country WHERE Continent = 'Asia');
show warnings;
/* select#1 */ select `world`.`city`.`ID` AS `ID`,`world`.`city`.`Name` AS
`Name`,`world`.`city`.`CountryCode` AS `CountryCode`,`world`.`city`.`District`
AS `District`,`world`.`city`.`Population` AS `Population` from
`world`.`country` join `world`.`city` where ((`world`.`city`.`CountryCode` =
`world`.`country`.`Code`) and (`world`.`country`.`Continent` = 'Asia'))
1 row in set (0.00 sec)
EXPLAIN FORMAT=JSON
SELECT * FROM City WHERE CountryCode IN

(SELECT Code FROM Country WHERE Continent = 'Asia');
{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "327.58"
},
"nested_loop": [
{
"table": {
"table_name": "Country",
"access_type": "ref",
..
"key": "c",
..
"using_index": true,
..
"used_columns": [
"Code",
"Continent"
..
{
"table": {
"table_name": "City",
"access_type": "ref",
"possible_keys": [
"CountryCode"
],
"key": "CountryCode",
..
"ref": [
"world.Country.Code"
],
..
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
SELECT * FROM Country WHERE Code IN
(SELECT CountryCode FROM CountryLanguage 

WHERE isOfficial=1);
Subquery (cont.)
• When non-unique the optimizer needs to pick a semi-join strategy
• Multiple options: FirstMatch, MaterializeLookup,
DuplicatesWeedout
101
ALTER TABLE CountryLanguage ADD INDEX i (isOfficial);
EXPLAIN FORMAT=JSON SELECT * FROM Country WHERE Code IN
(SELECT CountryCode FROM CountryLanguage WHERE isOfficial=1);
{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "98.39"
},
"nested_loop": [
{
"table": {
"table_name": "Country",
"access_type": "ALL",
"possible_keys": [
"PRIMARY"
],
..
"filtered": "100.00",
..
"table": {
"table_name": "<subquery2>",
"access_type": "eq_ref",
"key": "<auto_key>",
"key_length": "3",
"ref": [
"world.Country.Code"
],
"rows_examined_per_scan": 1,
"materialized_from_subquery": {
"using_temporary_table": true,
"query_block": {
"table": {
"table_name": "CountryLanguage",
"access_type": "ref",
..
"key": "i",
..
"using_index": true,
..
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Agenda
1. Introduction
2. Server Architecture
3. B+trees
4. EXPLAIN
5. Optimizer Trace
6. Logical
Transformations
7. Cost Based
Optimization
8. Hints and Switches
9. Comparing Plans
10.Composite Indexes
11.Covering Indexes
12.Visual Explain
13.Transient Plans
14.Subqueries
15.CTEs and Views
16.Joins
17.Aggregation
18.Descending Indexes
19.Sorting
20.Partitioning
21.Query Rewrite
22.Invisible Indexes
23.Profiling
24.JSON
25.Character Sets
103
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Views
• A way of saving a SELECT statement as a table
• Allows for simplified queries
• Processed using one of two methods internally:
– Merge - transform the view to be combined with the query.
– Materialize - save the contents of the view in a temporary table,
then begin querying
104
ALTER TABLE country ADD INDEX c_n (continent, name);
CREATE VIEW vCountry_Asia AS SELECT * FROM Country WHERE Continent='Asia';
EXPLAIN FORMAT=JSON
SELECT * FROM vCountry_Asia WHERE Name='China';
{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "0.35"
},
"table": {
"table_name": "country",
"access_type": "ref",
"possible_keys": [
..
"c_n"
],
"key": "c_n",
"used_key_parts": [
"Continent",
"Name"
],
"key_length": "53",
"ref": [
"const",
"const"
],
..
This is the base table
Predicates from the view
definition and query
combined
SHOW WARNINGS;
/* select#1 */ select
`world`.`Country`.`Code` AS `Code`,
`world`.`Country`.`Name` AS `Name`,
`world`.`Country`.`Continent` AS `Continent`,
`world`.`Country`.`Region` AS `Region`,
`world`.`Country`.`SurfaceArea` AS `SurfaceArea`,
`world`.`Country`.`IndepYear` AS `IndepYear`,
`world`.`Country`.`Population` AS `Population`,
`world`.`Country`.`LifeExpectancy` AS `LifeExpectancy`,
`world`.`Country`.`GNP` AS `GNP`,
`world`.`Country`.`GNPOld` AS `GNPOld`,
`world`.`Country`.`LocalName` AS `LocalName`,
`world`.`Country`.`GovernmentForm` AS `GovernmentForm`,
`world`.`Country`.`HeadOfState` AS `HeadOfState`,
`world`.`Country`.`Capital` AS `Capital`,
`world`.`Country`.`Code2` AS `Code2`
from `world`.`Country`
where
((`world`.`Country`.`Continent` = 'Asia')
and (`world`.`Country`.`Name` = 'China'))
CREATE VIEW vCountrys_Per_Continent AS
SELECT Continent, COUNT(*) as Count FROM Country
GROUP BY Continent;
EXPLAIN FORMAT=JSON
SELECT * FROM vCountrys_Per_Continent WHERE Continent='Asia';
{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "3.64"
},
"table": {
"table_name": "vCountrys_Per_Continent",
"access_type": "ref",
"possible_keys": [
"<auto_key0>"
],
"key": "<auto_key0>",
"used_key_parts": [
"Continent"
],
"key_length": "1",
"ref": [
"const"
],
..
"used_columns": [
"Continent",
"Count"
],
..
This is the view name
..
"materialized_from_subquery": {
"using_temporary_table": true,
"dependent": false,
"cacheable": true,
"query_block": {
"select_id": 2,
"cost_info": {
"query_cost": "25.40"
},
This is only the cost of
accessing the materialized table
This step happens first.
SHOW WARNINGS;
/* select#1 */ select
`vCountrys_Per_Continent`.`Continent` AS `Continent`,
`vCountrys_Per_Continent`.`Count` AS `Count`
from `world`.`vCountrys_Per_Continent`
where (`vCountrys_Per_Continent`.`Continent` = 'Asia')
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
WITH (CTE)
• A view for query-only duration
• Same optimizations available as views:
– Merge - transform the CTE to be combined with the query.
– Materialize - save the contents of the CTE in a temporary table,
then begin querying
109
# Identical Queries - CTE and VIEW
WITH vCountry_Asia AS (SELECT * FROM Country WHERE
Continent='Asia')
SELECT * FROM vCountry_Asia WHERE Name='China';
CREATE VIEW vCountry_Asia AS SELECT * FROM Country WHERE
Continent='Asia';
SELECT * FROM vCountry_Asia WHERE Name='China';
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
CTEs are new!
• May provide performance enhancements over legacy code using temporary
tables - which never merge.
• Derived tables may need to materialize more than once. A CTE does not! i.e.
111
SELECT * FROM my_table, (SELECT ... ) as t1 ...
UNION ALL
SELECT * FROM my_table, (SELECT ... ) as t1 ...
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
WITH RECURSIVE - new!
WITH RECURSIVE my_cte AS (
SELECT 1 AS n
UNION ALL
SELECT 1+n FROM my_cte WHERE n<10
)
SELECT * FROM my_cte;
+------+
| n |
+------+
| 1 |
| 2 |
..
| 9 |
| 10 |
+------+
10 rows in set (0.01 sec)
112
{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "2.84"
},
"table": {
"table_name": "my_cte",
"access_type": "ALL",
..
"used_columns": [
"n"
],
"materialized_from_subquery": {
"using_temporary_table": true,
"dependent": false,
"cacheable": true,
"query_block": {
"union_result": {
"using_temporary_table": false,
..
..
{
"dependent": false,
"cacheable": true,
"query_block": {
"select_id": 3,
"recursive": true,
"cost_info": {
"query_cost": "2.72"
},
"table": {
"table_name": "my_cte",
"access_type": "ALL",
..
"used_columns": [
"n"
],
"attached_condition": 

"(`my_cte`.`n` < 10)"
}
..
Requires a
temporary table for
intermediate results
Cost per iteration
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Agenda
1. Introduction
2. Server Architecture
3. B+trees
4. EXPLAIN
5. Optimizer Trace
6. Logical
Transformations
7. Cost Based
Optimization
8. Hints and Switches
9. Comparing Plans
10.Composite Indexes
11.Covering Indexes
12.Visual Explain
13.Transient Plans
14.Subqueries
15.CTEs and Views
16.Joins
17.Aggregation
18.Descending Indexes
19.Sorting
20.Partitioning
21.Query Rewrite
22.Invisible Indexes
23.Profiling
24.JSON
25.Character Sets
114
SELECT
Country.Name as Country, City.Name as Capital,
Language
FROM
City
INNER JOIN Country ON Country.Capital=City.id
INNER JOIN CountryLanguage ON
CountryLanguage.CountryCode=Country.code
WHERE
Country.Continent='Asia' and
CountryLanguage.IsOfficial='T';
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Join Strategy (Nested Loop Join)
1. Pick Driving Table (Country)
2. For each row in Country

step through to City table
3. For each row in City table

step through to

CountryLanguage table
4. Repeat
116
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Join efficiency
• Important to eliminate work before accessing other tables (WHERE
clause should have lots of predicates that filter driving table)
• Indexes are required on the columns that connect between driving
table, and subsequent tables:
117
ON Country.Capital=City.id
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
INNER JOIN vs LEFT JOIN
• LEFT JOIN semantically says “right row is optional”.
– Forces JOIN order to be left side first.
– Reduces possible ways to join tables
118
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Join Order Hints
• One of the most frequent types of hints to apply
• New join order hints in 8.0:
– JOIN_FIXED_ORDER
– JOIN_ORDER
– JOIN_PREFIX
– JOIN_SUFFIX
119
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Agenda
1. Introduction
2. Server Architecture
3. B+trees
4. EXPLAIN
5. Optimizer Trace
6. Logical
Transformations
7. Cost Based
Optimization
8. Hints and Switches
9. Comparing Plans
10.Composite Indexes
11.Covering Indexes
12.Visual Explain
13.Transient Plans
14.Subqueries
15.CTEs and Views
16.Joins
17.Aggregation
18.Descending Indexes
19.Sorting
20.Partitioning
21.Query Rewrite
22.Invisible Indexes
23.Profiling
24.JSON
25.Character Sets
120
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Group By - Loose Index Scan
• Scan the index from start to finish without buffering. Results are
pipelined to client:
121
SELECT count(*) as c, continent FROM Country 

GROUP BY continent;
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Group By - Index Filtering Rows
• Use the index to eliminate as much work as possible
• Store rows in intermediate temporary file and then sort
122
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Group By - Index Filtering + Guaranteed Order
• Use the index to eliminate as much work as possible
• The index also maintains order
123
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
UNION
• Requires an intermediate temporary table to weed out duplicate
rows
• The optimizer does not really have any optimizations for UNION
(such as a merge with views)
124
EXPLAIN FORMAT=JSON
SELECT * FROM City WHERE CountryCode = 'CAN'
UNION
SELECT * FROM City WHERE CountryCode = 'USA'
{
"union_result": {
"using_temporary_table": true,
"table_name": "<union1,2>",
"access_type": "ALL",
"query_specifications": [
{
"dependent": false,
"cacheable": true,
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "17.15"
},
"table": {
"table_name": "City",
"access_type": "ref",
..
"key": "CountryCode",
..
Temporary table to
de-duplicate
{
"dependent": false,
"cacheable": true,
"query_block": {
"select_id": 2,
"cost_info": {
"query_cost": "46.15"
},
"table": {
"table_name": "City",
"access_type": "ref",
"possible_keys": [
"CountryCode"
],
"key": "CountryCode",
"used_key_parts": [
"CountryCode"
],
"key_length": "3",
"ref": [
"const"
],
..
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
UNION ALL
• Results may contain duplicate rows
• Does not require an intermediate temporary table in simple use
cases. i.e. no result ordering.
• Otherwise similar to UNION
126
EXPLAIN FORMAT=JSON
SELECT * FROM City WHERE CountryCode = 'CAN'
UNION ALL
SELECT * FROM City WHERE CountryCode = 'USA'
{
"query_block": {
"union_result": {
"using_temporary_table": false,
"query_specifications": [
{
"dependent": false,
"cacheable": true,
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "17.15"
},
"table": {
"table_name": "City",
"access_type": "ref",
..
"key": "CountryCode",
..
{
"dependent": false,
"cacheable": true,
"query_block": {
"select_id": 2,
"cost_info": {
"query_cost": "46.15"
},
"table": {
"table_name": "City",
"access_type": "ref",
"possible_keys": [
"CountryCode"
],
"key": "CountryCode",
"used_key_parts": [
"CountryCode"
],
"key_length": "3",
"ref": [
"const"
],
..
No temporary table
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Agenda
1. Introduction
2. Server Architecture
3. B+trees
4. EXPLAIN
5. Optimizer Trace
6. Logical
Transformations
7. Cost Based
Optimization
8. Hints and Switches
9. Comparing Plans
10.Composite Indexes
11.Covering Indexes
12.Visual Explain
13.Transient Plans
14.Subqueries
15.CTEs and Views
16.Joins
17.Aggregation
18.Descending Indexes
19.Sorting
20.Partitioning
21.Query Rewrite
22.Invisible Indexes
23.Profiling
24.JSON
25.Character Sets
128
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Descending Indexes
• B+tree indexes are ordered
• In 8.0 you can specify the order
• Use cases:
– Faster to scan in order
– Can’t change direction in a composite index
129
EXPLAIN FORMAT=JSON
SELECT * FROM Country WHERE continent='Asia' AND population > 5000000
ORDER BY population DESC;
{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "7.91"
},
"ordering_operation": {
"using_filesort": false,
"table": {
"table_name": "Country",
"access_type": "range",
..
"key": "c_p",
..
"backward_index_scan": true,
..
Still uses the index, but
about 15% slower
EXPLAIN FORMAT=JSON
SELECT * FROM Country WHERE continent IN ('Asia', 'Oceania') AND population > 5000000
ORDER BY continent ASC, population DESC
{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "48.36"
},
"ordering_operation": {
"using_filesort": true,
"cost_info": {
"sort_cost": "33.00"
},
"table": {
"table_name": "Country",
"access_type": "range",
"key": "c_p",
..
"rows_examined_per_scan": 33,
"rows_produced_per_join": 33,
"filtered": "100.00",
..
Must sort values of
population in reverse
ALTER TABLE Country DROP INDEX c_p, DROP INDEX c_p_n,
ADD INDEX c_p_desc (continent ASC, population DESC);
EXPLAIN FORMAT=JSON
SELECT * FROM Country WHERE continent IN ('Asia', 'Oceania') AND population > 5000000
ORDER BY continent ASC, population DESC;
{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "15.36"
},
"ordering_operation": {
"using_filesort": false,
"table": {
"table_name": "Country",
"access_type": "range",
..
"key": "c_p_desc",
"used_key_parts": [
"Continent",
"Population"
],
"key_length": "5",
..
TIP: The optimizer does not consider sort cost in
evaluating plans. You may need to FORCE INDEX or
DROP similar ascending indexes to use it.
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Agenda
1. Introduction
2. Server Architecture
3. B+trees
4. EXPLAIN
5. Optimizer Trace
6. Logical
Transformations
7. Cost Based
Optimization
8. Hints and Switches
9. Comparing Plans
10.Composite Indexes
11.Covering Indexes
12.Visual Explain
13.Transient Plans
14.Subqueries
15.CTEs and Views
16.Joins
17.Aggregation
18.Descending Indexes
19.Sorting
20.Partitioning
21.Query Rewrite
22.Invisible Indexes
23.Profiling
24.JSON
25.Character Sets
133
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
How is ORDER BY optimized?
1. Via an Index
2. Top N Buffer (“priority queue”)
3. Using temporary files
134
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Via an Index
• B+tree indexes are ordered
• Some ORDER BY queries do not require sorting at all
135
EXPLAIN FORMAT=JSON
SELECT * FROM Country WHERE continent='Asia' ORDER BY population;
{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "9.60"
},
"ordering_operation": {
"using_filesort": false,
..
"key": "c_p",
The order is provided by
c_p
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Via a Priority Queue
• Special ORDER BY + small limit optimization
• Keeps top N records in an in memory buffer
• Usage is NOT shown in EXPLAIN
136
SELECT * FROM Country IGNORE INDEX (p, p_c)
ORDER BY population LIMIT 10;
"select#": 1,
"steps": [
{
"filesort_information": [
{
"direction": "asc",
"table": "`country` IGNORE INDEX (`p_c`) IGNORE INDEX (`p`)",
"field": "Population"
}
],
"filesort_priority_queue_optimization": {
"limit": 10,
"chosen": true
},
"filesort_execution": [
],
"filesort_summary": {
"memory_available": 262144,
"key_size": 4,
"row_size": 272,
"max_rows_per_buffer": 11,
"num_rows_estimate": 587,
"num_rows_found": 11,
"num_examined_rows": 239,
"num_tmp_files": 0,
"sort_buffer_size": 3080,
"sort_algorithm": "std::sort",
"unpacked_addon_fields": "using_priority_queue",
"sort_mode": "<fixed_sort_key, additional_fields>”
..
OPTIMIZER TRACE
showing Priority Queue for
sort
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Using Temporary Files
• Either “Alternative Sort Algorithm” (no blobs present) or “Original
Sort Algorithm”
138
SELECT * FROM Country IGNORE INDEX (p, p_c)
ORDER BY population;
"select#": 1,
"steps": [
{
"filesort_information": [
{
"direction": "asc",
"table": "`country` IGNORE INDEX (`p_c`) IGNORE INDEX (`p`)",
"field": "Population"
}
],
"filesort_priority_queue_optimization": {
"usable": false,
"cause": "not applicable (no LIMIT)"
},
"filesort_execution": [
],
"filesort_summary": {
"memory_available": 262144,
"key_size": 4,
"row_size": 274,
"max_rows_per_buffer": 587,
"num_rows_estimate": 587,
"num_rows_found": 239,
"num_examined_rows": 239,
"num_tmp_files": 0,
"sort_buffer_size": 165536,
"sort_algorithm": "std::stable_sort",
"sort_mode": "<fixed_sort_key, packed_additional_fields>"
..
Not Using Priority Sort
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Agenda
1. Introduction
2. Server Architecture
3. B+trees
4. EXPLAIN
5. Optimizer Trace
6. Logical
Transformations
7. Cost Based
Optimization
8. Hints and Switches
9. Comparing Plans
10.Composite Indexes
11.Covering Indexes
12.Visual Explain
13.Transient Plans
14.Subqueries
15.CTEs and Views
16.Joins
17.Aggregation
18.Descending Indexes
19.Sorting
20.Partitioning
21.Query Rewrite
22.Invisible Indexes
23.Profiling
24.JSON
25.Character Sets
140
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Partitioning
• Split a table physically into smaller tables
• At the user-level make it still appear as one table
141
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Use Cases
• Can be a better fit low cardinality columns than indexing
• Useful for time series data with retention scheme
• i.e. drop data older than 3 months
• Data where queries always have some locality
• i.e. store_id, region
142
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Partition Pruning
• Optimizer looks at query and identifies which partitions need to be
accessed
143
ALTER TABLE CountryLanguage MODIFY IsOfficial CHAR(1) NOT NULL DEFAULT 'F', DROP
PRIMARY KEY, ADD PRIMARY KEY(CountryCode, Language, IsOfficial);

ALTER TABLE CountryLanguage PARTITION BY LIST COLUMNS (IsOfficial) (
PARTITION pUnofficial VALUES IN ('F'),
PARTITION pOfficial VALUES IN ('T')
);
EXPLAIN FORMAT=JSON
SELECT * FROM CountryLanguage WHERE isOfficial='T' AND
CountryCode='CAN';
{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "2.40"
},
"table": {
"table_name": "CountryLanguage",
"partitions": [
"pOfficial"
],
"access_type": "ref",
..
"key": "PRIMARY",
..
Only accesses one
partition
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Explicit Partition Selection
• Also possible to “target” a partition
• Consider this similar to query hints
145
SELECT * FROM CountryLanguage PARTITION (pOfficial)
WHERE CountryCode='CAN';
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Agenda
1. Introduction
2. Server Architecture
3. B+trees
4. EXPLAIN
5. Optimizer Trace
6. Logical
Transformations
7. Cost Based
Optimization
8. Hints and Switches
9. Comparing Plans
10.Composite Indexes
11.Covering Indexes
12.Visual Explain
13.Transient Plans
14.Subqueries
15.CTEs and Views
16.Joins
17.Aggregation
18.Descending Indexes
19.Sorting
20.Partitioning
21.Query Rewrite
22.Invisible Indexes
23.Profiling
24.JSON
25.Character Sets
146
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Query Rewrite
• MySQL allows you to change queries before they are executed
• Insert a hint, or remove a join that is not required
147
mysql -u root -p < install_rewriter.sql
INSERT INTO query_rewrite.rewrite_rules(pattern_database, pattern,
replacement) VALUES (
"world",
"SELECT * FROM Country WHERE population > ? AND continent=?",
"SELECT * FROM Country WHERE population > ? AND continent=? LIMIT 1"
);
CALL query_rewrite.flush_rewrite_rules();
SELECT * FROM Country WHERE population > 5000000 AND
continent='Asia';
SHOW WARNINGS;
*********************** 1. row ***********************
Level: Note
Code: 1105
Message: Query 'SELECT * FROM Country WHERE population >
5000000 AND continent='Asia'' rewritten to 'SELECT *
FROM Country WHERE population > 5000000 AND
continent='Asia' LIMIT 1' by a query rewrite plugin
1 row in set (0.00 sec)
SELECT * FROM query_rewrite.rewrite_rulesG
********************** 1. row **********************
id: 1
pattern: SELECT * FROM Country WHERE
population > ? AND continent=?
pattern_database: world
replacement: SELECT * FROM Country WHERE
population > ? AND continent=? LIMIT 1
enabled: YES
message: NULL
pattern_digest: 88876bbb502cef6efddcc661cce77deb
normalized_pattern: select `*` from `world`.`country`
where ((`population` > ?) and (`continent` = ?))
1 row in set (0.00 sec)
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Agenda
1. Introduction
2. Server Architecture
3. B+trees
4. EXPLAIN
5. Optimizer Trace
6. Logical
Transformations
7. Cost Based
Optimization
8. Hints and Switches
9. Comparing Plans
10.Composite Indexes
11.Covering Indexes
12.Visual Explain
13.Transient Plans
14.Subqueries
15.CTEs and Views
16.Joins
17.Aggregation
18.Descending Indexes
19.Sorting
20.Partitioning
21.Query Rewrite
22.Invisible Indexes
23.Profiling
24.JSON
25.Character Sets
150
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Changing Indexes is a Destructive Operation
• Removing an index can make some queries much slower
• Adding can cause some existing query plans to change
• Old-style hints will generate errors if indexes are removed
151
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Invisible Indexes, the “Recycle Bin”
• Hide the indexes from the optimizer
• Will no longer be considered as part of query execution plans
• Still kept up to date and are maintained by insert/update/delete
statements
152
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Invisible Indexes: Soft Delete
ALTER TABLE Country ALTER INDEX c INVISIBLE;
SELECT * FROM information_schema.statistics WHERE is_visible='NO';
*************************** 1. row ***************************
TABLE_CATALOG: def
TABLE_SCHEMA: world
TABLE_NAME: Country
NON_UNIQUE: 1
INDEX_SCHEMA: world
INDEX_NAME: c
SEQ_IN_INDEX: 1
COLUMN_NAME: Continent
COLLATION: A
CARDINALITY: 7
SUB_PART: NULL
PACKED: NULL
NULLABLE:
INDEX_TYPE: BTREE
COMMENT: disabled
INDEX_COMMENT:
IS_VISIBLE: NO
153
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Invisible Indexes: Staged Rollout
ALTER TABLE Country ADD INDEX c (Continent)
INVISIBLE;
# after some time
ALTER TABLE Country ALTER INDEX c VISIBLE;
154
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Finding Unused Indexes
SELECT * FROM sys.schema_unused_indexes;
+---------------+-------------+------------+
| object_schema | object_name | index_name |
+---------------+-------------+------------+
| world | Country | p |
| world | Country | p_c |
+---------------+-------------+------------+
2 rows in set (0.01 sec)
155
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Do indexes hurt reads or writes?
• They can have some impact on both:
– On writes, indexes need to space, and to be maintained
– On reads, lets use an example…
156
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Indexes Hurting Reads
CREATE TABLE t1 (
id INT NOT NULL primary key auto_increment,
a VARCHAR(255) NOT NULL,
b VARCHAR(255) NOT NULL,
c TEXT,
d TEXT,
INDEX a (a),
INDEX ab (a,b));
# Sample Query
SELECT * FROM t1 WHERE a = 'abc' AND b = 'bcd';
157
Both indexes are candidates.
Both will be examined.
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
A use case for invisible indexes!
CREATE TABLE t1 (
id INT NOT NULL primary key auto_increment,
a VARCHAR(255) NOT NULL,
b VARCHAR(255) NOT NULL,
c TEXT,
d TEXT,
INDEX a (a),
INDEX ab (a,b));
# Consider:
SELECT count(*) FROM t1 FORCE INDEX (a)

WHERE a='1234' AND id=1234;
158
Index (a) is made redundant by
(a,b). Can we drop it?
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 159
No, due to clustered Index!
FORCE INDEX (a) WHERE a=‘1234' AND id=1234;
{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "0.35"
},
"table": {
"table_name": "t1",
"access_type": "const",
"possible_keys": [
"a"
],
"key": "a",
"used_key_parts": [
"a",
"id"
],
..
FORCE INDEX (ab) WHERE a='1234' AND id=1234;
{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "11.80"
},
"table": {
"table_name": "t1",
"access_type": "ref",
"possible_keys": [
"ab"
],
"key": "ab",
"used_key_parts": [
"a"
],
..
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Agenda
1. Introduction
2. Server Architecture
3. B+trees
4. EXPLAIN
5. Optimizer Trace
6. Logical
Transformations
7. Cost Based
Optimization
8. Hints and Switches
9. Comparing Plans
10.Composite Indexes
11.Covering Indexes
12.Visual Explain
13.Transient Plans
14.Subqueries
15.CTEs and Views
16.Joins
17.Aggregation
18.Descending Indexes
19.Sorting
20.Partitioning
21.Query Rewrite
22.Invisible Indexes
23.Profiling
24.JSON
25.Character Sets
160
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Profiling
• Optimizer only shows estimates from pre-execution view
• Can be useful to know actual time spent
• Support for profiling is only very basic
161
wget http://www.tocker.ca/files/ps-show-profiles.sql
mysql -u root -p < ps-show-profiles.sql
CALL sys.enable_profiling();
CALL sys.show_profiles;
*************************** 1. row ***************************
Event_ID: 22
Duration: 495.02 us
Query: SELECT * FROM Country WHERE co ... Asia' and population > 5000000
1 row in set (0.00 sec)
CALL sys.show_profile_for_event_id(22);
+----------------------+-----------+
| Status | Duration |
+----------------------+-----------+
| starting | 64.82 us |
| checking permissions | 4.10 us |
| Opening tables | 11.87 us |
| init | 29.74 us |
| System lock | 5.63 us |
| optimizing | 8.74 us |
| statistics | 139.38 us |
| preparing | 11.94 us |
| executing | 348.00 ns |
| Sending data | 192.59 us |
| end | 1.17 us |
| query end | 4.60 us |
| closing tables | 4.07 us |
| freeing items | 13.60 us |
| cleaning up | 734.00 ns |
+----------------------+-----------+
15 rows in set (0.00 sec)
SELECT * FROM Country WHERE Continent='Antarctica' and SLEEP(5);
CALL sys.show_profiles();
CALL sys.show_profile_for_event_id(<event_id>);
+----------------------+-----------+
| Status | Duration |
+----------------------+-----------+
| starting | 103.89 us |
| checking permissions | 4.48 us |
| Opening tables | 17.78 us |
| init | 45.75 us |
| System lock | 8.37 us |
| optimizing | 11.98 us |
| statistics | 144.78 us |
| preparing | 15.78 us |
| executing | 634.00 ns |
| Sending data | 116.15 us |
| User sleep | 5.00 s |
| User sleep | 5.00 s |
| User sleep | 5.00 s |
| User sleep | 5.00 s |
| User sleep | 5.00 s |
| end | 2.05 us |
| query end | 5.63 us |
| closing tables | 7.30 us |
| freeing items | 20.19 us |
| cleaning up | 1.20 us |
+----------------------+-----------+
20 rows in set (0.01 sec)
Sleeps for each row after
index used on (c)
SELECT region, count(*) as c FROM Country GROUP BY region;
CALL sys.show_profiles();
CALL sys.show_profile_for_event_id(<event_id>);
+----------------------+-----------+
| Status | Duration |
+----------------------+-----------+
| starting | 87.43 us |
| checking permissions | 4.93 us |
| Opening tables | 17.35 us |
| init | 25.81 us |
| System lock | 9.04 us |
| optimizing | 3.37 us |
| statistics | 18.31 us |
| preparing | 10.94 us |
| Creating tmp table | 35.57 us |
| Sorting result | 2.38 us |
| executing | 741.00 ns |
| Sending data | 446.03 us |
| Creating sort index | 49.45 us |
| end | 1.71 us |
| query end | 4.85 us |
| removing tmp table | 4.71 us |
| closing tables | 6.12 us |
| freeing items | 17.17 us |
| cleaning up | 1.00 us |
+----------------------+-----------+
19 rows in set (0.01 sec)
SELECT * FROM performance_schema.events_statements_history_long
WHERE event_id=<event_id>G
*********************** 1. row ***********************
THREAD_ID: 3062
EVENT_ID: 1566
END_EVENT_ID: 1585
EVENT_NAME: statement/sql/select
SOURCE: init_net_server_extension.cc:80
TIMER_START: 588883869566277000
TIMER_END: 588883870317683000
TIMER_WAIT: 751406000
LOCK_TIME: 132000000
SQL_TEXT: SELECT region, 

count(*) as c FROM Country GROUP BY region
DIGEST: d3a04b346fe48da4f1f5c2e06628a245
DIGEST_TEXT: SELECT `region` ,

COUNT ( * ) AS `c` FROM `Country` 

GROUP BY `region`
CURRENT_SCHEMA: world
OBJECT_TYPE: NULL
OBJECT_SCHEMA: NULL
OBJECT_NAME: NULL
OBJECT_INSTANCE_BEGIN: NULL
MYSQL_ERRNO: 0
RETURNED_SQLSTATE: NULL
MESSAGE_TEXT: NULL
ERRORS: 0
WARNINGS: 0
..
..
ROWS_AFFECTED: 0
ROWS_SENT: 25
ROWS_EXAMINED: 289
CREATED_TMP_DISK_TABLES: 0
CREATED_TMP_TABLES: 1
SELECT_FULL_JOIN: 0
SELECT_FULL_RANGE_JOIN: 0
SELECT_RANGE: 0
SELECT_RANGE_CHECK: 0
SELECT_SCAN: 1
SORT_MERGE_PASSES: 0
SORT_RANGE: 0
SORT_ROWS: 25
SORT_SCAN: 1
NO_INDEX_USED: 1
NO_GOOD_INDEX_USED: 0
NESTING_EVENT_ID: NULL
NESTING_EVENT_TYPE: NULL
NESTING_EVENT_LEVEL: 0
For non-aggregate queries rows sent
vs. rows examined helps indicate index
effectiveness.
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Agenda
1. Introduction
2. Server Architecture
3. B+trees
4. EXPLAIN
5. Optimizer Trace
6. Logical
Transformations
7. Cost Based
Optimization
8. Hints and Switches
9. Comparing Plans
10.Composite Indexes
11.Covering Indexes
12.Visual Explain
13.Transient Plans
14.Subqueries
15.CTEs and Views
16.Joins
17.Aggregation
18.Descending Indexes
19.Sorting
20.Partitioning
21.Query Rewrite
22.Invisible Indexes
23.Profiling
24.JSON
25.Character Sets
166
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
JSON
• Optimizer has native support for JSON with indexes on generated
columns used for matching JSON path expressions
167
CREATE TABLE CountryJson (Code char(3) not null primary key, doc JSON NOT NULL);
INSERT INTO CountryJSON SELECT code,
JSON_OBJECT(
'Name', Name,
'Continent', Continent,
..
'HeadOfState',HeadOfState,
'Capital', Capital,
'Code2', Code2
) FROM Country;
EXPLAIN FORMAT=JSON

SELECT * FROM CountryJSON where doc->>"$.Name" = ‘Canada';
{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "48.80"
},
"table": {
"table_name": "CountryJSON",
"access_type": "ALL",
"rows_examined_per_scan": 239,
"rows_produced_per_join": 239,
"filtered": "100.00",
"cost_info": {
"read_cost": "1.00",
"eval_cost": "47.80",
"prefix_cost": "48.80",
"data_read_per_join": "3K"
},
..
ALTER TABLE CountryJSON ADD Name char(52) AS (doc->>"$.Name"),
ADD INDEX n (Name);
EXPLAIN FORMAT=JSON
SELECT * FROM CountryJSON where doc->>"$.Name" = ‘Canada';
{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "1.20"
},
"table": {
"table_name": "CountryJSON",
"access_type": "ref",
..
"key": "n",
..
"key_length": "53",
"ref": [
"const"
],
..
Key from virtual column
Matches expression from
indexed virtual column
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
JSON Comparator
• JSON types compare to MySQL types
170
SELECT CountryJSON.* FROM CountryJSON 

INNER JOIN Country ON CountryJSON.doc->>"$.Name" = Country.Name WHERE
Country.Name=‘Canada';
********************** 1. row **********************
Code: CAN
doc: {"GNP": 598862, "Name": "Canada", "Code2": "CA", "GNPOld": 625626, "Region":
"North America", "Capital": 1822, "Continent": "North America", "IndepYear": 1867,
"LocalName": "Canada", "Population": 31147000, "HeadOfState": "Elisabeth II",
"SurfaceArea": 9970610, "GovernmentForm": "Constitutional Monarchy, Federation",
"LifeExpectancy": 79.4000015258789}
Name: Canada
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Agenda
1. Introduction
2. Server Architecture
3. B+trees
4. EXPLAIN
5. Optimizer Trace
6. Logical
Transformations
7. Cost Based
Optimization
8. Hints and Switches
9. Comparing Plans
10.Composite Indexes
11.Covering Indexes
12.Visual Explain
13.Transient Plans
14.Subqueries
15.CTEs and Views
16.Joins
17.Aggregation
18.Descending Indexes
19.Sorting
20.Partitioning
21.Query Rewrite
22.Invisible Indexes
23.Profiling
24.JSON
25.Character Sets
171
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Character Sets
• The default character set in MySQL 8.0 is utf8mb4
• Utf8mb4 is variable length (1-4 bytes)
• InnoDB will always store as variable size for both CHAR and
VARCHAR
• Some buffers inside MySQL may require the fixed length (4 bytes)
172
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Character Sets (cont.)
• CHAR(n) or VARCHAR(n) refers to n characters - x4 for maximum length
• EXPLAIN will always show the maximum length
• Mysqldump will preserve character set
173


ALTER TABLE City DROP FOREIGN KEY city_ibfk_1;
ALTER TABLE CountryLanguage DROP FOREIGN KEY
countryLanguage_ibfk_1;
ALTER TABLE Country CONVERT TO CHARACTER SET
utf8mb4;
{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "0.35"
},
"table": {
"table_name": "Country",
"access_type": "ref",
"possible_keys": [
"n"
],
"key": "n",
"used_key_parts": [
"Name"
],
"key_length": "52",
..
"rows_examined_per_scan": 1,
"rows_produced_per_join": 1,
"filtered": "100.00",
"cost_info": {
"read_cost": "0.25",
"eval_cost": "0.10",
"prefix_cost": "0.35",
"data_read_per_join": "264"
},
..
{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "0.35"
},
"table": {
"table_name": "Country",
"access_type": "ref",
"possible_keys": [
"n"
],
"key": "n",
"used_key_parts": [
"Name"
],
"key_length": "208",
..
"rows_examined_per_scan": 1,
"rows_produced_per_join": 1,
"filtered": "100.00",
"cost_info": {
"read_cost": "0.25",
"eval_cost": "0.10",
"prefix_cost": "0.35",
"data_read_per_join": "968"
},
..
Key length as latin1 Key length as utf8
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Conclusion
• Thank you for coming!
• This presentation is available as a website:

www.unofficialmysqlguide.com
175
MySQL 8.0 Optimizer Guide

More Related Content

What's hot (20)

The MySQL Query Optimizer Explained Through Optimizer Trace
The MySQL Query Optimizer Explained Through Optimizer TraceThe MySQL Query Optimizer Explained Through Optimizer Trace
The MySQL Query Optimizer Explained Through Optimizer Trace
oysteing
 
How to Analyze and Tune MySQL Queries for Better Performance
How to Analyze and Tune MySQL Queries for Better PerformanceHow to Analyze and Tune MySQL Queries for Better Performance
How to Analyze and Tune MySQL Queries for Better Performance
oysteing
 
MySQL Performance Tuning: Top 10 Tips
MySQL Performance Tuning: Top 10 TipsMySQL Performance Tuning: Top 10 Tips
MySQL Performance Tuning: Top 10 Tips
OSSCube
 
How to Use JSON in MySQL Wrong
How to Use JSON in MySQL WrongHow to Use JSON in MySQL Wrong
How to Use JSON in MySQL Wrong
Karwin Software Solutions LLC
 
The InnoDB Storage Engine for MySQL
The InnoDB Storage Engine for MySQLThe InnoDB Storage Engine for MySQL
The InnoDB Storage Engine for MySQL
Morgan Tocker
 
MySQL查询优化浅析
MySQL查询优化浅析MySQL查询优化浅析
MySQL查询优化浅析
frogd
 
MySQL Optimizer Cost Model
MySQL Optimizer Cost ModelMySQL Optimizer Cost Model
MySQL Optimizer Cost Model
Olav Sandstå
 
InnoDB Internal
InnoDB InternalInnoDB Internal
InnoDB Internal
mysqlops
 
InnoDB MVCC Architecture (by 권건우)
InnoDB MVCC Architecture (by 권건우)InnoDB MVCC Architecture (by 권건우)
InnoDB MVCC Architecture (by 권건우)
I Goo Lee.
 
ClickHouse Query Performance Tips and Tricks, by Robert Hodges, Altinity CEO
ClickHouse Query Performance Tips and Tricks, by Robert Hodges, Altinity CEOClickHouse Query Performance Tips and Tricks, by Robert Hodges, Altinity CEO
ClickHouse Query Performance Tips and Tricks, by Robert Hodges, Altinity CEO
Altinity Ltd
 
How to Analyze and Tune MySQL Queries for Better Performance
How to Analyze and Tune MySQL Queries for Better PerformanceHow to Analyze and Tune MySQL Queries for Better Performance
How to Analyze and Tune MySQL Queries for Better Performance
oysteing
 
High Performance, High Reliability Data Loading on ClickHouse
High Performance, High Reliability Data Loading on ClickHouseHigh Performance, High Reliability Data Loading on ClickHouse
High Performance, High Reliability Data Loading on ClickHouse
Altinity Ltd
 
How to Take Advantage of Optimizer Improvements in MySQL 8.0
How to Take Advantage of Optimizer Improvements in MySQL 8.0How to Take Advantage of Optimizer Improvements in MySQL 8.0
How to Take Advantage of Optimizer Improvements in MySQL 8.0
Norvald Ryeng
 
MySQL Query And Index Tuning
MySQL Query And Index TuningMySQL Query And Index Tuning
MySQL Query And Index Tuning
Manikanda kumar
 
Dd and atomic ddl pl17 dublin
Dd and atomic ddl pl17 dublinDd and atomic ddl pl17 dublin
Dd and atomic ddl pl17 dublin
Ståle Deraas
 
Redo log improvements MYSQL 8.0
Redo log improvements MYSQL 8.0Redo log improvements MYSQL 8.0
Redo log improvements MYSQL 8.0
Mydbops
 
MySQL Query Optimization
MySQL Query OptimizationMySQL Query Optimization
MySQL Query Optimization
Morgan Tocker
 
New Indexing and Aggregation Pipeline Capabilities in MongoDB 4.2
New Indexing and Aggregation Pipeline Capabilities in MongoDB 4.2New Indexing and Aggregation Pipeline Capabilities in MongoDB 4.2
New Indexing and Aggregation Pipeline Capabilities in MongoDB 4.2
Antonios Giannopoulos
 
How to Choose the Right Database for Your Workloads
How to Choose the Right Database for Your WorkloadsHow to Choose the Right Database for Your Workloads
How to Choose the Right Database for Your Workloads
InfluxData
 
Open Source 101 2022 - MySQL Indexes and Histograms
Open Source 101 2022 - MySQL Indexes and HistogramsOpen Source 101 2022 - MySQL Indexes and Histograms
Open Source 101 2022 - MySQL Indexes and Histograms
Frederic Descamps
 
The MySQL Query Optimizer Explained Through Optimizer Trace
The MySQL Query Optimizer Explained Through Optimizer TraceThe MySQL Query Optimizer Explained Through Optimizer Trace
The MySQL Query Optimizer Explained Through Optimizer Trace
oysteing
 
How to Analyze and Tune MySQL Queries for Better Performance
How to Analyze and Tune MySQL Queries for Better PerformanceHow to Analyze and Tune MySQL Queries for Better Performance
How to Analyze and Tune MySQL Queries for Better Performance
oysteing
 
MySQL Performance Tuning: Top 10 Tips
MySQL Performance Tuning: Top 10 TipsMySQL Performance Tuning: Top 10 Tips
MySQL Performance Tuning: Top 10 Tips
OSSCube
 
The InnoDB Storage Engine for MySQL
The InnoDB Storage Engine for MySQLThe InnoDB Storage Engine for MySQL
The InnoDB Storage Engine for MySQL
Morgan Tocker
 
MySQL查询优化浅析
MySQL查询优化浅析MySQL查询优化浅析
MySQL查询优化浅析
frogd
 
MySQL Optimizer Cost Model
MySQL Optimizer Cost ModelMySQL Optimizer Cost Model
MySQL Optimizer Cost Model
Olav Sandstå
 
InnoDB Internal
InnoDB InternalInnoDB Internal
InnoDB Internal
mysqlops
 
InnoDB MVCC Architecture (by 권건우)
InnoDB MVCC Architecture (by 권건우)InnoDB MVCC Architecture (by 권건우)
InnoDB MVCC Architecture (by 권건우)
I Goo Lee.
 
ClickHouse Query Performance Tips and Tricks, by Robert Hodges, Altinity CEO
ClickHouse Query Performance Tips and Tricks, by Robert Hodges, Altinity CEOClickHouse Query Performance Tips and Tricks, by Robert Hodges, Altinity CEO
ClickHouse Query Performance Tips and Tricks, by Robert Hodges, Altinity CEO
Altinity Ltd
 
How to Analyze and Tune MySQL Queries for Better Performance
How to Analyze and Tune MySQL Queries for Better PerformanceHow to Analyze and Tune MySQL Queries for Better Performance
How to Analyze and Tune MySQL Queries for Better Performance
oysteing
 
High Performance, High Reliability Data Loading on ClickHouse
High Performance, High Reliability Data Loading on ClickHouseHigh Performance, High Reliability Data Loading on ClickHouse
High Performance, High Reliability Data Loading on ClickHouse
Altinity Ltd
 
How to Take Advantage of Optimizer Improvements in MySQL 8.0
How to Take Advantage of Optimizer Improvements in MySQL 8.0How to Take Advantage of Optimizer Improvements in MySQL 8.0
How to Take Advantage of Optimizer Improvements in MySQL 8.0
Norvald Ryeng
 
MySQL Query And Index Tuning
MySQL Query And Index TuningMySQL Query And Index Tuning
MySQL Query And Index Tuning
Manikanda kumar
 
Dd and atomic ddl pl17 dublin
Dd and atomic ddl pl17 dublinDd and atomic ddl pl17 dublin
Dd and atomic ddl pl17 dublin
Ståle Deraas
 
Redo log improvements MYSQL 8.0
Redo log improvements MYSQL 8.0Redo log improvements MYSQL 8.0
Redo log improvements MYSQL 8.0
Mydbops
 
MySQL Query Optimization
MySQL Query OptimizationMySQL Query Optimization
MySQL Query Optimization
Morgan Tocker
 
New Indexing and Aggregation Pipeline Capabilities in MongoDB 4.2
New Indexing and Aggregation Pipeline Capabilities in MongoDB 4.2New Indexing and Aggregation Pipeline Capabilities in MongoDB 4.2
New Indexing and Aggregation Pipeline Capabilities in MongoDB 4.2
Antonios Giannopoulos
 
How to Choose the Right Database for Your Workloads
How to Choose the Right Database for Your WorkloadsHow to Choose the Right Database for Your Workloads
How to Choose the Right Database for Your Workloads
InfluxData
 
Open Source 101 2022 - MySQL Indexes and Histograms
Open Source 101 2022 - MySQL Indexes and HistogramsOpen Source 101 2022 - MySQL Indexes and Histograms
Open Source 101 2022 - MySQL Indexes and Histograms
Frederic Descamps
 

Similar to MySQL 8.0 Optimizer Guide (20)

What's New MySQL 8.0?
What's New MySQL 8.0?What's New MySQL 8.0?
What's New MySQL 8.0?
OracleMySQL
 
MySQL 8.0 in a nutshell
MySQL 8.0 in a nutshellMySQL 8.0 in a nutshell
MySQL 8.0 in a nutshell
OracleMySQL
 
State ofdolphin short
State ofdolphin shortState ofdolphin short
State ofdolphin short
Mandy Ang
 
20180420 hk-the powerofmysql8
20180420 hk-the powerofmysql820180420 hk-the powerofmysql8
20180420 hk-the powerofmysql8
Ivan Ma
 
SQL for Analytics.pdfSQL for Analytics.pdf
SQL for Analytics.pdfSQL for Analytics.pdfSQL for Analytics.pdfSQL for Analytics.pdf
SQL for Analytics.pdfSQL for Analytics.pdf
namtunguyen6
 
MySQL 8.0.1 DMR
MySQL 8.0.1 DMRMySQL 8.0.1 DMR
MySQL 8.0.1 DMR
MySQL Brasil
 
What's New in MySQL 8.0 @ HKOSC 2017
What's New in MySQL 8.0 @ HKOSC 2017What's New in MySQL 8.0 @ HKOSC 2017
What's New in MySQL 8.0 @ HKOSC 2017
Ivan Ma
 
Developers’ mDay u Banjoj Luci - Bogdan Kecman, Oracle – MySQL Server 8.0
Developers’ mDay u Banjoj Luci - Bogdan Kecman, Oracle – MySQL Server 8.0Developers’ mDay u Banjoj Luci - Bogdan Kecman, Oracle – MySQL Server 8.0
Developers’ mDay u Banjoj Luci - Bogdan Kecman, Oracle – MySQL Server 8.0
mCloud
 
Developers' mDay 2017. - Bogdan Kecman Oracle
Developers' mDay 2017. - Bogdan Kecman OracleDevelopers' mDay 2017. - Bogdan Kecman Oracle
Developers' mDay 2017. - Bogdan Kecman Oracle
mCloud
 
MySQL Optimizer: What's New in 8.0
MySQL Optimizer: What's New in 8.0MySQL Optimizer: What's New in 8.0
MySQL Optimizer: What's New in 8.0
Manyi Lu
 
Node.js and the MySQL Document Store
Node.js and the MySQL Document StoreNode.js and the MySQL Document Store
Node.js and the MySQL Document Store
Rui Quelhas
 
Confoo 2021 - MySQL Indexes & Histograms
Confoo 2021 - MySQL Indexes & HistogramsConfoo 2021 - MySQL Indexes & Histograms
Confoo 2021 - MySQL Indexes & Histograms
Dave Stokes
 
MySQL como Document Store PHP Conference 2017
MySQL como Document Store PHP Conference 2017MySQL como Document Store PHP Conference 2017
MySQL como Document Store PHP Conference 2017
MySQL Brasil
 
SkiPHP -- Database Basics for PHP
SkiPHP -- Database Basics for PHP SkiPHP -- Database Basics for PHP
SkiPHP -- Database Basics for PHP
Dave Stokes
 
MySQL 8.0 Released Update
MySQL 8.0 Released UpdateMySQL 8.0 Released Update
MySQL 8.0 Released Update
Keith Hollman
 
Dutch PHP Conference 2021 - MySQL Indexes and Histograms
Dutch PHP Conference 2021 - MySQL Indexes and HistogramsDutch PHP Conference 2021 - MySQL Indexes and Histograms
Dutch PHP Conference 2021 - MySQL Indexes and Histograms
Dave Stokes
 
Python and the MySQL Document Store
Python and the MySQL Document StorePython and the MySQL Document Store
Python and the MySQL Document Store
Jesper Wisborg Krogh
 
MySQL Day Paris 2018 - What’s New in MySQL 8.0 ?
MySQL Day Paris 2018 - What’s New in MySQL 8.0 ?MySQL Day Paris 2018 - What’s New in MySQL 8.0 ?
MySQL Day Paris 2018 - What’s New in MySQL 8.0 ?
Olivier DASINI
 
20190713_MySQL開発最新動向
20190713_MySQL開発最新動向20190713_MySQL開発最新動向
20190713_MySQL開発最新動向
Machiko Ikoma
 
Journey to SAS Analytics Grid with SAS, R, Python
Journey to SAS Analytics Grid with SAS, R, PythonJourney to SAS Analytics Grid with SAS, R, Python
Journey to SAS Analytics Grid with SAS, R, Python
Sumit Sarkar
 
What's New MySQL 8.0?
What's New MySQL 8.0?What's New MySQL 8.0?
What's New MySQL 8.0?
OracleMySQL
 
MySQL 8.0 in a nutshell
MySQL 8.0 in a nutshellMySQL 8.0 in a nutshell
MySQL 8.0 in a nutshell
OracleMySQL
 
State ofdolphin short
State ofdolphin shortState ofdolphin short
State ofdolphin short
Mandy Ang
 
20180420 hk-the powerofmysql8
20180420 hk-the powerofmysql820180420 hk-the powerofmysql8
20180420 hk-the powerofmysql8
Ivan Ma
 
SQL for Analytics.pdfSQL for Analytics.pdf
SQL for Analytics.pdfSQL for Analytics.pdfSQL for Analytics.pdfSQL for Analytics.pdf
SQL for Analytics.pdfSQL for Analytics.pdf
namtunguyen6
 
What's New in MySQL 8.0 @ HKOSC 2017
What's New in MySQL 8.0 @ HKOSC 2017What's New in MySQL 8.0 @ HKOSC 2017
What's New in MySQL 8.0 @ HKOSC 2017
Ivan Ma
 
Developers’ mDay u Banjoj Luci - Bogdan Kecman, Oracle – MySQL Server 8.0
Developers’ mDay u Banjoj Luci - Bogdan Kecman, Oracle – MySQL Server 8.0Developers’ mDay u Banjoj Luci - Bogdan Kecman, Oracle – MySQL Server 8.0
Developers’ mDay u Banjoj Luci - Bogdan Kecman, Oracle – MySQL Server 8.0
mCloud
 
Developers' mDay 2017. - Bogdan Kecman Oracle
Developers' mDay 2017. - Bogdan Kecman OracleDevelopers' mDay 2017. - Bogdan Kecman Oracle
Developers' mDay 2017. - Bogdan Kecman Oracle
mCloud
 
MySQL Optimizer: What's New in 8.0
MySQL Optimizer: What's New in 8.0MySQL Optimizer: What's New in 8.0
MySQL Optimizer: What's New in 8.0
Manyi Lu
 
Node.js and the MySQL Document Store
Node.js and the MySQL Document StoreNode.js and the MySQL Document Store
Node.js and the MySQL Document Store
Rui Quelhas
 
Confoo 2021 - MySQL Indexes & Histograms
Confoo 2021 - MySQL Indexes & HistogramsConfoo 2021 - MySQL Indexes & Histograms
Confoo 2021 - MySQL Indexes & Histograms
Dave Stokes
 
MySQL como Document Store PHP Conference 2017
MySQL como Document Store PHP Conference 2017MySQL como Document Store PHP Conference 2017
MySQL como Document Store PHP Conference 2017
MySQL Brasil
 
SkiPHP -- Database Basics for PHP
SkiPHP -- Database Basics for PHP SkiPHP -- Database Basics for PHP
SkiPHP -- Database Basics for PHP
Dave Stokes
 
MySQL 8.0 Released Update
MySQL 8.0 Released UpdateMySQL 8.0 Released Update
MySQL 8.0 Released Update
Keith Hollman
 
Dutch PHP Conference 2021 - MySQL Indexes and Histograms
Dutch PHP Conference 2021 - MySQL Indexes and HistogramsDutch PHP Conference 2021 - MySQL Indexes and Histograms
Dutch PHP Conference 2021 - MySQL Indexes and Histograms
Dave Stokes
 
Python and the MySQL Document Store
Python and the MySQL Document StorePython and the MySQL Document Store
Python and the MySQL Document Store
Jesper Wisborg Krogh
 
MySQL Day Paris 2018 - What’s New in MySQL 8.0 ?
MySQL Day Paris 2018 - What’s New in MySQL 8.0 ?MySQL Day Paris 2018 - What’s New in MySQL 8.0 ?
MySQL Day Paris 2018 - What’s New in MySQL 8.0 ?
Olivier DASINI
 
20190713_MySQL開発最新動向
20190713_MySQL開発最新動向20190713_MySQL開発最新動向
20190713_MySQL開発最新動向
Machiko Ikoma
 
Journey to SAS Analytics Grid with SAS, R, Python
Journey to SAS Analytics Grid with SAS, R, PythonJourney to SAS Analytics Grid with SAS, R, Python
Journey to SAS Analytics Grid with SAS, R, Python
Sumit Sarkar
 
Ad

More from Morgan Tocker (20)

Introducing Spirit - Online Schema Change
Introducing Spirit - Online Schema ChangeIntroducing Spirit - Online Schema Change
Introducing Spirit - Online Schema Change
Morgan Tocker
 
MySQL Usability Guidelines
MySQL Usability GuidelinesMySQL Usability Guidelines
MySQL Usability Guidelines
Morgan Tocker
 
My First 90 days with Vitess
My First 90 days with VitessMy First 90 days with Vitess
My First 90 days with Vitess
Morgan Tocker
 
FOSDEM MySQL and Friends Devroom
FOSDEM MySQL and Friends DevroomFOSDEM MySQL and Friends Devroom
FOSDEM MySQL and Friends Devroom
Morgan Tocker
 
Introducing TiDB - Percona Live Frankfurt
Introducing TiDB - Percona Live FrankfurtIntroducing TiDB - Percona Live Frankfurt
Introducing TiDB - Percona Live Frankfurt
Morgan Tocker
 
TiDB Introduction - Boston MySQL Meetup Group
TiDB Introduction - Boston MySQL Meetup GroupTiDB Introduction - Boston MySQL Meetup Group
TiDB Introduction - Boston MySQL Meetup Group
Morgan Tocker
 
TiDB Introduction - San Francisco MySQL Meetup
TiDB Introduction - San Francisco MySQL MeetupTiDB Introduction - San Francisco MySQL Meetup
TiDB Introduction - San Francisco MySQL Meetup
Morgan Tocker
 
TiDB Introduction
TiDB IntroductionTiDB Introduction
TiDB Introduction
Morgan Tocker
 
MySQL Server Defaults
MySQL Server DefaultsMySQL Server Defaults
MySQL Server Defaults
Morgan Tocker
 
MySQL Cloud Service Deep Dive
MySQL Cloud Service Deep DiveMySQL Cloud Service Deep Dive
MySQL Cloud Service Deep Dive
Morgan Tocker
 
MySQL 5.7 + JSON
MySQL 5.7 + JSONMySQL 5.7 + JSON
MySQL 5.7 + JSON
Morgan Tocker
 
Using MySQL in Automated Testing
Using MySQL in Automated TestingUsing MySQL in Automated Testing
Using MySQL in Automated Testing
Morgan Tocker
 
Upcoming changes in MySQL 5.7
Upcoming changes in MySQL 5.7Upcoming changes in MySQL 5.7
Upcoming changes in MySQL 5.7
Morgan Tocker
 
MySQL Performance Metrics that Matter
MySQL Performance Metrics that MatterMySQL Performance Metrics that Matter
MySQL Performance Metrics that Matter
Morgan Tocker
 
MySQL For Linux Sysadmins
MySQL For Linux SysadminsMySQL For Linux Sysadmins
MySQL For Linux Sysadmins
Morgan Tocker
 
MySQL: From Single Instance to Big Data
MySQL: From Single Instance to Big DataMySQL: From Single Instance to Big Data
MySQL: From Single Instance to Big Data
Morgan Tocker
 
MySQL NoSQL APIs
MySQL NoSQL APIsMySQL NoSQL APIs
MySQL NoSQL APIs
Morgan Tocker
 
MySQL 5.7: Core Server Changes
MySQL 5.7: Core Server ChangesMySQL 5.7: Core Server Changes
MySQL 5.7: Core Server Changes
Morgan Tocker
 
MySQL 5.6 - Operations and Diagnostics Improvements
MySQL 5.6 - Operations and Diagnostics ImprovementsMySQL 5.6 - Operations and Diagnostics Improvements
MySQL 5.6 - Operations and Diagnostics Improvements
Morgan Tocker
 
Locking and Concurrency Control
Locking and Concurrency ControlLocking and Concurrency Control
Locking and Concurrency Control
Morgan Tocker
 
Introducing Spirit - Online Schema Change
Introducing Spirit - Online Schema ChangeIntroducing Spirit - Online Schema Change
Introducing Spirit - Online Schema Change
Morgan Tocker
 
MySQL Usability Guidelines
MySQL Usability GuidelinesMySQL Usability Guidelines
MySQL Usability Guidelines
Morgan Tocker
 
My First 90 days with Vitess
My First 90 days with VitessMy First 90 days with Vitess
My First 90 days with Vitess
Morgan Tocker
 
FOSDEM MySQL and Friends Devroom
FOSDEM MySQL and Friends DevroomFOSDEM MySQL and Friends Devroom
FOSDEM MySQL and Friends Devroom
Morgan Tocker
 
Introducing TiDB - Percona Live Frankfurt
Introducing TiDB - Percona Live FrankfurtIntroducing TiDB - Percona Live Frankfurt
Introducing TiDB - Percona Live Frankfurt
Morgan Tocker
 
TiDB Introduction - Boston MySQL Meetup Group
TiDB Introduction - Boston MySQL Meetup GroupTiDB Introduction - Boston MySQL Meetup Group
TiDB Introduction - Boston MySQL Meetup Group
Morgan Tocker
 
TiDB Introduction - San Francisco MySQL Meetup
TiDB Introduction - San Francisco MySQL MeetupTiDB Introduction - San Francisco MySQL Meetup
TiDB Introduction - San Francisco MySQL Meetup
Morgan Tocker
 
MySQL Server Defaults
MySQL Server DefaultsMySQL Server Defaults
MySQL Server Defaults
Morgan Tocker
 
MySQL Cloud Service Deep Dive
MySQL Cloud Service Deep DiveMySQL Cloud Service Deep Dive
MySQL Cloud Service Deep Dive
Morgan Tocker
 
Using MySQL in Automated Testing
Using MySQL in Automated TestingUsing MySQL in Automated Testing
Using MySQL in Automated Testing
Morgan Tocker
 
Upcoming changes in MySQL 5.7
Upcoming changes in MySQL 5.7Upcoming changes in MySQL 5.7
Upcoming changes in MySQL 5.7
Morgan Tocker
 
MySQL Performance Metrics that Matter
MySQL Performance Metrics that MatterMySQL Performance Metrics that Matter
MySQL Performance Metrics that Matter
Morgan Tocker
 
MySQL For Linux Sysadmins
MySQL For Linux SysadminsMySQL For Linux Sysadmins
MySQL For Linux Sysadmins
Morgan Tocker
 
MySQL: From Single Instance to Big Data
MySQL: From Single Instance to Big DataMySQL: From Single Instance to Big Data
MySQL: From Single Instance to Big Data
Morgan Tocker
 
MySQL 5.7: Core Server Changes
MySQL 5.7: Core Server ChangesMySQL 5.7: Core Server Changes
MySQL 5.7: Core Server Changes
Morgan Tocker
 
MySQL 5.6 - Operations and Diagnostics Improvements
MySQL 5.6 - Operations and Diagnostics ImprovementsMySQL 5.6 - Operations and Diagnostics Improvements
MySQL 5.6 - Operations and Diagnostics Improvements
Morgan Tocker
 
Locking and Concurrency Control
Locking and Concurrency ControlLocking and Concurrency Control
Locking and Concurrency Control
Morgan Tocker
 
Ad

Recently uploaded (20)

The rise of e-commerce has redefined how retailers operate—and reconciliation...
The rise of e-commerce has redefined how retailers operate—and reconciliation...The rise of e-commerce has redefined how retailers operate—and reconciliation...
The rise of e-commerce has redefined how retailers operate—and reconciliation...
Prachi Desai
 
Neuralink Templateeeeeeeeeeeeeeeeeeeeeeeeee
Neuralink TemplateeeeeeeeeeeeeeeeeeeeeeeeeeNeuralink Templateeeeeeeeeeeeeeeeeeeeeeeeee
Neuralink Templateeeeeeeeeeeeeeeeeeeeeeeeee
alexandernoetzold
 
Key AI Technologies Used by Indian Artificial Intelligence Companies
Key AI Technologies Used by Indian Artificial Intelligence CompaniesKey AI Technologies Used by Indian Artificial Intelligence Companies
Key AI Technologies Used by Indian Artificial Intelligence Companies
Mypcot Infotech
 
Design by Contract - Building Robust Software with Contract-First Development
Design by Contract - Building Robust Software with Contract-First DevelopmentDesign by Contract - Building Robust Software with Contract-First Development
Design by Contract - Building Robust Software with Contract-First Development
Par-Tec S.p.A.
 
COBOL Programming with VSCode - IBM Certificate
COBOL Programming with VSCode - IBM CertificateCOBOL Programming with VSCode - IBM Certificate
COBOL Programming with VSCode - IBM Certificate
VICTOR MAESTRE RAMIREZ
 
Maintaining + Optimizing Database Health: Vendors, Orchestrations, Enrichment...
Maintaining + Optimizing Database Health: Vendors, Orchestrations, Enrichment...Maintaining + Optimizing Database Health: Vendors, Orchestrations, Enrichment...
Maintaining + Optimizing Database Health: Vendors, Orchestrations, Enrichment...
BradBedford3
 
Micro-Metrics Every Performance Engineer Should Validate Before Sign-Off
Micro-Metrics Every Performance Engineer Should Validate Before Sign-OffMicro-Metrics Every Performance Engineer Should Validate Before Sign-Off
Micro-Metrics Every Performance Engineer Should Validate Before Sign-Off
Tier1 app
 
Boost Student Engagement with Smart Attendance Software for Schools
Boost Student Engagement with Smart Attendance Software for SchoolsBoost Student Engagement with Smart Attendance Software for Schools
Boost Student Engagement with Smart Attendance Software for Schools
Visitu
 
AI and Deep Learning with NVIDIA Technologies
AI and Deep Learning with NVIDIA TechnologiesAI and Deep Learning with NVIDIA Technologies
AI and Deep Learning with NVIDIA Technologies
SandeepKS52
 
Why Indonesia’s $12.63B Alt-Lending Boom Needs Loan Servicing Automation & Re...
Why Indonesia’s $12.63B Alt-Lending Boom Needs Loan Servicing Automation & Re...Why Indonesia’s $12.63B Alt-Lending Boom Needs Loan Servicing Automation & Re...
Why Indonesia’s $12.63B Alt-Lending Boom Needs Loan Servicing Automation & Re...
Prachi Desai
 
Topic 26 Security Testing Considerations.pptx
Topic 26 Security Testing Considerations.pptxTopic 26 Security Testing Considerations.pptx
Topic 26 Security Testing Considerations.pptx
marutnand8
 
iOS Developer Resume 2025 | Pramod Kumar
iOS Developer Resume 2025 | Pramod KumariOS Developer Resume 2025 | Pramod Kumar
iOS Developer Resume 2025 | Pramod Kumar
Pramod Kumar
 
Software Engineering Process, Notation & Tools Introduction - Part 4
Software Engineering Process, Notation & Tools Introduction - Part 4Software Engineering Process, Notation & Tools Introduction - Part 4
Software Engineering Process, Notation & Tools Introduction - Part 4
Gaurav Sharma
 
Marketo & Dynamics can be Most Excellent to Each Other – The Sequel
Marketo & Dynamics can be Most Excellent to Each Other – The SequelMarketo & Dynamics can be Most Excellent to Each Other – The Sequel
Marketo & Dynamics can be Most Excellent to Each Other – The Sequel
BradBedford3
 
Top 11 Fleet Management Software Providers in 2025 (2).pdf
Top 11 Fleet Management Software Providers in 2025 (2).pdfTop 11 Fleet Management Software Providers in 2025 (2).pdf
Top 11 Fleet Management Software Providers in 2025 (2).pdf
Trackobit
 
Leveraging Foundation Models to Infer Intents
Leveraging Foundation Models to Infer IntentsLeveraging Foundation Models to Infer Intents
Leveraging Foundation Models to Infer Intents
Keheliya Gallaba
 
14 Years of Developing nCine - An Open Source 2D Game Framework
14 Years of Developing nCine - An Open Source 2D Game Framework14 Years of Developing nCine - An Open Source 2D Game Framework
14 Years of Developing nCine - An Open Source 2D Game Framework
Angelo Theodorou
 
Essentials of Resource Planning in a Downturn
Essentials of Resource Planning in a DownturnEssentials of Resource Planning in a Downturn
Essentials of Resource Planning in a Downturn
OnePlan Solutions
 
Agile Software Engineering Methodologies
Agile Software Engineering MethodologiesAgile Software Engineering Methodologies
Agile Software Engineering Methodologies
Gaurav Sharma
 
IMAGE CLASSIFICATION USING CONVOLUTIONAL NEURAL NETWORK.P.pptx
IMAGE CLASSIFICATION USING CONVOLUTIONAL NEURAL NETWORK.P.pptxIMAGE CLASSIFICATION USING CONVOLUTIONAL NEURAL NETWORK.P.pptx
IMAGE CLASSIFICATION USING CONVOLUTIONAL NEURAL NETWORK.P.pptx
usmanch7829
 
The rise of e-commerce has redefined how retailers operate—and reconciliation...
The rise of e-commerce has redefined how retailers operate—and reconciliation...The rise of e-commerce has redefined how retailers operate—and reconciliation...
The rise of e-commerce has redefined how retailers operate—and reconciliation...
Prachi Desai
 
Neuralink Templateeeeeeeeeeeeeeeeeeeeeeeeee
Neuralink TemplateeeeeeeeeeeeeeeeeeeeeeeeeeNeuralink Templateeeeeeeeeeeeeeeeeeeeeeeeee
Neuralink Templateeeeeeeeeeeeeeeeeeeeeeeeee
alexandernoetzold
 
Key AI Technologies Used by Indian Artificial Intelligence Companies
Key AI Technologies Used by Indian Artificial Intelligence CompaniesKey AI Technologies Used by Indian Artificial Intelligence Companies
Key AI Technologies Used by Indian Artificial Intelligence Companies
Mypcot Infotech
 
Design by Contract - Building Robust Software with Contract-First Development
Design by Contract - Building Robust Software with Contract-First DevelopmentDesign by Contract - Building Robust Software with Contract-First Development
Design by Contract - Building Robust Software with Contract-First Development
Par-Tec S.p.A.
 
COBOL Programming with VSCode - IBM Certificate
COBOL Programming with VSCode - IBM CertificateCOBOL Programming with VSCode - IBM Certificate
COBOL Programming with VSCode - IBM Certificate
VICTOR MAESTRE RAMIREZ
 
Maintaining + Optimizing Database Health: Vendors, Orchestrations, Enrichment...
Maintaining + Optimizing Database Health: Vendors, Orchestrations, Enrichment...Maintaining + Optimizing Database Health: Vendors, Orchestrations, Enrichment...
Maintaining + Optimizing Database Health: Vendors, Orchestrations, Enrichment...
BradBedford3
 
Micro-Metrics Every Performance Engineer Should Validate Before Sign-Off
Micro-Metrics Every Performance Engineer Should Validate Before Sign-OffMicro-Metrics Every Performance Engineer Should Validate Before Sign-Off
Micro-Metrics Every Performance Engineer Should Validate Before Sign-Off
Tier1 app
 
Boost Student Engagement with Smart Attendance Software for Schools
Boost Student Engagement with Smart Attendance Software for SchoolsBoost Student Engagement with Smart Attendance Software for Schools
Boost Student Engagement with Smart Attendance Software for Schools
Visitu
 
AI and Deep Learning with NVIDIA Technologies
AI and Deep Learning with NVIDIA TechnologiesAI and Deep Learning with NVIDIA Technologies
AI and Deep Learning with NVIDIA Technologies
SandeepKS52
 
Why Indonesia’s $12.63B Alt-Lending Boom Needs Loan Servicing Automation & Re...
Why Indonesia’s $12.63B Alt-Lending Boom Needs Loan Servicing Automation & Re...Why Indonesia’s $12.63B Alt-Lending Boom Needs Loan Servicing Automation & Re...
Why Indonesia’s $12.63B Alt-Lending Boom Needs Loan Servicing Automation & Re...
Prachi Desai
 
Topic 26 Security Testing Considerations.pptx
Topic 26 Security Testing Considerations.pptxTopic 26 Security Testing Considerations.pptx
Topic 26 Security Testing Considerations.pptx
marutnand8
 
iOS Developer Resume 2025 | Pramod Kumar
iOS Developer Resume 2025 | Pramod KumariOS Developer Resume 2025 | Pramod Kumar
iOS Developer Resume 2025 | Pramod Kumar
Pramod Kumar
 
Software Engineering Process, Notation & Tools Introduction - Part 4
Software Engineering Process, Notation & Tools Introduction - Part 4Software Engineering Process, Notation & Tools Introduction - Part 4
Software Engineering Process, Notation & Tools Introduction - Part 4
Gaurav Sharma
 
Marketo & Dynamics can be Most Excellent to Each Other – The Sequel
Marketo & Dynamics can be Most Excellent to Each Other – The SequelMarketo & Dynamics can be Most Excellent to Each Other – The Sequel
Marketo & Dynamics can be Most Excellent to Each Other – The Sequel
BradBedford3
 
Top 11 Fleet Management Software Providers in 2025 (2).pdf
Top 11 Fleet Management Software Providers in 2025 (2).pdfTop 11 Fleet Management Software Providers in 2025 (2).pdf
Top 11 Fleet Management Software Providers in 2025 (2).pdf
Trackobit
 
Leveraging Foundation Models to Infer Intents
Leveraging Foundation Models to Infer IntentsLeveraging Foundation Models to Infer Intents
Leveraging Foundation Models to Infer Intents
Keheliya Gallaba
 
14 Years of Developing nCine - An Open Source 2D Game Framework
14 Years of Developing nCine - An Open Source 2D Game Framework14 Years of Developing nCine - An Open Source 2D Game Framework
14 Years of Developing nCine - An Open Source 2D Game Framework
Angelo Theodorou
 
Essentials of Resource Planning in a Downturn
Essentials of Resource Planning in a DownturnEssentials of Resource Planning in a Downturn
Essentials of Resource Planning in a Downturn
OnePlan Solutions
 
Agile Software Engineering Methodologies
Agile Software Engineering MethodologiesAgile Software Engineering Methodologies
Agile Software Engineering Methodologies
Gaurav Sharma
 
IMAGE CLASSIFICATION USING CONVOLUTIONAL NEURAL NETWORK.P.pptx
IMAGE CLASSIFICATION USING CONVOLUTIONAL NEURAL NETWORK.P.pptxIMAGE CLASSIFICATION USING CONVOLUTIONAL NEURAL NETWORK.P.pptx
IMAGE CLASSIFICATION USING CONVOLUTIONAL NEURAL NETWORK.P.pptx
usmanch7829
 

MySQL 8.0 Optimizer Guide

  • 1. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | MySQL 8.0 Optimizer Guide Morgan Tocker MySQL Product Manager (Server) Copyright © 2017, Oracle and/or its affiliates. All rights reserved.
  • 3. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Safe Harbor Statement 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, and timing of any features or functionality described for Oracle’s products remains at the sole discretion of Oracle. 3
  • 4. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Agenda 1. Introduction 2. Server Architecture 3. B+trees 4. EXPLAIN 5. Optimizer Trace 6. Logical Transformations 7. Cost Based Optimization 8. Hints and Switches 9. Comparing Plans 10.Composite Indexes 11.Covering Indexes 12.Visual Explain 13.Transient Plans 14.Subqueries 15.CTEs and Views 16.Joins 17.Aggregation 18.Descending Indexes 19.Sorting 20.Partitioning 21.Query Rewrite 22.Invisible Indexes 23.Profiling 24.JSON 25.Character Sets 4
  • 5. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Introduction • SQL is declarative • You state “what you want” not “how you want” • Can’t usually sight check queries to understand execution efficiency • Database management system is like a GPS navigation system. It finds the “best”route. 5
  • 6. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 6 GPS…
  • 7. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 7 MySQL Optimizer
  • 8. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Diagnostic Commands • EXPLAIN (all versions) • EXPLAIN FORMAT=JSON (5.6+) – Supported by Workbench in Visual format • Optimizer Trace (5.6+) 8
  • 9. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Examples from “The World Schema” • Contains Cities, Countries, Language statistics • Download from: – https://dev.mysql.com/doc/index-other.html • Very small data set – Good for learning – Not good for explaining performance differences 9
  • 10. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Primary Table we are using CREATE TABLE `Country` ( `Code` char(3) NOT NULL DEFAULT '', `Name` char(52) NOT NULL DEFAULT '', `Continent` enum('Asia','Europe','North America','Africa','Oceania','Antarctica','South America') NOT NULL DEFAULT 'Asia', `Region` char(26) NOT NULL DEFAULT '', `SurfaceArea` float(10,2) NOT NULL DEFAULT '0.00', `IndepYear` smallint(6) DEFAULT NULL, `Population` int(11) NOT NULL DEFAULT '0', `LifeExpectancy` float(3,1) DEFAULT NULL, `GNP` float(10,2) DEFAULT NULL, `GNPOld` float(10,2) DEFAULT NULL, `LocalName` char(45) NOT NULL DEFAULT '', `GovernmentForm` char(45) NOT NULL DEFAULT '', `HeadOfState` char(60) DEFAULT NULL, `Capital` int(11) DEFAULT NULL, `Code2` char(2) NOT NULL DEFAULT '', PRIMARY KEY (`Code`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 1 row in set (0.00 sec) 10
  • 11. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Companion Website • Content from “The Unofficial MySQL 8.0 Optimizer Guide” • http://www.unofficialmysqlguide.com/ • More detailed text for many of the examples here… • Most still applies to 5.6+ • EXPLAIN FORMAT=JSON in 5.6 does not show cost • Costs will be different • Output from Optimizer Trace may differ • Some features will be missing 11
  • 12. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Danger: Code on slides! • Some examples may appear small • Please feel free to download this deck from: • https://www.slideshare.net/morgo/mysql-80-optimizer-guide • Follow along on your laptop 12
  • 13. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Agenda 1. Introduction 2. Server Architecture 3. B+trees 4. EXPLAIN 5. Optimizer Trace 6. Logical Transformations 7. Cost Based Optimization 8. Hints and Switches 9. Comparing Plans 10.Composite Indexes 11.Covering Indexes 12.Visual Explain 13.Transient Plans 14.Subqueries 15.CTEs and Views 16.Joins 17.Aggregation 18.Descending Indexes 19.Sorting 20.Partitioning 21.Query Rewrite 22.Invisible Indexes 23.Profiling 24.JSON 25.Character Sets 13
  • 14. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 14 Server Architecture
  • 15. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Just the Important Parts • Comprised of the Server and Storage Engines • Query Optimization happens at the Server Level • Semantically there are four stages of Query Optimization • Followed by Query Execution 15
  • 16. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Agenda 1. Introduction 2. Server Architecture 3. B+trees 4. EXPLAIN 5. Optimizer Trace 6. Logical Transformations 7. Cost Based Optimization 8. Hints and Switches 9. Comparing Plans 10.Composite Indexes 11.Covering Indexes 12.Visual Explain 13.Transient Plans 14.Subqueries 15.CTEs and Views 16.Joins 17.Aggregation 18.Descending Indexes 19.Sorting 20.Partitioning 21.Query Rewrite 22.Invisible Indexes 23.Profiling 24.JSON 25.Character Sets 16
  • 17. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | B+trees • When we mean “add an index” we usually mean “add a B+tree index”: – Includes PRIMARY, UNIQUE, INDEX type indexes. • Understanding the basic structure of B+trees helps with optimization 17
  • 18. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Binary Tree • Not the same as a B+tree • Understand Binary Tree first then compare and contrast 18 Locate 829813 in a (balanced) binary tree of 1MM ~= 20 hops. is this good?
  • 19. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | B+tree • Amortizes disk accesses by clustering into pages: • Can achieve same outcome in two hops: 19 CREATE TABLE users (
 id INT NOT NULL auto_increment,
 username VARCHAR(32) NOT NULL,
 payload TEXT,
 PRIMARY KEY (id)
 );
  • 20. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | B+tree • Amortizes disk 
 accesses by clustering
 into pages • Can achieve same 
 outcome in two hops: 20
  • 21. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | B-trees are wide not deep • From the root page: values >= 800788 but < 829908 are on page 16386. • From page 16386: values >= 829804 but < 829830 are on leaf page 32012. • Large fan out factor; 1000+ keys/page which point to another index page with 1000+ keys/page 21
  • 22. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | InnoDB uses a Clustered Index • In InnoDB the data rows are also stored in a B+tree, organized by the primary key • Secondary key indexes always include the value of the primary key 22
  • 23. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Agenda 1. Introduction 2. Server Architecture 3. B+trees 4. EXPLAIN 5. Optimizer Trace 6. Logical Transformations 7. Cost Based Optimization 8. Hints and Switches 9. Comparing Plans 10.Composite Indexes 11.Covering Indexes 12.Visual Explain 13.Transient Plans 14.Subqueries 15.CTEs and Views 16.Joins 17.Aggregation 18.Descending Indexes 19.Sorting 20.Partitioning 21.Query Rewrite 22.Invisible Indexes 23.Profiling 24.JSON 25.Character Sets 23
  • 24. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | EXPLAIN • Pre-execution view of how MySQL intends to execute a query • Prints what MySQL considers the best plan after a process of considering potentially thousands of choices 24
  • 25. EXPLAIN FORMAT=JSON SELECT * FROM Country WHERE continent='Asia' and population > 5000000; { "query_block": { "select_id": 1, "cost_info": { "query_cost": "25.40" }, "table": { "table_name": "country", "access_type": "ALL", "rows_examined_per_scan": 239, "rows_produced_per_join": 11, "filtered": "6.46", .. "attached_condition": "((`world`.`country`.`Continent` = 'Asia') and (`world`.`country`.`Population` > 5000000))" } } }
  • 26. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | What indexes will make this query faster? • Some Suggestions: – Index on p (population) – Index on c (continent) – Index on p_c (population, continent) – Index on c_p (continent, population) 26
  • 27. ALTER TABLE Country ADD INDEX p (population); EXPLAIN FORMAT=JSON SELECT * FROM Country WHERE continent='Asia' and population > 5000000; { "query_block": { "select_id": 1, "cost_info": { "query_cost": "25.40" }, "table": { "table_name": "Country", "access_type": "ALL", "possible_keys": [ "p" ], "rows_examined_per_scan": 239, "rows_produced_per_join": 15, "filtered": "6.46", .. "attached_condition": "((`world`.`country`.`Continent` = 'Asia') and (`world`.`country`.`Population` > 5000000))" ..
  • 28. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 28 Why would an index not be used?
  • 29. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Agenda 1. Introduction 2. Server Architecture 3. B+trees 4. EXPLAIN 5. Optimizer Trace 6. Logical Transformations 7. Cost Based Optimization 8. Hints and Switches 9. Comparing Plans 10.Composite Indexes 11.Covering Indexes 12.Visual Explain 13.Transient Plans 14.Subqueries 15.CTEs and Views 16.Joins 17.Aggregation 18.Descending Indexes 19.Sorting 20.Partitioning 21.Query Rewrite 22.Invisible Indexes 23.Profiling 24.JSON 25.Character Sets 29
  • 30. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Optimizer Trace • What other choices did EXPLAIN not show? • Why was that choice made? • Output is quite verbose 30
  • 31. ALTER TABLE Country ADD INDEX p (population); EXPLAIN FORMAT=JSON SELECT * FROM Country WHERE continent='Asia' and population > 5000000; { "query_block": { "select_id": 1, "cost_info": { "query_cost": "25.40" }, "table": { "table_name": "Country", "access_type": "ALL", "possible_keys": [ "p" ], "rows_examined_per_scan": 239, "rows_produced_per_join": 15, "filtered": "6.46", "cost_info": { "read_cost": "23.86", "eval_cost": "1.54", "prefix_cost": "25.40", "data_read_per_join": "3K" }, .. "attached_condition": "((`world`.`country`.`Continent` = 'Asia') and (`world`.`country`.`Population` > 5000000))" .. It’s available but not used. Why?
  • 32. SET optimizer_trace="enabled=on"; SELECT * FROM Country WHERE continent='Asia' and population > 5000000; SELECT * FROM information_schema.optimizer_trace; { "steps": [ { "join_preparation": { "select#": 1, "steps": [ { "expanded_query": "/* select#1 */ select `country`.`Code` AS `Code`,`country`.`Name` AS `Name`,`country`.`Continent` AS `Continent`,`country`.`Region` AS `Region`,`country`.`SurfaceArea` AS `SurfaceArea`,`country`.`IndepYear` AS `IndepYear`,`country`.`Population` AS `Population`,`country`.`LifeExpectancy` AS `LifeExpectancy`,`country`.`GNP` AS `GNP`,`country`.`GNPOld` AS `GNPOld`,`country`.`LocalName` AS `LocalName`,`country`.`GovernmentForm` AS `GovernmentForm`,`country`.`HeadOfState` AS `HeadOfState`,`country`.`Capital` AS `Capital`,`country`.`Code2` AS `Code2` from `country` where ((`country`.`Continent` = 'Asia') and (`country`.`Population` > 5000000))" } ] } }, { "join_optimization": { "select#": 1, "steps": [ { "condition_processing": { "condition": "WHERE", Page 1 of 6
  • 33. "original_condition": "((`country`.`Continent` = 'Asia') and (`country`.`Population` > 5000000))", "steps": [ { "transformation": "equality_propagation", "resulting_condition": "((`country`.`Population` > 5000000) and multiple equal('Asia', `country`.`Continent`))" }, { "transformation": "constant_propagation", "resulting_condition": "((`country`.`Population` > 5000000) and multiple equal('Asia', `country`.`Continent`))" }, { "transformation": "trivial_condition_removal", "resulting_condition": "((`country`.`Population` > 5000000) and multiple equal('Asia', `country`.`Continent`))" } ] } }, { "substitute_generated_columns": { } }, { "table_dependencies": [ { "table": "`country`", "row_may_be_null": false, "map_bit": 0, Page 2 of 6
  • 34. "depends_on_map_bits": [ ] } ] }, { "ref_optimizer_key_uses": [ ] }, { "rows_estimation": [ { "table": "`country`", "range_analysis": { "table_scan": { "rows": 239, "cost": 27.5 }, "potential_range_indexes": [ { "index": "PRIMARY", "usable": false, "cause": "not_applicable" }, { "index": "p", "usable": true, "key_parts": [ "Population", "Code" ] Page 3 of 6
  • 35. } ], "setup_range_conditions": [ ], "group_index_range": { "chosen": false, "cause": "not_group_by_or_distinct" }, "analyzing_range_alternatives": { "range_scan_alternatives": [ { "index": "p", "ranges": [ "5000000 < Population" ], "index_dives_for_eq_ranges": true, "rowid_ordered": false, "using_mrr": false, "index_only": false, "rows": 108, "cost": 38.06, "chosen": false, "cause": "cost" } ], "analyzing_roworder_intersect": { "usable": false, "cause": "too_few_roworder_scans" } } } Aha! It was too expensive. Page 4 of 6
  • 36. } ] }, { "considered_execution_plans": [ { "plan_prefix": [ ], "table": "`country`", "best_access_path": { "considered_access_paths": [ { "rows_to_scan": 239, "access_type": "scan", "resulting_rows": 239, "cost": 25.4, "chosen": true } ] }, "condition_filtering_pct": 100, "rows_for_plan": 239, "cost_for_plan": 25.4, "chosen": true } ] }, { "attaching_conditions_to_tables": { "original_condition": "((`country`.`Continent` = 
 'Asia') and (`country`.`Population` > 5000000))", Prefer to table scan instead Page 5 of 6
  • 37. "attached_conditions_computation": [ ], "attached_conditions_summary": [ { "table": "`country`", "attached": "((`country`.`Continent` = 'Asia') and (`country`.`Population` > 5000000))" } ] } }, { "refine_plan": [ { "table": "`country`" } ] } ] } }, { "join_execution": { "select#": 1, "steps": [ ] } } ] } Page 6 of 6
  • 38. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 38 Why would an index not be used? "analyzing_range_alternatives": { "range_scan_alternatives": [ { "index": "p", "ranges": [ "5000000 < Population" ], "index_dives_for_eq_ranges": true, "rowid_ordered": false, "using_mrr": false, "index_only": false, "rows": 108, "cost": 38.06, "chosen": false, "cause": "cost" } ], OPTIMIZER TRACE: .. "query_block": { "select_id": 1, "cost_info": { "query_cost": "48.86" }, "table": { "table_name": "Country", "access_type": "range", "possible_keys": [ "p" ], "key": "p", .. FORCE INDEX (p):
  • 39. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 39 Reason again…
  • 40. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Agenda 1. Introduction 2. Server Architecture 3. B+trees 4. EXPLAIN 5. Optimizer Trace 6. Logical Transformations 7. Cost Based Optimization 8. Hints and Switches 9. Comparing Plans 10.Composite Indexes 11.Covering Indexes 12.Visual Explain 13.Transient Plans 14.Subqueries 15.CTEs and Views 16.Joins 17.Aggregation 18.Descending Indexes 19.Sorting 20.Partitioning 21.Query Rewrite 22.Invisible Indexes 23.Profiling 24.JSON 25.Character Sets 40
  • 41. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Logical Transformations • First part of optimization
 is eliminating 
 unnecessary work 41
  • 42. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Why eliminate unnecessary work? • Short-cut/reduce number of execution plans that need to be evaluated • Transform parts of queries to take advantage of better execution strategies • Think of a how a compiler transforms code to be more efficient • MySQL does similar at runtime 42
  • 43. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Example: SELECT * FROM Country
 WHERE population > 5000000 AND continent='Asia' 
 AND 1=1; 43
  • 44. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | SHOW WARNINGS says: EXPLAIN FORMAT=JSON SELECT * FROM Country WHERE population > 5000000 AND 1=1; SHOW WARNINGS; /* select#1 */ select
 `world`.`Country`.`Code` AS `Code`,
 `world`.`Country`.`Name` AS `Name`,
 `world`.`Country`.`Continent` AS `Continent`,
 `world`.`Country`.`Region` AS `Region`,
 `world`.`Country`.`SurfaceArea` AS `SurfaceArea`,
 `world`.`Country`.`IndepYear` AS `IndepYear`,
 `world`.`Country`.`Population` AS `Population`,
 `world`.`Country`.`LifeExpectancy` AS `LifeExpectancy`,
 `world`.`Country`.`GNP` AS `GNP`,
 `world`.`Country`.`GNPOld` AS `GNPOld`,
 `world`.`Country`.`LocalName` AS `LocalName`,
 `world`.`Country`.`GovernmentForm` AS `GovernmentForm`,
 `world`.`Country`.`HeadOfState` AS `HeadOfState`,
 `world`.`Country`.`Capital` AS `Capital`,
 `world`.`Country`.`Code2` AS `Code2`
 from `world`.`Country`
 where (`world`.`Country`.`Population` > 5000000) 44
  • 45. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | .. "steps": [ { "condition_processing": { "condition": "WHERE", "original_condition": "((`Country`.`Population` > 5000000) and (1 = 1))", "steps": [ { "transformation": "equality_propagation", "resulting_condition": "((`Country`.`Population` > 5000000) and (1 = 1))" }, { "transformation": "constant_propagation", "resulting_condition": "((`Country`.`Population` > 5000000) and (1 = 1))" }, { "transformation": "trivial_condition_removal", "resulting_condition": "(`Country`.`Population` > 5000000)" .. OPTIMIZER TRACE says: 45
  • 46. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | What sort of transformations can occur? • Merging views back with definition of base tables • Derived table in FROM clause merged back into base tables • Unique subqueries converted directly to INNER JOIN statements • Primary key lookup converted to constant values. – Shortcut plans that will need to be evaluated. 46
  • 47. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Primary Key Lookup SELECT * FROM Country WHERE code='CAN' /* select#1 */ select 'CAN' AS `Code`, 'Canada' AS `Name`, 'North America' AS `Continent`, 'North America' AS `Region`, '9970610.00' AS `SurfaceArea`, '1867' AS `IndepYear`, '31147000' AS `Population`, '79.4' AS `LifeExpectancy`, '598862.00' AS `GNP`, '625626.00' AS `GNPOld`, 'Canada' AS `LocalName`, 'Constitutional Monarchy, Federation' AS `GovernmentForm`, 'Elisabeth II' AS `HeadOfState`, '1822' AS `Capital`, 'CA' AS `Code2` from `world`.`Country` where 1 47
  • 48. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Primary key does not exist SELECT * FROM Country WHERE code='XYZ' /* select#1 */ select NULL AS `Code`,NULL AS `Name`,NULL AS `Continent`,NULL AS `Region`, NULL AS `SurfaceArea`,NULL AS `IndepYear`,NULL AS `Population`,NULL AS `LifeExpectancy`,NULL AS `GNP`, NULL AS `GNPOld`,NULL AS `LocalName`,NULL AS `GovernmentForm`,NULL AS `HeadOfState`,NULL AS `Capital`, NULL AS `Code2` from `world`.`Country` where multiple equal('XYZ', NULL) 48
  • 49. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Impossible WHERE SELECT * FROM Country WHERE code='CAN' AND 1=0 /* select#1 */ select `world`.`Country`.`Code` AS `Code`,`world`.`Country`.`Name` AS `Name`, `world`.`Country`.`Continent` AS `Continent`,`world`.`Country`.`Region` AS `Region`, `world`.`Country`.`SurfaceArea` AS `SurfaceArea`,`world`.`Country`.`IndepYear` AS `IndepYear`, `world`.`Country`.`Population` AS `Population`,`world`.`Country`.`LifeExpectancy` AS `LifeExpectancy`, `world`.`Country`.`GNP` AS `GNP`,`world`.`Country`.`GNPOld` AS `GNPOld`, `world`.`Country`.`LocalName` AS `LocalName`,`world`.`Country`.`GovernmentForm` AS `GovernmentForm`, `world`.`Country`.`HeadOfState` AS `HeadOfState`,`world`.`Country`.`Capital` AS `Capital`, `world`.`Country`.`Code2` AS `Code2` from `world`.`Country` where 0 49
  • 50. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Are transformations always safe? • Yes they should be • New transformations (and execution strategies) may return non deterministic queries in a different order • Some illegal statements as a result of derived_merge transformation 50
  • 52. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Agenda 1. Introduction 2. Server Architecture 3. B+trees 4. EXPLAIN 5. Optimizer Trace 6. Logical Transformations 7. Cost Based Optimization 8. Hints and Switches 9. Comparing Plans 10.Composite Indexes 11.Covering Indexes 12.Visual Explain 13.Transient Plans 14.Subqueries 15.CTEs and Views 16.Joins 17.Aggregation 18.Descending Indexes 19.Sorting 20.Partitioning 21.Query Rewrite 22.Invisible Indexes 23.Profiling 24.JSON 25.Character Sets 52
  • 53. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Query Optimizer Strategy • Model each of the possible execution plans (using support from statistics and meta data) • Pick the plan with the lowest cost 53
  • 54. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Model you say? 1. Assign a cost to each operation 2. Evaluate how many operations each possible plan would take 3. Sum up the total 4. Choose the plan with the lowest overall cost 54
  • 55. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | How are statistics calculated? • Dictionary Information • Cardinality Statistics • Records In Range Dynamic Sampling • Table Size 55
  • 56. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 56 Example Model: Table Scan SELECT * FROM Country WHERE continent='Asia' and population > 5000000; IO Cost: # pages in table * (IO_BLOCK_READ_COST | MEMORY_BLOCK_READ_COST) CPU Cost: # records * ROW_EVALUATE_COST Defaults:
 IO_BLOCK_READ_COST = 1
 MEMORY_BLOCK_READ_COST = 0.25
 ROW_EVALUATE_COST=0.1 Values: # pages in table = 6 # records = 239 100% on Disk: 
 = (6 * 1) + (0.1 * 239) = 29.9 EXPLAIN said cost was 25.40 New! MySQL 8.0 estimates how many of the pages will be in memory. SELECT clust_index_size from INNODB_SYS_TABLESTATS WHERE name='world/country' 100% in Memory:
 = (6 * 0.25) + (0.1 * 239) = 25.4
  • 57. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 57 Example Model: Range Scan SELECT * FROM Country WHERE continent='Asia' and population > 5000000; IO Cost: # records_in_range * (IO_BLOCK_READ_COST | MEMORY_BLOCK_READ_COST)
 CPU Cost:
 # records_in_range * ROW_EVALUATE_COST
 + # records_in_range * ROW_EVALUATE_COST 
 
 
 
 
 = (108 * 0.25) + ( (108 * 0.1) + (108 * 0.1) ) = 48.6 Evaluate range condition Evaluate WHERE condition Compares to "query_cost": “48.86" in EXPLAIN. 100% in memory. On disk = 129.6
  • 58. { "query_block": { "select_id": 1, "cost_info": { "query_cost": "25.40" }, "table": { "table_name": "country", "access_type": "ALL", "possible_keys": [ "p" ], .. "cost_info": { "read_cost": "23.86", "eval_cost": "1.54", "prefix_cost": "25.40", "data_read_per_join": "3K" }, .. CPU Cost IO Cost Total Cost
  • 59. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Cost Constant Refinement select * from mysql.server_cost; +------------------------------+------------+---------------------+---------+---------------+ | cost_name | cost_value | last_update | comment | default_value | +------------------------------+------------+---------------------+---------+---------------+ | disk_temptable_create_cost | NULL | 2017-04-14 16:01:42 | NULL | 20 | | disk_temptable_row_cost | NULL | 2017-04-14 16:01:42 | NULL | 0.5 | | key_compare_cost | NULL | 2017-04-14 16:01:42 | NULL | 0.05 | | memory_temptable_create_cost | NULL | 2017-04-14 16:01:42 | NULL | 1 | | memory_temptable_row_cost | NULL | 2017-04-14 16:01:42 | NULL | 0.1 | | row_evaluate_cost | NULL | 2017-04-14 16:01:42 | NULL | 0.1 | +------------------------------+------------+---------------------+---------+---------------+ 6 rows in set (0.00 sec) select * from mysql.engine_costG *************************** 1. row *************************** engine_name: default device_type: 0 cost_name: io_block_read_cost cost_value: NULL last_update: 2017-04-14 16:01:42 comment: NULL default_value: 1 59
  • 60. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Cost Constant Refinement UPDATE mysql.server_cost SET cost_value=1 WHERE cost_name=‘row_evaluate_cost'; UPDATE mysql.engine_cost set cost_value = 1; FLUSH OPTIMIZER_COSTS; EXPLAIN FORMAT=JSON SELECT * FROM Country WHERE continent='Asia' and population > 5000000; { "query_block": { "select_id": 1, "cost_info": { "query_cost": "245.00" }, "table": { "table_name": "Country", "access_type": "ALL", .. 60 Increase row evaluate cost from 0.1 to 1. Make memory and IO block read cost the same. New Table Scan Cost: = (6 * 1) + (1 * 239) = 245
  • 61. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Are plans exhaustively evaluated? • Short cuts are taken to not spend too much time in planning: – Some parts of queries may be transformed to limit plans evaluated – The optimizer will by default limit the search depth of bad plans:
 optimizer_search_depth=64
 optimizer_prune_level=1 61
  • 62. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Agenda 1. Introduction 2. Server Architecture 3. B+trees 4. EXPLAIN 5. Optimizer Trace 6. Logical Transformations 7. Cost Based Optimization 8. Hints and Switches 9. Comparing Plans 10.Composite Indexes 11.Covering Indexes 12.Visual Explain 13.Transient Plans 14.Subqueries 15.CTEs and Views 16.Joins 17.Aggregation 18.Descending Indexes 19.Sorting 20.Partitioning 21.Query Rewrite 22.Invisible Indexes 23.Profiling 24.JSON 25.Character Sets 62
  • 63. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | How often is the query optimizer wrong? • Yes it happens • Similar to GPS; you may not have traffic data available for all streets • The model may be incomplete or imperfect • There exist method(s) to overwrite it 63
  • 64. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Hints and Switches • Typically a better level of override to modifying cost constants • Come in three varieties: – Old Style Hints – New Comment-Style Hints – Switches 64
  • 65. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Old Style Hints • Have SQL and Hint intermingled • Cause errors when indexes don’t exist 65 SELECT * FROM Country FORCE INDEX (p) WHERE population > 5000000; SELECT * FROM Country IGNORE INDEX (p) WHERE population > 5000000; SELECT * FROM Country USE INDEX (p) WHERE population > 5000000; SELECT STRAIGHT_JOIN ..; SELECT * FROM Country STRAIGHT_JOIN ..;
  • 66. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | New Comment-Style Hints • Can be added by a system that doesn’t understand SQL • Clearer defined semantics as a hint not a directive • Fine granularity 66 SELECT /*+ NO_RANGE_OPTIMIZATION (Country) */ * FROM Country WHERE Population > 1000000000 AND Continent=‘Asia';
  • 67. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Switches • As new optimizations are added, some cause regressions • Allow the specific optimization to be disabled (SESSION or GLOBAL) 67 SELECT @@optimizer_switch; 
 index_merge=on,index_merge_union=on,index_merge_sort_union=on,
 index_merge_intersection=on,engine_condition_pushdown=on,
 index_condition_pushdown=on,mrr=on,mrr_cost_based=on,
 block_nested_loop=on,batched_key_access=off,materialization=on,
 semijoin=on,loosescan=on,firstmatch=on,duplicateweedout=on,
 subquery_materialization_cost_based=on,use_index_extensions=on,
 condition_fanout_filter=on,derived_merge=on
  • 68. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | How to consider hints and switches • They provide immediate pain relief to production problems at the cost of maintenance • They add technical debt to your applications 68
  • 69. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Agenda 1. Introduction 2. Server Architecture 3. B+trees 4. EXPLAIN 5. Optimizer Trace 6. Logical Transformations 7. Cost Based Optimization 8. Hints and Switches 9. Comparing Plans 10.Composite Indexes 11.Covering Indexes 12.Visual Explain 13.Transient Plans 14.Subqueries 15.CTEs and Views 16.Joins 17.Aggregation 18.Descending Indexes 19.Sorting 20.Partitioning 21.Query Rewrite 22.Invisible Indexes 23.Profiling 24.JSON 25.Character Sets 69
  • 70. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Our simple query with n candidate indexes • Indexes exist on p(population) and c(continent): 70 SELECT * FROM Country
 WHERE population > 50000000 AND continent=‘Asia'; >50M, how many are less? How many countries in Asia vs total world? Does order of predicates matter? No.
  • 71. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Role of the Optimizer • Given these many choices, which is the best choice? • A good GPS navigator finds the fastest route! • We can expect a good query optimizer to do similar 71
  • 72. ALTER TABLE Country ADD INDEX c (continent); EXPLAIN FORMAT=JSON # 50M
 SELECT * FROM Country WHERE population > 50000000 AND continent=‘Asia'; { "query_block": { "select_id": 1, "cost_info": { "query_cost": "9.60" }, "table": { "table_name": "Country", "access_type": "ref", "possible_keys": [ "p", "c" ], "key": "c", "used_key_parts": [ "Continent" ], "key_length": "1", "ref": [ "const" ], .. "attached_condition": "(`world`.`country`.`Population` > 50000000)" .. Continent is determined to be lower cost.
  • 73. EXPLAIN FORMAT=JSON # 500M SELECT * FROM Country WHERE continent='Asia' and population > 500000000; { "query_block": { "select_id": 1, "cost_info": { "query_cost": "1.16" }, "table": { "table_name": "Country", "access_type": "range", "possible_keys": [ "p", "c" ], "key": "p", "used_key_parts": [ "Population" ], "key_length": "4", .. "attached_condition": "(`world`.`country`.`Continent` = ‘Asia')" .. Change the predicate, the query plan changes.
  • 74. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Query Plan Evaluation • Evaluated for each query, and thus each set of predicates • Currently not cached* • For prepared statements, permanent transformations are cached 74 * Cardinality statistics are cached. Don’t get confused.
  • 75. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 75 Cost Estimates p>5M c=’Asia’ p>50M, c=’Asia’ p>500M, c=’Asia’ p 48.86 11.06 1.16 c 9.60 9.60 9.60 ALL 25.40 25.40 25.40 p
  • 76. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Agenda 1. Introduction 2. Server Architecture 3. B+trees 4. EXPLAIN 5. Optimizer Trace 6. Logical Transformations 7. Cost Based Optimization 8. Hints and Switches 9. Comparing Plans 10.Composite Indexes 11.Covering Indexes 12.Visual Explain 13.Transient Plans 14.Subqueries 15.CTEs and Views 16.Joins 17.Aggregation 18.Descending Indexes 19.Sorting 20.Partitioning 21.Query Rewrite 22.Invisible Indexes 23.Profiling 24.JSON 25.Character Sets 76
  • 77. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | The role of composite indexes • Useful when two or more predicates combined improves filtering effect. i.e.
 
 Not all countries with a population > 5M are in Asia 77
  • 78. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Composite Indexes • p_c (population, continent) • c_p (continent, population) 78
  • 79. ALTER TABLE Country ADD INDEX p_c (Population, Continent); EXPLAIN FORMAT=JSON SELECT * FROM Country FORCE INDEX (p_c) WHERE continent='Asia' and population > 5000000; { "query_block": { "select_id": 1, "cost_info": { "query_cost": "48.86" }, "table": { "table_name": "Country", "access_type": "range", "possible_keys": [ "p_c" ], "key": "p_c", "used_key_parts": [ "Population" ], "key_length": "4", .. Only part of the key is used!
  • 80. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Rule of Thumb • Index on (const, range) instead of (range, const) • Applies to all databases 80
  • 81. ALTER TABLE Country ADD INDEX c_p (Continent, Population);
 EXPLAIN FORMAT=JSON
 SELECT * FROM Country WHERE continent='Asia' and population > 5000000;
 { "query_block": { "select_id": 1, "cost_info": { "query_cost": "7.91" }, "table": { "table_name": "Country", "access_type": "range", "possible_keys": [ "p", "c", "p_c", "c_p" ], "key": "c_p", "used_key_parts": [ "Continent", "Population" ], "key_length": “5”,
 .. All of the key is used
  • 82. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Composite Left-most Rule • An index on (Continent, Population) can also be used as an index on (Continent) • It can not be used as an index on (Population) 82
  • 83. EXPLAIN FORMAT=JSON 
 SELECT * FROM Country FORCE INDEX (c_p) WHERE population > 500000000; { "query_block": { "select_id": 1, "cost_info": { "query_cost": "83.90" }, "table": { "table_name": "Country", "access_type": "ALL", "rows_examined_per_scan": 239, "rows_produced_per_join": 79, "filtered": "33.33", .. "attached_condition": "(`world`.`country`.`Population` > 500000000)" ..
  • 84. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Agenda 1. Introduction 2. Server Architecture 3. B+trees 4. EXPLAIN 5. Optimizer Trace 6. Logical Transformations 7. Cost Based Optimization 8. Hints and Switches 9. Comparing Plans 10.Composite Indexes 11.Covering Indexes 12.Visual Explain 13.Transient Plans 14.Subqueries 15.CTEs and Views 16.Joins 17.Aggregation 18.Descending Indexes 19.Sorting 20.Partitioning 21.Query Rewrite 22.Invisible Indexes 23.Profiling 24.JSON 25.Character Sets 84
  • 85. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Covering Indexes • A special kind of composite index • All information returned just by accessing the index 85
  • 86. ALTER TABLE Country ADD INDEX c_p_n (Continent,Population,Name); EXPLAIN FORMAT=JSON SELECT Name FROM Country WHERE continent='Asia' and population > 5000000; { "query_block": { "select_id": 1, "cost_info": { "query_cost": "3.72" }, "table": { "table_name": "Country", "access_type": "range", "possible_keys": [ .. "c_p_n" ], "key": "c_p_n", "used_key_parts": [ "Continent", "Population" ], "key_length": "5", .. "filtered": "100.00", "using_index": true, .. Cost is reduced by 53% Using index means "covering index"
  • 87. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Use cases • Can be used as in this example • Also beneficial in join conditions (join through covering index on intermediate table) • Useful in aggregate queries 87
  • 88. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Agenda 1. Introduction 2. Server Architecture 3. B+trees 4. EXPLAIN 5. Optimizer Trace 6. Logical Transformations 7. Cost Based Optimization 8. Hints and Switches 9. Comparing Plans 10.Composite Indexes 11.Covering Indexes 12.Visual Explain 13.Transient Plans 14.Subqueries 15.CTEs and Views 16.Joins 17.Aggregation 18.Descending Indexes 19.Sorting 20.Partitioning 21.Query Rewrite 22.Invisible Indexes 23.Profiling 24.JSON 25.Character Sets 88
  • 89. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Visual Explain • For complex queries, it is useful to see visual representation • Visualizations in this deck are produced by MySQL Workbench. 89
  • 90. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Agenda 1. Introduction 2. Server Architecture 3. B+trees 4. EXPLAIN 5. Optimizer Trace 6. Logical Transformations 7. Cost Based Optimization 8. Hints and Switches 9. Comparing Plans 10.Composite Indexes 11.Covering Indexes 12.Visual Explain 13.Transient Plans 14.Subqueries 15.CTEs and Views 16.Joins 17.Aggregation 18.Descending Indexes 19.Sorting 20.Partitioning 21.Query Rewrite 22.Invisible Indexes 23.Profiling 24.JSON 25.Character Sets 90
  • 91. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | A quick recap: • So far we’ve talked about 4 candidate indexes: – p (population) – c (continent) – p_c (population, continent) – c_p (continent, population) • We’ve always used c=‘Asia’ and p > 5M 91
  • 92. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 92 Cost Estimates p>5M c=’Asia’ p>5M c=’Antarctica’ p>50M, c=’Asia’ p>50M c=’Antarctica’ p>500M, c=’Asia’ p>500M c=’Antarctica’ p 48.86 48.86 11.06 11.06 1.16 1.16 c 9.60 1.75 9.60 1.75 9.60 1.75 c_p 7.91 0.71 5.21 0.71 1.16 0.71 p_c 48.86 48.86 11.06 11.06 1.16 1.16 ALL 25.40 25.40 25.40 25.40 25.40 25.40
  • 93. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 93 Cost Estimates
  • 94. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 94 Actual Execution Time
  • 95. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Agenda 1. Introduction 2. Server Architecture 3. B+trees 4. EXPLAIN 5. Optimizer Trace 6. Logical Transformations 7. Cost Based Optimization 8. Hints and Switches 9. Comparing Plans 10.Composite Indexes 11.Covering Indexes 12.Visual Explain 13.Transient Plans 14.Subqueries 15.CTEs and Views 16.Joins 17.Aggregation 18.Descending Indexes 19.Sorting 20.Partitioning 21.Query Rewrite 22.Invisible Indexes 23.Profiling 24.JSON 25.Character Sets 95
  • 96. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Subquery (Scalar) • Can optimize away the inner part first and then cache it. • This avoids re-executing the inner part for-each-row 96 SELECT * FROM Country WHERE
 Code = (SELECT CountryCode FROM City WHERE name=‘Toronto’);
  • 97. EXPLAIN FORMAT=JSON SELECT * FROM Country WHERE Code = (SELECT CountryCode FROM City WHERE name=‘Toronto’); { "query_block": { "select_id": 1, "cost_info": { "query_cost": "1.00" }, "table": { "table_name": "Country", "access_type": "const", .. "key": "PRIMARY", .. }, "optimized_away_subqueries": [ { "dependent": false, "cacheable": true, "query_block": { "select_id": 2, "cost_info": { "query_cost": "425.05" }, "table": { "table_name": "City", "access_type": "ALL", .. (misleading visualization) First query + its cost Second query + its cost
  • 98. ALTER TABLE city ADD INDEX n (name); EXPLAIN FORMAT=JSON SELECT * FROM Country WHERE Code = (SELECT CountryCode FROM City WHERE name=‘Toronto’); { "query_block": { "select_id": 1, "cost_info": { "query_cost": "1.00" }, "table": { "table_name": "Country", "access_type": "const", .. "key": "PRIMARY", .. }, "optimized_away_subqueries": [ { "dependent": false, "cacheable": true, "query_block": { "select_id": 2, "cost_info": { "query_cost": "0.35" }, "table": { "table_name": "City", "access_type": "ref", "possible_keys": [ "n" ], "key": “n", .. First query + its cost Second query + its cost (misleading visualization)
  • 99. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Subquery (IN list) • When the result inner subquery returns unique results it can safely be transformed to an inner join: 99 EXPLAIN FORMAT=JSON SELECT * FROM City WHERE CountryCode IN
 (SELECT Code FROM Country WHERE Continent = 'Asia'); show warnings; /* select#1 */ select `world`.`city`.`ID` AS `ID`,`world`.`city`.`Name` AS `Name`,`world`.`city`.`CountryCode` AS `CountryCode`,`world`.`city`.`District` AS `District`,`world`.`city`.`Population` AS `Population` from `world`.`country` join `world`.`city` where ((`world`.`city`.`CountryCode` = `world`.`country`.`Code`) and (`world`.`country`.`Continent` = 'Asia')) 1 row in set (0.00 sec)
  • 100. EXPLAIN FORMAT=JSON SELECT * FROM City WHERE CountryCode IN
 (SELECT Code FROM Country WHERE Continent = 'Asia'); { "query_block": { "select_id": 1, "cost_info": { "query_cost": "327.58" }, "nested_loop": [ { "table": { "table_name": "Country", "access_type": "ref", .. "key": "c", .. "using_index": true, .. "used_columns": [ "Code", "Continent" .. { "table": { "table_name": "City", "access_type": "ref", "possible_keys": [ "CountryCode" ], "key": "CountryCode", .. "ref": [ "world.Country.Code" ], ..
  • 101. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | SELECT * FROM Country WHERE Code IN (SELECT CountryCode FROM CountryLanguage 
 WHERE isOfficial=1); Subquery (cont.) • When non-unique the optimizer needs to pick a semi-join strategy • Multiple options: FirstMatch, MaterializeLookup, DuplicatesWeedout 101
  • 102. ALTER TABLE CountryLanguage ADD INDEX i (isOfficial); EXPLAIN FORMAT=JSON SELECT * FROM Country WHERE Code IN (SELECT CountryCode FROM CountryLanguage WHERE isOfficial=1); { "query_block": { "select_id": 1, "cost_info": { "query_cost": "98.39" }, "nested_loop": [ { "table": { "table_name": "Country", "access_type": "ALL", "possible_keys": [ "PRIMARY" ], .. "filtered": "100.00", .. "table": { "table_name": "<subquery2>", "access_type": "eq_ref", "key": "<auto_key>", "key_length": "3", "ref": [ "world.Country.Code" ], "rows_examined_per_scan": 1, "materialized_from_subquery": { "using_temporary_table": true, "query_block": { "table": { "table_name": "CountryLanguage", "access_type": "ref", .. "key": "i", .. "using_index": true, ..
  • 103. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Agenda 1. Introduction 2. Server Architecture 3. B+trees 4. EXPLAIN 5. Optimizer Trace 6. Logical Transformations 7. Cost Based Optimization 8. Hints and Switches 9. Comparing Plans 10.Composite Indexes 11.Covering Indexes 12.Visual Explain 13.Transient Plans 14.Subqueries 15.CTEs and Views 16.Joins 17.Aggregation 18.Descending Indexes 19.Sorting 20.Partitioning 21.Query Rewrite 22.Invisible Indexes 23.Profiling 24.JSON 25.Character Sets 103
  • 104. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Views • A way of saving a SELECT statement as a table • Allows for simplified queries • Processed using one of two methods internally: – Merge - transform the view to be combined with the query. – Materialize - save the contents of the view in a temporary table, then begin querying 104
  • 105. ALTER TABLE country ADD INDEX c_n (continent, name); CREATE VIEW vCountry_Asia AS SELECT * FROM Country WHERE Continent='Asia'; EXPLAIN FORMAT=JSON SELECT * FROM vCountry_Asia WHERE Name='China'; { "query_block": { "select_id": 1, "cost_info": { "query_cost": "0.35" }, "table": { "table_name": "country", "access_type": "ref", "possible_keys": [ .. "c_n" ], "key": "c_n", "used_key_parts": [ "Continent", "Name" ], "key_length": "53", "ref": [ "const", "const" ], .. This is the base table Predicates from the view definition and query combined
  • 106. SHOW WARNINGS; /* select#1 */ select `world`.`Country`.`Code` AS `Code`, `world`.`Country`.`Name` AS `Name`, `world`.`Country`.`Continent` AS `Continent`, `world`.`Country`.`Region` AS `Region`, `world`.`Country`.`SurfaceArea` AS `SurfaceArea`, `world`.`Country`.`IndepYear` AS `IndepYear`, `world`.`Country`.`Population` AS `Population`, `world`.`Country`.`LifeExpectancy` AS `LifeExpectancy`, `world`.`Country`.`GNP` AS `GNP`, `world`.`Country`.`GNPOld` AS `GNPOld`, `world`.`Country`.`LocalName` AS `LocalName`, `world`.`Country`.`GovernmentForm` AS `GovernmentForm`, `world`.`Country`.`HeadOfState` AS `HeadOfState`, `world`.`Country`.`Capital` AS `Capital`, `world`.`Country`.`Code2` AS `Code2` from `world`.`Country` where ((`world`.`Country`.`Continent` = 'Asia') and (`world`.`Country`.`Name` = 'China'))
  • 107. CREATE VIEW vCountrys_Per_Continent AS SELECT Continent, COUNT(*) as Count FROM Country GROUP BY Continent; EXPLAIN FORMAT=JSON SELECT * FROM vCountrys_Per_Continent WHERE Continent='Asia'; { "query_block": { "select_id": 1, "cost_info": { "query_cost": "3.64" }, "table": { "table_name": "vCountrys_Per_Continent", "access_type": "ref", "possible_keys": [ "<auto_key0>" ], "key": "<auto_key0>", "used_key_parts": [ "Continent" ], "key_length": "1", "ref": [ "const" ], .. "used_columns": [ "Continent", "Count" ], .. This is the view name .. "materialized_from_subquery": { "using_temporary_table": true, "dependent": false, "cacheable": true, "query_block": { "select_id": 2, "cost_info": { "query_cost": "25.40" }, This is only the cost of accessing the materialized table This step happens first.
  • 108. SHOW WARNINGS; /* select#1 */ select `vCountrys_Per_Continent`.`Continent` AS `Continent`, `vCountrys_Per_Continent`.`Count` AS `Count` from `world`.`vCountrys_Per_Continent` where (`vCountrys_Per_Continent`.`Continent` = 'Asia')
  • 109. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | WITH (CTE) • A view for query-only duration • Same optimizations available as views: – Merge - transform the CTE to be combined with the query. – Materialize - save the contents of the CTE in a temporary table, then begin querying 109
  • 110. # Identical Queries - CTE and VIEW WITH vCountry_Asia AS (SELECT * FROM Country WHERE Continent='Asia') SELECT * FROM vCountry_Asia WHERE Name='China'; CREATE VIEW vCountry_Asia AS SELECT * FROM Country WHERE Continent='Asia'; SELECT * FROM vCountry_Asia WHERE Name='China';
  • 111. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | CTEs are new! • May provide performance enhancements over legacy code using temporary tables - which never merge. • Derived tables may need to materialize more than once. A CTE does not! i.e. 111 SELECT * FROM my_table, (SELECT ... ) as t1 ... UNION ALL SELECT * FROM my_table, (SELECT ... ) as t1 ...
  • 112. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | WITH RECURSIVE - new! WITH RECURSIVE my_cte AS ( SELECT 1 AS n UNION ALL SELECT 1+n FROM my_cte WHERE n<10 ) SELECT * FROM my_cte; +------+ | n | +------+ | 1 | | 2 | .. | 9 | | 10 | +------+ 10 rows in set (0.01 sec) 112
  • 113. { "query_block": { "select_id": 1, "cost_info": { "query_cost": "2.84" }, "table": { "table_name": "my_cte", "access_type": "ALL", .. "used_columns": [ "n" ], "materialized_from_subquery": { "using_temporary_table": true, "dependent": false, "cacheable": true, "query_block": { "union_result": { "using_temporary_table": false, .. .. { "dependent": false, "cacheable": true, "query_block": { "select_id": 3, "recursive": true, "cost_info": { "query_cost": "2.72" }, "table": { "table_name": "my_cte", "access_type": "ALL", .. "used_columns": [ "n" ], "attached_condition": 
 "(`my_cte`.`n` < 10)" } .. Requires a temporary table for intermediate results Cost per iteration
  • 114. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Agenda 1. Introduction 2. Server Architecture 3. B+trees 4. EXPLAIN 5. Optimizer Trace 6. Logical Transformations 7. Cost Based Optimization 8. Hints and Switches 9. Comparing Plans 10.Composite Indexes 11.Covering Indexes 12.Visual Explain 13.Transient Plans 14.Subqueries 15.CTEs and Views 16.Joins 17.Aggregation 18.Descending Indexes 19.Sorting 20.Partitioning 21.Query Rewrite 22.Invisible Indexes 23.Profiling 24.JSON 25.Character Sets 114
  • 115. SELECT Country.Name as Country, City.Name as Capital, Language FROM City INNER JOIN Country ON Country.Capital=City.id INNER JOIN CountryLanguage ON CountryLanguage.CountryCode=Country.code WHERE Country.Continent='Asia' and CountryLanguage.IsOfficial='T';
  • 116. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Join Strategy (Nested Loop Join) 1. Pick Driving Table (Country) 2. For each row in Country
 step through to City table 3. For each row in City table
 step through to
 CountryLanguage table 4. Repeat 116
  • 117. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Join efficiency • Important to eliminate work before accessing other tables (WHERE clause should have lots of predicates that filter driving table) • Indexes are required on the columns that connect between driving table, and subsequent tables: 117 ON Country.Capital=City.id
  • 118. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | INNER JOIN vs LEFT JOIN • LEFT JOIN semantically says “right row is optional”. – Forces JOIN order to be left side first. – Reduces possible ways to join tables 118
  • 119. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Join Order Hints • One of the most frequent types of hints to apply • New join order hints in 8.0: – JOIN_FIXED_ORDER – JOIN_ORDER – JOIN_PREFIX – JOIN_SUFFIX 119
  • 120. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Agenda 1. Introduction 2. Server Architecture 3. B+trees 4. EXPLAIN 5. Optimizer Trace 6. Logical Transformations 7. Cost Based Optimization 8. Hints and Switches 9. Comparing Plans 10.Composite Indexes 11.Covering Indexes 12.Visual Explain 13.Transient Plans 14.Subqueries 15.CTEs and Views 16.Joins 17.Aggregation 18.Descending Indexes 19.Sorting 20.Partitioning 21.Query Rewrite 22.Invisible Indexes 23.Profiling 24.JSON 25.Character Sets 120
  • 121. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Group By - Loose Index Scan • Scan the index from start to finish without buffering. Results are pipelined to client: 121 SELECT count(*) as c, continent FROM Country 
 GROUP BY continent;
  • 122. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Group By - Index Filtering Rows • Use the index to eliminate as much work as possible • Store rows in intermediate temporary file and then sort 122
  • 123. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Group By - Index Filtering + Guaranteed Order • Use the index to eliminate as much work as possible • The index also maintains order 123
  • 124. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | UNION • Requires an intermediate temporary table to weed out duplicate rows • The optimizer does not really have any optimizations for UNION (such as a merge with views) 124
  • 125. EXPLAIN FORMAT=JSON SELECT * FROM City WHERE CountryCode = 'CAN' UNION SELECT * FROM City WHERE CountryCode = 'USA' { "union_result": { "using_temporary_table": true, "table_name": "<union1,2>", "access_type": "ALL", "query_specifications": [ { "dependent": false, "cacheable": true, "query_block": { "select_id": 1, "cost_info": { "query_cost": "17.15" }, "table": { "table_name": "City", "access_type": "ref", .. "key": "CountryCode", .. Temporary table to de-duplicate { "dependent": false, "cacheable": true, "query_block": { "select_id": 2, "cost_info": { "query_cost": "46.15" }, "table": { "table_name": "City", "access_type": "ref", "possible_keys": [ "CountryCode" ], "key": "CountryCode", "used_key_parts": [ "CountryCode" ], "key_length": "3", "ref": [ "const" ], ..
  • 126. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | UNION ALL • Results may contain duplicate rows • Does not require an intermediate temporary table in simple use cases. i.e. no result ordering. • Otherwise similar to UNION 126
  • 127. EXPLAIN FORMAT=JSON SELECT * FROM City WHERE CountryCode = 'CAN' UNION ALL SELECT * FROM City WHERE CountryCode = 'USA' { "query_block": { "union_result": { "using_temporary_table": false, "query_specifications": [ { "dependent": false, "cacheable": true, "query_block": { "select_id": 1, "cost_info": { "query_cost": "17.15" }, "table": { "table_name": "City", "access_type": "ref", .. "key": "CountryCode", .. { "dependent": false, "cacheable": true, "query_block": { "select_id": 2, "cost_info": { "query_cost": "46.15" }, "table": { "table_name": "City", "access_type": "ref", "possible_keys": [ "CountryCode" ], "key": "CountryCode", "used_key_parts": [ "CountryCode" ], "key_length": "3", "ref": [ "const" ], .. No temporary table
  • 128. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Agenda 1. Introduction 2. Server Architecture 3. B+trees 4. EXPLAIN 5. Optimizer Trace 6. Logical Transformations 7. Cost Based Optimization 8. Hints and Switches 9. Comparing Plans 10.Composite Indexes 11.Covering Indexes 12.Visual Explain 13.Transient Plans 14.Subqueries 15.CTEs and Views 16.Joins 17.Aggregation 18.Descending Indexes 19.Sorting 20.Partitioning 21.Query Rewrite 22.Invisible Indexes 23.Profiling 24.JSON 25.Character Sets 128
  • 129. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Descending Indexes • B+tree indexes are ordered • In 8.0 you can specify the order • Use cases: – Faster to scan in order – Can’t change direction in a composite index 129
  • 130. EXPLAIN FORMAT=JSON SELECT * FROM Country WHERE continent='Asia' AND population > 5000000 ORDER BY population DESC; { "query_block": { "select_id": 1, "cost_info": { "query_cost": "7.91" }, "ordering_operation": { "using_filesort": false, "table": { "table_name": "Country", "access_type": "range", .. "key": "c_p", .. "backward_index_scan": true, .. Still uses the index, but about 15% slower
  • 131. EXPLAIN FORMAT=JSON SELECT * FROM Country WHERE continent IN ('Asia', 'Oceania') AND population > 5000000 ORDER BY continent ASC, population DESC { "query_block": { "select_id": 1, "cost_info": { "query_cost": "48.36" }, "ordering_operation": { "using_filesort": true, "cost_info": { "sort_cost": "33.00" }, "table": { "table_name": "Country", "access_type": "range", "key": "c_p", .. "rows_examined_per_scan": 33, "rows_produced_per_join": 33, "filtered": "100.00", .. Must sort values of population in reverse
  • 132. ALTER TABLE Country DROP INDEX c_p, DROP INDEX c_p_n, ADD INDEX c_p_desc (continent ASC, population DESC); EXPLAIN FORMAT=JSON SELECT * FROM Country WHERE continent IN ('Asia', 'Oceania') AND population > 5000000 ORDER BY continent ASC, population DESC; { "query_block": { "select_id": 1, "cost_info": { "query_cost": "15.36" }, "ordering_operation": { "using_filesort": false, "table": { "table_name": "Country", "access_type": "range", .. "key": "c_p_desc", "used_key_parts": [ "Continent", "Population" ], "key_length": "5", .. TIP: The optimizer does not consider sort cost in evaluating plans. You may need to FORCE INDEX or DROP similar ascending indexes to use it.
  • 133. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Agenda 1. Introduction 2. Server Architecture 3. B+trees 4. EXPLAIN 5. Optimizer Trace 6. Logical Transformations 7. Cost Based Optimization 8. Hints and Switches 9. Comparing Plans 10.Composite Indexes 11.Covering Indexes 12.Visual Explain 13.Transient Plans 14.Subqueries 15.CTEs and Views 16.Joins 17.Aggregation 18.Descending Indexes 19.Sorting 20.Partitioning 21.Query Rewrite 22.Invisible Indexes 23.Profiling 24.JSON 25.Character Sets 133
  • 134. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | How is ORDER BY optimized? 1. Via an Index 2. Top N Buffer (“priority queue”) 3. Using temporary files 134
  • 135. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Via an Index • B+tree indexes are ordered • Some ORDER BY queries do not require sorting at all 135 EXPLAIN FORMAT=JSON SELECT * FROM Country WHERE continent='Asia' ORDER BY population; { "query_block": { "select_id": 1, "cost_info": { "query_cost": "9.60" }, "ordering_operation": { "using_filesort": false, .. "key": "c_p", The order is provided by c_p
  • 136. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Via a Priority Queue • Special ORDER BY + small limit optimization • Keeps top N records in an in memory buffer • Usage is NOT shown in EXPLAIN 136 SELECT * FROM Country IGNORE INDEX (p, p_c) ORDER BY population LIMIT 10;
  • 137. "select#": 1, "steps": [ { "filesort_information": [ { "direction": "asc", "table": "`country` IGNORE INDEX (`p_c`) IGNORE INDEX (`p`)", "field": "Population" } ], "filesort_priority_queue_optimization": { "limit": 10, "chosen": true }, "filesort_execution": [ ], "filesort_summary": { "memory_available": 262144, "key_size": 4, "row_size": 272, "max_rows_per_buffer": 11, "num_rows_estimate": 587, "num_rows_found": 11, "num_examined_rows": 239, "num_tmp_files": 0, "sort_buffer_size": 3080, "sort_algorithm": "std::sort", "unpacked_addon_fields": "using_priority_queue", "sort_mode": "<fixed_sort_key, additional_fields>” .. OPTIMIZER TRACE showing Priority Queue for sort
  • 138. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Using Temporary Files • Either “Alternative Sort Algorithm” (no blobs present) or “Original Sort Algorithm” 138 SELECT * FROM Country IGNORE INDEX (p, p_c) ORDER BY population;
  • 139. "select#": 1, "steps": [ { "filesort_information": [ { "direction": "asc", "table": "`country` IGNORE INDEX (`p_c`) IGNORE INDEX (`p`)", "field": "Population" } ], "filesort_priority_queue_optimization": { "usable": false, "cause": "not applicable (no LIMIT)" }, "filesort_execution": [ ], "filesort_summary": { "memory_available": 262144, "key_size": 4, "row_size": 274, "max_rows_per_buffer": 587, "num_rows_estimate": 587, "num_rows_found": 239, "num_examined_rows": 239, "num_tmp_files": 0, "sort_buffer_size": 165536, "sort_algorithm": "std::stable_sort", "sort_mode": "<fixed_sort_key, packed_additional_fields>" .. Not Using Priority Sort
  • 140. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Agenda 1. Introduction 2. Server Architecture 3. B+trees 4. EXPLAIN 5. Optimizer Trace 6. Logical Transformations 7. Cost Based Optimization 8. Hints and Switches 9. Comparing Plans 10.Composite Indexes 11.Covering Indexes 12.Visual Explain 13.Transient Plans 14.Subqueries 15.CTEs and Views 16.Joins 17.Aggregation 18.Descending Indexes 19.Sorting 20.Partitioning 21.Query Rewrite 22.Invisible Indexes 23.Profiling 24.JSON 25.Character Sets 140
  • 141. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Partitioning • Split a table physically into smaller tables • At the user-level make it still appear as one table 141
  • 142. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Use Cases • Can be a better fit low cardinality columns than indexing • Useful for time series data with retention scheme • i.e. drop data older than 3 months • Data where queries always have some locality • i.e. store_id, region 142
  • 143. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Partition Pruning • Optimizer looks at query and identifies which partitions need to be accessed 143 ALTER TABLE CountryLanguage MODIFY IsOfficial CHAR(1) NOT NULL DEFAULT 'F', DROP PRIMARY KEY, ADD PRIMARY KEY(CountryCode, Language, IsOfficial);
 ALTER TABLE CountryLanguage PARTITION BY LIST COLUMNS (IsOfficial) ( PARTITION pUnofficial VALUES IN ('F'), PARTITION pOfficial VALUES IN ('T') );
  • 144. EXPLAIN FORMAT=JSON SELECT * FROM CountryLanguage WHERE isOfficial='T' AND CountryCode='CAN'; { "query_block": { "select_id": 1, "cost_info": { "query_cost": "2.40" }, "table": { "table_name": "CountryLanguage", "partitions": [ "pOfficial" ], "access_type": "ref", .. "key": "PRIMARY", .. Only accesses one partition
  • 145. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Explicit Partition Selection • Also possible to “target” a partition • Consider this similar to query hints 145 SELECT * FROM CountryLanguage PARTITION (pOfficial) WHERE CountryCode='CAN';
  • 146. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Agenda 1. Introduction 2. Server Architecture 3. B+trees 4. EXPLAIN 5. Optimizer Trace 6. Logical Transformations 7. Cost Based Optimization 8. Hints and Switches 9. Comparing Plans 10.Composite Indexes 11.Covering Indexes 12.Visual Explain 13.Transient Plans 14.Subqueries 15.CTEs and Views 16.Joins 17.Aggregation 18.Descending Indexes 19.Sorting 20.Partitioning 21.Query Rewrite 22.Invisible Indexes 23.Profiling 24.JSON 25.Character Sets 146
  • 147. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Query Rewrite • MySQL allows you to change queries before they are executed • Insert a hint, or remove a join that is not required 147 mysql -u root -p < install_rewriter.sql INSERT INTO query_rewrite.rewrite_rules(pattern_database, pattern, replacement) VALUES ( "world", "SELECT * FROM Country WHERE population > ? AND continent=?", "SELECT * FROM Country WHERE population > ? AND continent=? LIMIT 1" ); CALL query_rewrite.flush_rewrite_rules();
  • 148. SELECT * FROM Country WHERE population > 5000000 AND continent='Asia'; SHOW WARNINGS; *********************** 1. row *********************** Level: Note Code: 1105 Message: Query 'SELECT * FROM Country WHERE population > 5000000 AND continent='Asia'' rewritten to 'SELECT * FROM Country WHERE population > 5000000 AND continent='Asia' LIMIT 1' by a query rewrite plugin 1 row in set (0.00 sec)
  • 149. SELECT * FROM query_rewrite.rewrite_rulesG ********************** 1. row ********************** id: 1 pattern: SELECT * FROM Country WHERE population > ? AND continent=? pattern_database: world replacement: SELECT * FROM Country WHERE population > ? AND continent=? LIMIT 1 enabled: YES message: NULL pattern_digest: 88876bbb502cef6efddcc661cce77deb normalized_pattern: select `*` from `world`.`country` where ((`population` > ?) and (`continent` = ?)) 1 row in set (0.00 sec)
  • 150. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Agenda 1. Introduction 2. Server Architecture 3. B+trees 4. EXPLAIN 5. Optimizer Trace 6. Logical Transformations 7. Cost Based Optimization 8. Hints and Switches 9. Comparing Plans 10.Composite Indexes 11.Covering Indexes 12.Visual Explain 13.Transient Plans 14.Subqueries 15.CTEs and Views 16.Joins 17.Aggregation 18.Descending Indexes 19.Sorting 20.Partitioning 21.Query Rewrite 22.Invisible Indexes 23.Profiling 24.JSON 25.Character Sets 150
  • 151. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Changing Indexes is a Destructive Operation • Removing an index can make some queries much slower • Adding can cause some existing query plans to change • Old-style hints will generate errors if indexes are removed 151
  • 152. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Invisible Indexes, the “Recycle Bin” • Hide the indexes from the optimizer • Will no longer be considered as part of query execution plans • Still kept up to date and are maintained by insert/update/delete statements 152
  • 153. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Invisible Indexes: Soft Delete ALTER TABLE Country ALTER INDEX c INVISIBLE; SELECT * FROM information_schema.statistics WHERE is_visible='NO'; *************************** 1. row *************************** TABLE_CATALOG: def TABLE_SCHEMA: world TABLE_NAME: Country NON_UNIQUE: 1 INDEX_SCHEMA: world INDEX_NAME: c SEQ_IN_INDEX: 1 COLUMN_NAME: Continent COLLATION: A CARDINALITY: 7 SUB_PART: NULL PACKED: NULL NULLABLE: INDEX_TYPE: BTREE COMMENT: disabled INDEX_COMMENT: IS_VISIBLE: NO 153
  • 154. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Invisible Indexes: Staged Rollout ALTER TABLE Country ADD INDEX c (Continent) INVISIBLE; # after some time ALTER TABLE Country ALTER INDEX c VISIBLE; 154
  • 155. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Finding Unused Indexes SELECT * FROM sys.schema_unused_indexes; +---------------+-------------+------------+ | object_schema | object_name | index_name | +---------------+-------------+------------+ | world | Country | p | | world | Country | p_c | +---------------+-------------+------------+ 2 rows in set (0.01 sec) 155
  • 156. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Do indexes hurt reads or writes? • They can have some impact on both: – On writes, indexes need to space, and to be maintained – On reads, lets use an example… 156
  • 157. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Indexes Hurting Reads CREATE TABLE t1 ( id INT NOT NULL primary key auto_increment, a VARCHAR(255) NOT NULL, b VARCHAR(255) NOT NULL, c TEXT, d TEXT, INDEX a (a), INDEX ab (a,b)); # Sample Query SELECT * FROM t1 WHERE a = 'abc' AND b = 'bcd'; 157 Both indexes are candidates. Both will be examined.
  • 158. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | A use case for invisible indexes! CREATE TABLE t1 ( id INT NOT NULL primary key auto_increment, a VARCHAR(255) NOT NULL, b VARCHAR(255) NOT NULL, c TEXT, d TEXT, INDEX a (a), INDEX ab (a,b)); # Consider: SELECT count(*) FROM t1 FORCE INDEX (a)
 WHERE a='1234' AND id=1234; 158 Index (a) is made redundant by (a,b). Can we drop it?
  • 159. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | 159 No, due to clustered Index! FORCE INDEX (a) WHERE a=‘1234' AND id=1234; { "query_block": { "select_id": 1, "cost_info": { "query_cost": "0.35" }, "table": { "table_name": "t1", "access_type": "const", "possible_keys": [ "a" ], "key": "a", "used_key_parts": [ "a", "id" ], .. FORCE INDEX (ab) WHERE a='1234' AND id=1234; { "query_block": { "select_id": 1, "cost_info": { "query_cost": "11.80" }, "table": { "table_name": "t1", "access_type": "ref", "possible_keys": [ "ab" ], "key": "ab", "used_key_parts": [ "a" ], ..
  • 160. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Agenda 1. Introduction 2. Server Architecture 3. B+trees 4. EXPLAIN 5. Optimizer Trace 6. Logical Transformations 7. Cost Based Optimization 8. Hints and Switches 9. Comparing Plans 10.Composite Indexes 11.Covering Indexes 12.Visual Explain 13.Transient Plans 14.Subqueries 15.CTEs and Views 16.Joins 17.Aggregation 18.Descending Indexes 19.Sorting 20.Partitioning 21.Query Rewrite 22.Invisible Indexes 23.Profiling 24.JSON 25.Character Sets 160
  • 161. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Profiling • Optimizer only shows estimates from pre-execution view • Can be useful to know actual time spent • Support for profiling is only very basic 161 wget http://www.tocker.ca/files/ps-show-profiles.sql mysql -u root -p < ps-show-profiles.sql
  • 162. CALL sys.enable_profiling(); CALL sys.show_profiles; *************************** 1. row *************************** Event_ID: 22 Duration: 495.02 us Query: SELECT * FROM Country WHERE co ... Asia' and population > 5000000 1 row in set (0.00 sec) CALL sys.show_profile_for_event_id(22); +----------------------+-----------+ | Status | Duration | +----------------------+-----------+ | starting | 64.82 us | | checking permissions | 4.10 us | | Opening tables | 11.87 us | | init | 29.74 us | | System lock | 5.63 us | | optimizing | 8.74 us | | statistics | 139.38 us | | preparing | 11.94 us | | executing | 348.00 ns | | Sending data | 192.59 us | | end | 1.17 us | | query end | 4.60 us | | closing tables | 4.07 us | | freeing items | 13.60 us | | cleaning up | 734.00 ns | +----------------------+-----------+ 15 rows in set (0.00 sec)
  • 163. SELECT * FROM Country WHERE Continent='Antarctica' and SLEEP(5); CALL sys.show_profiles(); CALL sys.show_profile_for_event_id(<event_id>); +----------------------+-----------+ | Status | Duration | +----------------------+-----------+ | starting | 103.89 us | | checking permissions | 4.48 us | | Opening tables | 17.78 us | | init | 45.75 us | | System lock | 8.37 us | | optimizing | 11.98 us | | statistics | 144.78 us | | preparing | 15.78 us | | executing | 634.00 ns | | Sending data | 116.15 us | | User sleep | 5.00 s | | User sleep | 5.00 s | | User sleep | 5.00 s | | User sleep | 5.00 s | | User sleep | 5.00 s | | end | 2.05 us | | query end | 5.63 us | | closing tables | 7.30 us | | freeing items | 20.19 us | | cleaning up | 1.20 us | +----------------------+-----------+ 20 rows in set (0.01 sec) Sleeps for each row after index used on (c)
  • 164. SELECT region, count(*) as c FROM Country GROUP BY region; CALL sys.show_profiles(); CALL sys.show_profile_for_event_id(<event_id>); +----------------------+-----------+ | Status | Duration | +----------------------+-----------+ | starting | 87.43 us | | checking permissions | 4.93 us | | Opening tables | 17.35 us | | init | 25.81 us | | System lock | 9.04 us | | optimizing | 3.37 us | | statistics | 18.31 us | | preparing | 10.94 us | | Creating tmp table | 35.57 us | | Sorting result | 2.38 us | | executing | 741.00 ns | | Sending data | 446.03 us | | Creating sort index | 49.45 us | | end | 1.71 us | | query end | 4.85 us | | removing tmp table | 4.71 us | | closing tables | 6.12 us | | freeing items | 17.17 us | | cleaning up | 1.00 us | +----------------------+-----------+ 19 rows in set (0.01 sec)
  • 165. SELECT * FROM performance_schema.events_statements_history_long WHERE event_id=<event_id>G *********************** 1. row *********************** THREAD_ID: 3062 EVENT_ID: 1566 END_EVENT_ID: 1585 EVENT_NAME: statement/sql/select SOURCE: init_net_server_extension.cc:80 TIMER_START: 588883869566277000 TIMER_END: 588883870317683000 TIMER_WAIT: 751406000 LOCK_TIME: 132000000 SQL_TEXT: SELECT region, 
 count(*) as c FROM Country GROUP BY region DIGEST: d3a04b346fe48da4f1f5c2e06628a245 DIGEST_TEXT: SELECT `region` ,
 COUNT ( * ) AS `c` FROM `Country` 
 GROUP BY `region` CURRENT_SCHEMA: world OBJECT_TYPE: NULL OBJECT_SCHEMA: NULL OBJECT_NAME: NULL OBJECT_INSTANCE_BEGIN: NULL MYSQL_ERRNO: 0 RETURNED_SQLSTATE: NULL MESSAGE_TEXT: NULL ERRORS: 0 WARNINGS: 0 .. .. ROWS_AFFECTED: 0 ROWS_SENT: 25 ROWS_EXAMINED: 289 CREATED_TMP_DISK_TABLES: 0 CREATED_TMP_TABLES: 1 SELECT_FULL_JOIN: 0 SELECT_FULL_RANGE_JOIN: 0 SELECT_RANGE: 0 SELECT_RANGE_CHECK: 0 SELECT_SCAN: 1 SORT_MERGE_PASSES: 0 SORT_RANGE: 0 SORT_ROWS: 25 SORT_SCAN: 1 NO_INDEX_USED: 1 NO_GOOD_INDEX_USED: 0 NESTING_EVENT_ID: NULL NESTING_EVENT_TYPE: NULL NESTING_EVENT_LEVEL: 0 For non-aggregate queries rows sent vs. rows examined helps indicate index effectiveness.
  • 166. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Agenda 1. Introduction 2. Server Architecture 3. B+trees 4. EXPLAIN 5. Optimizer Trace 6. Logical Transformations 7. Cost Based Optimization 8. Hints and Switches 9. Comparing Plans 10.Composite Indexes 11.Covering Indexes 12.Visual Explain 13.Transient Plans 14.Subqueries 15.CTEs and Views 16.Joins 17.Aggregation 18.Descending Indexes 19.Sorting 20.Partitioning 21.Query Rewrite 22.Invisible Indexes 23.Profiling 24.JSON 25.Character Sets 166
  • 167. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | JSON • Optimizer has native support for JSON with indexes on generated columns used for matching JSON path expressions 167 CREATE TABLE CountryJson (Code char(3) not null primary key, doc JSON NOT NULL); INSERT INTO CountryJSON SELECT code, JSON_OBJECT( 'Name', Name, 'Continent', Continent, .. 'HeadOfState',HeadOfState, 'Capital', Capital, 'Code2', Code2 ) FROM Country;
  • 168. EXPLAIN FORMAT=JSON
 SELECT * FROM CountryJSON where doc->>"$.Name" = ‘Canada'; { "query_block": { "select_id": 1, "cost_info": { "query_cost": "48.80" }, "table": { "table_name": "CountryJSON", "access_type": "ALL", "rows_examined_per_scan": 239, "rows_produced_per_join": 239, "filtered": "100.00", "cost_info": { "read_cost": "1.00", "eval_cost": "47.80", "prefix_cost": "48.80", "data_read_per_join": "3K" }, ..
  • 169. ALTER TABLE CountryJSON ADD Name char(52) AS (doc->>"$.Name"), ADD INDEX n (Name); EXPLAIN FORMAT=JSON SELECT * FROM CountryJSON where doc->>"$.Name" = ‘Canada'; { "query_block": { "select_id": 1, "cost_info": { "query_cost": "1.20" }, "table": { "table_name": "CountryJSON", "access_type": "ref", .. "key": "n", .. "key_length": "53", "ref": [ "const" ], .. Key from virtual column Matches expression from indexed virtual column
  • 170. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | JSON Comparator • JSON types compare to MySQL types 170 SELECT CountryJSON.* FROM CountryJSON 
 INNER JOIN Country ON CountryJSON.doc->>"$.Name" = Country.Name WHERE Country.Name=‘Canada'; ********************** 1. row ********************** Code: CAN doc: {"GNP": 598862, "Name": "Canada", "Code2": "CA", "GNPOld": 625626, "Region": "North America", "Capital": 1822, "Continent": "North America", "IndepYear": 1867, "LocalName": "Canada", "Population": 31147000, "HeadOfState": "Elisabeth II", "SurfaceArea": 9970610, "GovernmentForm": "Constitutional Monarchy, Federation", "LifeExpectancy": 79.4000015258789} Name: Canada
  • 171. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Agenda 1. Introduction 2. Server Architecture 3. B+trees 4. EXPLAIN 5. Optimizer Trace 6. Logical Transformations 7. Cost Based Optimization 8. Hints and Switches 9. Comparing Plans 10.Composite Indexes 11.Covering Indexes 12.Visual Explain 13.Transient Plans 14.Subqueries 15.CTEs and Views 16.Joins 17.Aggregation 18.Descending Indexes 19.Sorting 20.Partitioning 21.Query Rewrite 22.Invisible Indexes 23.Profiling 24.JSON 25.Character Sets 171
  • 172. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Character Sets • The default character set in MySQL 8.0 is utf8mb4 • Utf8mb4 is variable length (1-4 bytes) • InnoDB will always store as variable size for both CHAR and VARCHAR • Some buffers inside MySQL may require the fixed length (4 bytes) 172
  • 173. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Character Sets (cont.) • CHAR(n) or VARCHAR(n) refers to n characters - x4 for maximum length • EXPLAIN will always show the maximum length • Mysqldump will preserve character set 173 
 ALTER TABLE City DROP FOREIGN KEY city_ibfk_1; ALTER TABLE CountryLanguage DROP FOREIGN KEY countryLanguage_ibfk_1; ALTER TABLE Country CONVERT TO CHARACTER SET utf8mb4;
  • 174. { "query_block": { "select_id": 1, "cost_info": { "query_cost": "0.35" }, "table": { "table_name": "Country", "access_type": "ref", "possible_keys": [ "n" ], "key": "n", "used_key_parts": [ "Name" ], "key_length": "52", .. "rows_examined_per_scan": 1, "rows_produced_per_join": 1, "filtered": "100.00", "cost_info": { "read_cost": "0.25", "eval_cost": "0.10", "prefix_cost": "0.35", "data_read_per_join": "264" }, .. { "query_block": { "select_id": 1, "cost_info": { "query_cost": "0.35" }, "table": { "table_name": "Country", "access_type": "ref", "possible_keys": [ "n" ], "key": "n", "used_key_parts": [ "Name" ], "key_length": "208", .. "rows_examined_per_scan": 1, "rows_produced_per_join": 1, "filtered": "100.00", "cost_info": { "read_cost": "0.25", "eval_cost": "0.10", "prefix_cost": "0.35", "data_read_per_join": "968" }, .. Key length as latin1 Key length as utf8
  • 175. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Conclusion • Thank you for coming! • This presentation is available as a website:
 www.unofficialmysqlguide.com 175