2012-05-22 22 views
0

這個問題可能很長,但問題其實很簡單。我有3個模型:列表,外觀和電影。列表通過外觀具有許多電影,並且它們應該按照聯合模型的屬性等級進行排序。那麼我應該使用哪些索引?這是我的模型目前的樣子:當查詢結果按has_many排序時,應該使用什麼索引:through association

# Models 
class Movie < ActiveRecord::Base 
    has_many :appearances, :dependent => :destroy 
    has_many :lists, :through => :appearances 
end 

class Appearance < ActiveRecord::Base 
    belongs_to :list 
    belongs_to :movie 
end 

class List < ActiveRecord::Base 
    has_many :appearances, :dependent => :destroy 
    has_many :movies, :through => :appearances 

    def self.find_complete(id) 
    List.includes({:appearances => :movie}).where("appearances.rank IS NOT NULL").order("appearances.rank ASC").find(id) 
    end 
end 

這裏是我已經有的索引。我需要一個複合索引嗎?或者只是按排名索引?

# Tables 
class CreateAppearances < ActiveRecord::Migration 
    def change 
    create_table :appearances do |t| 
     t.integer :list_id, :null => false 
     t.integer :movie_id, :null => false 
     t.integer :rank 
    end 
    add_index :appearances, :list_id 
    add_index :appearances, :movie_id 
    end 
end 

最後,有什麼辦法可以重構find_complete List方法嗎?就像使用default_scope一樣?不要忘記,排名可能爲空。

回答

1

ActiveRecord正在做兩個查詢。

SELECT DISTINCT `lists`.id 
FROM `lists` LEFT OUTER JOIN `appearances` ON `appearances`.`list_id` = `lists`.`id` 
      LEFT OUTER JOIN `movies` ON `movies`.`id` = `appearances`.`movie_id` 
WHERE `lists`.`id` = 1 AND (appearances.rank IS NOT NULL) 
ORDER BY appearances.rank ASC LIMIT 1 

SELECT `lists`.`id` AS t0_r0, `lists`.`name` AS t0_r1, `lists`.`created_at` AS t0_r2, `lists`.`updated_at` AS t0_r3, `appearances`.`id` AS t1_r0, `appearances`.`list_id` AS t1_r1, `appearances`.`movie_id` AS t1_r2, `appearances`.`rank` AS t1_r3, `appearances`.`created_at` AS t1_r4, `appearances`.`updated_at` AS t1_r5, `movies`.`id` AS t2_r0, `movies`.`name` AS t2_r1, `movies`.`created_at` AS t2_r2, `movies`.`updated_at` AS t2_r3 
FROM `lists` LEFT OUTER JOIN `appearances` ON `appearances`.`list_id` = `lists`.`id` 
      LEFT OUTER JOIN `movies` ON `movies`.`id` = `appearances`.`movie_id` 
WHERE `lists`.`id` = 1 AND `lists`.`id` IN (1) AND (appearances.rank IS NOT NULL) 
ORDER BY appearances.rank ASC 

在你所需要的兩種情況是既lists.id和appearances.rank的索引。一些數據庫將在多個表上創建索引。我也不知道你的數據庫是否足夠聰明,可以在appearances.list_id和appearances.rank上使用索引,但這是值得一試的。

add_index :appearances, [:list_id, :rank] 

如果這沒有幫助,至少index:rank,所以數據庫可能能夠避免排序。

+0

事實上,你是對的,它正在做兩個查詢。我想我應該在我的問題中解釋我正在使用PostgreSQL。我要去嘗試你的解決方案。 – Ashitaka

0

你必須看看Rails爲你的特定用例輸出什麼樣的查詢。

我最好猜測的是在外鍵列上添加索引,然後使用profiler一旦應用程序完成並加載數據,以查看特定查詢是否執行得不好,然後修復它們!

千萬不要試圖超越你的數據庫,只是測量和修復 - 其他任何事情最有可能花費你更多的性能比它節省。

你在這裏問的是一種過早優化的形式,也有點猜測,考慮Rails3 Arel將如何推遲執行,以便實際需要哪些索引在很大程度上取決於該關聯將如何使用以及如何遍歷。

0

重新檢查你的關聯。 如果

的List通過外觀

class List < ActiveRecord::Base 
has_many :appearances, :dependent => :destroy 
has_many :movies, :through => :appearances 
end 

class Appearance < ActiveRecord::Base 
belongs_to :list, :foreign_key => list_id 
has_many :movies 
end 

class Movie < ActiveRecord::Base 
belongs_to :appearance, :foreign_key => appearance_id, :dependent => :destroy 
end 

對於find_complete方法有很多電影我不明白爲什麼把它變成一個scope.Probably有工作要做因爲你已經在List模型中,並且看起來很奇怪,調用了List.includes ....在它自己內部。

沒有看到那個movie_id指數

class CreateAppearances < ActiveRecord::Migration 
    def change 
    create_table :appearances do |t| 
     t.integer :list_id, :null => false 
     t.integer :movie_id, :null => false 
     t.integer :rank 
    end 
    add_index :appearances, :list_id 
end 
end 

的需求,同時還需要爲您的電影表中的索引appearance_id。

我希望我不會丟失任何東西

相關問題