94
MySQL under the siege Database performance @SrcMinistry @MariuszGil

MySQL under the siege

Embed Size (px)

Citation preview

Page 1: MySQL under the siege

MySQL under the siege

Database performance

@SrcMinistry @MariuszGil

Page 2: MySQL under the siege

@SrcMinistry

Page 3: MySQL under the siege
Page 4: MySQL under the siege

Intro

Page 5: MySQL under the siege

LAMP

Page 6: MySQL under the siege

AdoDB

Page 7: MySQL under the siege

LNMP

Page 8: MySQL under the siege

LNMRP

Page 9: MySQL under the siege

LNMRRP

Page 10: MySQL under the siege

MySQL is still with us!

Page 11: MySQL under the siege

Reputation

Page 12: MySQL under the siege

4.x / MyISAM

Page 13: MySQL under the siege

Do you know MySQL?

Page 14: MySQL under the siege

Today

Page 15: MySQL under the siege

Decoupling from database

Page 16: MySQL under the siege

Database abstractions

Page 17: MySQL under the siege

Backend replacement

Page 18: MySQL under the siege
Page 19: MySQL under the siege

Problem

Page 20: MySQL under the siege

We’re living in web-scale era

Page 21: MySQL under the siege

Many unique users per day

Page 22: MySQL under the siege

Many queries per second

Page 23: MySQL under the siege
Page 24: MySQL under the siege

NoSQL!

Page 25: MySQL under the siege
Page 26: MySQL under the siege

MySQL is mature, stable and it just works.

Marty Weiner, Pinterest

Page 27: MySQL under the siege

Schema first

Page 28: MySQL under the siege

Schema last

Page 29: MySQL under the siege

Workloads

Page 30: MySQL under the siege

Writes?

Page 31: MySQL under the siege

Reads?

Page 32: MySQL under the siege

Data volume

Page 33: MySQL under the siege

DistroMySQL MariaDBPercona Server Drizzle WebScaleSQL

Page 34: MySQL under the siege

Use case

Page 35: MySQL under the siege

id client_id amount description created

Page 36: MySQL under the siege

id client_id amount description created

…{750M

} 1-3 months

Page 37: MySQL under the siege

Explaining

Page 38: MySQL under the siege

EXPLAIN EXTENDED SELECT City.Name FROM CityJOIN Country ON (City.CountryCode = Country.Code)WHERE City.CountryCode = 'IND' AND Country.Continent = 'ASIA' \G

********************** 1. row ********************** id: 1 select_type: SIMPLE table: Country type: const possible_keys: PRIMARY key: PRIMARY key_len: 3 ref: const rows: 1 filtered: 100.00 Extra: ********************** 2. row ********************** id: 1 select_type: SIMPLE table: City type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 4079 filtered: 100.00 Extra: Using where 2 rows in set, 1 warning (0.00 sec)

Page 39: MySQL under the siege

Simple tricks

Page 40: MySQL under the siege

Pagination

Page 41: MySQL under the siege

SELECT * FROM transactionWHERE client_id = 1 AND created BETWEEN '2015-01-01 00:00:00' AND '2015-03-10 23:59:59'ORDER BY created DESCLIMIT 10 OFFSET 1000 SELECT COUNT(*) FROM transactionWHERE client_id = 1 AND created BETWEEN '2015-01-01 00:00:00' AND '2015-03-10 23:59:59'

Page 42: MySQL under the siege

SELECT * FROM transactionWHERE client_id = 1 AND created BETWEEN '2015-01-01 00:00:00' AND '2015-03-10 23:59:59'ORDER BY created DESCLIMIT 11 OFFSET 1000

Page 43: MySQL under the siege

Indexes

Page 44: MySQL under the siege

CREATE INDEX description_idx ON transaction(description);

Page 45: MySQL under the siege

Selectivity

Page 46: MySQL under the siege

SELECT COUNT(*) FROM transaction; SELECT COUNT(DISTINCT(description)) FROM transaction; SELECT COUNT(DISTINCT(SUBSTRING(description, 1, 4))) FROM transaction; SELECT COUNT(DISTINCT(SUBSTRING(description, 1, 5))) FROM transaction; SELECT COUNT(DISTINCT(SUBSTRING(description, 1, 6))) FROM transaction; SELECT COUNT(DISTINCT(SUBSTRING(description, 1, 7))) FROM transaction; SELECT COUNT(DISTINCT(SUBSTRING(description, 1, 8))) FROM transaction; SELECT COUNT(DISTINCT(SUBSTRING(description, 1, 9))) FROM transaction; CREATE INDEX desc_idx ON transaction(description[8]);

Page 47: MySQL under the siege

(A, B) != (B, A)

Page 48: MySQL under the siege

Covering

Page 49: MySQL under the siege

SELECT * FROM transactionWHERE client_id = 1 AND created BETWEEN '2015-01-01 00:00:00' AND '2015-03-10 23:59:59'ORDER BY created DESCLIMIT 10

Page 50: MySQL under the siege

SELECT id FROM transactionWHERE client_id = 1 AND created BETWEEN '2015-01-01 00:00:00' AND '2015-03-10 23:59:59'ORDER BY id DESCLIMIT 10

Page 51: MySQL under the siege

Clustering

Page 52: MySQL under the siege

Caching

Page 53: MySQL under the siege

There are only two hard things in Computer Science: cache invalidation and naming things.

Phil Karlton

Page 54: MySQL under the siege

Query cache

Page 55: MySQL under the siege

Memcached

Page 56: MySQL under the siege

SELECT * FROM transaction AS t JOIN product AS p ON (p.id = t.product_id)WHERE t.client_id = 1 AND t.created BETWEEN '2015-03-10 00:00:00' AND '2015-03-10 23:59:59'

Page 57: MySQL under the siege

SELECT * FROM transaction AS t WHERE t.client_id = 1 AND t.created BETWEEN '2015-03-10 00:00:00' AND '2015-03-10 23:59:59’

SELECT * FROM productWHERE id IN (..., ..., ..., ..., ...)

Page 58: MySQL under the siege

InnoDB memcached plugin

Page 59: MySQL under the siege

ID generation

Page 60: MySQL under the siege
Page 61: MySQL under the siege

ID strategiesAuto integer Hashed strings* Auto integer + url hashing …* really bad idea…

Page 62: MySQL under the siege

<?php/* … */namespace \Doctrine\ORM\Id; use Doctrine\ORM\Id\AbstractIdGenerator; use Doctrine\ORM\EntityManager; /** * Represents an ID generator that uses the bigint generation. * * @since 1.0 */class BigIntGenerator extends AbstractIdGenerator{ /** * {@inheritdoc} */ public function generate(EntityManager $em, $entity) { return bcadd( time() << 32, rand(0, bcsub(bcpow(2, 32), 1)) ); } /** * {@inheritdoc} */ public function isPostInsertGenerator() { return false; } }

Page 63: MySQL under the siege

Partitioning

Page 64: MySQL under the siege

Functional partitioning

Page 65: MySQL under the siege

Data partitioning

Page 66: MySQL under the siege

id client_id amount description created id client_id amount description created

client_id % 8 = 0 client_id % 8 = 1

Page 67: MySQL under the siege

CREATE TABLE transaction ( --- DEFINITION) PARTITION BY HASH ( client_d )PARTITIONS 8;

Page 68: MySQL under the siege

id client_id amount description created id client_id amount description created

Nov 2015 Oct 2015

Page 69: MySQL under the siege

CREATE TABLE transaction ( --- DEFINITION) PARTITION BY RANGE ( UNIX_TIMESTAMP(created) ) ( PARTITION p0 VALUES LESS THAN ( UNIX_TIMESTAMP('2015-06-01 00:00:00') ), PARTITION p1 VALUES LESS THAN ( UNIX_TIMESTAMP('2015-07-01 00:00:00') ), PARTITION p2 VALUES LESS THAN ( UNIX_TIMESTAMP('2015-08-01 00:00:00') ), PARTITION p3 VALUES LESS THAN ( UNIX_TIMESTAMP('2015-09-01 00:00:00') ), PARTITION p4 VALUES LESS THAN ( UNIX_TIMESTAMP('2015-10-01 00:00:00') ), PARTITION p5 VALUES LESS THAN ( UNIX_TIMESTAMP('2015-11-01 00:00:00') ), PARTITION p6 VALUES LESS THAN ( UNIX_TIMESTAMP('2015-12-01 00:00:00') ), PARTITION pX VALUES LESS THAN ( MAXVALUE ));

Page 70: MySQL under the siege

id client_id amount description created id client_id amount description created

Nov 2015 Oct 2015

id client_id amount description created

client_id % 8 = 0

id client_id amount description created

client_id % 8 = 1

id client_id amount description created

client_id % 8 = 0

id client_id amount description created

client_id % 8 = 1

Page 71: MySQL under the siege

CREATE TABLE transaction ( --- DEFINITION) PARTITION BY RANGE ( UNIX_TIMESTAMP(created) ) SUBPARTITION BY HASH ( client_id ) SUBPARTITIONS 8 ( PARTITION p0 VALUES LESS THAN ( UNIX_TIMESTAMP('2015-06-01 00:00:00') ), PARTITION p1 VALUES LESS THAN ( UNIX_TIMESTAMP('2015-07-01 00:00:00') ), PARTITION p2 VALUES LESS THAN ( UNIX_TIMESTAMP('2015-08-01 00:00:00') ), PARTITION p3 VALUES LESS THAN ( UNIX_TIMESTAMP('2015-09-01 00:00:00') ), PARTITION p4 VALUES LESS THAN ( UNIX_TIMESTAMP('2015-10-01 00:00:00') ), PARTITION p5 VALUES LESS THAN ( UNIX_TIMESTAMP('2015-11-01 00:00:00') ), PARTITION p6 VALUES LESS THAN ( UNIX_TIMESTAMP('2015-12-01 00:00:00') ), PARTITION pX VALUES LESS THAN ( MAXVALUE ));

Page 72: MySQL under the siege

Denormalization

Page 73: MySQL under the siege

object_id user_id name created attr_1 attr_2 …

add columns

Page 74: MySQL under the siege

ALTER TABLE…

Page 75: MySQL under the siege

object_id user_id name created object_id attr_name attr_value

+add rows

Page 76: MySQL under the siege

Flagging

Page 77: MySQL under the siege

object_id user_id name created flag_1 flag_2 …

add columns

flag = 20 * flag1 + 21 * flag2 + 22 * flag3 + …

Page 78: MySQL under the siege

3NF is UFO*

* in web-scale applications

Page 79: MySQL under the siege

Maintenance

Page 80: MySQL under the siege

1 hour3 months

Page 81: MySQL under the siege

Lessons learned1. Identify bottleneck early 2. Remove biggest bottleneck early 3. Repeat

Page 82: MySQL under the siege

Tools

Page 83: MySQL under the siege

Slow log

Page 84: MySQL under the siege

# Time: 150109 11:38:55# User@Host: root[root] @ localhost []# Thread_id: 40 Schema: world Last_errno: 0 Killed: 0 # Query_time: 0.012989 Lock_time: 0.000033 Rows_sent: 4079 Rows_examined: 4079 Rows_affected: 0 Rows_read: 4079# Bytes_sent: 161085# Stored routine: world.improved_sp_logSET timestamp=1420803535; SELECT * FROM City; # Time: 130601 8:03:20.700441# User@Host: root[root] @ localhost [] Id: 43 # Schema: imdb Last_errno: 0 Killed: 0 # Query_time: 7.815071 Lock_time: 0.000261 Rows_sent: 4 Rows_examined: 1543720 Rows_affected: 0 # Bytes_sent: 272# Profile_starting: 0.000125 Profile_starting_cpu: 0.000120Profile_checking_permissions: 0.000021 Profile_checking_permissions_cpu: 0.000021Profile_Opening_tables: 0.000049 Profile_Opening_tables_cpu: 0.000048 Profile_init: 0.000048Profile_init_cpu: 0.000049 Profile_System_lock: 0.000049 Profile_System_lock_cpu: 0.000048Profile_optimizing: 0.000024 Profile_optimizing_cpu: 0.000024 Profile_statistics: 0.000036Profile_statistics_cpu: 0.000037 Profile_preparing: 0.000029 Profile_preparing_cpu: 0.000029Profile_executing: 0.000012 Profile_executing_cpu: 0.000012 Profile_Sending_data: 7.814583Profile_Sending_data_cpu: 7.811634 Profile_end: 0.000013 Profile_end_cpu: 0.000012Profile_query_end: 0.000014 Profile_query_end_cpu: 0.000014 Profile_closing_tables: 0.000023Profile_closing_tables_cpu: 0.000023 Profile_freeing_items: 0.000051Profile_freeing_items_cpu: 0.000050 Profile_logging_slow_query: 0.000006Profile_logging_slow_query_cpu: 0.000006# Profile_total: 7.815085 Profile_total_cpu: 7.812127SET timestamp=1370073800; SELECT id,title,production_year FROM title WHERE title = 'Bambi';

Page 85: MySQL under the siege

I/O

Page 86: MySQL under the siege

procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu---- r b swpd free buff cache si so bi bo in cs us sy id wa 0 0 1360 27788 125860 269804 0 0 390 43 308 572 8 3 84 5

Page 87: MySQL under the siege

Server status

Page 88: MySQL under the siege

mysql> SHOW STATUS; +--------------------------+------------+ | Variable_name | Value | +--------------------------+------------+ | Aborted_clients | 0 | | Aborted_connects | 0 | | Bytes_received | 155372598 | | Bytes_sent | 1176560426 | | Connections | 30023 | | Created_tmp_disk_tables | 0 | | Created_tmp_tables | 8340 | | Created_tmp_files | 60 | ... | Open_tables | 1 | | Open_files | 2 | | Open_streams | 0 | | Opened_tables | 44600 | | Questions | 2026873 | ... | Table_locks_immediate | 1920382 | | Table_locks_waited | 0 | | Threads_cached | 0 | | Threads_created | 30022 | | Threads_connected | 1 | | Threads_running | 1 | | Uptime | 80380 | +--------------------------+------------+

Page 89: MySQL under the siege
Page 90: MySQL under the siege

InnoTOP

Page 91: MySQL under the siege

Tests

Page 92: MySQL under the siege

Performance schema

Page 93: MySQL under the siege
Page 94: MySQL under the siege

@SrcMinistry

Thanks!

@MariuszGil

https://joind.in/16254