SlideShare a Scribd company logo
1 of 238
Download to read offline
Query Optimization: From 0 to 10 (and up to 5.7)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10
(and up to 5.7)
Jaime Crespo
Percona Live Europe 2015
-Amsterdam, 21 Sep 2015-
dbahire.com/pleu15
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
2
Agenda – First 3 hours
1. Introduction 5. FULLTEXT Search
2. Access Types and Basic
Indexing Techniques
6. Joins
3. Break 7. Subqueries
4. Multi-Column Indexing 8. Query Profiling
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
3
Agenda – Last 3 hours
1. General Optimizer
Improvements
6. SQL Mode Changes
2. Computed/Virtual Columns 7. GIS Improvements and JSON
Type
3. Query Rewrite Plugins 8. Results and Conclusions
4. Break 9. Q&A
5. Optimizer Hints
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
4
INTRODUCTION
Query Optimization: From 0 to 10 (and up to 5.7)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
5
This is me fighting bad query
performance
●
Sr. Database Administrator
at Wikimedia Foundation
●
Used to work as a trainer
for Oracle (MySQL), as a
Consultant (Percona) and
as a Freelance
administrator
(DBAHire.com)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
6
MySQL Versions
• 5.1 no longer has official support
• I will be showing you the results on mysql
versions 5.5-5.7/10.1
• MySQL 5.7 and MariaDB 10.1 in RC with great
new features
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
7
Recently Added Features
Related to Query Optimization
• Index Condition Pushdown
• Subquery Optimizations
materialization and semijoin)
• IN-to-EXISTS/EXISTS-to-IN
• JOIN-to-WHERE
• Multi-Range Read
• Batched Key Access
• Persistent InnoDB Statistics
• UNION ALL optimization
• Improved GIS support
• EXPLAIN FORMAT=JSON
• EXPLAIN
INSERT/UPDATE/DELETE
• Hash Join
• New optimizer hints
• New cost-based optimizer
• Optimizer Trace
• Filesort optimizations
• Virtual/computed columns
and “functional indexes”
• New JSON type
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
8
I Already Mentioned Some of Those
Topics during the Last Years
• Check my presentations here:
http://www.slideshare.net/jynus/
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
9
Example Application (I)
• Wiktionary (and all Wikimedia project's data) is
licensed under the Creative Commons BY-SA-2.5
License and is Copyright its Contributors
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
10
Example Application (II)
• OSM Database is licensed under the Open
DataBase License and is Copyright OpenStreetMap
Contributors
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
11
Install the example databases
●
Downloads and instructions at:
http://dbahire.com/pleu15
– Requirements: a MySQL or MariaDB installation
(MySQL Sandbox is suggested)
– The wiktionary and OSM extracts
●
Import them by doing:
$ bzcat <file> | mysql <database>
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
12
ACCESS TYPES AND BASIC
INDEXING TECHNIQUES
Query Optimization: From 0 to 10 (and up to 5.7)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
13
EXPLAIN
●
Essential to understand the execution plan of our
queries
– Works on SELECTs, INSERTs, UPDATEs,
REPLACEs, DELETEs and connections
– Fully documented on:
http://dev.mysql.com/doc/refman/5.6/en/expla
in-output.html
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
14
EXPLAIN Example
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page WHERE page_title
= 'Dutch';
+------+-------------+-------+------+---------------+------
+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key |
key_len | ref | rows | Extra |
+------+-------------+-------+------+---------------+------
+---------+------+------+-------------+
| 1 | SIMPLE | page | ALL | NULL | NULL | NULL
| NULL | 90956 | Using where |
+------+-------------+-------+------+---------------+------
+---------+------+------+-------------+
1 row in set (0.00 sec)
Difficult to see
something
Difficult to see
something
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
15
EXPLAIN Example (vertical
format)
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page WHERE
page_title = 'Dutch'G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: page
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 90956
Extra: Using where
1 row in set (0.00 sec)
Use G for
vertical
formatting
Use G for
vertical
formatting
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
16
EXPLAIN Example (id)
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page WHERE
page_title = 'Dutch'G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: page
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 90956
Extra: Using where
1 row in set (0.00 sec)
Indicates hierarchy
level, not execution
order
Indicates hierarchy
level, not execution
order
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
17
EXPLAIN Example (select_type)
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page WHERE
page_title = 'Dutch'G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: page
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 90956
Extra: Using where
1 row in set (0.00 sec)
Not a subquery or a
UNION
Not a subquery or a
UNION
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
18
EXPLAIN Example (table)
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page WHERE
page_title = 'Dutch'G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: page
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 90956
Extra: Using where
1 row in set (0.00 sec)
Table scanned for
this step
Table scanned for
this step
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
19
EXPLAIN Example (type)
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page WHERE
page_title = 'Dutch'G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: page
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 90956
Extra: Using where
1 row in set (0.00 sec)
All rows are read for
this table (FULL
TABLE SCAN)
All rows are read for
this table (FULL
TABLE SCAN)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
20
EXPLAIN Example (rows)
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page WHERE
page_title = 'Dutch'G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: page
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 90956
Extra: Using where
1 row in set (0.00 sec)
Estimated number
of rows to be read
(all table rows)
Estimated number
of rows to be read
(all table rows)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
21
How to improve performance?
● Let's add an index on page.page_title:
MariaDB [nlwiktionary]> ALTER TABLE page ADD INDEX
page_title (page_title);
Query OK, 0 rows affected (0.19 sec)
Records: 0 Duplicates: 0 Warnings: 0
MariaDB [nlwiktionary]> SELECT * FROM page
WHERE page_title = 'Dutch';
1 row in set (0.11 sec)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
22
Index creation results (type)
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page WHERE
page_title = 'Dutch'G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: page
type: ref
possible_keys: page_title
key: page_title
key_len: 257
ref: const
rows: 1
Extra: Using index condition
1 row in set (0.00 sec)
type: ref means that an
equality comparison will
be checked against an
index and several results
could be returned
type: ref means that an
equality comparison will
be checked against an
index and several results
could be returned
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
23
Index creation results
(possible_keys and key)
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page WHERE
page_title = 'Dutch'G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: page
type: ref
possible_keys: page_title
key: page_title
key_len: 257
ref: const
rows: 1
Extra: Using index condition
1 row in set (0.00 sec)
index(es) that the
optimizer considered
potentially useful, and
final index chosen
index(es) that the
optimizer considered
potentially useful, and
final index chosen
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
24
Index creation results (ref)
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page WHERE
page_title = 'Dutch'G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: page
type: ref
possible_keys: page_title
key: page_title
key_len: 257
ref: const
rows: 1
Extra: Using index condition
1 row in set (0.00 sec)
Index is compared
with a constant, not
with another table
Index is compared
with a constant, not
with another table
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
25
Index creation results (rows)
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page WHERE
page_title = 'Dutch'G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: page
type: ref
possible_keys: page_title
key: page_title
key_len: 257
ref: const
rows: 1
Extra: Using index condition
1 row in set (0.00 sec)
Only 1 row read. In this
case, estimation is exact
(thanks to index dive)
Only 1 row read. In this
case, estimation is exact
(thanks to index dive)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
26
Index creation results (query
time)
MariaDB [nlwiktionary]> SELECT * FROM page
WHERE page_title = 'Dutch';
1 row in set (0.00 sec) Query time has been
reduced substantially
Query time has been
reduced substantially
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
27
Types of indexes
●
BTREE
– B-TREE in MyISAM, B+TREE in InnoDB
●
HASH
– Only available for MEMORY and NDB
●
FULLTEXT
– Inverted indexes in MyISAM and InnoDB
●
SPATIAL
– RTREEs in MyISAM and InnoDB
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
28
Finding “Dutch” with a BTREE
EtchEtch
NastyNasty
BossBoss
GolfGolf
LeekLeek
SchoolSchool
AvastAvast
FreightFreight
LandscapeLandscape
RoverRover
DutchDutch
HarlemHarlem
MaelstromMaelstrom
WalrusWalrus
TABLETABLE
IcebergIceberg
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
29
Finding “Dutch” with a BTREE
EtchEtch
NastyNasty
BossBoss
GolfGolf
LeekLeek
SchoolSchool
AvastAvast
FreightFreight
LandscapeLandscape
RoverRover
DutchDutch
HarlemHarlem
MaelstromMaelstrom
WalrusWalrus
TABLETABLE
IcebergIceberg
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
30
Do indexes always work? (1/2)
● Can we use an index to make this query
faster?
SELECT * FROM page WHERE page_title like 'Spa%';
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
31
It is a range
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page WHERE
page_title like 'Spa%'G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: page
type: range
possible_keys: page_title
key: page_title
key_len: 257
ref: NULL
rows: 94
Extra: Using index condition
1 row in set (0.00 sec)
Despite not being an
equality, we can use the
index to find the values
quickly
Despite not being an
equality, we can use the
index to find the values
quickly
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
32
BTREE Indexes can be used for
ranges, too
EtchEtch
NastyNasty
BossBoss
GolfGolf
LeekLeek
SchoolSchool
AvastAvast
FreightFreight
LandscapeLandscape
RoverRover
DutchDutch
HarlemHarlem
MaelstromMaelstrom
WalrusWalrus
TABLETABLE
IcebergIceberg
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
33
Do indexes always work? (2/2)
● What about this other query?
SELECT * FROM page WHERE page_title like '%utch';
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
34
Let's check with EXPLAIN
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page WHERE
page_title like '%utch'G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: page
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 93189
Extra: Using where
1 row in set (0.00 sec)
No index can be used
for filtering. A full
table scan is
performed.
No index can be used
for filtering. A full
table scan is
performed.
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
35
BTREE Index
EtchEtch
NastyNasty
BossBoss
GolfGolf
LeekLeek
SchoolSchool
AvastAvast
FreightFreight
LandscapeLandscape
RoverRover
DutchDutch
HarlemHarlem
MaelstromMaelstrom
WalrusWalrus
TABLETABLE
IcebergIceberg
?
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
36
Btree indexes usage
● Filtering
– Equality (operator '=')
– Ranges (BETWEEN … AND, >, <, >=, <=, like 'prefix%')
– “EXISTS” operators: IN, OR on the same column
● Ordering
– ORDER BY (indexed columns)
– GROUP BY (indexed columns)
● Returning values directly from the index
– Covering index
– Functions like max(), min(), etc.
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
37
type: const
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision WHERE
rev_id = 2G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: revision
type: const
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: const
rows: 1
Extra:
1 row in set (0.00 sec)
'const' is a special case of 'ref',
when the index can assure
that only 1 results can be
returned (equality + primary
key or unique key). It is faster.
'const' is a special case of 'ref',
when the index can assure
that only 1 results can be
returned (equality + primary
key or unique key). It is faster.
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
38
type: NULL
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision WHERE
rev_id = -1G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: NULL
type: NULL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: NULL
Extra: Impossible WHERE noticed after reading const
tables
1 row in set (0.00 sec)
'NULL' is not really a plan,
just an optimization that
allow discarding
immediately impossible
conditions
'NULL' is not really a plan,
just an optimization that
allow discarding
immediately impossible
conditions
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
39
type: ref_or_null
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM user WHERE
user_email_token = '0' OR user_email_token IS NULLG
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: user
type: ref_or_null
possible_keys: user_email_token
key: user_email_token
key_len: 33
ref: const
rows: 2
Extra: Using index condition; Using where
1 row in set (0.00 sec)
Equivalent to 'ref', but
also has into account
NULL values
Equivalent to 'ref', but
also has into account
NULL values
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
40
type: range (using IN / OR)
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page WHERE
page_title IN ('Dutch', 'English', 'Spanish')G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: page
type: range
possible_keys: page_title
key: page_title
key_len: 257
ref: NULL
rows: 4
Extra: Using index condition
1 row in set (0.00 sec)
Despite being a range, its
execution is very
different from ranges
using like, between or
inequality operators
Despite being a range, its
execution is very
different from ranges
using like, between or
inequality operators
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
41
Is this a bug? (1/2)
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page WHERE
page_namespace = 2G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: page
type: ref
possible_keys: name_title
key: name_title
key_len: 4
ref: const
rows: 45
Extra:
1 row in set (0.00 sec)
An index is used to
return pages with ns=2
An index is used to
return pages with ns=2
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
42
Is this a bug? (2/2)
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page WHERE
page_namespace = 0G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: page
type: ALL
possible_keys: name_title
key: NULL
key_len: NULL
ref: NULL
rows: 7493
Extra: Using where
1 row in set (0.00 sec)
The index is not used
with ns=0
The index is not used
with ns=0
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
43
Using an index is sometimes
suboptimal
This point is not
fixed, and
depends on the
hardware and
buffer state
This point is not
fixed, and
depends on the
hardware and
buffer state
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
44
What index should we add to
make this query faster?
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision WHERE
left(rev_timestamp, 6) = '201509'G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: revision
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 163253
Extra: Using where
1 row in set (0.00 sec)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
45
The table has already an index on
rev_timestamp
MariaDB [nlwiktionary]> SHOW CREATE TABLE revisionG
*************************** 1. row ***************************
Table: revision
Create Table: CREATE TABLE `revision` (
...
KEY `rev_timestamp` (`rev_timestamp`),
Optimización de consultas con MySQL 5.6
© 2014 DBAHIRE.COM
We need to rewrite the query
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision WHERE
rev_timestamp >= '201509' and rev_timestamp < '201510'G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: revision
type: range
possible_keys: rev_timestamp
key: rev_timestamp
key_len: 14
ref: NULL
rows: 7
Extra: Using index condition
1 row in set (0.00 sec)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
47
This transformation is not trivial
or even possible in all cases
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision WHERE
substr(rev_timestamp, 5, 2) = '09'G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: revision
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
Rows: 173154
Extra: Using where
1 row in set (0.00 sec)
Can you think a way to
improve this query?
Can you think a way to
improve this query?
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
48
Indexes for Ordering
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page ORDER BY
page_touched DESC LIMIT 10G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: page
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 8720
Extra: Using filesort
1 row in set (0.00 sec)
"Using filesort" indicates that an
ordering is needed before
returning the results
"Using filesort" indicates that an
ordering is needed before
returning the results
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
49
If that is frequent, we can create
an index on page_touched...[nlwiktionary]> ALTER TABLE page ADD INDEX page_page_touched(page_touched);
Query OK, 0 rows affected (0.30 sec)
Records: 0 Duplicates: 0 Warnings: 0
[nlwiktionary]> EXPLAIN SELECT * FROM page ORDER BY page_touched DESC LIMIT
10G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: page
type: index
possible_keys: NULL
key: page_page_touched
key_len: 14
ref: NULL
rows: 10
Extra:
1 row in set (0.00 sec)
The index does not produce any
advantage for filtering
The index does not produce any
advantage for filtering
However, it is very effective by
helping avoiding the sort phase
However, it is very effective by
helping avoiding the sort phase
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
50
It can return data in index order
faster
EtchEtch
NastyNasty
BossBoss
GolfGolf
LeekLeek
SchoolSchool
AvastAvast
FreightFreight
LandscapeLandscape
RoverRover
DutchDutch
HarlemHarlem
MaelstromMaelstrom
WalrusWalrus
TABLETABLE
IcebergIceberg
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
51
Indexes and GROUP BY (no
indexes)
MariaDB [nlwiktionary]> EXPLAIN SELECT rev_page, count(*) FROM
revision IGNORE INDEX(rev_page_id, page_timestamp,
page_user_timestamp) GROUP BY rev_pageG
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: revision
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 201094
Extra: Using temporary; Using filesort
1 row in set (0.00 sec)
Without indexes, a temporary
table is created to order results
Without indexes, a temporary
table is created to order results
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
52
Trick: ORDER BY NULL avoids
filesortMariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision GROUP BY substr(rev_timestamp, 5, 2)
= '09'G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: revision
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 196824
Extra: Using temporary; Using filesort
1 row in set (0.00 sec)
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision GROUP BY substr(rev_timestamp, 5, 2)
= '09' ORDER BY NULLG
*************************** 1. row ***************************
...
rows: 196871
Extra: Using temporary
1 row in set (0.00 sec)
The advantage is not too big, but
it avoids the filesort
The advantage is not too big, but
it avoids the filesort
There is no good index in this
case
There is no good index in this
case
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
53
Indexes and GROUP BY
(rev_page_id)
MariaDB [nlwiktionary]> EXPLAIN SELECT rev_page, count(*) FROM
revision GROUP BY rev_pageG
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: revision
type: index
possible_keys: NULL
key: rev_page_id
key_len: 8
ref: NULL
rows: 192388
Extra: Using index
1 row in set (0.00 sec)
The index does not produce any
advantage for filtering (there is
no WHERE clause)
The index does not produce any
advantage for filtering (there is
no WHERE clause)
However, thanks to it we avoid a
sort and a temporary table
However, thanks to it we avoid a
sort and a temporary table
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
54
type: index, loose index scan and
covering index (1/3)
node_id version k v
234234344545 1 leaves deciduous
234234344546 3 name Northolt Road
234234344548 5 gps:latitude 490018321N
234234344549 6 access uncontrolled
234234344550 1 editor JOSM
234234344551 9 name Big Ben
234234344552 1 source survey
234234344557 1 name London Plane
CarlsbergCarlsberg
recyclingrecycling
Accurate as
of 2010
Accurate as
of 2010
Gwynne
Place
Gwynne
Place
Manor PlaceManor Place
treetree
490018321N490018321N
deciduousdeciduous
London PlaneLondon Plane
surveysurvey
Big BenBig Ben
JOSMJOSM
Northolt RoadNortholt Road
uncontrolleduncontrolled
London
Borough of
Southwark
London
Borough of
Southwark
With 'type:index', all rows are
read in index order (full index
scan)
With 'type:index', all rows are
read in index order (full index
scan)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
55
type: index, loose index scan and
covering index (2/3)
node_id version k v
234234344545 1 leaves deciduous
234234344546 3 name Northolt Road
234234344548 5 gps:latitude 490018321N
234234344549 6 access uncontrolled
234234344550 1 editor JOSM
234234344551 9 name Big Ben
234234344552 1 source survey
234234344557 1 name London Plane
CarlsbergCarlsberg
recyclingrecycling
Accurate as
of 2010
Accurate as
of 2010
Gwynne
Place
Gwynne
Place
Manor PlaceManor Place
treetree
490018321N490018321N
deciduousdeciduous
London PlaneLondon Plane
surveysurvey
Big BenBig Ben
JOSMJOSM
Northolt RoadNortholt Road
uncontrolleduncontrolled
London
Borough of
Southwark
London
Borough of
Southwark
If we have in addition 'Using
index for group-by' we have the
loose index scan optimization
If we have in addition 'Using
index for group-by' we have the
loose index scan optimization
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
56
Loose Index Scan Example
MariaDB [nlwiktionary]> EXPLAIN SELECT rev_page,
max(rev_timestamp) FROM revision GROUP BY rev_pageG
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: revision
type: range
possible_keys: NULL
key: page_timestamp
key_len: 4
ref: NULL
rows: 9769
Extra: Using index for group-by
1 row in set (0.00 sec)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
57
type: index, loose index scan and
covering index (3/3)
node_id version k v
234234344545 1 leaves deciduous
234234344546 3 name Northolt Road
234234344548 5 gps:latitude 490018321N
234234344549 6 access uncontrolled
234234344550 1 editor JOSM
234234344551 9 name Big Ben
234234344552 1 source survey
234234344557 1 name London Plane
CarlsbergCarlsberg
recyclingrecycling
Accurate as
of 2010
Accurate as
of 2010
Gwynne
Place
Gwynne
Place
Manor PlaceManor Place
treetree
490018321N490018321N
deciduousdeciduous
London PlaneLondon Plane
surveysurvey
Big BenBig Ben
JOSMJOSM
Northolt RoadNortholt Road
uncontrolleduncontrolled
London
Borough of
Southwark
London
Borough of
Southwark
If we have in addition 'Using
index' we have the covering index
optimization
If we have in addition 'Using
index' we have the covering index
optimization
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
58
Covering Index Example (1/3)
MariaDB [nlwiktionary]> ALTER TABLE revision DROP INDEX rev_page_id, drop index page_timestamp,
drop index page_user_timestamp;
Query OK, 0 rows affected (0.05 sec)
Records: 0 Duplicates: 0 Warnings: 0
MariaDB [nlwiktionary]> EXPLAIN SELECT count(DISTINCT rev_user) FROM revision WHERE rev_page =
790G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: revision
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 218384
Extra: Using where
1 row in set (0.00 sec)
MariaDB [nlwiktionary]> SELECT count(DISTINCT rev_user) FROM revision WHERE rev_page = 790G
*************************** 1. row ***************************
count(DISTINCT rev_user): 1
1 row in set (0.06 sec)
Let's start with no indexesLet's start with no indexes
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
59
Covering Index Example (2/3)
MariaDB [nlwiktionary]> ALTER TABLE revision ADD INDEX revision_rev_page(rev_page);
Query OK, 0 rows affected (0.44 sec)
Records: 0 Duplicates: 0 Warnings: 0
MariaDB [nlwiktionary]> EXPLAIN SELECT count(DISTINCT rev_user) FROM revision WHERE rev_page =
790G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: revision
type: ref
possible_keys: revision_rev_page
key: revision_rev_page
key_len: 4
ref: const
rows: 4863
Extra:
1 row in set (0.00 sec)
MariaDB [nlwiktionary]> SELECT count(DISTINCT rev_user) FROM revision WHERE rev_page = 790G
*************************** 1. row ***************************
count(DISTINCT rev_user): 1
1 row in set (0.01 sec)
Adding an index on rev_page
increases the speed due to
improved filtering
Adding an index on rev_page
increases the speed due to
improved filtering
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
60
Covering Index Example (3/3)
MariaDB [nlwiktionary]> ALTER TABLE revision ADD INDEX revision_rev_page_rev_user(rev_page,
rev_user);
Query OK, 0 rows affected (1.48 sec)
Records: 0 Duplicates: 0 Warnings: 0
MariaDB [nlwiktionary]> EXPLAIN SELECT count(DISTINCT rev_user) FROM revision WHERE rev_page =
790G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: revision
type: ref
possible_keys: revision_rev_page,revision_rev_page_rev_user
key: revision_rev_page_rev_user
key_len: 4
ref: const
rows: 4863
Extra: Using index
1 row in set (0.00 sec)
MariaDB [nlwiktionary]> SELECT count(DISTINCT rev_user) FROM revision WHERE rev_page = 790G
*************************** 1. row ***************************
count(DISTINCT rev_user): 1
1 row in set (0.00 sec)
rev_page, rev_user does not
increase the index
selectiveness, but allow to
return results directly from
the index
rev_page, rev_user does not
increase the index
selectiveness, but allow to
return results directly from
the index
The speed difference can be hugeThe speed difference can be huge
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
61
MULTI-COLUMN INDEXES
Query Optimization: From 0 to 10 (and up to 5.7)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
62
In many cases, conditions are
applied on more than one column
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision WHERE
rev_page = 790 and rev_timestamp < '2008'G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: revision
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 686822
Extra: Using where
1 row in set (0.00 sec)
Assuming there were no previously
created indexes, which would the
optimal one be?
Assuming there were no previously
created indexes, which would the
optimal one be?
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
63
Options for indexes
●
1 index on column (rev_page)
●
1 index on column (rev_timestamp)
●
2 indexes, 1 on (rev_page) and another on
(rev_timestamp)
●
1 multi-column index on (rev_page, rev_timestamp)
●
1 multi-column index on (rev_timestamp,rev_page)
Are these last 2 different from each other?
Would it depend on the query order?
Are these last 2 different from each other?
Would it depend on the query order?
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
64
A brief reminder about query parsing
SELECT * FROM revision WHERE rev_page = 790 and rev_timestamp < '2008'
SELECTSELECT
FieldsFields FROMFROM
revision.
rev_page
revision.
rev_page
==
(int constant)
790
(int constant)
790
revision.
rev_timest
amp
revision.
rev_timest
amp
<<
(string
constant)
'2008'
(string
constant)
'2008'
WHEREWHERE
revision.
rev_id
revision.
rev_id
... revisio
n
revisio
n
Order in the query is not
important
Order in the query is not
important
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
65
Index on (rev_page)
MariaDB [nlwiktionary]> ALTER TABLE revision ADD INDEX rev_page (rev_page);
Query OK, 0 rows affected (2.31 sec)
Records: 0 Duplicates: 0 Warnings: 0
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision WHERE rev_page = 790 and
rev_timestamp < '2008'G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: revision
type: ref
possible_keys: rev_page
key: rev_page
key_len: 4
ref: const
rows: 4863
Extra: Using where
1 row in set (0.00 sec)
Query time improves
significantly with this
index
Query time improves
significantly with this
index
Less rows are
scanned
Less rows are
scanned
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
66
Adding (rev_timestamp)
MariaDB [nlwiktionary]> ALTER TABLE revision ADD INDEX rev_timestamp
(rev_timestamp);
Query OK, 0 rows affected (1.77 sec)
Records: 0 Duplicates: 0 Warnings: 0
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision WHERE rev_page = 790
and rev_timestamp < '2008'G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: revision
type: ref
possible_keys: rev_page,rev_timestamp
key: rev_page
key_len: 4
ref: const
rows: 4863
Extra: Using where
1 row in set (0.01 sec)
rev_page is preferred
over rev_timestamp
rev_page is preferred
over rev_timestamp
In general, only one index can
be used per table access
In general, only one index can
be used per table access
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
67
Forcing the use of
(rev_timestamp)
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision FORCE
INDEX(rev_timestamp) WHERE rev_page = 790 and rev_timestamp <
'2008'G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: revision
type: range
possible_keys: rev_timestamp
key: rev_timestamp
key_len: 14
ref: NULL
rows: 343411
Extra: Using index condition; Using where
1 row in set (0.00 sec)
It is a range
access
It is a range
access
A lot more accessed rowsA lot more accessed rows
Forcing the index is worse than type:ALL!Forcing the index is worse than type:ALL!
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
68
Adding (rev_page,
rev_timestamp)MariaDB [nlwiktionary]> ALTER TABLE revision ADD INDEX
rev_page_rev_timestamp(rev_page, rev_timestamp);
Query OK, 0 rows affected (1.59 sec)
Records: 0 Duplicates: 0 Warnings: 0
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision WHERE rev_page = 790
and rev_timestamp < '2008'G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: revision
type: range
possible_keys: rev_page,rev_timestamp,rev_page_rev_timestamp
key: rev_page_rev_timestamp
key_len: 18
ref: NULL
rows: 1048
Extra: Using index condition
1 row in set (0.00 sec)
Reduced number of
rows scanned
Reduced number of
rows scanned
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
69
Is (rev_timestamp, rev_page) a
better option?MariaDB [nlwiktionary]> ALTER TABLE revision ADD INDEX rev_timestamp_rev_page
(rev_timestamp, rev_page);
Query OK, 0 rows affected (1.76 sec)
Records: 0 Duplicates: 0 Warnings: 0
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision WHERE rev_page = 790 and
rev_timestamp < '2008'G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: revision
type: range
possible_keys: rev_page,rev_timestamp,rev_page_rev_timestamp,rev_timestamp_rev_page
key: rev_page_rev_timestamp
key_len: 18
ref: NULL
rows: 1048
Extra: Using index condition
1 row in set (0.00 sec)
Previous index is still
preferred, why?
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
70
Forcing (rev_timestamp,
rev_page)
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision FORCE
INDEX(rev_timestamp_rev_page) WHERE rev_page = 790 and
rev_timestamp < '2008'G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: revision
type: range
possible_keys: rev_timestamp_rev_page
key: rev_timestamp_rev_page
key_len: 18
ref: NULL
rows: 343411
Extra: Using index condition
1 row in set (0.00 sec)
Only the first column is being
used effectively for filtering
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
71
A compound index produces a single
tree ordered by the 2 values
(23443, 2)(23443, 2)
(790, '2010')(790, '2010')
(54005,
'2016')
(54005,
'2016')
(15444,
'2011')
(15444,
'2011')
(790, '2012')(790, '2012')
(790, '2007')(790, '2007')
(84611, '2015')(84611, '2015')
(21702, '2014')(21702, '2014')
(1024, '2003')(1024, '2003')
(790, '2008')(790, '2008')
(46771, '2013')(46771, '2013')
(13605, '2006')(13605, '2006')
(790, '2011')(790, '2011')
(105, '2015')(105, '2015')
TABLETABLE
(12301, 1)(12301, 1)
rev_page = 790 and
rev_timestamp < '2008'
(rev_page,
rev_timestamp)
(rev_page,
rev_timestamp)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
72
The alternative index cannot be used
in such an effective way
('2008', 800)('2008', 800)
('2004', 24)('2004', 24)
('2014', 107)('2014', 107)
('2008', 155)('2008', 155)
('2004', 999)('2004', 999)
('2001', 276)('2001', 276)
('2015', 355)('2015', 355)
('2008', 790)('2008', 790)
('2005', 791)('2005', 791)
('2002', 205)('2002', 205)
('2010', 206)('2010', 206)
('2007', 201)('2007', 201)
('2004', 790)('2004', 790)
('2001', 105)('2001', 105)
TABLETABLE
('2006',
13605)
('2006',
13605)
(rev_timestamp,
rev_page)
(rev_timestamp,
rev_page)
rev_page = 790 and
rev_timestamp < '2008'
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
73
Order and column selection
• Range access using >, <, >=, <=, BETWEEN
can only be filtered once effectively, at the
end of an index
• When selecting indexes, prefer columns with
high cardinality (very selective)
– The optimal index can depend on the constants used
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
74
Use of "Handler_*" statistics
• They are post-execution statistics at row level
– Unlike EXPLAIN's "rows" column, they are exact, not a
guess
– They allow to compare query execution performance in
a deterministic way, independently of the execution
time
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
75
"Handler" Stats (indexed)
mysql> SHOW SESSION STATUS like 'Hand%';
+----------------------------+----------+
| Variable_name | Value |
+----------------------------+----------+
| Handler_commit | 80 |
| Handler_delete | 0 |
| Handler_discover | 0 |
| Handler_external_lock | 166 |
| Handler_mrr_init | 0 |
| Handler_prepare | 0 |
| Handler_read_first | 23 |
| Handler_read_key | 736212 |
| Handler_read_last | 0 |
| Handler_read_next | 22208001 |
| Handler_read_prev | 0 |
| Handler_read_rnd | 665215 |
| Handler_read_rnd_next | 14223297 |
| Handler_rollback | 0 |
| Handler_savepoint | 0 |
| Handler_savepoint_rollback | 0 |
| Handler_update | 66970 |
| Handler_write | 2869409 |
+----------------------------+----------+
18 rows in set (0.00 sec)
Number of times that the first entry
of an index was read. It may indicate
the number of full index scans
Number of times that the first entry
of an index was read. It may indicate
the number of full index scans
Number of time a row
has been retrieved
using an index
Number of time a row
has been retrieved
using an index
Next row has been
requested in index order
(typical for index scans or
ranges)
Next row has been
requested in index order
(typical for index scans or
ranges)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
76
"Handler" Stats (unindexed)
mysql> SHOW SESSION STATUS like 'Hand%';
+----------------------------+----------+
| Variable_name | Value |
+----------------------------+----------+
| Handler_commit | 80 |
| Handler_delete | 0 |
| Handler_discover | 0 |
| Handler_external_lock | 166 |
| Handler_mrr_init | 0 |
| Handler_prepare | 0 |
| Handler_read_first | 23 |
| Handler_read_key | 736212 |
| Handler_read_last | 0 |
| Handler_read_next | 22208001 |
| Handler_read_prev | 0 |
| Handler_read_rnd | 665215 |
| Handler_read_rnd_next | 14223297 |
| Handler_rollback | 0 |
| Handler_savepoint | 0 |
| Handler_savepoint_rollback | 0 |
| Handler_update | 66970 |
| Handler_write | 2869409 |
+----------------------------+----------+
18 rows in set (0.00 sec)
A row has been requested in a
specific position (typical for joins
or order by without indexes)
A row has been requested in a
specific position (typical for joins
or order by without indexes)
Request tp read the
next row in “table
order” (typical for full
table scans)
Request tp read the
next row in “table
order” (typical for full
table scans)
Insertions in SELECTS may
indicate temporary tables
Insertions in SELECTS may
indicate temporary tables
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
77
Comparing statistics of the
previous indexes (no indexes)MariaDB [nlwiktionary]> FLUSH STATUS;
Query OK, 0 rows affected (0.00 sec)
MariaDB [nlwiktionary]> SELECT * FROM revision IGNORE INDEX(rev_page, rev_timestamp, rev_page_rev_timestamp,
rev_timestamp_rev_page) WHERE rev_page = 790 and rev_timestamp < '2008';
1049 rows in set (0.58 sec)
MariaDB [nlwiktionary]> SHOW STATUS like 'Hand%';
+----------------------------+--------+
| Variable_name | Value |
+----------------------------+--------+
| Handler_commit | 1 |
| Handler_delete | 0 |
…
| Handler_read_first | 0 |
| Handler_read_key | 0 |
| Handler_read_last | 0 |
| Handler_read_next | 0 |
| Handler_read_prev | 0 |
| Handler_read_rnd | 0 |
| Handler_read_rnd_deleted | 0 |
| Handler_read_rnd_next | 820309 |
| Handler_rollback | 0 |
…
| Handler_update | 0 |
| Handler_write | 0 |
+----------------------------+--------+
25 rows in set (0.00 sec)
Typical result for a
full table scan
Typical result for a
full table scan
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
78
Index on (rev_page)
MariaDB [nlwiktionary]> SHOW STATUS like 'Hand%';
+----------------------------+-------+
| Variable_name | Value |
+----------------------------+-------+
| Handler_commit | 1 |
| Handler_delete | 0 |
…
| Handler_read_first | 0 |
| Handler_read_key | 1 |
| Handler_read_last | 0 |
| Handler_read_next | 4864 |
| Handler_read_prev | 0 |
| Handler_read_rnd | 0 |
| Handler_read_rnd_deleted | 0 |
| Handler_read_rnd_next | 0 |
| Handler_rollback | 0 |
…
| Handler_update | 0 |
| Handler_write | 0 |
+----------------------------+-------+
25 rows in set (0.01 sec)
Then, scan them one by one in
index order
Then, scan them one by one in
index order
Using the index, request the
first row with rev_page=790
Using the index, request the
first row with rev_page=790
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
79
Index on (rev_timestamp)
MariaDB [nlwiktionary]> SHOW STATUS like 'Hand%';
+----------------------------+---------+
| Variable_name | Value |
+----------------------------+---------+
| Handler_commit | 1 |
| Handler_delete | 0 |
…
| Handler_read_first | 0 |
| Handler_read_key | 1 |
| Handler_read_last | 0 |
| Handler_read_next | 199155 |
| Handler_read_prev | 0 |
| Handler_read_rnd | 0 |
| Handler_read_rnd_deleted | 0 |
| Handler_read_rnd_next | 0 |
| Handler_rollback | 0 |
…
| Handler_update | 0 |
| Handler_write | 0 |
+----------------------------+---------+
25 rows in set (0.00 sec)
Then, scan them one by one in
index order (more are matched)
Then, scan them one by one in
index order (more are matched)
Using the index, request the first
row where rev_timestamp<2008
Using the index, request the first
row where rev_timestamp<2008
Let's ignore ICP for nowLet's ignore ICP for now
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
80
Index on (rev_page,
rev_timestamp)MariaDB [nlwiktionary]> SHOW STATUS like 'Hand%';
+----------------------------+-------+
| Variable_name | Value |
+----------------------------+-------+
| Handler_commit | 1 |
| Handler_delete | 0 |
…
| Handler_read_first | 0 |
| Handler_read_key | 1 |
| Handler_read_last | 0 |
| Handler_read_next | 1049 |
| Handler_read_prev | 0 |
| Handler_read_rnd | 0 |
| Handler_read_rnd_deleted | 0 |
| Handler_read_rnd_next | 0 |
| Handler_rollback | 0 |
…
| Handler_update | 0 |
| Handler_write | 0 |
+----------------------------+-------+
25 rows in set (0.00 sec)
Rows scanned == Rows returnedRows scanned == Rows returned
With both conditions covered, we
can find the actual first row that
matches the condition using the
index
With both conditions covered, we
can find the actual first row that
matches the condition using the
index
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
81
Index on (rev_timestamp,
rev_page), no ICPMariaDB [nlwiktionary]> SHOW STATUS like 'Hand%';
+----------------------------+---------+
| Variable_name | Value |
+----------------------------+---------+
| Handler_commit | 1 |
| Handler_delete | 0 |
…
| Handler_read_first | 0 |
| Handler_read_key | 1 |
| Handler_read_last | 0 |
| Handler_read_next | 199155 |
| Handler_read_prev | 0 |
| Handler_read_rnd | 0 |
| Handler_read_rnd_deleted | 0 |
| Handler_read_rnd_next | 0 |
| Handler_rollback | 0 |
…
| Handler_update | 0 |
| Handler_write | 0 |
+----------------------------+---------+
25 rows in set (0.00 sec)
Assuming no ICP, exact same
results than with (rev_timestamp).
The extra column does not help.
Also, EXPLAIN's row count was
very off.
Assuming no ICP, exact same
results than with (rev_timestamp).
The extra column does not help.
Also, EXPLAIN's row count was
very off.
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
82
Redundant Indexes
● Creating all 4 previous indexes in production
is not a great idea
– "Left-most index prefix" allows, for
example (rev_page, rev_timestamp) doing
everything you can do with (rev_page)
– If two indexes have equal selectivity,
MySQL chooses the shortest one
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
83
"Left-most index" Example
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision FORCE
INDEX(rev_page_rev_timestamp) WHERE rev_page = 790G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: revision
type: ref
possible_keys: rev_page_rev_timestamp
key: rev_page_rev_timestamp
key_len: 4
ref: const
rows: 4863
Extra:
1 row in set (0.00 sec)
Only the first column is usedOnly the first column is used
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
84
Duplicate Indexes
●
It is very easy to create indexes with the same
exact definition (same columns and ordering)
– Set a convention for index naming (e.g
tablename_column1_column2_idx) – MySQL does
not allow 2 indexes with the same identifier
– Since MySQL 5.6, an warning is thrown if a
duplicate index is created
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
85
pt-duplicate-index-checker
$ pt-duplicate-key-checker h=127.0.0.1,P=5621,u=msandbox,p=msandbox
[…]
# rev_timestamp is a left-prefix of rev_timestamp_rev_page
# Key definitions:
# KEY `rev_timestamp` (`rev_timestamp`),
# KEY `rev_timestamp_rev_page` (`rev_timestamp`,`rev_page`)
# Column types:
# `rev_timestamp` binary(14) not null default '00000000000000'
# `rev_page` int(10) unsigned not null
# To remove this duplicate index, execute:
ALTER TABLE `nlwiktionary`.`revision` DROP INDEX `rev_timestamp`;
# rev_page is a left-prefix of rev_page_rev_timestamp
# Key definitions:
# KEY `rev_page` (`rev_page`),
# KEY `rev_page_rev_timestamp` (`rev_page`,`rev_timestamp`),
# Column types:
# `rev_page` int(10) unsigned not null
# `rev_timestamp` binary(14) not null default '00000000000000'
# To remove this duplicate index, execute:
ALTER TABLE `nlwiktionary`.`revision` DROP INDEX `rev_page`;
# ###################################################### Summary of indexes
########################################
# Size Duplicate Indexes 15478317
# Total Duplicate Indexes 4
# Total Indexes 285
Simple tool to check
redundant and
duplicate indexes
Simple tool to check
redundant and
duplicate indexes
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
86
"OR"-style conditions over the
same column
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision WHERE
rev_page = 790 OR rev_page = 795 OR rev_page = 1024G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: revision
type: range
possible_keys: rev_page,rev_page_rev_timestamp
key: rev_page
key_len: 4
ref: NULL
rows: 4890
Extra: Using index condition; Using where
1 row in set (0.01 sec)
Equivalent to:
SELECT * FROM revision WHERE
rev_page IN (790, 795, 1024)
Equivalent to:
SELECT * FROM revision WHERE
rev_page IN (790, 795, 1024)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
87
Handlers on "IN" / "OR"
conditions over the same column+----------------------------+-------+
| Variable_name | Value |
+----------------------------+-------+
| Handler_commit | 1 |
| Handler_delete | 0 |
…
| Handler_prepare | 0 |
| Handler_read_first | 0 |
| Handler_read_key | 3 |
| Handler_read_last | 0 |
| Handler_read_next | 4891 |
| Handler_read_prev | 0 |
| Handler_read_rnd | 0 |
| Handler_read_rnd_deleted | 0 |
| Handler_read_rnd_next | 0 |
| Handler_rollback | 0 |
…
| Handler_update | 0 |
| Handler_write | 0 |
+----------------------------+-------+
25 rows in set (0.00 sec)
Despite identifying themselves
as “range”s, the execution is
slightly different, one index dive
(similar to a ref) is done per
value. This can be an issue in
conditions with thousands of
items.
Despite identifying themselves
as “range”s, the execution is
slightly different, one index dive
(similar to a ref) is done per
value. This can be an issue in
conditions with thousands of
items.
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
88
"OR"-style conditions over
different columns
● We cannot use a single index efficiently for
both conditions
– We can scan both conditions separatelly
and mix the results, discarding duplicates
– Or use an index for one condition and not
for the other
– Index merge allows to use two indexes for
a single table access simultaneously
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
89
Index Merge Example
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision WHERE
rev_page = 790 or rev_timestamp < '2004'G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: revision
type: index_merge
possible_keys: rev_page,rev_timestamp,rev_page_rev_timestamp,
rev_timestamp_rev_page
key: rev_page,rev_timestamp
key_len: 4,14
ref: NULL
rows: 4871
Extra: Using sort_union(rev_page,rev_timestamp); Using
where
1 row in set (0.00 sec)
Both indexes are used, then
combined using the "union"
operation
Both indexes are used, then
combined using the "union"
operation
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
90
INDEX_MERGE Issues
● Sometimes it is faster to to execute the
sentence using UNION:
– This is specially true with (UNION ALL)
since MySQL 5.7, if you do not care about
duplicates
● There are also interseccion merges, but
multi-column indexes are preferred
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
91
Disabling optimizer features (I)
●
The optimizer_switch variable allows enabling and
disablig globally or per session many query
optimizer features:
MariaDB [nlwiktionary]> SHOW VARIABLES like 'optimizer_switch'G
*************************** 1. row ***************************
Variable_name: optimizer_switch
Value:
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersec
tion=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_cond
ition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on
,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,parti
al_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=
off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join
_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination
=on,extended_keys=on,exists_to_in=on
1 row in set (0.00 sec)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
92
Deshabilitar características del
optimizador (II)MariaDB [nlwiktionary]> SET optimizer_switch='index_merge_sort_union=off';
Query OK, 0 rows affected (0.00 sec)
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision WHERE rev_page = 790
or rev_timestamp < '2004'G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: revision
type: ALL
possible_keys:
rev_page,rev_timestamp,rev_page_rev_timestamp,rev_timestamp_rev_page
key: NULL
key_len: NULL
ref: NULL
rows: 686822
Extra: Using where
1 row in set (0.00 sec)
This will only have effect for
the current session.
This will only have effect for
the current session.
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
93
What happens if we have two
ranges?
●
As seen previously, we cannot use efficiently two
range types on the same table access. Alternatives:
– Use only one index for the most selective column
– Use index condition pushdown to get an
advantage
– Change one of the two ranges into a discrete "IN"
comparison/bucketize with a new column
– Use quadtrees or R-TREEs (spatial indexing)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
94
Example of Bucketizing (I)
MariaDB [nlwiktionary]> EXPLAIN SELECT count(*) FROM revision
WHERE rev_timestamp < '2008' AND rev_len > 5500G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: revision
type: ALL
possible_keys: rev_timestamp,rev_timestamp_rev_page
key: NULL
key_len: NULL
ref: NULL
rows: 686822
Extra: Using where
1 row in set (0.00 sec)
Looks like only an index on
(rev_timestamp) or (rev_len)
would be useful as we have 2
ranges.
Looks like only an index on
(rev_timestamp) or (rev_len)
would be useful as we have 2
ranges.
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
95
Example of Bucketizing (II)
MariaDB [nlwiktionary]> ALTER TABLE revision ADD COLUMN
rev_len_cat int;
Query OK, 0 rows affected (38.28 sec)
Records: 0 Duplicates: 0 Warnings: 0
MariaDB [nlwiktionary]> UPDATE revision set rev_len_cat =
IF(rev_len < 10000, rev_len div 1000, 10);
Query OK, 820308 rows affected (15.19 sec)
Rows matched: 820308 Changed: 820308 Warnings: 0
MariaDB [nlwiktionary]> ALTER TABLE revision ADD INDEX
rev_len_cat_rev_timestamp (rev_len_cat, rev_timestamp);
Query OK, 0 rows affected (2.11 sec)
Records: 0 Duplicates: 0 Warnings: 0
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
96
Example of Bucketizing (III)
MariaDB [nlwiktionary]> EXPLAIN SELECT count(*) FROM revision WHERE
rev_timestamp < '2008' AND rev_len > 5500 AND rev_len_cat IN (5, 6,
7, 8, 9, 10)G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: revision
type: range
possible_keys:
rev_timestamp,rev_timestamp_rev_page,rev_len_cat_rev_timestamp
key: rev_len_cat_rev_timestamp
key_len: 19
ref: NULL
rows: 4442
Extra: Using where
1 row in set (0.00 sec)
We did some transformations
to both the structure and the
query.
We did some transformations
to both the structure and the
query.
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
97
Example of Index Condition
PushdownMariaDB [nlwiktionary]> ALTER TABLE revision ADD INDEX
rev_len_rev_timestamp(rev_len, rev_timestamp);
Query OK, 0 rows affected (1.77 sec)
Records: 0 Duplicates: 0 Warnings: 0
MariaDB [nlwiktionary]> SET optimizer_switch='index_condition_pushdown=on'; EXPLAIN
SELECT * FROM revision WHERE rev_timestamp < '2008' AND rev_len > 5500G
Query OK, 0 rows affected (0.00 sec)
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: revision
type: range
possible_keys: rev_timestamp,rev_timestamp_rev_page,rev_len_rev_timestamp
key: rev_len_rev_timestamp
key_len: 5
ref: NULL
rows: 38744
Extra: Using index condition
1 row in set (0.00 sec)
Index condition pushdown
(ICP) eanbles the engines to
use extra parts of the index
while avoiding costly row
movements to and from the
SQL layer
Index condition pushdown
(ICP) eanbles the engines to
use extra parts of the index
while avoiding costly row
movements to and from the
SQL layer
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
98
ICP Issues
●
Differences in execution time is more significative
when the extra column condition is very selective
(getting 5x the original performance)
●
ICP is ignored when using covering Index, making
the performance worse
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
99
Does LIMIT improve the
performance? (I)
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page ORDER BY page_touchedG
*************************** 1. row ***************************
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 90956
Extra: Using filesort
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page ORDER BY page_touched LIMIT 10G
*************************** 1. row ***************************
type: index
possible_keys: NULL
key: page_page_touched
key_len: 14
ref: NULL
rows: 10
Extra:
1 row in set (0.00 sec)
In some cases it can be
essential to allow
effective usage of the
indexes
In some cases it can be
essential to allow
effective usage of the
indexes
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
100
Does LIMIT improve the
performance? (II)MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision ORDER BY rev_commentG
*************************** 1. row ***************************
[...] type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 817636
Extra: Using filesort
1 row in set (0.00 sec)
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision ORDER BY rev_comment LIMIT 10G
*************************** 1. row ***************************
[…] table: revision
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 817636
Extra: Using filesort
1 row in set (0.00 sec)
In other cases, it has no
effect on the scanned
rows (just on the
returned ones)
In other cases, it has no
effect on the scanned
rows (just on the
returned ones)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
101
Does LIMIT improve the
performance? (I)MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page ORDER BY page_title LIMIT 100G
*************************** 1. row ***************************
type: index
possible_keys: NULL
key: page_title
key_len: 257
ref: NULL
rows: 100
Extra:
1 row in set (0.00 sec)
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page ORDER BY page_title LIMIT 10000, 100G
*************************** 1. row ***************************
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 90956
Extra: Using filesort
1 row in set (0.00 sec)
In this case,
performance will vary
depending on the
offset (not ideal)
In this case,
performance will vary
depending on the
offset (not ideal)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
102
Can we filter and sort at the same
time using indexes?
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision WHERE
rev_comment='' ORDER BY rev_timestamp ASCG
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: revision
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 817636
Extra: Using where; Using filesort
1 row in set (0.00 sec)
This query is slow
because a) the full
table scan
This query is slow
because a) the full
table scan
b) Required sort
after filtering
b) Required sort
after filtering
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
103
Adding and index on
(rev_comment, rev_timestamp)MariaDB [nlwiktionary]> ALTER TABLE revision ADD INDEX
rev_comment_rev_timestamp (rev_comment, rev_timestamp);
Query OK, 0 rows affected (3.19 sec)
Records: 0 Duplicates: 0 Warnings: 0
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision WHERE rev_comment=''
ORDER BY rev_timestamp ASCG
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: revision
type: ref
possible_keys: rev_comment_rev_timestamp
key: rev_comment_rev_timestamp
key_len: 769
ref: const
rows: 266462
Extra: Using index condition; Using where
1 row in set (0.00 sec)
Both type: ALL and
filesort have
disappeared
Both type: ALL and
filesort have
disappeared
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
104
This is not always possible
MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision WHERE
rev_len > 5500 ORDER BY rev_timestamp ASCG
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: revision
type: range
possible_keys: rev_len_rev_timestamp
key: rev_len_rev_timestamp
key_len: 5
ref: NULL
rows: 38744
Extra: Using index condition; Using filesort
1 row in set (0.00 sec)
The range makes impossible
to use the index optimally
for the the ORDER BY: either
we filter (rev_len) or sort
(rev_timestamp)
The range makes impossible
to use the index optimally
for the the ORDER BY: either
we filter (rev_len) or sort
(rev_timestamp)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
105
A Strange Game. The Only
Winning Move is Not to Play
mysql-5.6.21 (osm) > SELECT * FROM nodes FORCE
INDEX(version_idx) WHERE version < 15 ORDER BY changeset_id;
/* type: range, Using filesort */
2859673 rows in set (30.58 sec)
mysql-5.6.21 (osm) > SELECT * FROM nodes FORCE
INDEX(changeset_id_idx) WHERE version < 15 ORDER BY
changeset_id;
/* type: index */
2859673 rows in set (30.92 sec)
mysql-5.6.21 (osm) > SELECT * FROM nodes WHERE version < 15
ORDER BY changeset_id;
/* type: ALL, Using filesort */
2859673 rows in set (16.54 sec)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
106
MyISAM Internals
node_id versio k v
234234344545 1 leaves deciduous
(empty row)
234234344548 5 gps:latitude 490018321N
234234344549 6 access uncontrolled
(empty row)
234234344551 9 name Big Ben
234234344552 1 source survey
234234344557 1 name London Plane
234234344552 2 source survey
234234344557 2 name London Plane
CarlsbergCarlsberg
recyclingrecycling
Accurate as
of 2010
Accurate as
of 2010
Gwynne
Place
Gwynne
Place
Manor PlaceManor Place
treetree
490018321N490018321N
deciduousdeciduous
London PlaneLondon Plane
surveysurvey
Big BenBig Ben
JOSMJOSM
Northolt RoadNortholt Road
uncontrolleduncontrolled
London
Borough of
Southwark
London
Borough of
Southwark
Data (revision.MYD)Index (part of revision.MYI)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
107
InnoDB Internals (PRIMARY)
Data
clustered
always
using the
primary
key
Data
clustered
always
using the
primary
key
244
208
105
476
356
702
605
811
771
702
476
244
version k v
1 leaves deciduous
3 name Northolt Road
5 gps:latitu 490018321N
6 access uncontrolled
1 editor JOSM
9 name Big Ben
2 source survey
1 name London Plane
7 amenity pub
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
108
InnoDB Internals (Secondary)
6
3
1
1
1
1
3
2
6
5
9
7
PK
356
105
702
811
476
208
Secondary
indexes
contain the
primary key
value
Secondary
indexes
contain the
primary key
value
PK / Datosíndice
(version)
244
208
105
476
356
702
605
811
771
702
476
244
version k v
1 leaves deciduous
3 name Northolt Road
5 gps:latitu 490018321N
6 access uncontrolled
1 editor JOSM
9 name Big Ben
2 source survey
1 name London Plane
7 amenity pub
605
244
771
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
109
Consequences of using InnoDB (I)
●
Every table should have a primary key
– If one is not defined, MySQL will choose an
available NOT NULL unique key
– If that is not possible, an internal 6-byte row
identifier will be generated (not user-accesible)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
110
Consequences of using
InnoDB (II)
●
Inserting in primary key order is much faster
– Less fragmentation/page-split
– Usage of "batch" mode, improving insert speed
●
Using auto-increment keys as primary keys can be
a good idea for InnoDB
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
111
Consequences of using
InnoDB (III)
• A very long primary key may increment
substantially the size of secondary keys
– Int or bigint types are recommended instead of UUIDs
or other long strings
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
112
Differences in size
mysql-5.6.21 (osm) > CREATE
TABLE pk_int (id int
PRIMARY KEY auto_increment,
a int,
b int,
c int,
d int);
Query OK, 0 rows affected
(0.16 sec)
mysql-5.6.21 (osm) > CREATE
TABLE pk_uuid (id char(36)
PRIMARY KEY,
a int,
b int,
c int,
d int);
Query OK, 0 rows affected
(0.04 sec)
pk_int pk_uuid
0
8500000
17000000
25500000
34000000
42500000
12,582,912
20,971,520
13,631,488
32,505,856
.ibd size (no secondary indexes) .ibd size (with secondary indexes)
bytes
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
113
Extended primary key
optimization
●
As the primary key is part of all seconady keys,
this can be used “for free”:
– For row filtering (since MySQL 5.6)
– To return results in primary key order
– To avoid reading data from the table (covering
index)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
114
Extended Primary Key Example
mysql-5.6.21 (osm) > EXPLAIN SELECT node_id FROM nodes WHERE
changeset_id = 24284 and node_id <> 146472942G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: nodes
type: range
possible_keys: PRIMARY,changeset_id_idx
key: changeset_id_idx
key_len: 16
ref: NULL
rows: 50
Extra: Using where; Using index
1 row in set (0.07 sec)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
115
FULLTEXT SEARCH
Query Optimization: From 0 to 10 (and up to 5.7)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
116
Fuzzy Search of
“gloucester/Gloucester’s/etc”
●
“Typical” way to solve this:
mysql-5.7.5 (osm) >
SELECT way_id as id, v
FROM way_tags
WHERE v like '%gloucester%';
425 rows in set (0.46 sec)
Too slowToo slow
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
117
Let’s Add an Index
mysql-5.7.5 (osm) > ALTER TABLE way_tags ADD INDEX(v);
Query OK, 0 rows affected (6.44 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql-5.7.5 (osm) > SELECT ...;
425 rows in set (0.38 sec)
mysql-5.7.5 (osm) > EXPLAIN SELECT way as type, way_id as
id, v FROM way_tags WHERE v like '%gloucester%';
+----+.+-------+---------------+------+---------+------+---------+----------+--------------------------+
| id |.| type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+.+-------+---------------+------+---------+------+---------+----------+--------------------------+
| 1 |.| index | NULL | v_2 | 767 | NULL | 1333338 | 11.11 | Using where; Using index |
+----+.+-------+---------------+------+---------+------+---------+----------+--------------------------+
1 row in set, 1 warning (0.01 sec)
Still slow, why?Still slow, why?
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
118
Fulltext Index
mysql-5.7.5 (osm) > ALTER TABLE way_tags add FULLTEXT index(v);
Query OK, 0 rows affected (3.20 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql-5.7.5 (osm) > SELECT ...;
425 rows in set (0.00 sec)
mysql-5.7.5 (osm) > EXPLAIN SELECT 'way' as type, way_id as id, v
FROM way_tags WHERE MATCH(v) AGAINST ('+gloucester*' IN BOOLEAN
MODE);
+----+.+----------+---------------+------+---------+-------+------+----------+-----------------------------------+
| id |.| type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+.+----------+---------------+------+---------+-------+------+----------+-----------------------------------+
| 1 |.| fulltext | v | v | 0 | const | 1 | 100.00 | Using where; Ft_hints: no_ranking |
+----+.+----------+---------------+------+---------+-------+------+----------+-----------------------------------+
1 row in set, 1 warning (0.00 sec)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
119
Newer Fulltext Optimizations
mysql-5.5.40 (osm) > EXPLAIN SELECT count(*) FROM way_tags_myisam WHERE MATCH(v) AGAINST('gloucester');
+----+-------------+-----------------+----------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------------+----------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | way_tags_myisam | fulltext | v | v | 0 | | 1 | Using where |
+----+-------------+-----------------+----------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)
mysql-5.5.40 (osm) > SHOW STATUS like 'Hand%';
+----------------------------+-------+
| Variable_name | Value |
+----------------------------+-------+
| Handler_commit | 0 |
| Handler_delete | 0 |
...
| Handler_read_first | 0 |
| Handler_read_key | 0 |
| Handler_read_last | 0 |
| Handler_read_next | 425 |
| Handler_read_prev | 0 |
| Handler_read_rnd | 0 |
| Handler_read_rnd_next | 0 |
...
| Handler_update | 0 |
| Handler_write | 0 |
+----------------------------+-------+
16 rows in set (0.00 sec)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
120
Newer Fulltext Optimizations
(cont.)mysql-5.7.5 (osm) > EXPLAIN SELECT count(*) FROM way_tags WHERE MATCH(v) AGAINST('gloucester');
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+------------------------------+
| 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Select tables optimized away |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+------------------------------+
1 row in set, 1 warning (0.00 sec)
mysql-5.7.5 (osm) > SHOW STATUS like 'Hand%';
+----------------------------+-------+
| Variable_name | Value |
+----------------------------+-------+
| Handler_commit | 1 |
| Handler_delete | 0 |
...
| Handler_read_first | 0 |
| Handler_read_key | 0 |
| Handler_read_last | 0 |
| Handler_read_next | 0 |
| Handler_read_prev | 0 |
| Handler_read_rnd | 0 |
| Handler_read_rnd_next | 0 |
...
| Handler_update | 0 |
| Handler_write | 0 |
+----------------------------+-------+
18 rows in set (0.00 sec)
It’s
counting
directly
from the
FULLTEXT
index
It’s
counting
directly
from the
FULLTEXT
index
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
121
Open Issues and Limitations
● No postfix support (wildcards)
● Simple Ranking (and different from MyISAM)
● No stemming support
● Some multi-language limitations
More on FULLTEXT InnoDB support:
http://www.drdobbs.com/database/full-text-search-with-innodb/231902587
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
122
Alternatives
●
Apache Lucene
– Solr
– Elasticsearch
●
Sphinx
– SphinxSE
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
123
JOINS
Query Optimization: From 0 to 10 (and up to 5.7)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
124
(Block) Nested Loop Join
●
Until MySQL 5.5 there was only one algorithm to
execute a JOIN:
node_id version lat lon
1 1 52 0.5
1 2 52 0.5
2 1 51 1
3 1 53 1.5
node_id version k v
1 1 name Big Benn
1 1 tourism attraction
1 2 name Big Ben
1 2 tourism attraction
3 1 name London Eye
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
125
Extra Access type: eq_ref
mysql-5.6.21 (osm) > EXPLAIN SELECT * FROM nodes JOIN node_tags
USING(node_id, version) WHERE node_tags.v= 'Big Ben'G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: node_tags
type: ref
possible_keys: PRIMARY,v_idx
key: v_idx
key_len: 767
ref: const
rows: 1
Extra: Using where; Using index
*************************** 2. row ***************************
id: 1
select_type: SIMPLE
table: nodes
type: eq_ref
possible_keys: PRIMARY,version_idx
key: PRIMARY
key_len: 16
ref: osm.node_tags.node_id,osm.node_tags.version
rows: 1
Extra: NULL
2 rows in set (0.00 sec)
eq_ref is similar to ref, but
allows faster JOINS
because, by using a unique
key, it only has to search
one row for each previous
result
eq_ref is similar to ref, but
allows faster JOINS
because, by using a unique
key, it only has to search
one row for each previous
result
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
126
JOIN Optimization
●
Two main goals:
– Perform an effective filtering on each table
access, if possible using indexes
– Perform the access in the most efficient table
order
●
When joining 3 or more tables in a star schema,
the "covering index" strategy can have a huge
impact
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
127
Example: optimize this JOIN (I)
SELECT n.node_id, n.latitude, n.longitude
FROM way_nodes w_n
JOIN way_tags w_t
ON w_n.way_id = w_t.way_id and
w_n.version = w_t.version
JOIN nodes n
ON w_n.node_id = n.node_id
JOIN node_tags n_t
ON n.node_id = n_t.node_id and
n.version = n_t.version
WHERE w_t.k = 'building' and
n_t.k = 'entrance' and
n_t.v = 'main';
We start without
secondary indexes
We start without
secondary indexes
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
128
Example: optimize this JOIN (II)
************************ 1. row ************************
id: 1
select_type: SIMPLE
table: w_t
type: index
possible_keys: PRIMARY
key: PRIMARY
key_len: 783
ref: NULL
rows: 1335702
Extra: Using where; Using index
************************ 2. row ************************
id: 1
select_type: SIMPLE
table: w_n
type: ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 16
ref: osm.w_t.way_id,osm.w_t.version
rows: 3
Extra: NULL
mysql-5.6.21 (osm) > SELECT …
858 rows in set (9.00 sec)
************************ 3. row ************************
id: 1
select_type: SIMPLE
table: n_t
type: ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 8
ref: osm.w_n.node_id
rows: 1
Extra: Using where
************************ 4. row ************************
id: 1
select_type: SIMPLE
table: n
type: eq_ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 16
ref: osm.w_n.node_id,osm.n_t.version
rows: 1
Extra: Using index
4 rows in set (0.01 sec)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
129
Example: optimize this JOIN (III)
mysql-5.6.21 (osm) > ALTER TABLE way_tags ADD
INDEX k_idx(k);
Query OK, 0 rows affected (4.80 sec)
Records: 0 Duplicates: 0 Warnings: 0
Creating an index
on way_tags.k
Creating an index
on way_tags.k
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
130
Example: optimize this JOIN (IV)
********************** 1. row **********************
id: 1
select_type: SIMPLE
table: w_t
type: ref
possible_keys: PRIMARY,k_idx
key: k_idx
key_len: 767
ref: const
rows: 452274
Extra: Using where; Using index
********************** 2. row **********************
id: 1
select_type: SIMPLE
table: w_n
type: ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 16
ref: osm.w_t.way_id,osm.w_t.version
rows: 3
Extra: NULL
mysql-5.6.21 (osm) > SELECT …
858 rows in set (8.58 sec)
It seems like the index
is not very useful
It seems like the index
is not very useful
********************** 3. row **********************
id: 1
select_type: SIMPLE
table: n_t
type: ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 8
ref: osm.w_n.node_id
rows: 1
Extra: Using where
********************** 4. row **********************
id: 1
select_type: SIMPLE
table: n
type: eq_ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 16
ref: osm.w_n.node_id,osm.n_t.version
rows: 1
Extra: NULL
4 rows in set (0.00 sec)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
131
Example: optimize this JOIN (V)
mysql-5.6.21 (osm) > ALTER TABLE node_tags ADD
INDEX k_idx(k);
Query OK, 0 rows affected (2.82 sec)
Records: 0 Duplicates: 0 Warnings: 0
The order does not seem
to be adequate, let's try
adding an index to start
by accessing node_tags
The order does not seem
to be adequate, let's try
adding an index to start
by accessing node_tags
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
132
Example: optimize this JOIN (VI)
********************** 1. row **********************
id: 1
select_type: SIMPLE
table: w_t
type: ref
possible_keys: PRIMARY,k_idx
key: k_idx
key_len: 767
ref: const
rows: 452274
Extra: Using where; Using index
********************** 2. row **********************
id: 1
select_type: SIMPLE
table: w_n
type: ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 16
ref: osm.w_t.way_id,osm.w_t.version
rows: 3
Extra: NULL
mysql-5.6.21 (osm) > SELECT …
858 rows in set (7.33 sec)
********************** 3. row **********************
id: 1
select_type: SIMPLE
table: n_t
type: ref
possible_keys: PRIMARY,k_idx
key: PRIMARY
key_len: 8
ref: osm.w_n.node_id
rows: 1
Extra: Using where
********************** 4. row **********************
id: 1
select_type: SIMPLE
table: n
type: eq_ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 16
ref: osm.w_n.node_id,osm.n_t.version
rows: 1
Extra: NULL
4 rows in set (0.00 sec)
It keeps using
the wrong
order, even if
we delete the
w_t.k_idx
index
It keeps using
the wrong
order, even if
we delete the
w_t.k_idx
index
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
133
Example: optimize this JOIN (VII)
SELECT STRAIGHT_JOIN n.node_id, n.latitude, n.longitude
FROM node_tags n_t
JOIN nodes n
ON n.node_id = n_t.node_id and
n.version = n_t.version
JOIN way_nodes w_n
ON w_n.node_id = n.node_id
JOIN way_tags w_t
ON w_n.way_id = w_t.way_id and
w_n.version = w_t.version
WHERE w_t.k = 'building' and
n_t.k = 'entrance' and
n_t.v = 'main';
Let's see why rewriting it
into this query
Let's see why rewriting it
into this query
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
134
Example: optimize this JOIN (VIII)
********************** 1. row **********************
id: 1
select_type: SIMPLE
table: n_t
type: ref
possible_keys: PRIMARY,k_idx
key: k_idx
key_len: 767
ref: const
rows: 2390
Extra: Using index condition; Using where
********************** 2. row **********************
id: 1
select_type: SIMPLE
table: n
type: eq_ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 16
ref: osm.n_t.node_id,osm.n_t.version
rows: 1
Extra: NULL
There is no index
on w_n that would
allow efficient
access
There is no index
on w_n that would
allow efficient
access
********************** 3. row **********************
id: 1
select_type: SIMPLE
table: w_n
type: ALL
possible_keys: PRIMARY
key: NULL
key_len: NULL
ref: NULL
rows: 3597858
Extra: Using where; Using join buffer (Block
Nested Loop)
********************** 4. row **********************
id: 1
select_type: SIMPLE
table: w_t
type: eq_ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 783
ref: osm.w_n.way_id,osm.w_n.version,const
rows: 1
Extra: Using where; Using index
4 rows in set (0.00 sec)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
135
Example: optimize this JOIN (IX)
mysql-5.6.21 (osm) > ALTER TABLE way_nodes ADD
INDEX node_id_idx(node_id);
Query OK, 0 rows affected (17.77 sec)
Records: 0 Duplicates: 0 Warnings: 0
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
136
Example: optimize this JOIN (X)
********************** 1. row **********************
id: 1
select_type: SIMPLE
table: n_t
type: ref
possible_keys: PRIMARY,k_idx
key: k_idx
key_len: 767
ref: const
rows: 2390
Extra: Using index condition; Using where
********************** 2. row **********************
id: 1
select_type: SIMPLE
table: n
type: eq_ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 16
ref: osm.n_t.node_id,osm.n_t.version
rows: 1
Extra: NULL
mysql-5.6.21 (osm) > SELECT …
858 rows in set (0.73 sec)
Now it starts by
the right table
(without
STRAIGHT_JOIN)
Now it starts by
the right table
(without
STRAIGHT_JOIN)
********************** 3. row **********************
id: 1
select_type: SIMPLE
table: w_n
type: ref
possible_keys: PRIMARY,node_id_idx
key: node_id_idx
key_len: 8
ref: osm.n_t.node_id
rows: 1
Extra: Using index
********************** 4. row **********************
id: 1
select_type: SIMPLE
table: w_t
type: eq_ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 783
ref: osm.w_n.way_id,osm.w_n.version,const
rows: 1
Extra: Using where; Using index
4 rows in set (0.04 sec)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
137
Example: optimize this JOIN (XI)
************************* 1. row *************************
id: 1
select_type: SIMPLE
table: n_t
type: ref
possible_keys: PRIMARY,k_idx,k_v_idx
key: k_v_idx
key_len: 1534
ref: const,const
rows: 900
Extra: Using where; Using index
************************* 2. row *************************
id: 1
select_type: SIMPLE
table: n
type: eq_ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 16
ref: osm.n_t.node_id,osm.n_t.version
rows: 1
Extra: NULL
mysql-5.6.21 (osm) > SELECT ...
858 rows in set (0.02 sec)
An index on (k,v) is
even better
An index on (k,v) is
even better
************************ 3. row ************************
id: 1
select_type: SIMPLE
table: w_n
type: ref
possible_keys: PRIMARY,node_id_idx
key: node_id_idx
key_len: 8
ref: osm.n_t.node_id
rows: 1
Extra: Using index
************************ 4. row ************************
id: 1
select_type: SIMPLE
table: w_t
type: eq_ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 783
ref: osm.w_n.way_id,osm.w_n.version,const
rows: 1
Extra: Using where; Using index
4 rows in set (0.00 sec)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
138
“New” JOIN methods
●
MySQL 5.6 added:
– Batch Key Access
●
MariaDB has since 5.3:
– Batch Key Access
– Hash Joins
– Slightly modified versions of the above ones
(with “incremental” buffers to join 3 or more
tables)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
139
Multi-range read
• This optimization orders results obtained
from a secondary key in primary key/physical
order before accessing the rows
– It may help exection time of queries when disk-bound
– It requires tunning of the read_rnd_buffer_size (size of
the buffer used for ordering the results)
• BKA JOINs are based on the mrr optimization
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
140
MRR Example (I)
mysql-5.6.21 (osm) > EXPLAIN SELECT * FROM nodes WHERE timestamp >=
'2013-07-01 00:00:00' AND timestamp < '2014-01-01 00:00:00'G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: nodes
type: range
possible_keys: nodes_timestamp_idx
key: nodes_timestamp_idx
key_len: 5
ref: NULL
rows: 429684
Extra: Using index condition; Using MRR
1 row in set (0.02 sec)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
141
MRR example (II)
[restart]
mysql> SET optimizer_switch='mrr=off';
mysql> SELECT * FROM nodes WHERE timestamp >= '2013-07-01 00:00:00' AND timestamp <
'2014-01-01 00:00:00';
205617 rows in set (5.16 sec)
mysql> SELECT * FROM nodes WHERE timestamp >= '2013-07-01 00:00:00' AND timestamp <
'2014-01-01 00:00:00';
205617 rows in set (0.60 sec)
[restart]
mysql> SET read_rnd_buffer_size=50 * 1024 * 1024;
mysql> SELECT * FROM nodes WHERE timestamp >= '2013-07-01 00:00:00' AND timestamp <
'2014-01-01 00:00:00';
205617 rows in set (2.39 sec)
mysql> SELECT * FROM nodes WHERE timestamp >= '2013-07-01 00:00:00' AND timestamp <
'2014-01-01 00:00:00';
205617 rows in set (0.73 sec)
“Cold” results are
significantly better with
mrr (but it can impact
negatively, too)
“Cold” results are
significantly better with
mrr (but it can impact
negatively, too)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
142
Batch Key Access
node_id version lat lon
1 1 52 0.5
1 2 52 0.5
2 1 51 1
3 1 53 1.5
node_id version k v
1 1 name Big Benn
1 1 tourism attraction
1 2 name Big Ben
1 2 tourism attraction
3 1 amenity cafe
Buffer
sorted in
physical/PK
order
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
143
Hash Joins
• Only work for equi-joins
node_id version lat lon
1 1 52 0.5
1 2 52 0.5
2 1 51 1
3 1 53 1.5
node_id version k v
1 1 name Big Benn
1 1 tourism attraction
1 2 name Big Ben
1 2 tourism attraction
3 1 amenity cafe
Hash table
for faster
access to
rows
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
144
MySQL Configuration
• BKA requires changes of default optimizer
configuration:
mysql-5.7.5 (osm) > SET optimizer_switch= 'mrr=on';
mysql-5.7.5 (osm) > SET optimizer_switch= 'mrr_cost_based=off';
mysql-5.7.5 (osm) > SET optimizer_switch= 'batch_key_access=on';
– Additionally, configuring the join_buffer_size adequately
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
145
MariaDB configuration
mariadb-10.0.14 (osm) > SET optimizer_switch = 'join_cache_incremental=on';
mariadb-10.0.14 (osm) > SET optimizer_switch = 'join_cache_hashed=on';
mariadb-10.0.14 (osm) > SET optimizer_switch = 'join_cache_bka=on';
- Enabled by default
mariadb-10.0.14 (osm) > SET join_cache_level = 3 (for hash joins)
mariadb-10.0.14 (osm) > SET join_cache_level = 5 (for BKA)
- Also, configure join_buffer_size appropriately.
- Hash joins, like BKA, are highly dependent on disk-bound DBs to be
effective due to the extra overhead
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
146
Nested Loop Join (cold buffers
buffer_pool=100MB, join_buffer=4M)
mariadb-10.0.14 (osm) > EXPLAIN SELECT
changeset_id, count(*) FROM changesets JOIN nodes
on changesets.id = nodes.changeset_id GROUP BY
visibleG
******************** 1. row ********************
id: 1
select_type: SIMPLE
table: changesets
type: index
possible_keys: PRIMARY
key: PRIMARY
key_len: 8
ref: NULL
rows: 69115
Extra: Using index; Using temporary; Using
filesort
******************** 2. row ********************
id: 1
select_type: SIMPLE
table: nodes
type: ref
possible_keys: changeset_id
key: changeset_id
key_len: 8
ref: osm.changesets.id
rows: 19
Extra:
2 rows in set (0.00 sec)
mariadb-10.0.14 (osm) > SELECT visible, count(*)
FROM changesets JOIN nodes on changesets.id =
nodes.changeset_id GROUP BY visible;
+---------+----------+
| visible | count(*) |
+---------+----------+
| 1 | 2865312 |
+---------+----------+
1 row in set (32.86 sec)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
147
Hash Join (cold buffers,
buffer_pool=100M, join_buffer=4M)
mariadb-10.0.14 (osm) > EXPLAIN SELECT
changeset_id, count(*) FROM changesets JOIN
nodes on changesets.id = nodes.changeset_id
GROUP BY visibleG
******************** 1. row ********************
id: 1
select_type: SIMPLE
table: changesets
type: index
possible_keys: PRIMARY
key: PRIMARY
key_len: 8
ref: NULL
rows: 69115
Extra: Using index; Using temporary;
Using filesort
******************** 2. row ********************
id: 1
select_type: SIMPLE
table: nodes
type: hash_ALL
possible_keys: changeset_id
key: #hash#changeset_id
key_len: 8
ref: osm.changesets.id
rows: 2781732
Extra: Using join buffer (flat, BNLH join)
2 rows in set (0.00 sec)
mariadb-10.0.14 (osm) > SELECT visible, count(*)
FROM changesets JOIN nodes on changesets.id =
nodes.changeset_id GROUP BY visible;
+---------+----------+
| visible | count(*) |
+---------+----------+
| 1 | 2865312 |
+---------+----------+
1 row in set (6.66 sec)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
148
SUBQUERIES
Query Optimization: From 0 to 10 (and up to 5.7)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
149
Access types:
unique_subquery/index_subquery
mysql-5.6.21 (osm) > EXPLAIN SELECT
* FROM node_tags WHERE v = 'Big Ben'
and node_id NOT IN (SELECT node_id
FROM nodes WHERE tile < 100000000)G
************** 1. row **************
id: 1
select_type: PRIMARY
table: node_tags
type: ref
possible_keys: v_idx
key: v_idx
key_len: 767
ref: const
rows: 1
Extra: Using where; Using
index
Unique
subquery
is similar,
but using a
unique or
primary
key
Unique
subquery
is similar,
but using a
unique or
primary
key
************** 2. row **************
id: 2
select_type: DEPENDENT SUBQUERY
table: nodes
type: index_subquery
possible_keys: PRIMARY,nodes_tile_idx
key: PRIMARY
key_len: 8
ref: func
rows: 1
Extra: Using where
2 rows in set (0.00 sec)
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
150
Subqueries in MySQL
●
MySQL versions traditionally had very bad press
regarding subquries
– It was common to recommend rewriting them
(when possible) into JOINS
●
Since MySQL 5.6, its query execution plans have
improved significantly
© 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0
Query Optimization: From 0 to 10 (and up to 5.7)
151
Lazy Materialization of derived
tables
●
Option available since MySQL 5.6
– Improves the execution time of EXPLAIN (it no
longer needs to execute subqueries)
– Derived tables can be indexed automatically at
execution time to improve its performance
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)
Query optimization: from 0 to 10 (and up to 5.7)

More Related Content

What's hot

High Performance Hibernate JavaZone 2016
High Performance Hibernate JavaZone 2016High Performance Hibernate JavaZone 2016
High Performance Hibernate JavaZone 2016Vlad Mihalcea
 
Mysql 57-upcoming-changes
Mysql 57-upcoming-changesMysql 57-upcoming-changes
Mysql 57-upcoming-changesMorgan Tocker
 
MySQL Replication — Advanced Features / Петр Зайцев (Percona)
MySQL Replication — Advanced Features / Петр Зайцев (Percona)MySQL Replication — Advanced Features / Петр Зайцев (Percona)
MySQL Replication — Advanced Features / Петр Зайцев (Percona)Ontico
 
MySQL Performance Schema in 20 Minutes
 MySQL Performance Schema in 20 Minutes MySQL Performance Schema in 20 Minutes
MySQL Performance Schema in 20 MinutesSveta Smirnova
 
Performance Schema for MySQL Troubleshooting
Performance Schema for MySQL TroubleshootingPerformance Schema for MySQL Troubleshooting
Performance Schema for MySQL TroubleshootingSveta Smirnova
 
MySQL Performance Metrics that Matter
MySQL Performance Metrics that MatterMySQL Performance Metrics that Matter
MySQL Performance Metrics that MatterMorgan Tocker
 
MySQL shell and It's utilities - Praveen GR (Mydbops Team)
MySQL shell and It's utilities - Praveen GR (Mydbops Team)MySQL shell and It's utilities - Praveen GR (Mydbops Team)
MySQL shell and It's utilities - Praveen GR (Mydbops Team)Mydbops
 
MySQL 5.7 innodb_enhance_partii_20160527
MySQL 5.7 innodb_enhance_partii_20160527MySQL 5.7 innodb_enhance_partii_20160527
MySQL 5.7 innodb_enhance_partii_20160527Saewoong Lee
 
Why MySQL Replication Fails, and How to Get it Back
Why MySQL Replication Fails, and How to Get it BackWhy MySQL Replication Fails, and How to Get it Back
Why MySQL Replication Fails, and How to Get it BackSveta Smirnova
 
Intro ProxySQL
Intro ProxySQLIntro ProxySQL
Intro ProxySQLI Goo Lee
 
Parallel Replication in MySQL and MariaDB
Parallel Replication in MySQL and MariaDBParallel Replication in MySQL and MariaDB
Parallel Replication in MySQL and MariaDBMydbops
 
Proxysql ha plam_2016_2_keynote
Proxysql ha plam_2016_2_keynoteProxysql ha plam_2016_2_keynote
Proxysql ha plam_2016_2_keynoteMarco Tusa
 
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 ImprovementsMorgan Tocker
 
ProxySQL - High Performance and HA Proxy for MySQL
ProxySQL - High Performance and HA Proxy for MySQLProxySQL - High Performance and HA Proxy for MySQL
ProxySQL - High Performance and HA Proxy for MySQLRené Cannaò
 
Barcelona mysqlnd qc
Barcelona mysqlnd qcBarcelona mysqlnd qc
Barcelona mysqlnd qcAnis Berejeb
 

What's hot (20)

Zendcon zray
Zendcon zrayZendcon zray
Zendcon zray
 
High Performance Hibernate JavaZone 2016
High Performance Hibernate JavaZone 2016High Performance Hibernate JavaZone 2016
High Performance Hibernate JavaZone 2016
 
Mysql 57-upcoming-changes
Mysql 57-upcoming-changesMysql 57-upcoming-changes
Mysql 57-upcoming-changes
 
MySQL Replication — Advanced Features / Петр Зайцев (Percona)
MySQL Replication — Advanced Features / Петр Зайцев (Percona)MySQL Replication — Advanced Features / Петр Зайцев (Percona)
MySQL Replication — Advanced Features / Петр Зайцев (Percona)
 
MySQL Performance Schema in 20 Minutes
 MySQL Performance Schema in 20 Minutes MySQL Performance Schema in 20 Minutes
MySQL Performance Schema in 20 Minutes
 
Performance Schema for MySQL Troubleshooting
Performance Schema for MySQL TroubleshootingPerformance Schema for MySQL Troubleshooting
Performance Schema for MySQL Troubleshooting
 
MySQL Performance Metrics that Matter
MySQL Performance Metrics that MatterMySQL Performance Metrics that Matter
MySQL Performance Metrics that Matter
 
ProxySQL para mysql
ProxySQL para mysqlProxySQL para mysql
ProxySQL para mysql
 
MySQL shell and It's utilities - Praveen GR (Mydbops Team)
MySQL shell and It's utilities - Praveen GR (Mydbops Team)MySQL shell and It's utilities - Praveen GR (Mydbops Team)
MySQL shell and It's utilities - Praveen GR (Mydbops Team)
 
MySQL 5.7 innodb_enhance_partii_20160527
MySQL 5.7 innodb_enhance_partii_20160527MySQL 5.7 innodb_enhance_partii_20160527
MySQL 5.7 innodb_enhance_partii_20160527
 
Why MySQL Replication Fails, and How to Get it Back
Why MySQL Replication Fails, and How to Get it BackWhy MySQL Replication Fails, and How to Get it Back
Why MySQL Replication Fails, and How to Get it Back
 
Intro ProxySQL
Intro ProxySQLIntro ProxySQL
Intro ProxySQL
 
MySQL NoSQL APIs
MySQL NoSQL APIsMySQL NoSQL APIs
MySQL NoSQL APIs
 
MySQL 5.7 + JSON
MySQL 5.7 + JSONMySQL 5.7 + JSON
MySQL 5.7 + JSON
 
Scaling PHP web apps
Scaling PHP web appsScaling PHP web apps
Scaling PHP web apps
 
Parallel Replication in MySQL and MariaDB
Parallel Replication in MySQL and MariaDBParallel Replication in MySQL and MariaDB
Parallel Replication in MySQL and MariaDB
 
Proxysql ha plam_2016_2_keynote
Proxysql ha plam_2016_2_keynoteProxysql ha plam_2016_2_keynote
Proxysql ha plam_2016_2_keynote
 
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
 
ProxySQL - High Performance and HA Proxy for MySQL
ProxySQL - High Performance and HA Proxy for MySQLProxySQL - High Performance and HA Proxy for MySQL
ProxySQL - High Performance and HA Proxy for MySQL
 
Barcelona mysqlnd qc
Barcelona mysqlnd qcBarcelona mysqlnd qc
Barcelona mysqlnd qc
 

Viewers also liked

14. Query Optimization in DBMS
14. Query Optimization in DBMS14. Query Optimization in DBMS
14. Query Optimization in DBMSkoolkampus
 
7 convolutional codes
7 convolutional codes7 convolutional codes
7 convolutional codesVarun Raj
 
Error control coding bch, reed-solomon etc..
Error control coding   bch, reed-solomon etc..Error control coding   bch, reed-solomon etc..
Error control coding bch, reed-solomon etc..Madhumita Tamhane
 
Implementation of reed solomon codes basics
Implementation of reed solomon codes basicsImplementation of reed solomon codes basics
Implementation of reed solomon codes basicsRam Singh Yadav
 
Convolutional Codes And Their Decoding
Convolutional Codes And Their DecodingConvolutional Codes And Their Decoding
Convolutional Codes And Their DecodingKakali Saharia
 
Transaction Management - Lecture 11 - Introduction to Databases (1007156ANR)
Transaction Management - Lecture 11 - Introduction to Databases (1007156ANR)Transaction Management - Lecture 11 - Introduction to Databases (1007156ANR)
Transaction Management - Lecture 11 - Introduction to Databases (1007156ANR)Beat Signer
 
Instruction set of 8085
Instruction set  of 8085Instruction set  of 8085
Instruction set of 8085shiji v r
 
08. Object Oriented Database in DBMS
08. Object Oriented Database in DBMS08. Object Oriented Database in DBMS
08. Object Oriented Database in DBMSkoolkampus
 
12. Indexing and Hashing in DBMS
12. Indexing and Hashing in DBMS12. Indexing and Hashing in DBMS
12. Indexing and Hashing in DBMSkoolkampus
 
Transaction Management
Transaction Management Transaction Management
Transaction Management Visakh V
 
Transaction management and concurrency control
Transaction management and concurrency controlTransaction management and concurrency control
Transaction management and concurrency controlDhani Ahmad
 
Transaction management
Transaction managementTransaction management
Transaction managementrenuka_a
 
Query optimization
Query optimizationQuery optimization
Query optimizationdixitdavey
 
Distributed DBMS - Unit 8 - Distributed Transaction Management & Concurrency ...
Distributed DBMS - Unit 8 - Distributed Transaction Management & Concurrency ...Distributed DBMS - Unit 8 - Distributed Transaction Management & Concurrency ...
Distributed DBMS - Unit 8 - Distributed Transaction Management & Concurrency ...Gyanmanjari Institute Of Technology
 

Viewers also liked (19)

14. Query Optimization in DBMS
14. Query Optimization in DBMS14. Query Optimization in DBMS
14. Query Optimization in DBMS
 
Microfluidics project
Microfluidics projectMicrofluidics project
Microfluidics project
 
I Tlecture 13a
I Tlecture 13aI Tlecture 13a
I Tlecture 13a
 
7 convolutional codes
7 convolutional codes7 convolutional codes
7 convolutional codes
 
Bch codes
Bch codesBch codes
Bch codes
 
Error control coding bch, reed-solomon etc..
Error control coding   bch, reed-solomon etc..Error control coding   bch, reed-solomon etc..
Error control coding bch, reed-solomon etc..
 
BCH Codes
BCH CodesBCH Codes
BCH Codes
 
Implementation of reed solomon codes basics
Implementation of reed solomon codes basicsImplementation of reed solomon codes basics
Implementation of reed solomon codes basics
 
Convolutional codes
Convolutional codesConvolutional codes
Convolutional codes
 
Convolutional Codes And Their Decoding
Convolutional Codes And Their DecodingConvolutional Codes And Their Decoding
Convolutional Codes And Their Decoding
 
Transaction Management - Lecture 11 - Introduction to Databases (1007156ANR)
Transaction Management - Lecture 11 - Introduction to Databases (1007156ANR)Transaction Management - Lecture 11 - Introduction to Databases (1007156ANR)
Transaction Management - Lecture 11 - Introduction to Databases (1007156ANR)
 
Instruction set of 8085
Instruction set  of 8085Instruction set  of 8085
Instruction set of 8085
 
08. Object Oriented Database in DBMS
08. Object Oriented Database in DBMS08. Object Oriented Database in DBMS
08. Object Oriented Database in DBMS
 
12. Indexing and Hashing in DBMS
12. Indexing and Hashing in DBMS12. Indexing and Hashing in DBMS
12. Indexing and Hashing in DBMS
 
Transaction Management
Transaction Management Transaction Management
Transaction Management
 
Transaction management and concurrency control
Transaction management and concurrency controlTransaction management and concurrency control
Transaction management and concurrency control
 
Transaction management
Transaction managementTransaction management
Transaction management
 
Query optimization
Query optimizationQuery optimization
Query optimization
 
Distributed DBMS - Unit 8 - Distributed Transaction Management & Concurrency ...
Distributed DBMS - Unit 8 - Distributed Transaction Management & Concurrency ...Distributed DBMS - Unit 8 - Distributed Transaction Management & Concurrency ...
Distributed DBMS - Unit 8 - Distributed Transaction Management & Concurrency ...
 

Similar to Query optimization: from 0 to 10 (and up to 5.7)

Query Optimization with MySQL 5.7 and MariaDB 10: Even newer tricks
Query Optimization with MySQL 5.7 and MariaDB 10: Even newer tricksQuery Optimization with MySQL 5.7 and MariaDB 10: Even newer tricks
Query Optimization with MySQL 5.7 and MariaDB 10: Even newer tricksJaime Crespo
 
MySQL crash course by moshe kaplan
MySQL crash course by moshe kaplanMySQL crash course by moshe kaplan
MySQL crash course by moshe kaplanMoshe Kaplan
 
Big Data Seminar: Analytics, Hadoop, Map Reduce, Mongo and other great stuff
Big Data Seminar: Analytics, Hadoop, Map Reduce, Mongo and other great stuffBig Data Seminar: Analytics, Hadoop, Map Reduce, Mongo and other great stuff
Big Data Seminar: Analytics, Hadoop, Map Reduce, Mongo and other great stuffMoshe Kaplan
 
O365 Saturday - Deepdive SharePoint Client Side Rendering
O365 Saturday - Deepdive SharePoint Client Side RenderingO365 Saturday - Deepdive SharePoint Client Side Rendering
O365 Saturday - Deepdive SharePoint Client Side RenderingRiwut Libinuko
 
When and Why to Use MariaDB: New Features in 10.0 to 10.5
When and Why to Use MariaDB: New Features in 10.0 to 10.5When and Why to Use MariaDB: New Features in 10.0 to 10.5
When and Why to Use MariaDB: New Features in 10.0 to 10.5Ian Gilfillan
 
web2py:Web development like a boss
web2py:Web development like a bossweb2py:Web development like a boss
web2py:Web development like a bossFrancisco Ribeiro
 
Web Systems Architecture by Moshe Kaplan
Web Systems Architecture by Moshe KaplanWeb Systems Architecture by Moshe Kaplan
Web Systems Architecture by Moshe KaplanMoshe Kaplan
 
ZZ BC#7.5 asp.net mvc practice and guideline refresh!
ZZ BC#7.5 asp.net mvc practice  and guideline refresh! ZZ BC#7.5 asp.net mvc practice  and guideline refresh!
ZZ BC#7.5 asp.net mvc practice and guideline refresh! Chalermpon Areepong
 
Automating your php infrastructure with the zend server api
Automating your php infrastructure with the zend server apiAutomating your php infrastructure with the zend server api
Automating your php infrastructure with the zend server apiYonni Mendes
 
Optimize the obvious
Optimize the obviousOptimize the obvious
Optimize the obviousdrhenner
 
Apache Calcite Tutorial - BOSS 21
Apache Calcite Tutorial - BOSS 21Apache Calcite Tutorial - BOSS 21
Apache Calcite Tutorial - BOSS 21Stamatis Zampetakis
 
Web Development Foundation & Team Collaboration
Web Development Foundation & Team CollaborationWeb Development Foundation & Team Collaboration
Web Development Foundation & Team CollaborationSupanat Potiwarakorn
 
6 tips for improving ruby performance
6 tips for improving ruby performance6 tips for improving ruby performance
6 tips for improving ruby performanceEngine Yard
 
C# Advanced L09-HTML5+ASP
C# Advanced L09-HTML5+ASPC# Advanced L09-HTML5+ASP
C# Advanced L09-HTML5+ASPMohammad Shaker
 
Normalizing x pages web development
Normalizing x pages web development Normalizing x pages web development
Normalizing x pages web development Shean McManus
 
Intro to .NET for Government Developers
Intro to .NET for Government DevelopersIntro to .NET for Government Developers
Intro to .NET for Government DevelopersFrank La Vigne
 
Consuming REST Services in BizTalk 2010
Consuming REST Services in BizTalk 2010Consuming REST Services in BizTalk 2010
Consuming REST Services in BizTalk 2010Daniel Toomey
 

Similar to Query optimization: from 0 to 10 (and up to 5.7) (20)

Query Optimization with MySQL 5.7 and MariaDB 10: Even newer tricks
Query Optimization with MySQL 5.7 and MariaDB 10: Even newer tricksQuery Optimization with MySQL 5.7 and MariaDB 10: Even newer tricks
Query Optimization with MySQL 5.7 and MariaDB 10: Even newer tricks
 
MySQL crash course by moshe kaplan
MySQL crash course by moshe kaplanMySQL crash course by moshe kaplan
MySQL crash course by moshe kaplan
 
Big Data Seminar: Analytics, Hadoop, Map Reduce, Mongo and other great stuff
Big Data Seminar: Analytics, Hadoop, Map Reduce, Mongo and other great stuffBig Data Seminar: Analytics, Hadoop, Map Reduce, Mongo and other great stuff
Big Data Seminar: Analytics, Hadoop, Map Reduce, Mongo and other great stuff
 
MySQL 8.0.1 DMR
MySQL 8.0.1 DMRMySQL 8.0.1 DMR
MySQL 8.0.1 DMR
 
O365 Saturday - Deepdive SharePoint Client Side Rendering
O365 Saturday - Deepdive SharePoint Client Side RenderingO365 Saturday - Deepdive SharePoint Client Side Rendering
O365 Saturday - Deepdive SharePoint Client Side Rendering
 
When and Why to Use MariaDB: New Features in 10.0 to 10.5
When and Why to Use MariaDB: New Features in 10.0 to 10.5When and Why to Use MariaDB: New Features in 10.0 to 10.5
When and Why to Use MariaDB: New Features in 10.0 to 10.5
 
web2py:Web development like a boss
web2py:Web development like a bossweb2py:Web development like a boss
web2py:Web development like a boss
 
Web Systems Architecture by Moshe Kaplan
Web Systems Architecture by Moshe KaplanWeb Systems Architecture by Moshe Kaplan
Web Systems Architecture by Moshe Kaplan
 
ZZ BC#7.5 asp.net mvc practice and guideline refresh!
ZZ BC#7.5 asp.net mvc practice  and guideline refresh! ZZ BC#7.5 asp.net mvc practice  and guideline refresh!
ZZ BC#7.5 asp.net mvc practice and guideline refresh!
 
ASP.NET 4.0 Demo
ASP.NET 4.0 DemoASP.NET 4.0 Demo
ASP.NET 4.0 Demo
 
Automating your php infrastructure with the zend server api
Automating your php infrastructure with the zend server apiAutomating your php infrastructure with the zend server api
Automating your php infrastructure with the zend server api
 
Optimize the obvious
Optimize the obviousOptimize the obvious
Optimize the obvious
 
Apache Calcite Tutorial - BOSS 21
Apache Calcite Tutorial - BOSS 21Apache Calcite Tutorial - BOSS 21
Apache Calcite Tutorial - BOSS 21
 
Web Development Foundation & Team Collaboration
Web Development Foundation & Team CollaborationWeb Development Foundation & Team Collaboration
Web Development Foundation & Team Collaboration
 
6 tips for improving ruby performance
6 tips for improving ruby performance6 tips for improving ruby performance
6 tips for improving ruby performance
 
C# 4.0 - Whats New
C# 4.0 - Whats NewC# 4.0 - Whats New
C# 4.0 - Whats New
 
C# Advanced L09-HTML5+ASP
C# Advanced L09-HTML5+ASPC# Advanced L09-HTML5+ASP
C# Advanced L09-HTML5+ASP
 
Normalizing x pages web development
Normalizing x pages web development Normalizing x pages web development
Normalizing x pages web development
 
Intro to .NET for Government Developers
Intro to .NET for Government DevelopersIntro to .NET for Government Developers
Intro to .NET for Government Developers
 
Consuming REST Services in BizTalk 2010
Consuming REST Services in BizTalk 2010Consuming REST Services in BizTalk 2010
Consuming REST Services in BizTalk 2010
 

More from Jaime Crespo

Haciendo copias de seguridad de todo el conocimiento humano con python y soft...
Haciendo copias de seguridad de todo el conocimiento humano con python y soft...Haciendo copias de seguridad de todo el conocimiento humano con python y soft...
Haciendo copias de seguridad de todo el conocimiento humano con python y soft...Jaime Crespo
 
Backing up Wikipedia Databases
Backing up Wikipedia DatabasesBacking up Wikipedia Databases
Backing up Wikipedia DatabasesJaime Crespo
 
Query Optimization with MySQL 8.0 and MariaDB 10.3: The Basics
Query Optimization with MySQL 8.0 and MariaDB 10.3: The BasicsQuery Optimization with MySQL 8.0 and MariaDB 10.3: The Basics
Query Optimization with MySQL 8.0 and MariaDB 10.3: The BasicsJaime Crespo
 
Wikipedia Burgos devfest 2017
Wikipedia Burgos devfest 2017Wikipedia Burgos devfest 2017
Wikipedia Burgos devfest 2017Jaime Crespo
 
Scaling and hardware provisioning for databases (lessons learned at wikipedia)
Scaling and hardware provisioning for databases (lessons learned at wikipedia)Scaling and hardware provisioning for databases (lessons learned at wikipedia)
Scaling and hardware provisioning for databases (lessons learned at wikipedia)Jaime Crespo
 
MySQL Schema Design in Practice
MySQL Schema Design in PracticeMySQL Schema Design in Practice
MySQL Schema Design in PracticeJaime Crespo
 
MySQL at Wikipedia: How we do relational data at the Wikimedia Foundation
MySQL at Wikipedia: How we do relational data at the Wikimedia FoundationMySQL at Wikipedia: How we do relational data at the Wikimedia Foundation
MySQL at Wikipedia: How we do relational data at the Wikimedia FoundationJaime Crespo
 
Query Optimization with MySQL 5.6: Old and New Tricks - Percona Live London 2013
Query Optimization with MySQL 5.6: Old and New Tricks - Percona Live London 2013Query Optimization with MySQL 5.6: Old and New Tricks - Percona Live London 2013
Query Optimization with MySQL 5.6: Old and New Tricks - Percona Live London 2013Jaime Crespo
 
MySQL GUI Administration
MySQL GUI AdministrationMySQL GUI Administration
MySQL GUI AdministrationJaime Crespo
 
Software libre para gestión de proyectos
Software libre para gestión de proyectosSoftware libre para gestión de proyectos
Software libre para gestión de proyectosJaime Crespo
 
warptalk: Experiencia de usuario y usabilidad
warptalk: Experiencia de usuario y usabilidadwarptalk: Experiencia de usuario y usabilidad
warptalk: Experiencia de usuario y usabilidadJaime Crespo
 

More from Jaime Crespo (12)

Haciendo copias de seguridad de todo el conocimiento humano con python y soft...
Haciendo copias de seguridad de todo el conocimiento humano con python y soft...Haciendo copias de seguridad de todo el conocimiento humano con python y soft...
Haciendo copias de seguridad de todo el conocimiento humano con python y soft...
 
Backing up Wikipedia Databases
Backing up Wikipedia DatabasesBacking up Wikipedia Databases
Backing up Wikipedia Databases
 
Query Optimization with MySQL 8.0 and MariaDB 10.3: The Basics
Query Optimization with MySQL 8.0 and MariaDB 10.3: The BasicsQuery Optimization with MySQL 8.0 and MariaDB 10.3: The Basics
Query Optimization with MySQL 8.0 and MariaDB 10.3: The Basics
 
Wikipedia Burgos devfest 2017
Wikipedia Burgos devfest 2017Wikipedia Burgos devfest 2017
Wikipedia Burgos devfest 2017
 
Scaling and hardware provisioning for databases (lessons learned at wikipedia)
Scaling and hardware provisioning for databases (lessons learned at wikipedia)Scaling and hardware provisioning for databases (lessons learned at wikipedia)
Scaling and hardware provisioning for databases (lessons learned at wikipedia)
 
MySQL Schema Design in Practice
MySQL Schema Design in PracticeMySQL Schema Design in Practice
MySQL Schema Design in Practice
 
MySQL at Wikipedia: How we do relational data at the Wikimedia Foundation
MySQL at Wikipedia: How we do relational data at the Wikimedia FoundationMySQL at Wikipedia: How we do relational data at the Wikimedia Foundation
MySQL at Wikipedia: How we do relational data at the Wikimedia Foundation
 
Query Optimization with MySQL 5.6: Old and New Tricks - Percona Live London 2013
Query Optimization with MySQL 5.6: Old and New Tricks - Percona Live London 2013Query Optimization with MySQL 5.6: Old and New Tricks - Percona Live London 2013
Query Optimization with MySQL 5.6: Old and New Tricks - Percona Live London 2013
 
Why MySQL
Why MySQLWhy MySQL
Why MySQL
 
MySQL GUI Administration
MySQL GUI AdministrationMySQL GUI Administration
MySQL GUI Administration
 
Software libre para gestión de proyectos
Software libre para gestión de proyectosSoftware libre para gestión de proyectos
Software libre para gestión de proyectos
 
warptalk: Experiencia de usuario y usabilidad
warptalk: Experiencia de usuario y usabilidadwarptalk: Experiencia de usuario y usabilidad
warptalk: Experiencia de usuario y usabilidad
 

Recently uploaded

Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...stazi3110
 
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024StefanoLambiase
 
The Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfThe Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfPower Karaoke
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEEVICTOR MAESTRE RAMIREZ
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEOrtus Solutions, Corp
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityNeo4j
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxTier1 app
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantAxelRicardoTrocheRiq
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio, Inc.
 
Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Velvetech LLC
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software DevelopersVinodh Ram
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...gurkirankumar98700
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...OnePlan Solutions
 
Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)Hr365.us smith
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...soniya singh
 
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataBradBedford3
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)OPEN KNOWLEDGE GmbH
 
Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Andreas Granig
 
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)jennyeacort
 

Recently uploaded (20)

Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
 
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
 
The Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfThe Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdf
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEE
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered Sustainability
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service Consultant
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
 
Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software Developers
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...
 
Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)
 
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort ServiceHot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
 
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)
 
Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024
 
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
 

Query optimization: from 0 to 10 (and up to 5.7)

  • 1. Query Optimization: From 0 to 10 (and up to 5.7) © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) Jaime Crespo Percona Live Europe 2015 -Amsterdam, 21 Sep 2015- dbahire.com/pleu15
  • 2. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 2 Agenda – First 3 hours 1. Introduction 5. FULLTEXT Search 2. Access Types and Basic Indexing Techniques 6. Joins 3. Break 7. Subqueries 4. Multi-Column Indexing 8. Query Profiling
  • 3. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 3 Agenda – Last 3 hours 1. General Optimizer Improvements 6. SQL Mode Changes 2. Computed/Virtual Columns 7. GIS Improvements and JSON Type 3. Query Rewrite Plugins 8. Results and Conclusions 4. Break 9. Q&A 5. Optimizer Hints
  • 4. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 4 INTRODUCTION Query Optimization: From 0 to 10 (and up to 5.7)
  • 5. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 5 This is me fighting bad query performance ● Sr. Database Administrator at Wikimedia Foundation ● Used to work as a trainer for Oracle (MySQL), as a Consultant (Percona) and as a Freelance administrator (DBAHire.com)
  • 6. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 6 MySQL Versions • 5.1 no longer has official support • I will be showing you the results on mysql versions 5.5-5.7/10.1 • MySQL 5.7 and MariaDB 10.1 in RC with great new features
  • 7. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 7 Recently Added Features Related to Query Optimization • Index Condition Pushdown • Subquery Optimizations materialization and semijoin) • IN-to-EXISTS/EXISTS-to-IN • JOIN-to-WHERE • Multi-Range Read • Batched Key Access • Persistent InnoDB Statistics • UNION ALL optimization • Improved GIS support • EXPLAIN FORMAT=JSON • EXPLAIN INSERT/UPDATE/DELETE • Hash Join • New optimizer hints • New cost-based optimizer • Optimizer Trace • Filesort optimizations • Virtual/computed columns and “functional indexes” • New JSON type
  • 8. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 8 I Already Mentioned Some of Those Topics during the Last Years • Check my presentations here: http://www.slideshare.net/jynus/
  • 9. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 9 Example Application (I) • Wiktionary (and all Wikimedia project's data) is licensed under the Creative Commons BY-SA-2.5 License and is Copyright its Contributors
  • 10. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 10 Example Application (II) • OSM Database is licensed under the Open DataBase License and is Copyright OpenStreetMap Contributors
  • 11. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 11 Install the example databases ● Downloads and instructions at: http://dbahire.com/pleu15 – Requirements: a MySQL or MariaDB installation (MySQL Sandbox is suggested) – The wiktionary and OSM extracts ● Import them by doing: $ bzcat <file> | mysql <database>
  • 12. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 12 ACCESS TYPES AND BASIC INDEXING TECHNIQUES Query Optimization: From 0 to 10 (and up to 5.7)
  • 13. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 13 EXPLAIN ● Essential to understand the execution plan of our queries – Works on SELECTs, INSERTs, UPDATEs, REPLACEs, DELETEs and connections – Fully documented on: http://dev.mysql.com/doc/refman/5.6/en/expla in-output.html
  • 14. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 14 EXPLAIN Example MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page WHERE page_title = 'Dutch'; +------+-------------+-------+------+---------------+------ +---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +------+-------------+-------+------+---------------+------ +---------+------+------+-------------+ | 1 | SIMPLE | page | ALL | NULL | NULL | NULL | NULL | 90956 | Using where | +------+-------------+-------+------+---------------+------ +---------+------+------+-------------+ 1 row in set (0.00 sec) Difficult to see something Difficult to see something
  • 15. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 15 EXPLAIN Example (vertical format) MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page WHERE page_title = 'Dutch'G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: page type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 90956 Extra: Using where 1 row in set (0.00 sec) Use G for vertical formatting Use G for vertical formatting
  • 16. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 16 EXPLAIN Example (id) MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page WHERE page_title = 'Dutch'G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: page type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 90956 Extra: Using where 1 row in set (0.00 sec) Indicates hierarchy level, not execution order Indicates hierarchy level, not execution order
  • 17. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 17 EXPLAIN Example (select_type) MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page WHERE page_title = 'Dutch'G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: page type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 90956 Extra: Using where 1 row in set (0.00 sec) Not a subquery or a UNION Not a subquery or a UNION
  • 18. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 18 EXPLAIN Example (table) MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page WHERE page_title = 'Dutch'G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: page type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 90956 Extra: Using where 1 row in set (0.00 sec) Table scanned for this step Table scanned for this step
  • 19. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 19 EXPLAIN Example (type) MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page WHERE page_title = 'Dutch'G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: page type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 90956 Extra: Using where 1 row in set (0.00 sec) All rows are read for this table (FULL TABLE SCAN) All rows are read for this table (FULL TABLE SCAN)
  • 20. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 20 EXPLAIN Example (rows) MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page WHERE page_title = 'Dutch'G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: page type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 90956 Extra: Using where 1 row in set (0.00 sec) Estimated number of rows to be read (all table rows) Estimated number of rows to be read (all table rows)
  • 21. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 21 How to improve performance? ● Let's add an index on page.page_title: MariaDB [nlwiktionary]> ALTER TABLE page ADD INDEX page_title (page_title); Query OK, 0 rows affected (0.19 sec) Records: 0 Duplicates: 0 Warnings: 0 MariaDB [nlwiktionary]> SELECT * FROM page WHERE page_title = 'Dutch'; 1 row in set (0.11 sec)
  • 22. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 22 Index creation results (type) MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page WHERE page_title = 'Dutch'G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: page type: ref possible_keys: page_title key: page_title key_len: 257 ref: const rows: 1 Extra: Using index condition 1 row in set (0.00 sec) type: ref means that an equality comparison will be checked against an index and several results could be returned type: ref means that an equality comparison will be checked against an index and several results could be returned
  • 23. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 23 Index creation results (possible_keys and key) MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page WHERE page_title = 'Dutch'G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: page type: ref possible_keys: page_title key: page_title key_len: 257 ref: const rows: 1 Extra: Using index condition 1 row in set (0.00 sec) index(es) that the optimizer considered potentially useful, and final index chosen index(es) that the optimizer considered potentially useful, and final index chosen
  • 24. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 24 Index creation results (ref) MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page WHERE page_title = 'Dutch'G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: page type: ref possible_keys: page_title key: page_title key_len: 257 ref: const rows: 1 Extra: Using index condition 1 row in set (0.00 sec) Index is compared with a constant, not with another table Index is compared with a constant, not with another table
  • 25. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 25 Index creation results (rows) MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page WHERE page_title = 'Dutch'G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: page type: ref possible_keys: page_title key: page_title key_len: 257 ref: const rows: 1 Extra: Using index condition 1 row in set (0.00 sec) Only 1 row read. In this case, estimation is exact (thanks to index dive) Only 1 row read. In this case, estimation is exact (thanks to index dive)
  • 26. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 26 Index creation results (query time) MariaDB [nlwiktionary]> SELECT * FROM page WHERE page_title = 'Dutch'; 1 row in set (0.00 sec) Query time has been reduced substantially Query time has been reduced substantially
  • 27. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 27 Types of indexes ● BTREE – B-TREE in MyISAM, B+TREE in InnoDB ● HASH – Only available for MEMORY and NDB ● FULLTEXT – Inverted indexes in MyISAM and InnoDB ● SPATIAL – RTREEs in MyISAM and InnoDB
  • 28. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 28 Finding “Dutch” with a BTREE EtchEtch NastyNasty BossBoss GolfGolf LeekLeek SchoolSchool AvastAvast FreightFreight LandscapeLandscape RoverRover DutchDutch HarlemHarlem MaelstromMaelstrom WalrusWalrus TABLETABLE IcebergIceberg
  • 29. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 29 Finding “Dutch” with a BTREE EtchEtch NastyNasty BossBoss GolfGolf LeekLeek SchoolSchool AvastAvast FreightFreight LandscapeLandscape RoverRover DutchDutch HarlemHarlem MaelstromMaelstrom WalrusWalrus TABLETABLE IcebergIceberg
  • 30. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 30 Do indexes always work? (1/2) ● Can we use an index to make this query faster? SELECT * FROM page WHERE page_title like 'Spa%';
  • 31. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 31 It is a range MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page WHERE page_title like 'Spa%'G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: page type: range possible_keys: page_title key: page_title key_len: 257 ref: NULL rows: 94 Extra: Using index condition 1 row in set (0.00 sec) Despite not being an equality, we can use the index to find the values quickly Despite not being an equality, we can use the index to find the values quickly
  • 32. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 32 BTREE Indexes can be used for ranges, too EtchEtch NastyNasty BossBoss GolfGolf LeekLeek SchoolSchool AvastAvast FreightFreight LandscapeLandscape RoverRover DutchDutch HarlemHarlem MaelstromMaelstrom WalrusWalrus TABLETABLE IcebergIceberg
  • 33. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 33 Do indexes always work? (2/2) ● What about this other query? SELECT * FROM page WHERE page_title like '%utch';
  • 34. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 34 Let's check with EXPLAIN MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page WHERE page_title like '%utch'G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: page type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 93189 Extra: Using where 1 row in set (0.00 sec) No index can be used for filtering. A full table scan is performed. No index can be used for filtering. A full table scan is performed.
  • 35. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 35 BTREE Index EtchEtch NastyNasty BossBoss GolfGolf LeekLeek SchoolSchool AvastAvast FreightFreight LandscapeLandscape RoverRover DutchDutch HarlemHarlem MaelstromMaelstrom WalrusWalrus TABLETABLE IcebergIceberg ?
  • 36. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 36 Btree indexes usage ● Filtering – Equality (operator '=') – Ranges (BETWEEN … AND, >, <, >=, <=, like 'prefix%') – “EXISTS” operators: IN, OR on the same column ● Ordering – ORDER BY (indexed columns) – GROUP BY (indexed columns) ● Returning values directly from the index – Covering index – Functions like max(), min(), etc.
  • 37. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 37 type: const MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision WHERE rev_id = 2G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: revision type: const possible_keys: PRIMARY key: PRIMARY key_len: 4 ref: const rows: 1 Extra: 1 row in set (0.00 sec) 'const' is a special case of 'ref', when the index can assure that only 1 results can be returned (equality + primary key or unique key). It is faster. 'const' is a special case of 'ref', when the index can assure that only 1 results can be returned (equality + primary key or unique key). It is faster.
  • 38. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 38 type: NULL MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision WHERE rev_id = -1G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: NULL type: NULL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: NULL Extra: Impossible WHERE noticed after reading const tables 1 row in set (0.00 sec) 'NULL' is not really a plan, just an optimization that allow discarding immediately impossible conditions 'NULL' is not really a plan, just an optimization that allow discarding immediately impossible conditions
  • 39. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 39 type: ref_or_null MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM user WHERE user_email_token = '0' OR user_email_token IS NULLG *************************** 1. row *************************** id: 1 select_type: SIMPLE table: user type: ref_or_null possible_keys: user_email_token key: user_email_token key_len: 33 ref: const rows: 2 Extra: Using index condition; Using where 1 row in set (0.00 sec) Equivalent to 'ref', but also has into account NULL values Equivalent to 'ref', but also has into account NULL values
  • 40. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 40 type: range (using IN / OR) MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page WHERE page_title IN ('Dutch', 'English', 'Spanish')G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: page type: range possible_keys: page_title key: page_title key_len: 257 ref: NULL rows: 4 Extra: Using index condition 1 row in set (0.00 sec) Despite being a range, its execution is very different from ranges using like, between or inequality operators Despite being a range, its execution is very different from ranges using like, between or inequality operators
  • 41. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 41 Is this a bug? (1/2) MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page WHERE page_namespace = 2G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: page type: ref possible_keys: name_title key: name_title key_len: 4 ref: const rows: 45 Extra: 1 row in set (0.00 sec) An index is used to return pages with ns=2 An index is used to return pages with ns=2
  • 42. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 42 Is this a bug? (2/2) MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page WHERE page_namespace = 0G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: page type: ALL possible_keys: name_title key: NULL key_len: NULL ref: NULL rows: 7493 Extra: Using where 1 row in set (0.00 sec) The index is not used with ns=0 The index is not used with ns=0
  • 43. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 43 Using an index is sometimes suboptimal This point is not fixed, and depends on the hardware and buffer state This point is not fixed, and depends on the hardware and buffer state
  • 44. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 44 What index should we add to make this query faster? MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision WHERE left(rev_timestamp, 6) = '201509'G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: revision type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 163253 Extra: Using where 1 row in set (0.00 sec)
  • 45. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 45 The table has already an index on rev_timestamp MariaDB [nlwiktionary]> SHOW CREATE TABLE revisionG *************************** 1. row *************************** Table: revision Create Table: CREATE TABLE `revision` ( ... KEY `rev_timestamp` (`rev_timestamp`),
  • 46. Optimización de consultas con MySQL 5.6 © 2014 DBAHIRE.COM We need to rewrite the query MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision WHERE rev_timestamp >= '201509' and rev_timestamp < '201510'G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: revision type: range possible_keys: rev_timestamp key: rev_timestamp key_len: 14 ref: NULL rows: 7 Extra: Using index condition 1 row in set (0.00 sec)
  • 47. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 47 This transformation is not trivial or even possible in all cases MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision WHERE substr(rev_timestamp, 5, 2) = '09'G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: revision type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL Rows: 173154 Extra: Using where 1 row in set (0.00 sec) Can you think a way to improve this query? Can you think a way to improve this query?
  • 48. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 48 Indexes for Ordering MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page ORDER BY page_touched DESC LIMIT 10G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: page type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 8720 Extra: Using filesort 1 row in set (0.00 sec) "Using filesort" indicates that an ordering is needed before returning the results "Using filesort" indicates that an ordering is needed before returning the results
  • 49. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 49 If that is frequent, we can create an index on page_touched...[nlwiktionary]> ALTER TABLE page ADD INDEX page_page_touched(page_touched); Query OK, 0 rows affected (0.30 sec) Records: 0 Duplicates: 0 Warnings: 0 [nlwiktionary]> EXPLAIN SELECT * FROM page ORDER BY page_touched DESC LIMIT 10G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: page type: index possible_keys: NULL key: page_page_touched key_len: 14 ref: NULL rows: 10 Extra: 1 row in set (0.00 sec) The index does not produce any advantage for filtering The index does not produce any advantage for filtering However, it is very effective by helping avoiding the sort phase However, it is very effective by helping avoiding the sort phase
  • 50. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 50 It can return data in index order faster EtchEtch NastyNasty BossBoss GolfGolf LeekLeek SchoolSchool AvastAvast FreightFreight LandscapeLandscape RoverRover DutchDutch HarlemHarlem MaelstromMaelstrom WalrusWalrus TABLETABLE IcebergIceberg
  • 51. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 51 Indexes and GROUP BY (no indexes) MariaDB [nlwiktionary]> EXPLAIN SELECT rev_page, count(*) FROM revision IGNORE INDEX(rev_page_id, page_timestamp, page_user_timestamp) GROUP BY rev_pageG *************************** 1. row *************************** id: 1 select_type: SIMPLE table: revision type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 201094 Extra: Using temporary; Using filesort 1 row in set (0.00 sec) Without indexes, a temporary table is created to order results Without indexes, a temporary table is created to order results
  • 52. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 52 Trick: ORDER BY NULL avoids filesortMariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision GROUP BY substr(rev_timestamp, 5, 2) = '09'G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: revision type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 196824 Extra: Using temporary; Using filesort 1 row in set (0.00 sec) MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision GROUP BY substr(rev_timestamp, 5, 2) = '09' ORDER BY NULLG *************************** 1. row *************************** ... rows: 196871 Extra: Using temporary 1 row in set (0.00 sec) The advantage is not too big, but it avoids the filesort The advantage is not too big, but it avoids the filesort There is no good index in this case There is no good index in this case
  • 53. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 53 Indexes and GROUP BY (rev_page_id) MariaDB [nlwiktionary]> EXPLAIN SELECT rev_page, count(*) FROM revision GROUP BY rev_pageG *************************** 1. row *************************** id: 1 select_type: SIMPLE table: revision type: index possible_keys: NULL key: rev_page_id key_len: 8 ref: NULL rows: 192388 Extra: Using index 1 row in set (0.00 sec) The index does not produce any advantage for filtering (there is no WHERE clause) The index does not produce any advantage for filtering (there is no WHERE clause) However, thanks to it we avoid a sort and a temporary table However, thanks to it we avoid a sort and a temporary table
  • 54. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 54 type: index, loose index scan and covering index (1/3) node_id version k v 234234344545 1 leaves deciduous 234234344546 3 name Northolt Road 234234344548 5 gps:latitude 490018321N 234234344549 6 access uncontrolled 234234344550 1 editor JOSM 234234344551 9 name Big Ben 234234344552 1 source survey 234234344557 1 name London Plane CarlsbergCarlsberg recyclingrecycling Accurate as of 2010 Accurate as of 2010 Gwynne Place Gwynne Place Manor PlaceManor Place treetree 490018321N490018321N deciduousdeciduous London PlaneLondon Plane surveysurvey Big BenBig Ben JOSMJOSM Northolt RoadNortholt Road uncontrolleduncontrolled London Borough of Southwark London Borough of Southwark With 'type:index', all rows are read in index order (full index scan) With 'type:index', all rows are read in index order (full index scan)
  • 55. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 55 type: index, loose index scan and covering index (2/3) node_id version k v 234234344545 1 leaves deciduous 234234344546 3 name Northolt Road 234234344548 5 gps:latitude 490018321N 234234344549 6 access uncontrolled 234234344550 1 editor JOSM 234234344551 9 name Big Ben 234234344552 1 source survey 234234344557 1 name London Plane CarlsbergCarlsberg recyclingrecycling Accurate as of 2010 Accurate as of 2010 Gwynne Place Gwynne Place Manor PlaceManor Place treetree 490018321N490018321N deciduousdeciduous London PlaneLondon Plane surveysurvey Big BenBig Ben JOSMJOSM Northolt RoadNortholt Road uncontrolleduncontrolled London Borough of Southwark London Borough of Southwark If we have in addition 'Using index for group-by' we have the loose index scan optimization If we have in addition 'Using index for group-by' we have the loose index scan optimization
  • 56. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 56 Loose Index Scan Example MariaDB [nlwiktionary]> EXPLAIN SELECT rev_page, max(rev_timestamp) FROM revision GROUP BY rev_pageG *************************** 1. row *************************** id: 1 select_type: SIMPLE table: revision type: range possible_keys: NULL key: page_timestamp key_len: 4 ref: NULL rows: 9769 Extra: Using index for group-by 1 row in set (0.00 sec)
  • 57. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 57 type: index, loose index scan and covering index (3/3) node_id version k v 234234344545 1 leaves deciduous 234234344546 3 name Northolt Road 234234344548 5 gps:latitude 490018321N 234234344549 6 access uncontrolled 234234344550 1 editor JOSM 234234344551 9 name Big Ben 234234344552 1 source survey 234234344557 1 name London Plane CarlsbergCarlsberg recyclingrecycling Accurate as of 2010 Accurate as of 2010 Gwynne Place Gwynne Place Manor PlaceManor Place treetree 490018321N490018321N deciduousdeciduous London PlaneLondon Plane surveysurvey Big BenBig Ben JOSMJOSM Northolt RoadNortholt Road uncontrolleduncontrolled London Borough of Southwark London Borough of Southwark If we have in addition 'Using index' we have the covering index optimization If we have in addition 'Using index' we have the covering index optimization
  • 58. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 58 Covering Index Example (1/3) MariaDB [nlwiktionary]> ALTER TABLE revision DROP INDEX rev_page_id, drop index page_timestamp, drop index page_user_timestamp; Query OK, 0 rows affected (0.05 sec) Records: 0 Duplicates: 0 Warnings: 0 MariaDB [nlwiktionary]> EXPLAIN SELECT count(DISTINCT rev_user) FROM revision WHERE rev_page = 790G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: revision type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 218384 Extra: Using where 1 row in set (0.00 sec) MariaDB [nlwiktionary]> SELECT count(DISTINCT rev_user) FROM revision WHERE rev_page = 790G *************************** 1. row *************************** count(DISTINCT rev_user): 1 1 row in set (0.06 sec) Let's start with no indexesLet's start with no indexes
  • 59. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 59 Covering Index Example (2/3) MariaDB [nlwiktionary]> ALTER TABLE revision ADD INDEX revision_rev_page(rev_page); Query OK, 0 rows affected (0.44 sec) Records: 0 Duplicates: 0 Warnings: 0 MariaDB [nlwiktionary]> EXPLAIN SELECT count(DISTINCT rev_user) FROM revision WHERE rev_page = 790G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: revision type: ref possible_keys: revision_rev_page key: revision_rev_page key_len: 4 ref: const rows: 4863 Extra: 1 row in set (0.00 sec) MariaDB [nlwiktionary]> SELECT count(DISTINCT rev_user) FROM revision WHERE rev_page = 790G *************************** 1. row *************************** count(DISTINCT rev_user): 1 1 row in set (0.01 sec) Adding an index on rev_page increases the speed due to improved filtering Adding an index on rev_page increases the speed due to improved filtering
  • 60. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 60 Covering Index Example (3/3) MariaDB [nlwiktionary]> ALTER TABLE revision ADD INDEX revision_rev_page_rev_user(rev_page, rev_user); Query OK, 0 rows affected (1.48 sec) Records: 0 Duplicates: 0 Warnings: 0 MariaDB [nlwiktionary]> EXPLAIN SELECT count(DISTINCT rev_user) FROM revision WHERE rev_page = 790G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: revision type: ref possible_keys: revision_rev_page,revision_rev_page_rev_user key: revision_rev_page_rev_user key_len: 4 ref: const rows: 4863 Extra: Using index 1 row in set (0.00 sec) MariaDB [nlwiktionary]> SELECT count(DISTINCT rev_user) FROM revision WHERE rev_page = 790G *************************** 1. row *************************** count(DISTINCT rev_user): 1 1 row in set (0.00 sec) rev_page, rev_user does not increase the index selectiveness, but allow to return results directly from the index rev_page, rev_user does not increase the index selectiveness, but allow to return results directly from the index The speed difference can be hugeThe speed difference can be huge
  • 61. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 61 MULTI-COLUMN INDEXES Query Optimization: From 0 to 10 (and up to 5.7)
  • 62. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 62 In many cases, conditions are applied on more than one column MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision WHERE rev_page = 790 and rev_timestamp < '2008'G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: revision type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 686822 Extra: Using where 1 row in set (0.00 sec) Assuming there were no previously created indexes, which would the optimal one be? Assuming there were no previously created indexes, which would the optimal one be?
  • 63. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 63 Options for indexes ● 1 index on column (rev_page) ● 1 index on column (rev_timestamp) ● 2 indexes, 1 on (rev_page) and another on (rev_timestamp) ● 1 multi-column index on (rev_page, rev_timestamp) ● 1 multi-column index on (rev_timestamp,rev_page) Are these last 2 different from each other? Would it depend on the query order? Are these last 2 different from each other? Would it depend on the query order?
  • 64. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 64 A brief reminder about query parsing SELECT * FROM revision WHERE rev_page = 790 and rev_timestamp < '2008' SELECTSELECT FieldsFields FROMFROM revision. rev_page revision. rev_page == (int constant) 790 (int constant) 790 revision. rev_timest amp revision. rev_timest amp << (string constant) '2008' (string constant) '2008' WHEREWHERE revision. rev_id revision. rev_id ... revisio n revisio n Order in the query is not important Order in the query is not important
  • 65. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 65 Index on (rev_page) MariaDB [nlwiktionary]> ALTER TABLE revision ADD INDEX rev_page (rev_page); Query OK, 0 rows affected (2.31 sec) Records: 0 Duplicates: 0 Warnings: 0 MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision WHERE rev_page = 790 and rev_timestamp < '2008'G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: revision type: ref possible_keys: rev_page key: rev_page key_len: 4 ref: const rows: 4863 Extra: Using where 1 row in set (0.00 sec) Query time improves significantly with this index Query time improves significantly with this index Less rows are scanned Less rows are scanned
  • 66. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 66 Adding (rev_timestamp) MariaDB [nlwiktionary]> ALTER TABLE revision ADD INDEX rev_timestamp (rev_timestamp); Query OK, 0 rows affected (1.77 sec) Records: 0 Duplicates: 0 Warnings: 0 MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision WHERE rev_page = 790 and rev_timestamp < '2008'G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: revision type: ref possible_keys: rev_page,rev_timestamp key: rev_page key_len: 4 ref: const rows: 4863 Extra: Using where 1 row in set (0.01 sec) rev_page is preferred over rev_timestamp rev_page is preferred over rev_timestamp In general, only one index can be used per table access In general, only one index can be used per table access
  • 67. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 67 Forcing the use of (rev_timestamp) MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision FORCE INDEX(rev_timestamp) WHERE rev_page = 790 and rev_timestamp < '2008'G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: revision type: range possible_keys: rev_timestamp key: rev_timestamp key_len: 14 ref: NULL rows: 343411 Extra: Using index condition; Using where 1 row in set (0.00 sec) It is a range access It is a range access A lot more accessed rowsA lot more accessed rows Forcing the index is worse than type:ALL!Forcing the index is worse than type:ALL!
  • 68. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 68 Adding (rev_page, rev_timestamp)MariaDB [nlwiktionary]> ALTER TABLE revision ADD INDEX rev_page_rev_timestamp(rev_page, rev_timestamp); Query OK, 0 rows affected (1.59 sec) Records: 0 Duplicates: 0 Warnings: 0 MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision WHERE rev_page = 790 and rev_timestamp < '2008'G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: revision type: range possible_keys: rev_page,rev_timestamp,rev_page_rev_timestamp key: rev_page_rev_timestamp key_len: 18 ref: NULL rows: 1048 Extra: Using index condition 1 row in set (0.00 sec) Reduced number of rows scanned Reduced number of rows scanned
  • 69. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 69 Is (rev_timestamp, rev_page) a better option?MariaDB [nlwiktionary]> ALTER TABLE revision ADD INDEX rev_timestamp_rev_page (rev_timestamp, rev_page); Query OK, 0 rows affected (1.76 sec) Records: 0 Duplicates: 0 Warnings: 0 MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision WHERE rev_page = 790 and rev_timestamp < '2008'G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: revision type: range possible_keys: rev_page,rev_timestamp,rev_page_rev_timestamp,rev_timestamp_rev_page key: rev_page_rev_timestamp key_len: 18 ref: NULL rows: 1048 Extra: Using index condition 1 row in set (0.00 sec) Previous index is still preferred, why?
  • 70. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 70 Forcing (rev_timestamp, rev_page) MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision FORCE INDEX(rev_timestamp_rev_page) WHERE rev_page = 790 and rev_timestamp < '2008'G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: revision type: range possible_keys: rev_timestamp_rev_page key: rev_timestamp_rev_page key_len: 18 ref: NULL rows: 343411 Extra: Using index condition 1 row in set (0.00 sec) Only the first column is being used effectively for filtering
  • 71. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 71 A compound index produces a single tree ordered by the 2 values (23443, 2)(23443, 2) (790, '2010')(790, '2010') (54005, '2016') (54005, '2016') (15444, '2011') (15444, '2011') (790, '2012')(790, '2012') (790, '2007')(790, '2007') (84611, '2015')(84611, '2015') (21702, '2014')(21702, '2014') (1024, '2003')(1024, '2003') (790, '2008')(790, '2008') (46771, '2013')(46771, '2013') (13605, '2006')(13605, '2006') (790, '2011')(790, '2011') (105, '2015')(105, '2015') TABLETABLE (12301, 1)(12301, 1) rev_page = 790 and rev_timestamp < '2008' (rev_page, rev_timestamp) (rev_page, rev_timestamp)
  • 72. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 72 The alternative index cannot be used in such an effective way ('2008', 800)('2008', 800) ('2004', 24)('2004', 24) ('2014', 107)('2014', 107) ('2008', 155)('2008', 155) ('2004', 999)('2004', 999) ('2001', 276)('2001', 276) ('2015', 355)('2015', 355) ('2008', 790)('2008', 790) ('2005', 791)('2005', 791) ('2002', 205)('2002', 205) ('2010', 206)('2010', 206) ('2007', 201)('2007', 201) ('2004', 790)('2004', 790) ('2001', 105)('2001', 105) TABLETABLE ('2006', 13605) ('2006', 13605) (rev_timestamp, rev_page) (rev_timestamp, rev_page) rev_page = 790 and rev_timestamp < '2008'
  • 73. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 73 Order and column selection • Range access using >, <, >=, <=, BETWEEN can only be filtered once effectively, at the end of an index • When selecting indexes, prefer columns with high cardinality (very selective) – The optimal index can depend on the constants used
  • 74. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 74 Use of "Handler_*" statistics • They are post-execution statistics at row level – Unlike EXPLAIN's "rows" column, they are exact, not a guess – They allow to compare query execution performance in a deterministic way, independently of the execution time
  • 75. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 75 "Handler" Stats (indexed) mysql> SHOW SESSION STATUS like 'Hand%'; +----------------------------+----------+ | Variable_name | Value | +----------------------------+----------+ | Handler_commit | 80 | | Handler_delete | 0 | | Handler_discover | 0 | | Handler_external_lock | 166 | | Handler_mrr_init | 0 | | Handler_prepare | 0 | | Handler_read_first | 23 | | Handler_read_key | 736212 | | Handler_read_last | 0 | | Handler_read_next | 22208001 | | Handler_read_prev | 0 | | Handler_read_rnd | 665215 | | Handler_read_rnd_next | 14223297 | | Handler_rollback | 0 | | Handler_savepoint | 0 | | Handler_savepoint_rollback | 0 | | Handler_update | 66970 | | Handler_write | 2869409 | +----------------------------+----------+ 18 rows in set (0.00 sec) Number of times that the first entry of an index was read. It may indicate the number of full index scans Number of times that the first entry of an index was read. It may indicate the number of full index scans Number of time a row has been retrieved using an index Number of time a row has been retrieved using an index Next row has been requested in index order (typical for index scans or ranges) Next row has been requested in index order (typical for index scans or ranges)
  • 76. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 76 "Handler" Stats (unindexed) mysql> SHOW SESSION STATUS like 'Hand%'; +----------------------------+----------+ | Variable_name | Value | +----------------------------+----------+ | Handler_commit | 80 | | Handler_delete | 0 | | Handler_discover | 0 | | Handler_external_lock | 166 | | Handler_mrr_init | 0 | | Handler_prepare | 0 | | Handler_read_first | 23 | | Handler_read_key | 736212 | | Handler_read_last | 0 | | Handler_read_next | 22208001 | | Handler_read_prev | 0 | | Handler_read_rnd | 665215 | | Handler_read_rnd_next | 14223297 | | Handler_rollback | 0 | | Handler_savepoint | 0 | | Handler_savepoint_rollback | 0 | | Handler_update | 66970 | | Handler_write | 2869409 | +----------------------------+----------+ 18 rows in set (0.00 sec) A row has been requested in a specific position (typical for joins or order by without indexes) A row has been requested in a specific position (typical for joins or order by without indexes) Request tp read the next row in “table order” (typical for full table scans) Request tp read the next row in “table order” (typical for full table scans) Insertions in SELECTS may indicate temporary tables Insertions in SELECTS may indicate temporary tables
  • 77. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 77 Comparing statistics of the previous indexes (no indexes)MariaDB [nlwiktionary]> FLUSH STATUS; Query OK, 0 rows affected (0.00 sec) MariaDB [nlwiktionary]> SELECT * FROM revision IGNORE INDEX(rev_page, rev_timestamp, rev_page_rev_timestamp, rev_timestamp_rev_page) WHERE rev_page = 790 and rev_timestamp < '2008'; 1049 rows in set (0.58 sec) MariaDB [nlwiktionary]> SHOW STATUS like 'Hand%'; +----------------------------+--------+ | Variable_name | Value | +----------------------------+--------+ | Handler_commit | 1 | | Handler_delete | 0 | … | Handler_read_first | 0 | | Handler_read_key | 0 | | Handler_read_last | 0 | | Handler_read_next | 0 | | Handler_read_prev | 0 | | Handler_read_rnd | 0 | | Handler_read_rnd_deleted | 0 | | Handler_read_rnd_next | 820309 | | Handler_rollback | 0 | … | Handler_update | 0 | | Handler_write | 0 | +----------------------------+--------+ 25 rows in set (0.00 sec) Typical result for a full table scan Typical result for a full table scan
  • 78. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 78 Index on (rev_page) MariaDB [nlwiktionary]> SHOW STATUS like 'Hand%'; +----------------------------+-------+ | Variable_name | Value | +----------------------------+-------+ | Handler_commit | 1 | | Handler_delete | 0 | … | Handler_read_first | 0 | | Handler_read_key | 1 | | Handler_read_last | 0 | | Handler_read_next | 4864 | | Handler_read_prev | 0 | | Handler_read_rnd | 0 | | Handler_read_rnd_deleted | 0 | | Handler_read_rnd_next | 0 | | Handler_rollback | 0 | … | Handler_update | 0 | | Handler_write | 0 | +----------------------------+-------+ 25 rows in set (0.01 sec) Then, scan them one by one in index order Then, scan them one by one in index order Using the index, request the first row with rev_page=790 Using the index, request the first row with rev_page=790
  • 79. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 79 Index on (rev_timestamp) MariaDB [nlwiktionary]> SHOW STATUS like 'Hand%'; +----------------------------+---------+ | Variable_name | Value | +----------------------------+---------+ | Handler_commit | 1 | | Handler_delete | 0 | … | Handler_read_first | 0 | | Handler_read_key | 1 | | Handler_read_last | 0 | | Handler_read_next | 199155 | | Handler_read_prev | 0 | | Handler_read_rnd | 0 | | Handler_read_rnd_deleted | 0 | | Handler_read_rnd_next | 0 | | Handler_rollback | 0 | … | Handler_update | 0 | | Handler_write | 0 | +----------------------------+---------+ 25 rows in set (0.00 sec) Then, scan them one by one in index order (more are matched) Then, scan them one by one in index order (more are matched) Using the index, request the first row where rev_timestamp<2008 Using the index, request the first row where rev_timestamp<2008 Let's ignore ICP for nowLet's ignore ICP for now
  • 80. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 80 Index on (rev_page, rev_timestamp)MariaDB [nlwiktionary]> SHOW STATUS like 'Hand%'; +----------------------------+-------+ | Variable_name | Value | +----------------------------+-------+ | Handler_commit | 1 | | Handler_delete | 0 | … | Handler_read_first | 0 | | Handler_read_key | 1 | | Handler_read_last | 0 | | Handler_read_next | 1049 | | Handler_read_prev | 0 | | Handler_read_rnd | 0 | | Handler_read_rnd_deleted | 0 | | Handler_read_rnd_next | 0 | | Handler_rollback | 0 | … | Handler_update | 0 | | Handler_write | 0 | +----------------------------+-------+ 25 rows in set (0.00 sec) Rows scanned == Rows returnedRows scanned == Rows returned With both conditions covered, we can find the actual first row that matches the condition using the index With both conditions covered, we can find the actual first row that matches the condition using the index
  • 81. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 81 Index on (rev_timestamp, rev_page), no ICPMariaDB [nlwiktionary]> SHOW STATUS like 'Hand%'; +----------------------------+---------+ | Variable_name | Value | +----------------------------+---------+ | Handler_commit | 1 | | Handler_delete | 0 | … | Handler_read_first | 0 | | Handler_read_key | 1 | | Handler_read_last | 0 | | Handler_read_next | 199155 | | Handler_read_prev | 0 | | Handler_read_rnd | 0 | | Handler_read_rnd_deleted | 0 | | Handler_read_rnd_next | 0 | | Handler_rollback | 0 | … | Handler_update | 0 | | Handler_write | 0 | +----------------------------+---------+ 25 rows in set (0.00 sec) Assuming no ICP, exact same results than with (rev_timestamp). The extra column does not help. Also, EXPLAIN's row count was very off. Assuming no ICP, exact same results than with (rev_timestamp). The extra column does not help. Also, EXPLAIN's row count was very off.
  • 82. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 82 Redundant Indexes ● Creating all 4 previous indexes in production is not a great idea – "Left-most index prefix" allows, for example (rev_page, rev_timestamp) doing everything you can do with (rev_page) – If two indexes have equal selectivity, MySQL chooses the shortest one
  • 83. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 83 "Left-most index" Example MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision FORCE INDEX(rev_page_rev_timestamp) WHERE rev_page = 790G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: revision type: ref possible_keys: rev_page_rev_timestamp key: rev_page_rev_timestamp key_len: 4 ref: const rows: 4863 Extra: 1 row in set (0.00 sec) Only the first column is usedOnly the first column is used
  • 84. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 84 Duplicate Indexes ● It is very easy to create indexes with the same exact definition (same columns and ordering) – Set a convention for index naming (e.g tablename_column1_column2_idx) – MySQL does not allow 2 indexes with the same identifier – Since MySQL 5.6, an warning is thrown if a duplicate index is created
  • 85. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 85 pt-duplicate-index-checker $ pt-duplicate-key-checker h=127.0.0.1,P=5621,u=msandbox,p=msandbox […] # rev_timestamp is a left-prefix of rev_timestamp_rev_page # Key definitions: # KEY `rev_timestamp` (`rev_timestamp`), # KEY `rev_timestamp_rev_page` (`rev_timestamp`,`rev_page`) # Column types: # `rev_timestamp` binary(14) not null default '00000000000000' # `rev_page` int(10) unsigned not null # To remove this duplicate index, execute: ALTER TABLE `nlwiktionary`.`revision` DROP INDEX `rev_timestamp`; # rev_page is a left-prefix of rev_page_rev_timestamp # Key definitions: # KEY `rev_page` (`rev_page`), # KEY `rev_page_rev_timestamp` (`rev_page`,`rev_timestamp`), # Column types: # `rev_page` int(10) unsigned not null # `rev_timestamp` binary(14) not null default '00000000000000' # To remove this duplicate index, execute: ALTER TABLE `nlwiktionary`.`revision` DROP INDEX `rev_page`; # ###################################################### Summary of indexes ######################################## # Size Duplicate Indexes 15478317 # Total Duplicate Indexes 4 # Total Indexes 285 Simple tool to check redundant and duplicate indexes Simple tool to check redundant and duplicate indexes
  • 86. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 86 "OR"-style conditions over the same column MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision WHERE rev_page = 790 OR rev_page = 795 OR rev_page = 1024G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: revision type: range possible_keys: rev_page,rev_page_rev_timestamp key: rev_page key_len: 4 ref: NULL rows: 4890 Extra: Using index condition; Using where 1 row in set (0.01 sec) Equivalent to: SELECT * FROM revision WHERE rev_page IN (790, 795, 1024) Equivalent to: SELECT * FROM revision WHERE rev_page IN (790, 795, 1024)
  • 87. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 87 Handlers on "IN" / "OR" conditions over the same column+----------------------------+-------+ | Variable_name | Value | +----------------------------+-------+ | Handler_commit | 1 | | Handler_delete | 0 | … | Handler_prepare | 0 | | Handler_read_first | 0 | | Handler_read_key | 3 | | Handler_read_last | 0 | | Handler_read_next | 4891 | | Handler_read_prev | 0 | | Handler_read_rnd | 0 | | Handler_read_rnd_deleted | 0 | | Handler_read_rnd_next | 0 | | Handler_rollback | 0 | … | Handler_update | 0 | | Handler_write | 0 | +----------------------------+-------+ 25 rows in set (0.00 sec) Despite identifying themselves as “range”s, the execution is slightly different, one index dive (similar to a ref) is done per value. This can be an issue in conditions with thousands of items. Despite identifying themselves as “range”s, the execution is slightly different, one index dive (similar to a ref) is done per value. This can be an issue in conditions with thousands of items.
  • 88. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 88 "OR"-style conditions over different columns ● We cannot use a single index efficiently for both conditions – We can scan both conditions separatelly and mix the results, discarding duplicates – Or use an index for one condition and not for the other – Index merge allows to use two indexes for a single table access simultaneously
  • 89. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 89 Index Merge Example MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision WHERE rev_page = 790 or rev_timestamp < '2004'G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: revision type: index_merge possible_keys: rev_page,rev_timestamp,rev_page_rev_timestamp, rev_timestamp_rev_page key: rev_page,rev_timestamp key_len: 4,14 ref: NULL rows: 4871 Extra: Using sort_union(rev_page,rev_timestamp); Using where 1 row in set (0.00 sec) Both indexes are used, then combined using the "union" operation Both indexes are used, then combined using the "union" operation
  • 90. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 90 INDEX_MERGE Issues ● Sometimes it is faster to to execute the sentence using UNION: – This is specially true with (UNION ALL) since MySQL 5.7, if you do not care about duplicates ● There are also interseccion merges, but multi-column indexes are preferred
  • 91. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 91 Disabling optimizer features (I) ● The optimizer_switch variable allows enabling and disablig globally or per session many query optimizer features: MariaDB [nlwiktionary]> SHOW VARIABLES like 'optimizer_switch'G *************************** 1. row *************************** Variable_name: optimizer_switch Value: index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersec tion=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_cond ition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on ,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,parti al_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys= off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join _cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination =on,extended_keys=on,exists_to_in=on 1 row in set (0.00 sec)
  • 92. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 92 Deshabilitar características del optimizador (II)MariaDB [nlwiktionary]> SET optimizer_switch='index_merge_sort_union=off'; Query OK, 0 rows affected (0.00 sec) MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision WHERE rev_page = 790 or rev_timestamp < '2004'G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: revision type: ALL possible_keys: rev_page,rev_timestamp,rev_page_rev_timestamp,rev_timestamp_rev_page key: NULL key_len: NULL ref: NULL rows: 686822 Extra: Using where 1 row in set (0.00 sec) This will only have effect for the current session. This will only have effect for the current session.
  • 93. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 93 What happens if we have two ranges? ● As seen previously, we cannot use efficiently two range types on the same table access. Alternatives: – Use only one index for the most selective column – Use index condition pushdown to get an advantage – Change one of the two ranges into a discrete "IN" comparison/bucketize with a new column – Use quadtrees or R-TREEs (spatial indexing)
  • 94. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 94 Example of Bucketizing (I) MariaDB [nlwiktionary]> EXPLAIN SELECT count(*) FROM revision WHERE rev_timestamp < '2008' AND rev_len > 5500G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: revision type: ALL possible_keys: rev_timestamp,rev_timestamp_rev_page key: NULL key_len: NULL ref: NULL rows: 686822 Extra: Using where 1 row in set (0.00 sec) Looks like only an index on (rev_timestamp) or (rev_len) would be useful as we have 2 ranges. Looks like only an index on (rev_timestamp) or (rev_len) would be useful as we have 2 ranges.
  • 95. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 95 Example of Bucketizing (II) MariaDB [nlwiktionary]> ALTER TABLE revision ADD COLUMN rev_len_cat int; Query OK, 0 rows affected (38.28 sec) Records: 0 Duplicates: 0 Warnings: 0 MariaDB [nlwiktionary]> UPDATE revision set rev_len_cat = IF(rev_len < 10000, rev_len div 1000, 10); Query OK, 820308 rows affected (15.19 sec) Rows matched: 820308 Changed: 820308 Warnings: 0 MariaDB [nlwiktionary]> ALTER TABLE revision ADD INDEX rev_len_cat_rev_timestamp (rev_len_cat, rev_timestamp); Query OK, 0 rows affected (2.11 sec) Records: 0 Duplicates: 0 Warnings: 0
  • 96. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 96 Example of Bucketizing (III) MariaDB [nlwiktionary]> EXPLAIN SELECT count(*) FROM revision WHERE rev_timestamp < '2008' AND rev_len > 5500 AND rev_len_cat IN (5, 6, 7, 8, 9, 10)G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: revision type: range possible_keys: rev_timestamp,rev_timestamp_rev_page,rev_len_cat_rev_timestamp key: rev_len_cat_rev_timestamp key_len: 19 ref: NULL rows: 4442 Extra: Using where 1 row in set (0.00 sec) We did some transformations to both the structure and the query. We did some transformations to both the structure and the query.
  • 97. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 97 Example of Index Condition PushdownMariaDB [nlwiktionary]> ALTER TABLE revision ADD INDEX rev_len_rev_timestamp(rev_len, rev_timestamp); Query OK, 0 rows affected (1.77 sec) Records: 0 Duplicates: 0 Warnings: 0 MariaDB [nlwiktionary]> SET optimizer_switch='index_condition_pushdown=on'; EXPLAIN SELECT * FROM revision WHERE rev_timestamp < '2008' AND rev_len > 5500G Query OK, 0 rows affected (0.00 sec) *************************** 1. row *************************** id: 1 select_type: SIMPLE table: revision type: range possible_keys: rev_timestamp,rev_timestamp_rev_page,rev_len_rev_timestamp key: rev_len_rev_timestamp key_len: 5 ref: NULL rows: 38744 Extra: Using index condition 1 row in set (0.00 sec) Index condition pushdown (ICP) eanbles the engines to use extra parts of the index while avoiding costly row movements to and from the SQL layer Index condition pushdown (ICP) eanbles the engines to use extra parts of the index while avoiding costly row movements to and from the SQL layer
  • 98. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 98 ICP Issues ● Differences in execution time is more significative when the extra column condition is very selective (getting 5x the original performance) ● ICP is ignored when using covering Index, making the performance worse
  • 99. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 99 Does LIMIT improve the performance? (I) MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page ORDER BY page_touchedG *************************** 1. row *************************** type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 90956 Extra: Using filesort MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page ORDER BY page_touched LIMIT 10G *************************** 1. row *************************** type: index possible_keys: NULL key: page_page_touched key_len: 14 ref: NULL rows: 10 Extra: 1 row in set (0.00 sec) In some cases it can be essential to allow effective usage of the indexes In some cases it can be essential to allow effective usage of the indexes
  • 100. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 100 Does LIMIT improve the performance? (II)MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision ORDER BY rev_commentG *************************** 1. row *************************** [...] type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 817636 Extra: Using filesort 1 row in set (0.00 sec) MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision ORDER BY rev_comment LIMIT 10G *************************** 1. row *************************** […] table: revision type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 817636 Extra: Using filesort 1 row in set (0.00 sec) In other cases, it has no effect on the scanned rows (just on the returned ones) In other cases, it has no effect on the scanned rows (just on the returned ones)
  • 101. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 101 Does LIMIT improve the performance? (I)MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page ORDER BY page_title LIMIT 100G *************************** 1. row *************************** type: index possible_keys: NULL key: page_title key_len: 257 ref: NULL rows: 100 Extra: 1 row in set (0.00 sec) MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM page ORDER BY page_title LIMIT 10000, 100G *************************** 1. row *************************** type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 90956 Extra: Using filesort 1 row in set (0.00 sec) In this case, performance will vary depending on the offset (not ideal) In this case, performance will vary depending on the offset (not ideal)
  • 102. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 102 Can we filter and sort at the same time using indexes? MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision WHERE rev_comment='' ORDER BY rev_timestamp ASCG *************************** 1. row *************************** id: 1 select_type: SIMPLE table: revision type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 817636 Extra: Using where; Using filesort 1 row in set (0.00 sec) This query is slow because a) the full table scan This query is slow because a) the full table scan b) Required sort after filtering b) Required sort after filtering
  • 103. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 103 Adding and index on (rev_comment, rev_timestamp)MariaDB [nlwiktionary]> ALTER TABLE revision ADD INDEX rev_comment_rev_timestamp (rev_comment, rev_timestamp); Query OK, 0 rows affected (3.19 sec) Records: 0 Duplicates: 0 Warnings: 0 MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision WHERE rev_comment='' ORDER BY rev_timestamp ASCG *************************** 1. row *************************** id: 1 select_type: SIMPLE table: revision type: ref possible_keys: rev_comment_rev_timestamp key: rev_comment_rev_timestamp key_len: 769 ref: const rows: 266462 Extra: Using index condition; Using where 1 row in set (0.00 sec) Both type: ALL and filesort have disappeared Both type: ALL and filesort have disappeared
  • 104. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 104 This is not always possible MariaDB [nlwiktionary]> EXPLAIN SELECT * FROM revision WHERE rev_len > 5500 ORDER BY rev_timestamp ASCG *************************** 1. row *************************** id: 1 select_type: SIMPLE table: revision type: range possible_keys: rev_len_rev_timestamp key: rev_len_rev_timestamp key_len: 5 ref: NULL rows: 38744 Extra: Using index condition; Using filesort 1 row in set (0.00 sec) The range makes impossible to use the index optimally for the the ORDER BY: either we filter (rev_len) or sort (rev_timestamp) The range makes impossible to use the index optimally for the the ORDER BY: either we filter (rev_len) or sort (rev_timestamp)
  • 105. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 105 A Strange Game. The Only Winning Move is Not to Play mysql-5.6.21 (osm) > SELECT * FROM nodes FORCE INDEX(version_idx) WHERE version < 15 ORDER BY changeset_id; /* type: range, Using filesort */ 2859673 rows in set (30.58 sec) mysql-5.6.21 (osm) > SELECT * FROM nodes FORCE INDEX(changeset_id_idx) WHERE version < 15 ORDER BY changeset_id; /* type: index */ 2859673 rows in set (30.92 sec) mysql-5.6.21 (osm) > SELECT * FROM nodes WHERE version < 15 ORDER BY changeset_id; /* type: ALL, Using filesort */ 2859673 rows in set (16.54 sec)
  • 106. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 106 MyISAM Internals node_id versio k v 234234344545 1 leaves deciduous (empty row) 234234344548 5 gps:latitude 490018321N 234234344549 6 access uncontrolled (empty row) 234234344551 9 name Big Ben 234234344552 1 source survey 234234344557 1 name London Plane 234234344552 2 source survey 234234344557 2 name London Plane CarlsbergCarlsberg recyclingrecycling Accurate as of 2010 Accurate as of 2010 Gwynne Place Gwynne Place Manor PlaceManor Place treetree 490018321N490018321N deciduousdeciduous London PlaneLondon Plane surveysurvey Big BenBig Ben JOSMJOSM Northolt RoadNortholt Road uncontrolleduncontrolled London Borough of Southwark London Borough of Southwark Data (revision.MYD)Index (part of revision.MYI)
  • 107. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 107 InnoDB Internals (PRIMARY) Data clustered always using the primary key Data clustered always using the primary key 244 208 105 476 356 702 605 811 771 702 476 244 version k v 1 leaves deciduous 3 name Northolt Road 5 gps:latitu 490018321N 6 access uncontrolled 1 editor JOSM 9 name Big Ben 2 source survey 1 name London Plane 7 amenity pub
  • 108. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 108 InnoDB Internals (Secondary) 6 3 1 1 1 1 3 2 6 5 9 7 PK 356 105 702 811 476 208 Secondary indexes contain the primary key value Secondary indexes contain the primary key value PK / Datosíndice (version) 244 208 105 476 356 702 605 811 771 702 476 244 version k v 1 leaves deciduous 3 name Northolt Road 5 gps:latitu 490018321N 6 access uncontrolled 1 editor JOSM 9 name Big Ben 2 source survey 1 name London Plane 7 amenity pub 605 244 771
  • 109. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 109 Consequences of using InnoDB (I) ● Every table should have a primary key – If one is not defined, MySQL will choose an available NOT NULL unique key – If that is not possible, an internal 6-byte row identifier will be generated (not user-accesible)
  • 110. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 110 Consequences of using InnoDB (II) ● Inserting in primary key order is much faster – Less fragmentation/page-split – Usage of "batch" mode, improving insert speed ● Using auto-increment keys as primary keys can be a good idea for InnoDB
  • 111. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 111 Consequences of using InnoDB (III) • A very long primary key may increment substantially the size of secondary keys – Int or bigint types are recommended instead of UUIDs or other long strings
  • 112. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 112 Differences in size mysql-5.6.21 (osm) > CREATE TABLE pk_int (id int PRIMARY KEY auto_increment, a int, b int, c int, d int); Query OK, 0 rows affected (0.16 sec) mysql-5.6.21 (osm) > CREATE TABLE pk_uuid (id char(36) PRIMARY KEY, a int, b int, c int, d int); Query OK, 0 rows affected (0.04 sec) pk_int pk_uuid 0 8500000 17000000 25500000 34000000 42500000 12,582,912 20,971,520 13,631,488 32,505,856 .ibd size (no secondary indexes) .ibd size (with secondary indexes) bytes
  • 113. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 113 Extended primary key optimization ● As the primary key is part of all seconady keys, this can be used “for free”: – For row filtering (since MySQL 5.6) – To return results in primary key order – To avoid reading data from the table (covering index)
  • 114. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 114 Extended Primary Key Example mysql-5.6.21 (osm) > EXPLAIN SELECT node_id FROM nodes WHERE changeset_id = 24284 and node_id <> 146472942G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: nodes type: range possible_keys: PRIMARY,changeset_id_idx key: changeset_id_idx key_len: 16 ref: NULL rows: 50 Extra: Using where; Using index 1 row in set (0.07 sec)
  • 115. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 115 FULLTEXT SEARCH Query Optimization: From 0 to 10 (and up to 5.7)
  • 116. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 116 Fuzzy Search of “gloucester/Gloucester’s/etc” ● “Typical” way to solve this: mysql-5.7.5 (osm) > SELECT way_id as id, v FROM way_tags WHERE v like '%gloucester%'; 425 rows in set (0.46 sec) Too slowToo slow
  • 117. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 117 Let’s Add an Index mysql-5.7.5 (osm) > ALTER TABLE way_tags ADD INDEX(v); Query OK, 0 rows affected (6.44 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql-5.7.5 (osm) > SELECT ...; 425 rows in set (0.38 sec) mysql-5.7.5 (osm) > EXPLAIN SELECT way as type, way_id as id, v FROM way_tags WHERE v like '%gloucester%'; +----+.+-------+---------------+------+---------+------+---------+----------+--------------------------+ | id |.| type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+.+-------+---------------+------+---------+------+---------+----------+--------------------------+ | 1 |.| index | NULL | v_2 | 767 | NULL | 1333338 | 11.11 | Using where; Using index | +----+.+-------+---------------+------+---------+------+---------+----------+--------------------------+ 1 row in set, 1 warning (0.01 sec) Still slow, why?Still slow, why?
  • 118. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 118 Fulltext Index mysql-5.7.5 (osm) > ALTER TABLE way_tags add FULLTEXT index(v); Query OK, 0 rows affected (3.20 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql-5.7.5 (osm) > SELECT ...; 425 rows in set (0.00 sec) mysql-5.7.5 (osm) > EXPLAIN SELECT 'way' as type, way_id as id, v FROM way_tags WHERE MATCH(v) AGAINST ('+gloucester*' IN BOOLEAN MODE); +----+.+----------+---------------+------+---------+-------+------+----------+-----------------------------------+ | id |.| type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+.+----------+---------------+------+---------+-------+------+----------+-----------------------------------+ | 1 |.| fulltext | v | v | 0 | const | 1 | 100.00 | Using where; Ft_hints: no_ranking | +----+.+----------+---------------+------+---------+-------+------+----------+-----------------------------------+ 1 row in set, 1 warning (0.00 sec)
  • 119. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 119 Newer Fulltext Optimizations mysql-5.5.40 (osm) > EXPLAIN SELECT count(*) FROM way_tags_myisam WHERE MATCH(v) AGAINST('gloucester'); +----+-------------+-----------------+----------+---------------+------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-----------------+----------+---------------+------+---------+------+------+-------------+ | 1 | SIMPLE | way_tags_myisam | fulltext | v | v | 0 | | 1 | Using where | +----+-------------+-----------------+----------+---------------+------+---------+------+------+-------------+ 1 row in set (0.00 sec) mysql-5.5.40 (osm) > SHOW STATUS like 'Hand%'; +----------------------------+-------+ | Variable_name | Value | +----------------------------+-------+ | Handler_commit | 0 | | Handler_delete | 0 | ... | Handler_read_first | 0 | | Handler_read_key | 0 | | Handler_read_last | 0 | | Handler_read_next | 425 | | Handler_read_prev | 0 | | Handler_read_rnd | 0 | | Handler_read_rnd_next | 0 | ... | Handler_update | 0 | | Handler_write | 0 | +----------------------------+-------+ 16 rows in set (0.00 sec)
  • 120. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 120 Newer Fulltext Optimizations (cont.)mysql-5.7.5 (osm) > EXPLAIN SELECT count(*) FROM way_tags WHERE MATCH(v) AGAINST('gloucester'); +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+------------------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+------------------------------+ | 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Select tables optimized away | +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+------------------------------+ 1 row in set, 1 warning (0.00 sec) mysql-5.7.5 (osm) > SHOW STATUS like 'Hand%'; +----------------------------+-------+ | Variable_name | Value | +----------------------------+-------+ | Handler_commit | 1 | | Handler_delete | 0 | ... | Handler_read_first | 0 | | Handler_read_key | 0 | | Handler_read_last | 0 | | Handler_read_next | 0 | | Handler_read_prev | 0 | | Handler_read_rnd | 0 | | Handler_read_rnd_next | 0 | ... | Handler_update | 0 | | Handler_write | 0 | +----------------------------+-------+ 18 rows in set (0.00 sec) It’s counting directly from the FULLTEXT index It’s counting directly from the FULLTEXT index
  • 121. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 121 Open Issues and Limitations ● No postfix support (wildcards) ● Simple Ranking (and different from MyISAM) ● No stemming support ● Some multi-language limitations More on FULLTEXT InnoDB support: http://www.drdobbs.com/database/full-text-search-with-innodb/231902587
  • 122. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 122 Alternatives ● Apache Lucene – Solr – Elasticsearch ● Sphinx – SphinxSE
  • 123. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 123 JOINS Query Optimization: From 0 to 10 (and up to 5.7)
  • 124. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 124 (Block) Nested Loop Join ● Until MySQL 5.5 there was only one algorithm to execute a JOIN: node_id version lat lon 1 1 52 0.5 1 2 52 0.5 2 1 51 1 3 1 53 1.5 node_id version k v 1 1 name Big Benn 1 1 tourism attraction 1 2 name Big Ben 1 2 tourism attraction 3 1 name London Eye
  • 125. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 125 Extra Access type: eq_ref mysql-5.6.21 (osm) > EXPLAIN SELECT * FROM nodes JOIN node_tags USING(node_id, version) WHERE node_tags.v= 'Big Ben'G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: node_tags type: ref possible_keys: PRIMARY,v_idx key: v_idx key_len: 767 ref: const rows: 1 Extra: Using where; Using index *************************** 2. row *************************** id: 1 select_type: SIMPLE table: nodes type: eq_ref possible_keys: PRIMARY,version_idx key: PRIMARY key_len: 16 ref: osm.node_tags.node_id,osm.node_tags.version rows: 1 Extra: NULL 2 rows in set (0.00 sec) eq_ref is similar to ref, but allows faster JOINS because, by using a unique key, it only has to search one row for each previous result eq_ref is similar to ref, but allows faster JOINS because, by using a unique key, it only has to search one row for each previous result
  • 126. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 126 JOIN Optimization ● Two main goals: – Perform an effective filtering on each table access, if possible using indexes – Perform the access in the most efficient table order ● When joining 3 or more tables in a star schema, the "covering index" strategy can have a huge impact
  • 127. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 127 Example: optimize this JOIN (I) SELECT n.node_id, n.latitude, n.longitude FROM way_nodes w_n JOIN way_tags w_t ON w_n.way_id = w_t.way_id and w_n.version = w_t.version JOIN nodes n ON w_n.node_id = n.node_id JOIN node_tags n_t ON n.node_id = n_t.node_id and n.version = n_t.version WHERE w_t.k = 'building' and n_t.k = 'entrance' and n_t.v = 'main'; We start without secondary indexes We start without secondary indexes
  • 128. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 128 Example: optimize this JOIN (II) ************************ 1. row ************************ id: 1 select_type: SIMPLE table: w_t type: index possible_keys: PRIMARY key: PRIMARY key_len: 783 ref: NULL rows: 1335702 Extra: Using where; Using index ************************ 2. row ************************ id: 1 select_type: SIMPLE table: w_n type: ref possible_keys: PRIMARY key: PRIMARY key_len: 16 ref: osm.w_t.way_id,osm.w_t.version rows: 3 Extra: NULL mysql-5.6.21 (osm) > SELECT … 858 rows in set (9.00 sec) ************************ 3. row ************************ id: 1 select_type: SIMPLE table: n_t type: ref possible_keys: PRIMARY key: PRIMARY key_len: 8 ref: osm.w_n.node_id rows: 1 Extra: Using where ************************ 4. row ************************ id: 1 select_type: SIMPLE table: n type: eq_ref possible_keys: PRIMARY key: PRIMARY key_len: 16 ref: osm.w_n.node_id,osm.n_t.version rows: 1 Extra: Using index 4 rows in set (0.01 sec)
  • 129. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 129 Example: optimize this JOIN (III) mysql-5.6.21 (osm) > ALTER TABLE way_tags ADD INDEX k_idx(k); Query OK, 0 rows affected (4.80 sec) Records: 0 Duplicates: 0 Warnings: 0 Creating an index on way_tags.k Creating an index on way_tags.k
  • 130. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 130 Example: optimize this JOIN (IV) ********************** 1. row ********************** id: 1 select_type: SIMPLE table: w_t type: ref possible_keys: PRIMARY,k_idx key: k_idx key_len: 767 ref: const rows: 452274 Extra: Using where; Using index ********************** 2. row ********************** id: 1 select_type: SIMPLE table: w_n type: ref possible_keys: PRIMARY key: PRIMARY key_len: 16 ref: osm.w_t.way_id,osm.w_t.version rows: 3 Extra: NULL mysql-5.6.21 (osm) > SELECT … 858 rows in set (8.58 sec) It seems like the index is not very useful It seems like the index is not very useful ********************** 3. row ********************** id: 1 select_type: SIMPLE table: n_t type: ref possible_keys: PRIMARY key: PRIMARY key_len: 8 ref: osm.w_n.node_id rows: 1 Extra: Using where ********************** 4. row ********************** id: 1 select_type: SIMPLE table: n type: eq_ref possible_keys: PRIMARY key: PRIMARY key_len: 16 ref: osm.w_n.node_id,osm.n_t.version rows: 1 Extra: NULL 4 rows in set (0.00 sec)
  • 131. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 131 Example: optimize this JOIN (V) mysql-5.6.21 (osm) > ALTER TABLE node_tags ADD INDEX k_idx(k); Query OK, 0 rows affected (2.82 sec) Records: 0 Duplicates: 0 Warnings: 0 The order does not seem to be adequate, let's try adding an index to start by accessing node_tags The order does not seem to be adequate, let's try adding an index to start by accessing node_tags
  • 132. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 132 Example: optimize this JOIN (VI) ********************** 1. row ********************** id: 1 select_type: SIMPLE table: w_t type: ref possible_keys: PRIMARY,k_idx key: k_idx key_len: 767 ref: const rows: 452274 Extra: Using where; Using index ********************** 2. row ********************** id: 1 select_type: SIMPLE table: w_n type: ref possible_keys: PRIMARY key: PRIMARY key_len: 16 ref: osm.w_t.way_id,osm.w_t.version rows: 3 Extra: NULL mysql-5.6.21 (osm) > SELECT … 858 rows in set (7.33 sec) ********************** 3. row ********************** id: 1 select_type: SIMPLE table: n_t type: ref possible_keys: PRIMARY,k_idx key: PRIMARY key_len: 8 ref: osm.w_n.node_id rows: 1 Extra: Using where ********************** 4. row ********************** id: 1 select_type: SIMPLE table: n type: eq_ref possible_keys: PRIMARY key: PRIMARY key_len: 16 ref: osm.w_n.node_id,osm.n_t.version rows: 1 Extra: NULL 4 rows in set (0.00 sec) It keeps using the wrong order, even if we delete the w_t.k_idx index It keeps using the wrong order, even if we delete the w_t.k_idx index
  • 133. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 133 Example: optimize this JOIN (VII) SELECT STRAIGHT_JOIN n.node_id, n.latitude, n.longitude FROM node_tags n_t JOIN nodes n ON n.node_id = n_t.node_id and n.version = n_t.version JOIN way_nodes w_n ON w_n.node_id = n.node_id JOIN way_tags w_t ON w_n.way_id = w_t.way_id and w_n.version = w_t.version WHERE w_t.k = 'building' and n_t.k = 'entrance' and n_t.v = 'main'; Let's see why rewriting it into this query Let's see why rewriting it into this query
  • 134. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 134 Example: optimize this JOIN (VIII) ********************** 1. row ********************** id: 1 select_type: SIMPLE table: n_t type: ref possible_keys: PRIMARY,k_idx key: k_idx key_len: 767 ref: const rows: 2390 Extra: Using index condition; Using where ********************** 2. row ********************** id: 1 select_type: SIMPLE table: n type: eq_ref possible_keys: PRIMARY key: PRIMARY key_len: 16 ref: osm.n_t.node_id,osm.n_t.version rows: 1 Extra: NULL There is no index on w_n that would allow efficient access There is no index on w_n that would allow efficient access ********************** 3. row ********************** id: 1 select_type: SIMPLE table: w_n type: ALL possible_keys: PRIMARY key: NULL key_len: NULL ref: NULL rows: 3597858 Extra: Using where; Using join buffer (Block Nested Loop) ********************** 4. row ********************** id: 1 select_type: SIMPLE table: w_t type: eq_ref possible_keys: PRIMARY key: PRIMARY key_len: 783 ref: osm.w_n.way_id,osm.w_n.version,const rows: 1 Extra: Using where; Using index 4 rows in set (0.00 sec)
  • 135. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 135 Example: optimize this JOIN (IX) mysql-5.6.21 (osm) > ALTER TABLE way_nodes ADD INDEX node_id_idx(node_id); Query OK, 0 rows affected (17.77 sec) Records: 0 Duplicates: 0 Warnings: 0
  • 136. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 136 Example: optimize this JOIN (X) ********************** 1. row ********************** id: 1 select_type: SIMPLE table: n_t type: ref possible_keys: PRIMARY,k_idx key: k_idx key_len: 767 ref: const rows: 2390 Extra: Using index condition; Using where ********************** 2. row ********************** id: 1 select_type: SIMPLE table: n type: eq_ref possible_keys: PRIMARY key: PRIMARY key_len: 16 ref: osm.n_t.node_id,osm.n_t.version rows: 1 Extra: NULL mysql-5.6.21 (osm) > SELECT … 858 rows in set (0.73 sec) Now it starts by the right table (without STRAIGHT_JOIN) Now it starts by the right table (without STRAIGHT_JOIN) ********************** 3. row ********************** id: 1 select_type: SIMPLE table: w_n type: ref possible_keys: PRIMARY,node_id_idx key: node_id_idx key_len: 8 ref: osm.n_t.node_id rows: 1 Extra: Using index ********************** 4. row ********************** id: 1 select_type: SIMPLE table: w_t type: eq_ref possible_keys: PRIMARY key: PRIMARY key_len: 783 ref: osm.w_n.way_id,osm.w_n.version,const rows: 1 Extra: Using where; Using index 4 rows in set (0.04 sec)
  • 137. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 137 Example: optimize this JOIN (XI) ************************* 1. row ************************* id: 1 select_type: SIMPLE table: n_t type: ref possible_keys: PRIMARY,k_idx,k_v_idx key: k_v_idx key_len: 1534 ref: const,const rows: 900 Extra: Using where; Using index ************************* 2. row ************************* id: 1 select_type: SIMPLE table: n type: eq_ref possible_keys: PRIMARY key: PRIMARY key_len: 16 ref: osm.n_t.node_id,osm.n_t.version rows: 1 Extra: NULL mysql-5.6.21 (osm) > SELECT ... 858 rows in set (0.02 sec) An index on (k,v) is even better An index on (k,v) is even better ************************ 3. row ************************ id: 1 select_type: SIMPLE table: w_n type: ref possible_keys: PRIMARY,node_id_idx key: node_id_idx key_len: 8 ref: osm.n_t.node_id rows: 1 Extra: Using index ************************ 4. row ************************ id: 1 select_type: SIMPLE table: w_t type: eq_ref possible_keys: PRIMARY key: PRIMARY key_len: 783 ref: osm.w_n.way_id,osm.w_n.version,const rows: 1 Extra: Using where; Using index 4 rows in set (0.00 sec)
  • 138. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 138 “New” JOIN methods ● MySQL 5.6 added: – Batch Key Access ● MariaDB has since 5.3: – Batch Key Access – Hash Joins – Slightly modified versions of the above ones (with “incremental” buffers to join 3 or more tables)
  • 139. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 139 Multi-range read • This optimization orders results obtained from a secondary key in primary key/physical order before accessing the rows – It may help exection time of queries when disk-bound – It requires tunning of the read_rnd_buffer_size (size of the buffer used for ordering the results) • BKA JOINs are based on the mrr optimization
  • 140. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 140 MRR Example (I) mysql-5.6.21 (osm) > EXPLAIN SELECT * FROM nodes WHERE timestamp >= '2013-07-01 00:00:00' AND timestamp < '2014-01-01 00:00:00'G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: nodes type: range possible_keys: nodes_timestamp_idx key: nodes_timestamp_idx key_len: 5 ref: NULL rows: 429684 Extra: Using index condition; Using MRR 1 row in set (0.02 sec)
  • 141. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 141 MRR example (II) [restart] mysql> SET optimizer_switch='mrr=off'; mysql> SELECT * FROM nodes WHERE timestamp >= '2013-07-01 00:00:00' AND timestamp < '2014-01-01 00:00:00'; 205617 rows in set (5.16 sec) mysql> SELECT * FROM nodes WHERE timestamp >= '2013-07-01 00:00:00' AND timestamp < '2014-01-01 00:00:00'; 205617 rows in set (0.60 sec) [restart] mysql> SET read_rnd_buffer_size=50 * 1024 * 1024; mysql> SELECT * FROM nodes WHERE timestamp >= '2013-07-01 00:00:00' AND timestamp < '2014-01-01 00:00:00'; 205617 rows in set (2.39 sec) mysql> SELECT * FROM nodes WHERE timestamp >= '2013-07-01 00:00:00' AND timestamp < '2014-01-01 00:00:00'; 205617 rows in set (0.73 sec) “Cold” results are significantly better with mrr (but it can impact negatively, too) “Cold” results are significantly better with mrr (but it can impact negatively, too)
  • 142. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 142 Batch Key Access node_id version lat lon 1 1 52 0.5 1 2 52 0.5 2 1 51 1 3 1 53 1.5 node_id version k v 1 1 name Big Benn 1 1 tourism attraction 1 2 name Big Ben 1 2 tourism attraction 3 1 amenity cafe Buffer sorted in physical/PK order
  • 143. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 143 Hash Joins • Only work for equi-joins node_id version lat lon 1 1 52 0.5 1 2 52 0.5 2 1 51 1 3 1 53 1.5 node_id version k v 1 1 name Big Benn 1 1 tourism attraction 1 2 name Big Ben 1 2 tourism attraction 3 1 amenity cafe Hash table for faster access to rows
  • 144. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 144 MySQL Configuration • BKA requires changes of default optimizer configuration: mysql-5.7.5 (osm) > SET optimizer_switch= 'mrr=on'; mysql-5.7.5 (osm) > SET optimizer_switch= 'mrr_cost_based=off'; mysql-5.7.5 (osm) > SET optimizer_switch= 'batch_key_access=on'; – Additionally, configuring the join_buffer_size adequately
  • 145. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 145 MariaDB configuration mariadb-10.0.14 (osm) > SET optimizer_switch = 'join_cache_incremental=on'; mariadb-10.0.14 (osm) > SET optimizer_switch = 'join_cache_hashed=on'; mariadb-10.0.14 (osm) > SET optimizer_switch = 'join_cache_bka=on'; - Enabled by default mariadb-10.0.14 (osm) > SET join_cache_level = 3 (for hash joins) mariadb-10.0.14 (osm) > SET join_cache_level = 5 (for BKA) - Also, configure join_buffer_size appropriately. - Hash joins, like BKA, are highly dependent on disk-bound DBs to be effective due to the extra overhead
  • 146. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 146 Nested Loop Join (cold buffers buffer_pool=100MB, join_buffer=4M) mariadb-10.0.14 (osm) > EXPLAIN SELECT changeset_id, count(*) FROM changesets JOIN nodes on changesets.id = nodes.changeset_id GROUP BY visibleG ******************** 1. row ******************** id: 1 select_type: SIMPLE table: changesets type: index possible_keys: PRIMARY key: PRIMARY key_len: 8 ref: NULL rows: 69115 Extra: Using index; Using temporary; Using filesort ******************** 2. row ******************** id: 1 select_type: SIMPLE table: nodes type: ref possible_keys: changeset_id key: changeset_id key_len: 8 ref: osm.changesets.id rows: 19 Extra: 2 rows in set (0.00 sec) mariadb-10.0.14 (osm) > SELECT visible, count(*) FROM changesets JOIN nodes on changesets.id = nodes.changeset_id GROUP BY visible; +---------+----------+ | visible | count(*) | +---------+----------+ | 1 | 2865312 | +---------+----------+ 1 row in set (32.86 sec)
  • 147. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 147 Hash Join (cold buffers, buffer_pool=100M, join_buffer=4M) mariadb-10.0.14 (osm) > EXPLAIN SELECT changeset_id, count(*) FROM changesets JOIN nodes on changesets.id = nodes.changeset_id GROUP BY visibleG ******************** 1. row ******************** id: 1 select_type: SIMPLE table: changesets type: index possible_keys: PRIMARY key: PRIMARY key_len: 8 ref: NULL rows: 69115 Extra: Using index; Using temporary; Using filesort ******************** 2. row ******************** id: 1 select_type: SIMPLE table: nodes type: hash_ALL possible_keys: changeset_id key: #hash#changeset_id key_len: 8 ref: osm.changesets.id rows: 2781732 Extra: Using join buffer (flat, BNLH join) 2 rows in set (0.00 sec) mariadb-10.0.14 (osm) > SELECT visible, count(*) FROM changesets JOIN nodes on changesets.id = nodes.changeset_id GROUP BY visible; +---------+----------+ | visible | count(*) | +---------+----------+ | 1 | 2865312 | +---------+----------+ 1 row in set (6.66 sec)
  • 148. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 148 SUBQUERIES Query Optimization: From 0 to 10 (and up to 5.7)
  • 149. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 149 Access types: unique_subquery/index_subquery mysql-5.6.21 (osm) > EXPLAIN SELECT * FROM node_tags WHERE v = 'Big Ben' and node_id NOT IN (SELECT node_id FROM nodes WHERE tile < 100000000)G ************** 1. row ************** id: 1 select_type: PRIMARY table: node_tags type: ref possible_keys: v_idx key: v_idx key_len: 767 ref: const rows: 1 Extra: Using where; Using index Unique subquery is similar, but using a unique or primary key Unique subquery is similar, but using a unique or primary key ************** 2. row ************** id: 2 select_type: DEPENDENT SUBQUERY table: nodes type: index_subquery possible_keys: PRIMARY,nodes_tile_idx key: PRIMARY key_len: 8 ref: func rows: 1 Extra: Using where 2 rows in set (0.00 sec)
  • 150. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 150 Subqueries in MySQL ● MySQL versions traditionally had very bad press regarding subquries – It was common to recommend rewriting them (when possible) into JOINS ● Since MySQL 5.6, its query execution plans have improved significantly
  • 151. © 2014 Jaime Crespo. http://jynus.com. License: CC-BY-SA-4.0 Query Optimization: From 0 to 10 (and up to 5.7) 151 Lazy Materialization of derived tables ● Option available since MySQL 5.6 – Improves the execution time of EXPLAIN (it no longer needs to execute subqueries) – Derived tables can be indexed automatically at execution time to improve its performance