Frage

Ich habe mit Kette Arel Abfragen versucht Bereiche verwenden, anstatt nur einige langatmige Logik ich in der Steuerung geschrieben. Aber die Bereiche langsamer sind als nur alle Datensätze bekommen und dann mit einer gewissen Logik durch sie siebt. Ich frage mich also, warum Bereiche sind besser.

Hier ist, was ich tue:

  • eine Frage hat viele Antworten
  • eine Antwort gehört zu einer Frage
  • eine Frage hat eine „question_type“ -Spalte, dass ich es sortieren

Erstens Tive die Art und Weise ...

in question.rb:

scope :answered, joins(:answers).order('answers.created_at desc')
scope :dogs, where(:question_type => "dogs")
scope :cats, where(:question_type => "cats")
scope :mermaids, where(:question_type => "mermaids")

in questions_controller.rb:

@dogs_recently_answered = Question.answered.dogs.uniq[0..9]
@cats_recently_answered = Question.answered.cats.uniq[0..9]
@mermaids_recently_answered = Question.answered.mermaids.uniq[0..9]

Dann in der Ansicht I-Zyklus durch diese Instanzvariablen (die nun Arrays sind mit höchstens 10 Elemente) und die Ergebnisse anzuzeigen.

Hier sind die Zeiten es die Seite (fünf Mal) laden dauert:

Abgeschlossene 200 OK in 535ms (Views: 189.6ms | Active: 46.2ms)

Abgeschlossene 200 OK in 573ms (Views: 186.0ms | Active: 46.3ms)

Abgeschlossene 200 OK in 577ms (Views: 189.0ms | Active: 45.6ms)

Abgeschlossene 200 OK in 532ms (Views: 182.9ms | Active: 46.1ms)

Abgeschlossene 200 OK in 577ms (Views: 186.7ms | Active: 46.9ms)

Nun, der unordentlich Controller Art und Weise ...

@answers = Answer.order("created_at desc")
@all_answered = []
@answers.each {|answer| @all_answered << answer.question}
@recently_answered = @all_answered.uniq
@dogs_all_answered = []
@cats_all_answered = []
@mermaids_all_answered = []
@recently_answered.each do |q|
  if q.question_type == "dogs"
    @dogs_all_answered << q
    @dogs_recently_answered = @dogs_all_answered[0..9]
  elsif q.question_type == "cats"
    @cats_all_answered << q
    @cats_recently_answered = @cats_all_answered[0..9]
  elsif q.question_type == "mermaids"
    @mermaids_all_answered << q
    @mermaids_recently_answered = @mermaids_all_answered[0..9]
  end
end

Und hier sind die Zeiten, dauert es jetzt die Seite zu laden (fünf Mal):

Abgeschlossene 200 OK in 475ms (Views: 196.5ms | Active: 34.5ms)

Abgeschlossene 200 OK in 480 ms (Views: 200.4ms | Active: 36.4ms)

Abgeschlossene 200 OK in 434ms (Views: 198.2ms | Active: 35.8ms)

Abgeschlossene 200 OK in 475ms (Views: 194.2ms | Active: 36.4ms)

Abgeschlossene 200 OK in 475ms (Views: 195.0ms | Active: 35.4ms)

So ...

Neben der Lesbarkeit, was durch Honen die Abfrage mit einem Umfang gewonnen werden? Ist es schließlich schneller geworden, wenn es mehr Aufzeichnungen?

War es hilfreich?

Lösung

Zuerst, ich bin sicher, dass ich nicht verstehen, wie eine Frage als einzigartig andere sein kann, so dass ich zu versuchen, aussehen würde, dass zu entfernen. Ich weiß nicht, die Logik Ihrer Daten, so dass nicht anwendbar sein könnte, aber es ist ein zusätzlicher Schritt, dass Sie möglicherweise in der Lage zu vermeiden.

Hier ist, wie ich es hätte nähern:

scope :answered, joins(:answers).order('answers.created_at desc')
scope :recent, take(10)
scope :dogs, where(:question_type => "dogs")
scope :cats, where(:question_type => "cats")
scope :mermaids, where(:question_type => "mermaids")

@dogs_recently_answered = Question.answered.dogs.recent
@cats_recently_answered = Question.answered.dogs.recent
@mermaids_recently_answered = Question.answered.dogs.recent

Dies verschiebt den TOP Teil der Abfrage an die Datenbank, wo es eher gehört als das Abrufen alle der Zeilen und dann alle, aber 10. Je nach uniquing Kriterien zu verwerfen, können Sie auch einen Bereich verwenden wie

scope :unique, select('DISTINCT column_name')

und dann können Sie Question.cats.unique.recent verwenden und alles in einer schnellen Abfrage erhalten, die die relationale Algebra nutzt die Datenbanksysteme sind für.

Andere Tipps

Ich denke, der Grund, warum die Bereiche sind in diesem Fall langsamer ist, weil sie in 3 separaten Datenbankabfragen führen, während der andere Ansatz das Wissen verwendet, dass alle drei Ergebnisse können durch die einzelne Abfrage befriedigt werden Sie verwenden.

Unter der Annahme, dass der Fall ist, ist es nicht verwunderlich, die Bereiche tun, 3 separate Abfragen, da das System nicht weiß, wann Sie die ersten Anruf, dass Sie die andere rufen direkt danach gehen. Vielleicht gibt es eine Optimierungsstrategie, die für dieses Szenario sinnvoll wäre, aber ich weiß nicht, dass Active implementiert es.

Wie auch immer, dies ist ein Nachteil des Umfangs in diesem speziellen Fall. Ich mag Bereiche, weil sie sauber / klar, flexibel und verkapselt eine benannte Abstraktion für eine Abfrage. AFAICT, in vielen Szenarien sind sie nicht merklich langsamer als die entsprechende direkte Abfrage.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top