Count Queries
• Manual: add custom code before queries.
• Auto: ORMs have listeners or data
collectors.
Slide 9
Slide 9 text
Slow Query log
• Open my.cnf
• Queries taking 0.2s or longer will be
logged.
• Open the log file and analyze the queries.
slow_query_log=ON
long_query_time=0.2
slow_query_log_file=/path/to/file
Slide 10
Slide 10 text
Example Schema
200
users
100
albums each
100
pictures each
2,000,000 pictures
Slide 11
Slide 11 text
Simple Query
• Get all pictures from user #1
• 38 seconds.
SELECT picture.id, picture.title
FROM picture
LEFT JOIN album ON picture.album_id = album.id
WHERE album.user_id = 1;
Slide 12
Slide 12 text
Why is it so Slow?
Slide 13
Slide 13 text
Explain
• Prefix with EXPLAIN:
• Each row = table scanned:
EXPLAIN SELECT picture.id, picture.title
FROM picture
LEFT JOIN album ON picture.album_id = album.id
WHERE album.user_id = 1;
+----+-------------+---------+------+---------------+------+---------+------+---------+--------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+---------------+------+---------+------+---------+--------------------------------+
| 1 | SIMPLE | album | ALL | NULL | NULL | NULL | NULL | 20000 | Using where |
| 1 | SIMPLE | picture | ALL | NULL | NULL | NULL | NULL | 2000000 | Using where; Using join buffer |
+----+-------------+---------+------+---------------+------+---------+------+---------+--------------------------------+
Slide 14
Slide 14 text
Explain
• Details:
• Because of the join,
we’re scanning all albums for each
picture.
• 40 billion rows scanned.
table : album
key : NULL
rows : 20,000
table : picture
key : NULL
rows : 2,000,000
Slide 15
Slide 15 text
Indexes
Slide 16
Slide 16 text
How do They Work?
Slide 17
Slide 17 text
Add an Index
• album.id
• Same query down to 2.38 sec.
• We just saved 36 sec on every request!
ALTER TABLE album ADD PRIMARY KEY(id);
Slide 18
Slide 18 text
Under the Hood
• Details:
• With the index,
we find our album right away.
• Total 2,000,000 rows scanned.
table : album
key : PRIMARY
rows : 1
table : picture
key : NULL
rows : 2,000,000
Slide 19
Slide 19 text
Add a Better Index
• picture.album_id
• Now down to 0.12 sec.
• 317 times faster than original.
ALTER TABLE picture ADD INDEX(album_id);
Slide 20
Slide 20 text
Under the Hood
• Details:
• Total 200,000 rows scanned.
table : album
key : NULL
rows : 20,000
table : picture
key : album_id
rows : 100
Slide 21
Slide 21 text
Add a Better Index
• album.user_id
• Now down to 0.10 sec.
• Gained another 17% in speed.
ALTER TABLE album ADD INDEX(user_id);
Slide 22
Slide 22 text
Under the Hood
• Details:
• With the second index,
we’re scanning 100 pics.
• Total 10,000 rows scanned.
table : album
key : user_id
rows : 100
table : picture
key : album_id
rows : 100
Slide 23
Slide 23 text
Don't Index Everything!
There is an index on each field
And all selects take long to yield.
Try finding which ones you need,
Remove the rest and feel the speed.
-- Anna Filina
Slide 24
Slide 24 text
Indexes Used
• Primary and foreign keys make for great
indexes.
• Also whatever you use in JOIN, WHERE,
ORDER BY.
Slide 25
Slide 25 text
Index Criteria
• Change frequency
◦ Good: picture.date
◦ Bad: picture.views
• Selectivity: how many different values?
◦ Good: user.id
◦ Bad: user.is_active
Slide 26
Slide 26 text
Indexing Strings
• Useful for LIKE searches.
• InnoDB
ALTER TABLE photo ADD FULLTEXT INDEX(description);
Slide 27
Slide 27 text
Should We Optimize
Further?
Slide 28
Slide 28 text
Airport Customs
• 5 customs officers, 1 min to process a
traveller.
• 5 travellers / min = fluid.
• 6 travellers / min = queue slowly builds.
• 1000 travellers / min = 3h wait if you
arrive on 2nd minute.
Slide 29
Slide 29 text
Smaller Indexes
• BIGINT as index is slower than TINYINT.
• Use UNSIGNED to double the maximum
value.
Slide 30
Slide 30 text
Tips for Better
Queries
Slide 31
Slide 31 text
Functions
• Avoid functions on an indexed column:
• The index will be ignored here.
SELECT id, title FROM picture
WHERE YEAR(created_date) >= 2011;
Slide 32
Slide 32 text
Limit
• Now down to 0.0009 sec.
• 100 times faster than the previous query.
• 42,000 times faster than original.
SELECT picture.id, picture.title
FROM picture
LEFT JOIN album ON picture.album.id = album.id
WHERE album.user_id = 1
LIMIT 25;
Slide 33
Slide 33 text
Other Constraints
• Range:
• Only makes sense if that column is
indexed:
SELECT picture.id, picture.title
FROM picture
LEFT JOIN album ON picture.album.id = album.id
WHERE album.user_id = 1
AND picture.id BETWEEN 26 AND 50; # 0.023 sec
ALTER TABLE picture ADD INDEX(id);
Slide 34
Slide 34 text
Other Constraints
• IN clause:
SELECT picture.id, picture.title
FROM picture
LEFT JOIN album ON picture.album.id = album.id
WHERE album.user_id = 1
AND picture.id IN (15,26,29,32,45); # 0.048 sec
Slide 35
Slide 35 text
Story
Slide 36
Slide 36 text
Problem
• New features released before sale
• Index was not used
• Creating too many tmp tables on disk
• Slow queries
• Long queue
Slide 37
Slide 37 text
How Did I Find the Problem?
• Status:
SHOW GLOBAL STATUS;
+------------------------------------------+-------------+
| Variable_name | Value |
+------------------------------------------+-------------+
| Aborted_clients | 0 |
| Aborted_connects | 0 |
| Binlog_cache_disk_use | 0 |
| Binlog_cache_use | 0 |
| Binlog_stmt_cache_disk_use | 0 |
| Binlog_stmt_cache_use | 0 |
| Bytes_received | 23378012 |
| Bytes_sent | 2707328 |
Slide 38
Slide 38 text
How Did I Find the Problem?
• Created_tmp_disk_tables
◦ Temporary tables created on order by, group
by, etc.
◦ Stored on disk when can't fit in RAM
◦ Maybe too big resultset.
◦ Are we using index?
• Handler_read_rnd_next
◦ Full or partial table scan
Slide 39
Slide 39 text
Split Tables
• MySQL can partition your tables
transparently.
◦ Creates multiple files on disk.
◦ Shows data as a single table.
Slide 40
Slide 40 text
Archives
• MySQL ARCHIVE storage engine:
◦ Doesn’t support UPDATE or DELETE
◦ Very fast for SELECT
• You can archive old transactions, news,
etc.
Slide 41
Slide 41 text
Split Databases
• Horizontal partitioning, sharding.
• Users 1-1000 and their data in database
#1
• Users 1001-2000 and their data in
database #2
Slide 42
Slide 42 text
Checklist
✓Count queries.
✓Log the slow ones.
✓Use EXPLAIN and
check number of
rows scanned.
✓Try different
indexes, remove
unused ones.
✓Use small indexes,
preferably
numeric.
✓Don’t use
functions on
indexed columns.
✓Make sure indexes
are used.
✓Limit number of
results.
✓Different storage
engines.
✓Split tables and
databases.