Slide 1

Slide 1 text

Rails with Massive Data 10 things you should know 12年8月19日星期日

Slide 2

Slide 2 text

about • fb.com/xdite • twitter.com/xdite • rocodev.com 12年8月19日星期日

Slide 3

Slide 3 text

Agenda • Don’t use ActiveRecord • Don’t use ActiveRecord • Don’t use ActiveRecord • Don’t use ActiveRecord • Don’t use ActiveRecord • ............ Unless you know what you’re doing 12年8月19日星期日

Slide 4

Slide 4 text

#1. Active Record is danger 12年8月19日星期日

Slide 5

Slide 5 text

typical usage posts = Post.where(:board_id => 5) post.each do |post| post.board_id = 1 post.save end ~ 1000 data : cool ~ 1000000 data : hell 12年8月19日星期日

Slide 6

Slide 6 text

problems posts = Post.where(:board_id => 5) post.each do |post| post.board_id = 1 post.save end load ~1000000 objects in memory trigger ~1000000 callbacks DB transaction update DB indexes 12年8月19日星期日

Slide 7

Slide 7 text

problems • memory bloat • too much callbacks • too much DB transaction • slow query ( update db indexes) 12年8月19日星期日

Slide 8

Slide 8 text

#2. update_all 12年8月19日星期日

Slide 9

Slide 9 text

update_all posts = Post.where(:board_id => 5) post.each do |post| post.board_id = 1 post.save end Post.update_all({:board_id => 1}, {:board_id => 5}) 12年8月19日星期日

Slide 10

Slide 10 text

#3. find_in_batches 12年8月19日星期日

Slide 11

Slide 11 text

find_in_batches Post.find_in_batches(:conditions => "board_id = 5", :batch_size => 1000) do |posts| posts.each do |post| post.board_id = 1 post.save end end load only ~1000 objects in memory 12年8月19日星期日

Slide 12

Slide 12 text

#4. transaction 12年8月19日星期日

Slide 13

Slide 13 text

transaction (0.3ms) BEGIN (0.5ms) COMMIT ~1000000 DB transaction 12年8月19日星期日

Slide 14

Slide 14 text

transaction Post.find_in_batches(:conditions => "board_id = 5", :batch_size => 1000) do | posts| Post.transaction do posts.each do |post| post.board_id = 1 post.save end end end ~ only 1000 transactions 12年8月19日星期日

Slide 15

Slide 15 text

#5. update_column 12年8月19日星期日

Slide 16

Slide 16 text

update_column posts = Post.where(:board_id => 5) post.each do |post| post.update_column(:board_id, 1 ) end ~ skip 1000000 * n callbacks 12年8月19日星期日

Slide 17

Slide 17 text

sneaky-save (gem) posts = Post.where(:board_id => 5) post.each do |post| post.board_id = 1 post.sneaky_save end ~ skip 1000000 * n callbacks 12年8月19日星期日

Slide 18

Slide 18 text

any question? 12年8月19日星期日

Slide 19

Slide 19 text

#6. select only needed 12年8月19日星期日

Slide 20

Slide 20 text

select only needed posts = Post.where(“id < 10”) Post Load (18.8ms) SELECT `posts`.* FROM `posts` WHERE (id < 10) “post.content” ~ 100k 10000 record ~ 1G Post.select("column 1, colum2").where 12年8月19日星期日

Slide 21

Slide 21 text

#7. delegate 12年8月19日星期日

Slide 22

Slide 22 text

move out big data class Post < ActiveRecord::Base has_one :meta after_create :create_meta delegate :content, :to => :meta end # -*- encoding : utf-8 -*- # == Schema Information # # Table name: post_data # # id :integer not null, primary key # post_id :integer # content :text # created_at :datetime not null # updated_at :datetime not null # 12年8月19日星期日

Slide 23

Slide 23 text

#8. indexes 12年8月19日星期日

Slide 24

Slide 24 text

add index on foreign key posts = Post.where(:board_id => 5) add_index :posts, :board_id 12年8月19日星期日

Slide 25

Slide 25 text

integer & varchar # -*- encoding : utf-8 -*- # == Schema Information # # Table name: post # # id :integer not null, primary key # board_id :integer # content :text # created_at :datetime not null # updated_at :datetime not null # # -*- encoding : utf-8 -*- # == Schema Information # # Table name: post # # id :integer not null, primary key # board_id :string(255) # content :text # created_at :datetime not null # updated_at :datetime not null # ~100x slower 12年8月19日星期日

Slide 26

Slide 26 text

對 MySQL 的 VARCHAR 欄位使用 INDEX 時 可以增加效率的方法… http://bit.ly/QdEK19 12年8月19日星期日

Slide 27

Slide 27 text

MySQL Indexing Best Practices http://bit.ly/Spi6F8 12年8月19日星期日

Slide 28

Slide 28 text

#9. delete / destroy 12年8月19日星期日

Slide 29

Slide 29 text

delete / destroy • destroy is slow • destroy go through callbacks 12年8月19日星期日

Slide 30

Slide 30 text

delete / destroy • delete is also slow..... • DELETE update indexes 12年8月19日星期日

Slide 31

Slide 31 text

solution 1. acts_as_archive ( gem ) (soft_delete) 2. INSERT to new table 12年8月19日星期日

Slide 32

Slide 32 text

#10. background job 12年8月19日星期日

Slide 33

Slide 33 text

background job 1. delayed_job ( not recommended) 2. resque 3. sidekiq 12年8月19日星期日

Slide 34

Slide 34 text

any question? 12年8月19日星期日

Slide 35

Slide 35 text

Thanks for listening 12年8月19日星期日