0% found this document useful (0 votes)
50 views

Need For Speed: MySQL Indexing

Indexes are the most important thing for MySQL database performance tuning. In this presentation we show how MySQL is using indexes and what we can do to improve MySQL performance.

Uploaded by

Oli Sennhauser
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
50 views

Need For Speed: MySQL Indexing

Indexes are the most important thing for MySQL database performance tuning. In this presentation we show how MySQL is using indexes and what we can do to improve MySQL performance.

Uploaded by

Oli Sennhauser
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 30

www.fromdual.

com

Need for Speed:


Indexierung unter MySQL
CeBIT 2014,
11. Mrz, Hannover
Oli Sennhauser
Senior MySQL Berater bei FromDual GmbH

[email protected]
1 / 30

ber FromDual GmbH

www.fromdual.com

FromDual bietet neutral und unabhngig:


Beratung fr MySQL, Galera Cluster,
MariaDB und Percona Server
Support fr MySQL und Galera Cluster
Remote-DBA Dienstleistungen
MySQL Schulung
OSB Alliance Mitglied

www.fromdual.com
2 / 30

Unsere Kunden

www.fromdual.com

3 / 30

MySQL und Indexierung

www.fromdual.com

MySQL Dokumentation:
The best way to improve the performance of SELECT operations is
to create indexes on one or more of the columns that are tested in
the query.

Grossartig! Aber:
Unnecessary indexes waste space and waste time to determine
which indexes to use. You must find the right balance to achieve
fast queries using the optimal set of indexes.

... hmmm, somit mssen wir wohl ein bisschen denken... :-(
4 / 30

Was ist ein Index?

Adams, Douglas:
The Hitchhiker's
Guide to the
Galaxy?

www.fromdual.com

Sennhauser, Oli,
Uster?

5 / 30

Index technisch gesehen

www.fromdual.com

MyISAM

InnoDB

6 / 30

MySQL nutzt Indizes:

www.fromdual.com

Um Eindeutigkeit zu erzwingen (PRIMARYKEY, UNIQUEKEY)

Um schnell auf Zeilen zuzugreifen und diese zu filtern (WHERE)

Um Joins schnell auszufhren (JOIN)

Um MIN() und MAX() Werte schnell zu finden

Fr Sortier- und Gruppier-Operationen (ORDERBY, GROUPBY)

Um Joins mittels eines Covering Index zu vermeiden

Um FOREIGNKEYConstraints (FOREIGNKEY) zu erzwingen

7 / 30

WHERE Klausel 1

www.fromdual.com

SELECT*
FROMcustomers
SHOWCREATETABLEcustomers\G
WHEREname='FromDual';
CREATETABLE`customers`(
`customer_id`smallint(5)unsigned
,`name`varchar(64)DEFAULTNULL
,PRIMARYKEY(`customer_id`)
)
EXPLAIN
SELECT*
FROMcustomers
WHEREname='FromDual';
+++++++
|table|type|possible_keys|key|rows|Extra|
+++++++
|customers|ALL|NULL|NULL|31978|Usingwhere|
+++++++
8 / 30

Wie legt man Indices an?

www.fromdual.com

ALTERTABLE

ADDPRIMARYKEY(id);

ADDUNIQUEKEY(uuid);

ADDFOREIGNKEY(customer_id)
REFERENCEScustomers(customer_id);

ADDINDEX(last_name,first_name);

ADDINDEXpre_ind(hash(8));

ADDFULLTEXTINDEX(last_name,
first_name);
9 / 30

WHERE Klausel 2

www.fromdual.com

ALTERTABLEcustomers
ADDINDEX(name);

CREATETABLE`customers`(
`customer_id`smallint(5)unsigned
Verbesserung:
20 ms 5 ms
,`name`varchar(64)DEFAULTNULL
,PRIMARYKEY(`customer_id`)
,KEY`name`(`name`)
)

+-----------+------+---------------+------+---------+-------+------+
| table
| type | possible_keys | key | key_len | ref
| rows |
+-----------+------+---------------+------+---------+-------+------+
| customers | ref | name
| name | 67
| const |
1 |
+-----------+------+---------------+------+---------+-------+------+
10 / 30

JOIN Klausel

www.fromdual.com

EXPLAINSELECT*
FROMcustomersASc
JOINordersASoONc.customer_id=o.customer_id
WHEREc.name='FromDual';
++++++++
|table|type|possible_keys|key|key_len|ref|rows|
++++++++
|c|ref|PRIMARY,name|name|67|const|1|
|o|ALL|NULL|NULL|NULL|NULL|1045105|
++++++++

Verbesserung: 450 ms 6 ms

ALTERTABLEorders
ADDINDEX(customer_id);
+-------+------+---------------+-------------+---------+---------------+------+
| table | type | possible_keys | key
| key_len | ref
| rows |
+-------+------+---------------+-------------+---------+---------------+------+
| c
| ref | PRIMARY,name | name
| 67
| const
|
1 |
| o
| ref | customer_id
| customer_id | 3
| c.customer_id |
8 |
+-------+------+---------------+-------------+---------+---------------+------+
11 / 30

Tabellen sortieren oder gruppieren

www.fromdual.com

ORDERBY,GROUPBY
EXPLAINSELECT*
FROMcontactsASc
WHERElast_name='Sennhauser'
ORDERBYlast_name,first_name;
++++++
|table|type|key|rows|Extra|
++++++
|c|ref|last_name|1561|Usingindexcondition;Usingwhere;Usingfilesort|
++++++

Verbesserung : 20 ms 7 ms

ALTERTABLEcontacts
ADDINDEX(last_name,first_name);
++++++
|table|type|key|rows|Extra|
++++++
|c|ref|last_name_2|1561|Usingwhere;Usingindex|
++++++
12 / 30

Covering Indices

www.fromdual.com

EXPLAIN
SELECTcustomer_id,amount
FROMordersASo
WHEREcustomer_id=59349;
++++++
|table|type|key|rows|Extra|
++++++
Und jetzt?
|o|ref|customer_id|15|NULL|
++++++
ALTERTABLEorders
ADDINDEX(customer_id,amount);
++++++
|table|type|key|rows|Extra|
++++++
|o|ref|customer_id_2|15|Usingindex|
++++++
13 / 30

Vorteil von Covering Indices

www.fromdual.com

Warum sind Covering Indices vorteilhaft?

ohne

mit
14 / 30

Finden von fehlenden Indices

www.fromdual.com

ER Diagramm? :-(
Hngt hauptschlich von der Business
Logik ab...
Wie FINDET man sie? --> Slow Query Log

MySQL Variablen:
Seit v5.1
on-line!

+-------------------------------+----------+
| Variable_name
| Value
|
+-------------------------------+----------+
| log_queries_not_using_indexes | ON
|
| long_query_time
| 0.250000 |
| min_examined_row_limit
| 100
|
| slow_query_log
| ON
|
| slow_query_log_file
| slow.log |
+-------------------------------+----------+
15 / 30

Indices sind nicht nur gut!

www.fromdual.com

Indices brauchen Platz (Platte, heisse Daten im RAM!)

Indices brauchen Zeit fr Wartung (CPU, RAM, I/O)

Optimizer braucht Zeit um herauszufinden, welchen


Index er nehmen soll.
Manchmal ist der Optimizer vllig verwirrt und trifft eine
falsche Entscheidung wenn zu viele (hnliche) Indices
vorhanden sind.
Es gilt die richtige Balance
fr schnelle Abfragen und
optimalen Indices zu finden.

16 / 30

Kleiner Index schnelle Abfrage

www.fromdual.com

Passt besser in RAM (weniger I/O)

Hhere Datendichte (Rows/Block)

Weniger CPU Zyklen

Prefixed Index:
ADDINDEXpre_ind(hash(8));

17 / 30

Indices vermeiden

Vermeide redundante (daher unntige) Indices

Wie kann so was passieren?

www.fromdual.com

Entwickler 1: Kreiert einen Foreign Key Constraint erledigt


Entwickler 2: Ouu! Abfrage ist langsam Oli hat gesagt:
Index anlegen erledigt
Entwickler 3: Ouu! Anfrage ist langsam Entwickler 2 ist ein
Idiot! Index anlegen erledigt
Frameworks vs. Entwickler

Upgrade Prozess vs. DevOps

Vermeide Indexes welche nicht benutz/bentigt werden!

18 / 30

Wie findet man solche Indices?

www.fromdual.com

SHOWCREATETABLE...\G
mysqldumpnodata>structure_dump.sql

Seit MySQL 5.6: PERFORMANCE_SCHEMA

Percona Server / MariaDB: Userstats

http://fromdual.com/mysql-performance-schema-hints
SELECT
FROM
WHERE
AND
ORDER

object_schema, object_name, index_name


performance_schema.table_io_waits_summary_by_index_usage
index_name IS NOT NULL
count_star = 0
BY object_schema, object_name;
19 / 30

Vermeide partiell redundante


Indices

www.fromdual.com

INDEX(city,last_name,first_name)

INDEX(city,last_name)

INDEX(city)

INDEX(last_name,city) ???

INDEX(first_name,last_name) !!!

20 / 30

Schlechte Selektivitt

Weg mit Indices mit schlechter Selektivitt (~= geringe


Kardinalitt)
Kandidaten sind:

status

gender

active

Wie findet man ob ein Feld eine


schlechte Selektivitt hat?
Indices (und Joins) sind teuer!!!

www.fromdual.com

SELECT status, COUNT(*)


FROM orders
GROUP BY status;
+--------+--------+
| status | cnt
|
+--------+--------+
|
0 | 393216 |
|
1 | 262144 |
|
2 |
12 |
|
3 |
36 |
|
4 |
24 |
|
5 |
4 |
|
6 |
8 |
+--------+--------+

Break-even zwischen 15% und 66%


Schauen wir mal ob der MySQL
Optimizer davon weiss... :-)
21 / 30

Optimizer liegt falsch!


SELECT * FROM orders WHERE status = 2;
+--------+------+---------------+--------+------+
| table | type | possible_keys | key
| rows |
+--------+------+---------------+--------+------+
| orders | ref | status
| status |
12 |
+--------+------+---------------+--------+------+
SELECT * FROM orders WHERE status = 0;
1.43 s
+--------+------+---------------+--------+--------+
| table | type | possible_keys | key
| rows
|
+--------+------+---------------+--------+--------+
| orders | ref | status
| status | 327469 |
+--------+------+---------------+--------+--------+

5.6.12 (nach ANALYZETABLE)

www.fromdual.com

SELECT status, COUNT(*)


FROM orders
GROUP BY status;
+--------+--------+
| status | cnt
|
+--------+--------+
|
0 | 393216 |
|
1 | 262144 |
|
2 |
12 |
|
3 |
36 |
|
4 |
24 |
|
5 |
4 |
|
6 |
8 |
+--------+--------+

SELECT * FROM orders IGNORE INDEX (status) WHERE status = 0;


0.44 s
+--------+------+---------------+------+--------+
| table | type | possible_keys | key | rows
|
+--------+------+---------------+------+--------+
| orders | ALL | NULL
| NULL | 654939 |
+--------+------+---------------+------+--------+
22 / 30

InnoDB PK und SK

www.fromdual.com

InnoDB kennt

Primary Keys und


Secondary Keys

23 / 30

Geclusterter Index

www.fromdual.com

InnoDB: Daten = Bltter des Primary Keys


Heisst auch Index Clustered Table (IOT)
Daten sind sortiert wie PK (Index ist sortiert)!
PK beeinflusst Lokalitt der Daten (physische
Lage)
AUTO_INCREMENT ~= Sortieren nach Zeit!

Gut in vielen Fllen


Wenn heisse Daten = aktuelle Daten
Schlecht fr Zeitreihen

Wenn heisse Daten = Daten pro Objekt


24 / 30

Beispiel: InnoDB

www.fromdual.com

A_Itsv_idxposypos...
117:30#42x,y,...
217:30#43x,y,...
317:30#44x,y,...

#42

alle 2'

...
200117:32#42x,y,...
200217:32#43x,y,...
200317:32#44x,y,...
Q1: in Zeilen? ~ 2000 Zeilen
A1: 1 Zeile ~ 100 byte
Q2: in bytes? ~ 200 kbyte
Q3: Default InnoDB block size? default: 16 kbyte
Q4: Avg. # Zeilen von LKW #42 in 1 InnoDB block? ~ 1
A2: 3 d und 720 pt/d ~2000 pt ~ 2000 rec ~ 2000 blk
Q5: Wie lange dauert das und warum (32 Mbyte)?
~ 2000 IOPS ~ 10s random read!!!
S: Alles im RAM oder starkes I/O-System oder ?

2000 LKWs

die letzten 3 Tage


25 / 30

Geclusterter PK rettet den Tag!

www.fromdual.com

tsv_idxposypos...
17:30#42x,y,...
17:32#42x,y,...
17:34#42x,y,...

...

#42

alle 2'

17:30#43x,y,...
17:32#43x,y,...
17:34#43x,y,...

...
17:30#44x,y,...

2000 LKWs

Q1: Avg. # Zeilen von LKW #42 in 1 InnoDB block? ~ 120


A1: 3 d und 720 pt/d ~2000 pt ~ 2000 rec ~ 20 blk
Q2: Wie lange dauert das und warum (320 kbyte)?
~ 1-2 IOPS ~ 10-20 ms sequential read!
S: Wow f=50 schneller! Nachteile?

die letzten 3 Tage


26 / 30

Index Hints

www.fromdual.com

MySQL Optimizer liegt manchmal falsch!


Wir mssen ihm nachhelfen...
Index Hints (Hinweise) sind:

USEINDEX(ind1,ind2)
Schau nur diese Indices an...
FORCEINDEX(ind3)

Nimm diesen Index ohne weiter nachzudenken


IGNOREINDEX(ind1,ind3)

Schau Dir alle Indices ausser diese an


Hints nur als allerletzte Rettung verwenden!

27 / 30

MySQL Variablen

www.fromdual.com

MySQL Variablen welche Indices beeinflussen

MyISAM: key_buffer_size

InnoDB: innodb_buffer_pool_size

InnoDB Change Buffer

innodb_change_buffer_max_size

innodb_change_buffering

Adaptive Hash Index (AHI)

MySQL 5.6.3 / 5.5.14 Indexlnge 767 3072 bytes

innodb_large_prefix

28 / 30

Wir suchen noch:

www.fromdual.com

Datenbank Enthusiast/in fr Support /


remote-DBA / Beratung
29 / 30

Q&A

www.fromdual.com

Fragen ?
Diskussion?
Anschliessend ist noch Zeit fr ein persnliches Gesprch...

FromDual bietet neutral und unabhngig:

MySQL Beratung

Remote-DBA

Support fr MySQL, Galera Cluster, MariaDB und Percona Server

MySQL Schulung

www.fromdual.com/presentations
30 / 30

You might also like