2016-04-18 6 views
0

Lassen Sie uns die folgenden Beziehungen (3 Modelle) betrachten:Wird has_many: Durchsetzen enorme Leistungseinbußen in RoR?

class Author < ActiveRecord::Base 
    has_many :authorships 
    has_many :papers, :through => :authorships 
end 
class Paper < ActiveRecord::Base 
    has_many :authorships, inverse_of: :paper, :dependent => :destroy 
    has_many :authors, :through => :authorships 
    accepts_nested_attributes_for :authorships, :allow_destroy => true 
end 
class Authorship < ActiveRecord::Base 
    belongs_to :paper 
    belongs_to :author 
    validate: rank, presence: true # position of the author 
end 

Wie Sie sehen können, verwende ich viel has_many und auch :through. Wenn ich paper.html.erb Seite blättern, die im Grunde alle Papiere und die entsprechenden Autoren zeigt, verlangsamt es das System sehr. Im Moment habe ich ungefähr 400 Artikel und 2000 Autorschaften, und es dauert 3 Sekunden, um die Seite zu laden, und aus dem Log sah ich RoR eine Menge von SQL-Abfragen, die Mehrheit der Abfragen sind Autoren abzurufen. Ich habe mich gefragt, das ist eine typische Sache in RoR. Danke für Ihre Hilfe.

+0

Können Sie auch Ihren Controller und Code anzeigen? –

Antwort

2

Das klingt eher nach einem Optimierungsproblem. Um Ihre ursprüngliche Frage zu beantworten, hat has_many: durch sich selbst keinen erkennbaren Unterschied. Sie hätten genau das gleiche Problem, wenn Sie nur zwei Tabellen für Paper und Authorship hätten.

Basierend auf, was Sie über Ihre Protokolle berichtet, nehme ich an Ihrem Code etwa wie folgt aussieht:

# Controller: 
@papers = Paper.all 

# View: 
<% @papers.each do |paper| %> 
    <%= paper.authors.join(', ') %> 
    <%# other code... %> 
<% end %> 

Welche Schienen tut, ist für jedes Mal, wenn Sie paper.authors nennen, wird es eine Abfrage ausführen, die Autoren zu holen zugeordnet mit diesem Papier. Wenn Sie 400 Papiere haben, werden Rails 400 Abfragen ausführen. Dies wird als n + 1-Abfrageproblem bezeichnet, wobei n Abfragen für jeden Datensatz zusammen mit der ersten Abfrage ausgeführt werden, um die ersten Datensätze zu erhalten. Rails hat eine nette Anleitung, wie Sie dieses Problem lösen können: http://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations

Sie möchten grundsätzlich vermeiden, eine Abfrage jedes Mal auszuführen, wenn Sie die Autoren für ein Papier erhalten möchten. Sie könnten stattdessen Ihre Papiere in der Steuerung wie folgt laden: @papers = Paper.includes(:author).all. Dies würde alle Papiere zusammen mit ihren assoziierten Autoren laden und nur 2 Abfragen ausführen: eine für alle Papiere und eine weitere für alle Autoren, die mit diesen Papieren verbunden sind.

Seien Sie jedoch vorsichtig mit der übermäßigen Verwendung .includes, weil es auch Ihre Ladezeit verlangsamen könnte, wenn Sie zu viele Datensätze haben. Rails benötigt auch Zeit, um jedes Paper und jedes Author Objekt im Speicher zu erstellen; Es würde derzeit 2400 Objekte basierend auf Ihren Datenbankdatensätzen erstellen. Nachdem Sie zu einer bestimmten Anzahl von Datensätzen gelangt sind, sollten Sie die Paginierungs- oder Suchfunktionalität hinzufügen, anstatt mehrere zehntausend Datensätze auf einer einzelnen Seite zu laden.

+0

Ich denke du meinst: Autoren, aber ja, es beschleunigt viel! – TimeString