Contenu connexe Similaire à More Better Nested Set Similaire à More Better Nested Set (20) More Better Nested Set4. Sectionモデルを作成2
migrationファイル
モデルは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
end
end
6. データを作成
ツリーを作成してみる
% ./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)
8. モデルに一行追加
class Section < ActiveRecord::Base
acts_as_nested_set
acts_as_section_map
end
※ acts_as_section_mapは
acts_as_nested_setの下に書くこと
9. コントローラー
1行追加
class WelcomeController <ApplicationController
def index
@table2=Section.table2
end
end
11. 関連テーブル
user.rb section.rb
class Section < ActiveRecord::Base
class CreateUsers < ActiveRecord::Migration
acts_as_nested_set
def self.up
acts_as_section_map
create_table :users do ¦t¦
has_many :users
t.column :name, :string, :null=>false
end
t.column :section_id, :integer
end
end
def self.down
drop_table :users
end
end
class User < ActiveRecord::Base
belongs_to :section
end
12. データ作成
userを作成し、sectionにぶら下げる
% ./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")'
20. 遅すぎる
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秒っておい!
21. インデックスを張ってみる
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秒に短縮!
まだ使い物にならないけど
22. すばやさの種を投入
class AddDepthToSections < ActiveRecord::Migration
def self.up
add_column :sections,:depth,:integer
Section.set_depth
end
def self.down
remove_column :sections,:depth
end
end
depthという項目を追加し、
値をセットする。depthというのは
文字通り深さの値(levelの結果)
23. すばやさの種の結果
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秒切ってメデタシメデタシ
25. 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)
ちなみにindex張る前は
% ./script/performance/benchmarker 100 'Section.find(:all).map(&:level)'
user system total real
#1 6.180000 0.530000 6.710000 ( 20.693455)
20.693 0.784=26.394
26倍早くなった!!
26. グー
おしまい
http://www001.upp.so-net.ne.jp/masa_gallery/edo.html