more better nested set

26
イケテル better nested set 研究会 藤岡岳之(xibbar)

Upload: xibbar

Post on 19-May-2015

1.207 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: More Better Nested Set

イケテルbetter nested set

研究会藤岡岳之(xibbar)

Page 2: More Better Nested Set

アジェンダ

better nested setを使って組織図を書く手軽に書きたいんだ~!

Page 3: More Better Nested Set

Sectionモデルを作成1

better nested setをインストール

Page 4: More Better Nested Set

Sectionモデルを作成2migrationファイルモデルはSectionという名前にすることにして、使用するカラムはnameだけにbetter nested setにはparent_id、lft、rgtという:integerなカラムが必要

class CreateSections < ActiveRecord::Migration def self.up create_table :sections do |t| t.column :name, :string, :null=>false t.column :parent_id, :integer t.column :lft, :integer t.column :rgt, :integer end end def self.down drop_table :sections endend

Page 5: More Better Nested Set

Sectionモデルを作成3

app/models/section.rbの中身

class Section < ActiveRecord::Base acts_as_nested_set

end

Page 6: More Better Nested Set

データを作成

ツリーを作成してみる% ./script/runner 'Section.create(:name=>"日本Ruby会議")'% ./script/runner 'Section.create(:name=>"東京Ruby会議").move_to_child_of Section.find_by_name("日本Ruby会議")'% ./script/runner 'Section.create(:name=>"札幌Ruby会議").move_to_child_of Section.find_by_name("日本Ruby会議")' % ./script/runner 'Section.create(:name=>"Akasaka.rb").move_to_child_of Section.find_by_name("東京Ruby会議")'% ./script/runner 'Section.create(:name=>"Asakusa.rb").move_to_child_of Section.find_by_name("東京Ruby会議")'

DBの中身は# select * from sections; id | name | parent_id | lft | rgt ----+--------------+-----------+-----+----- 1 | 日本Ruby会議 | | 1 | 10 2 | 東京Ruby会議 | 1 | 2 | 7 3 | 札幌Ruby会議 | 1 | 8 | 9 4 | Akasaka.rb | 2 | 3 | 4 5 | Asakusa.rb | 2 | 5 | 6(5 rows)

Page 8: More Better Nested Set

モデルに一行追加

class Section < ActiveRecord::Base acts_as_nested_set acts_as_section_mapend

※ acts_as_section_mapは  acts_as_nested_setの下に書くこと

Page 9: More Better Nested Set

コントローラー

class WelcomeController <ApplicationController def index @table2=Section.table2 endend

1行追加

Page 10: More Better Nested Set

ビュー

<% section_map(@table2) do |table| %> <%=table.name%> <% end %>

index.rhtml

※ テーブルの中身はブロックで指定

※ プラグインの魔法で、たったこれだけで組織図完成

Page 11: More Better Nested Set

関連テーブル

class CreateUsers < ActiveRecord::Migration def self.up create_table :users do |t| t.column :name, :string, :null=>false t.column :section_id, :integer end end def self.down drop_table :users endend

user.rb

class User < ActiveRecord::Base belongs_to :sectionend

section.rbclass Section < ActiveRecord::Base acts_as_nested_set acts_as_section_map has_many :usersend

Page 12: More Better Nested Set

データ作成

% ./script/runner 'Section.find_by_name("Akasaka.rb").users << User.create(:name=>"takai")'% ./script/runner 'Section.find_by_name("Akasaka.rb").users << User.create(:name=>"koichiroo")'% ./script/runner 'Section.find_by_name("Akasaka.rb").users << User.create(:name=>"takedasoft")'% ./script/runner 'Section.find_by_name("Asakusa.rb").users << User.create(:name=>"a_matsuda")' % ./script/runner 'Section.find_by_name("Asakusa.rb").users << User.create(:name=>"kakutani")' % ./script/runner 'Section.find_by_name("Asakusa.rb").users << User.create(:name=>"maiha")'

userを作成し、sectionにぶら下げる

Page 13: More Better Nested Set

ビューも直す

<% section_map(@table2) do |table| %> <%=table.name%> <ul> <% table.users.each do |user|%> <li><%=user.name%></li> <%end%> </ul><% end %>

index.rhtml

Page 14: More Better Nested Set

見た目を直そう

<% section_map(@table2,:table=>{:cellspacing=>"0",:style=>"border-collapse:collapse;"}, :td=>{:valign=>"top",:style=>"border:1px solid #666666;color:navy;"}) do |table| %> <%=table.name%> <ul> <% table.users.each do |user|%> <li style="font-size:12px;color:green"><%=user.name%></li> <%end%> </ul><% end %>

index.rhtml

Page 15: More Better Nested Set

のろくない?

数が多いとのろいぞでも、なんとかしちゃるでも今日はおしまい続きは次回以降

Page 16: More Better Nested Set

イケテルDBチューニング

xibbarこと藤岡岳之

Page 17: More Better Nested Set

ブログのぶくま

Page 18: More Better Nested Set

これでぎりぎり卒論になるんじゃなかろうか。長谷川がこけたら、これにしようかな。。。

なんだこれ!!

Page 19: More Better Nested Set

巨大な組織

(1..4).each{|n|Section.create(:name=>"Section:#{n}")}(5..60).each{|n|2.times{|m|Section.find_or_create_by_name("Section:#{n*2+m+3}").move_to_child_of Section.find_by_name("Section:#{n}")}}

120組織のツリーを作るスクリプト

Page 20: More Better Nested Set

遅すぎる

User Load (0.000204) SELECT * FROM users WHERE (users.section_id = 124) Completed in 18.13171 (0 reqs/sec) | Rendering: 7.49291 (41%) | DB: 10.46457 (57%) | 200 OK [http://localhost/welcome]

表示に18秒っておい!

Page 21: More Better Nested Set

インデックスを張ってみる

User Load (0.000182) SELECT * FROM users WHERE (users.section_id = 124) Completed in 10.01978 (0 reqs/sec) | Rendering: 6.97071 (69%) | DB: 2.87357 (28%) | 200 OK [http://localhost/welcome]

10秒に短縮!まだ使い物にならないけど

Page 22: More Better Nested Set

すばやさの種を投入class AddDepthToSections < ActiveRecord::Migration def self.up add_column :sections,:depth,:integer Section.set_depth end

def self.down remove_column :sections,:depth endend

depthという項目を追加し、値をセットする。depthというのは文字通り深さの値(levelの結果)

Page 23: More Better Nested Set

すばやさの種の結果

User Load (0.000180) SELECT * FROM users WHERE (users.section_id = 124) Completed in 0.84391 (1 reqs/sec) | Rendering: 0.40329 (47%) | DB: 0.27316 (32%) | 200 OK [http://localhost/welcome]

1秒切ってメデタシメデタシ

Page 24: More Better Nested Set

ちょっとだけ解説

のろさの原因はsectionが自分自身の深さを知るためにselect count(*)していることにある。(levelメソッド)これをカラムとして持つとツリーの構築の早さが圧倒的に違う(つまりdepthカラム)

Page 25: More Better Nested Set

benchmark% ./script/performance/benchmarker 100 'Section.find(:all).map(&:level)' user system total real#1 5.790000 0.470000 6.260000 ( 10.331682)

% ./script/performance/benchmarker 100 'Section.find(:all).map(&:depth)' user system total real#1 0.610000 0.010000 0.620000 ( 0.784886)

% ./script/performance/benchmarker 100 'Section.find(:all).map(&:level)' user system total real#1 6.180000 0.530000 6.710000 ( 20.693455)

ちなみにindex張る前は

20.693÷0.784=26.39426倍早くなった!!

Page 26: More Better Nested Set

グー

おしまい

http://www001.upp.so-net.ne.jp/masa_gallery/edo.html