efficient use of indexes in mysql
TRANSCRIPT
Indexes in MySQLAleksandr Kuzminsky
https://twindb.com
How to use indexes efficiently
Agenda
1. How data is organized2. Data access
Who we are
Aleks:● TwinDB co-founder● Dropbox DBA● ex-Percona consultant
Ovais:● TwinDB co-founder● Lithium lead DBA● ex-Percona consultant
How data is organized
Table in MySQL (InnoDB)
CREATE TABLE `actor`( `actor_id` SMALLINT(5) UNSIGNED NOT NULL, `first_name` VARCHAR(45) NOT NULL, `last_name` VARCHAR(45) NOT NULL, `last_update` TIMESTAMP NOT NULL, PRIMARY KEY (`actor_id`), KEY `idx_actor_last_name` (`last_name`) ) ENGINE=InnoDB;
B+ Tree
● O(log(n))● Shallow● Data in leaf pages
sakila.actor
PRIMARY idx_actor_last_name
actor_id first_name last_name last_update
1 PENELOPE GUINESS 2006-02-15 04:34:33
2 NICK WAHLBERG 2006-02-15 04:34:33
3 ED CHASE 2006-02-15 04:34:33
4 JENNIFER DAVIS 2006-02-15 04:34:33
5 JOHNNY WOOD 2006-02-15 04:34:33
... ... ... ...
last_name actor_id
AKROYD 58
AKROYD 92
AKROYD 182
ALLEN 118
ALLEN 145
... ...
Data Access
Fast if accessing table
andproducing result
is simultaneous
Point SELECT
SELECT * FROM actor WHERE actor_id = 3;
actor_id first_name last_name last_update
1 PENELOPE GUINESS 2006-02-15 04:34:33
2 NICK WAHLBERG 2006-02-15 04:34:33
3 ED CHASE 2006-02-15 04:34:33
4 JENNIFER DAVIS 2006-02-15 04:34:33
5 JOHNNY WOOD 2006-02-15 04:34:33
... ... ... ...
SELECT by range of keys
SELECT * FROM actor WHERE actor_id > 3;
actor_id first_name last_name last_update
1 PENELOPE GUINESS 2006-02-15 04:34:33
2 NICK WAHLBERG 2006-02-15 04:34:33
3 ED CHASE 2006-02-15 04:34:33
4 JENNIFER DAVIS 2006-02-15 04:34:33
5 JOHNNY WOOD 2006-02-15 04:34:33
... ... ... ...
Lookup by secondary key
actor_id first_name last_name last_update
117 RENEE TRACY 2006-02-15 04:34:33
118 CUBA ALLEN 2006-02-15 04:34:33
119 WARREN JACKMAN 2006-02-15 04:34:33
... ... ... ...
145 KIM ALLEN 2006-02-15 04:34:33
... ... ... ...
last_name actor_id
AKROYD 58
AKROYD 92
AKROYD 182
ALLEN 118
ALLEN 145
... ...
SELECT * FROM actor WHERE last_name = ‘ALLEN’;
Step 1 Step 2
Using index for data access
last_name actor_id
AKROYD 182
ALLEN 118
ALLEN 145
ALLEN 194
ASTAIRE 76
... ...
SELECT COUNT(*) FROM actor WHERE last_name = ‘ALLEN’;
Using index for data access
EXPLAIN SELECT COUNT(*) FROM actor WHERE last_name = ‘ALLEN’;
*************************** 1. row *************************** id: 1 select_type: SIMPLE table: actor type: refpossible_keys: idx_actor_last_name key: idx_actor_last_name key_len: 137 ref: const rows: 3 Extra: Using where; Using index
Covering indexesALTER TABLE actor ADD INDEX idx_last_first(last_name, first_name);SELECT first_name FROM actor WHERE last_name = 'ALLEN'
last_name first_name actor_id
AKROYD KIRSTEN 182
ALLEN CUBA 118
ALLEN KIM 145
ALLEN MERYL 194
ASTAIRE ANGELINA 76
... ...
*************************** 1. row ***************************
id: 1 select_type: SIMPLE table: actor type: refpossible_keys: idx_actor_last_name,idx_last_first key: idx_last_first key_len: 137 ref: const rows: 3 Extra: Using where; Using index
DISTINCT
*************************** 1. row ***************************
id: 1 select_type: SIMPLE table: actor type: indexpossible_keys: idx_actor_last_name,idx_last_first key: idx_actor_last_name key_len: 137 ref: NULL rows: 200 Extra: Using index
last_name actor_id
AKROYD 182
ALLEN 118
ALLEN 145
ALLEN 194
ASTAIRE 76
... ...
SELECT DISTINCT last_name FROM actor
GROUP BY
*************************** 1. row ***************************
id: 1 select_type: SIMPLE table: actor type: indexpossible_keys: idx_actor_last_name,idx_last_first key: idx_actor_last_name key_len: 137 ref: NULL rows: 200 Extra: Using index
last_name actor_id
AKROYD 182
ALLEN 118
ALLEN 145
ALLEN 194
ASTAIRE 76
... ...
SELECT last_name, COUNT(*) FROM actor GROUP BY last_name
Loose index scanALTER TABLE actor ADD COLUMN rank INT;UPDATE actor SET rank = ROUND(100 * RAND()); ALTER TABLE actor ADD INDEX idx_last_rank (last_name, rank);
last_name rank actor_id
AKROYD 40 58
AKROYD 42 92
AKROYD 95 182
ALLEN 19 194
ALLEN 35 118
... ...
Loose index scan
SELECT last_name, MIN(rank) FROM actor GROUP BY last_name
last_name rank actor_id
AKROYD 40 58
AKROYD 42 92
AKROYD 95 182
ALLEN 19 194
ALLEN 35 118
... ...
*************************** 1. row ***************************
id: 1 select_type: SIMPLE table: actor type: rangepossible_keys: …, idx_last_rank key: idx_last_rank key_len: 137 ref: NULL rows: 247 Extra: Using index for group-by
Sorting
SELECT * FROM actor WHERE last_name = 'AKROYD' ORDER BY rank
last_name rank actor_id
AKROYD 40 58
AKROYD 42 92
AKROYD 95 182
ALLEN 19 194
ALLEN 35 118
... ...
*************************** 1. row ***************************
id: 1 select_type: SIMPLE table: actor type: refpossible_keys: …, idx_last_rank key: idx_last_rank key_len: 137 ref: const rows: 3 Extra: Using where
Joining tablesSELECT title, first_name, last_name
FROM film
JOIN film_actor
ON film_actor.film_id = film.film_id
JOIN actor
ON actor.actor_id = film_actor.actor_id
ORDER BY title;
Joining tablesSELECT title, first_name, last_name
FROM film FORCE INDEX (`idx_title`)
JOIN film_actor
ON film_actor.film_id = film.film_id
JOIN actor
ON actor.actor_id = film_actor.actor_id
ORDER BY title;
How to compare efficiency
Q&A
Thank you!