Top Banner
High Performance Rails with MySQL Jervin Real, March 2014
45

High Performance Rails with MySQL

May 10, 2015

Download

Software

Jervin Real

RubyConfPH 2014
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: High Performance Rails with MySQL

High Performance Rails with MySQLJervin Real, March 2014

Page 2: High Performance Rails with MySQL

I am…

• Consultant, Percona

• @dotmanila

• http://dotmanila.com/blog/

• http://www.mysqlperformanceblog.com/

Page 3: High Performance Rails with MySQL

Rails Fu Mastah!

http://walksalong.files.wordpress.com/2007/05/bruce_on_rails.jpg

Page 4: High Performance Rails with MySQL

Beginner

http://www.devonring.ca/img/ouch.png

Page 5: High Performance Rails with MySQL

Customer Problems

Page 6: High Performance Rails with MySQL

Web Apps Performance

• Powerful servers

• CPUs, higher clock speeds

• Lots of memory

• Fast storage

• Scale in the cloud

• Agile development techniques

Page 7: High Performance Rails with MySQL

Why Not?

• Premature scaling is expensive

• Cost inefficient

• Agile means less effective measurement to compensate

for fast deployments

Page 8: High Performance Rails with MySQL

Squeeze the Software

• Exhaust application optimizations first

• You cannot optimize what you can’t measure

• Cacti, NewRelic, Scout

• NewRelic RPM Developer Mode, Rails Footnotes (2, 3,

4!), Google PerfTools for Ruby

Page 9: High Performance Rails with MySQL

• Dumb schemas and queries (somewhat)

Characteristics of Rails

:primary_key, :string, :text, :integer, :float, :decimal, :datetime, :timestamp, :time, :date, :binary, :boolean

Page 10: High Performance Rails with MySQL

• Dumb schemas

• Likes to use SHOW FIELDS

Characteristics of Rails

Page 11: High Performance Rails with MySQL

• Dumb schemas

• Likes to use SHOW FIELDS

• N+1 queries problem

• Well documented and discouraged for use

Characteristics of Rails

Page 12: High Performance Rails with MySQL

• Dumb schemas

• Likes to use SHOW FIELDS

• N+1 queries problem

• Well documented and discouraged for use

• Does SELECT FOR UPDATE

• NOOP transactions still wrapped in BEGIN/COMMIT

Characteristics of Rails

Page 13: High Performance Rails with MySQL

• FK relationships - logical - GOOD

Rails - Good

Page 14: High Performance Rails with MySQL

• FK relationships - logical - GOOD

• Knows how to use PRIMARY KEYs — VERY GOOD!

Rails - Good

Page 15: High Performance Rails with MySQL

• FK relationships - logical - GOOD

• Knows how to use PRIMARY KEYs — VERY GOOD!

• Knows NOOP changes - GOOD

Rails - Good

Page 16: High Performance Rails with MySQL

• FK relationships - logical - GOOD

• Knows how to use PRIMARY KEYs — VERY GOOD!

• Knows NOOP changes - GOOD

• Database agnostic - GOOD

Rails - Good

Page 17: High Performance Rails with MySQL

MySQL by Default

• Assumes you have less powerful hardware

• ironically on 5.5, assumes you have very powerful

CPUs - innodb_thread_concurrency = 0

Page 18: High Performance Rails with MySQL

MySQL by Default

• Assumes you have less powerful hardware

• ironically on 5.5, assumes you have very powerful

CPUs - innodb_thread_concurrency = 0

• Not optimized for faster storage

Page 19: High Performance Rails with MySQL

MySQL by Default

• Assumes you have less powerful hardware

• ironically on 5.5, assumes you have very powerful

CPUs - innodb_thread_concurrency = 0

• Not optimized for faster storage

• Still have bad configuration assumptions

• Query cache

• MyISAM < 5.5.5

Page 20: High Performance Rails with MySQL

MySQL by Default

• Assumes you have less powerful hardware

• ironically on 5.5, assumes you have very powerful

CPUs - innodb_thread_concurrency = 0

• Not optimized for faster storage

• Still have bad configuration assumptions

• Query cache

• MyISAM < 5.5.5

• Still haunted by mutexes

Page 21: High Performance Rails with MySQL

What to Optimize - MySQL

• Disable Query Cache

Page 22: High Performance Rails with MySQL

What to Optimize - MySQL

• Disable Query Cache

• query_cache_size = 0

Page 23: High Performance Rails with MySQL

What to Optimize - MySQL

• Disable Query Cache

• query_cache_size = 0

• query_cache_type = 0

Page 24: High Performance Rails with MySQL

What to Optimize - MySQL

• Disable Query Cache

• skip_name_resolve

Page 25: High Performance Rails with MySQL

What to Optimize - MySQL

• Disable Query Cache

• skip_name_resolve

• Use >= 5.5

Page 26: High Performance Rails with MySQL

What to Optimize - MySQL

• Disable Query Cache

• skip_name_resolve

• Use >= 5.5

• Use Indexes, EXPLAIN should be your friend!

Page 27: High Performance Rails with MySQL

What to Optimize - MySQL

• Disable Query Cache

• skip_name_resolve

• Use >= 5.5

• Use Indexes, EXPLAIN should be your friend!

• 5.6 does Subquery Optimizations

Page 28: High Performance Rails with MySQL

What to Optimize - MySQL

• Slow queries - search and destroy

• long_query_time = 0

• log_slow_verbosity - Percona Server

• pt-query-digest/Percona Cloud Tools

Page 29: High Performance Rails with MySQL

What to Optimize - MySQL

• Use InnoDB

innodb_buffer_pool_size       #  keep  hot  data  in  memory  innodb_log_file_size             #  allow  more  IO  buffer  innodb_flush_method  =  O_DIRECT  #  skip  OS  cache  innodb_[read|write]_io_threads  >  4  innodb_io_capacity  innodb_adaptive_flushing_method

Page 30: High Performance Rails with MySQL

What to Optimize - Rails

• counter_cache

• Good for InnoDB if you often SELECT COUNT(*)

• Indexes for find_by, where and family@posts  =  Post.where(title:  params[:keyword])  !mysql>  EXPLAIN  SELECT  `posts`.*  FROM  `posts`    WHERE  `posts`.`title`  =  'LongTitles'  \G  ***************************  1.  row  ***************************                        id:  1      select_type:  SIMPLE                  table:  posts                    type:  ALL  possible_keys:  NULL                      key:  NULL              key_len:  NULL                      ref:  NULL                    rows:  2                  Extra:  Using  where  1  row  in  set  (0.00  sec)

Page 31: High Performance Rails with MySQL

What to Optimize - Rails

• dependent: :destroy

24  Query          BEGIN  24  Query          SELECT  `comments`.*  FROM  `comments`    WHERE  `comments`.`post_id`  =  1  24  Query          DELETE  FROM  `comments`  WHERE  `comments`.`id`  =  2  24  Query          DELETE  FROM  `posts`  WHERE  `posts`.`id`  =  1  24  Query          COMMIT

24  Query          BEGIN  24  Query          DELETE  FROM  `comments`  WHERE  `comments`.`post_id`  =  4  24  Query          DELETE  FROM  `posts`  WHERE  `posts`.`id`  =  4  24  Query          COMMIT

BAD

Use dependent: :delete_all

Page 32: High Performance Rails with MySQL

What to Optimize - Rails

• Cache SHOW FIELDS output - patches for now

• Disable innodb_stats_on_metadata

Page 33: High Performance Rails with MySQL

What to Optimize - Rails

• Cache SHOW FIELDS output - patches for now

• Disable innodb_stats_on_metadata

• Pull only the columns you need - especially excluding

BLOBS

@posts  =  Post.select(“title”)

Page 34: High Performance Rails with MySQL

What to Optimize - Rails

• Avoid pessimistic locks when possible - SELECT … FOR

UPDATE - UPDATE directly and return affected rows

Page 35: High Performance Rails with MySQL

What to Optimize - Rails

• Avoid pessimistic locks when possible - SELECT … FOR

UPDATE - UPDATE directly and return affected rows

• Avoid N+1 queries - use JOIN or includes

Page 36: High Performance Rails with MySQL

What to Optimize - Rails

@posts  =  Post.limit(2)  [email protected]  do  |post|     puts  post.authors.name  end

24  SELECT    `posts`.*  FROM  `posts`    LIMIT  2  24  Query          SELECT    `authors`.*  FROM  `authors`    WHERE  `authors`.`id`  =  1    ORDER  BY  `authors`.`id`  ASC  LIMIT  1  24  Query          SELECT    `authors`.*  FROM  `authors`    WHERE  `authors`.`id`  =  2    ORDER  BY  `authors`.`id`  ASC  LIMIT  1

With this:

You get this:

Page 37: High Performance Rails with MySQL

What to Optimize - Rails

@posts  =  Post.includes(:authors).limit(2)

24  Query          SELECT    `posts`.*  FROM  `posts`    LIMIT  2  24  Query          SELECT  `authors`.*  FROM  `authors`    WHERE  `authors`.`id`  IN  (1,  2)

With this:

You get this:

Page 38: High Performance Rails with MySQL

What to Optimize - Rails

@posts  =  Post.joins(:authors).limit(2);

24  Query          SELECT    `posts`.*  FROM  `posts`  INNER  JOIN  `authors`  ON  `authors`.`id`  =  `posts`.`authors_id`  LIMIT  2

With this:

You get this:

Page 39: High Performance Rails with MySQL

What to Optimize - Rails

• Avoid pessimistic locks when possible - SELECT … FOR

UPDATE - UPDATE directly and return affected rows

• Avoid N+1 queries - use JOIN or includes

• Compress MySQL requests, especially transactions!

Page 40: High Performance Rails with MySQL

What to Optimize - Rails

• Avoid pessimistic locks when possible - SELECT … FOR

UPDATE - UPDATE directly and return affected rows

• Avoid N+1 queries - use JOIN or includes

• Compress MySQL requests, especially transactions!

• Learn and use SQL - find_by_sql

Page 41: High Performance Rails with MySQL

What to Optimize - Rails

• Avoid pessimistic locks when possible - SELECT … FOR

UPDATE - UPDATE directly and return affected rows

• Avoid N+1 queries - use JOIN or includes

• Compress MySQL requests, especially transactions!

• Learn and use SQL - find_by_sql

• Don’t accept Model defaults

Page 42: High Performance Rails with MySQL

Further Thoughts

• GDB, Strace, OProfile

• Smart aggregation, use summary tables when possible

• Rails > Caching > MySQL

• Avoid:config.action_controller.session_store  =  :active_record_store

Page 43: High Performance Rails with MySQL

http://www.amyvernon.net/wp-content/uploads/2014/01/upward-graph-striving.png

Page 44: High Performance Rails with MySQL

Thank you!

Page 45: High Performance Rails with MySQL

… and

• We’re hiring!

• http://www.percona.com/about-us/careers/open-

positions