Domanda

Ho cercato di catena query Arel utilizzando scopi, invece di utilizzare una logica prolisso ho scritto nel controller. Ma gli ambiti sono più lento di solo ottenere tutti i record e quindi spulciando tra loro con una certa logica. Mi chiedo, allora, perché gli ambiti sono meglio.

Ecco quello che sto facendo:

  • una domanda ha molte risposte
  • una risposta appartiene a una domanda
  • una domanda ha una colonna "question_type" che uso per risolvere la

In primo luogo, il modo in ambiti ...

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]

Poi nella vista, scorrere le variabili di istanza (che sono ora matrici contenenti al massimo 10 elementi) e visualizzare i risultati.

Qui ci sono i tempi che ci vuole per caricare la pagina (cinque volte differenti):

Completato 200 OK in 535ms (Viste: 189.6ms | ActiveRecord: 46.2ms)

Completato 200 OK in 573ms (Viste: 186.0ms | ActiveRecord: 46.3ms)

Completato 200 OK in 577ms (Viste: 189.0ms | ActiveRecord: 45.6ms)

Completato 200 OK in 532ms (Viste: 182.9ms | ActiveRecord: 46.1ms)

Completato 200 OK in 577ms (Viste: 186.7ms | ActiveRecord: 46.9ms)

Ora, il modo di controllo disordinato ...

@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

E qui sono i tempi che ci vuole per caricare la pagina ora (cinque volte diverse):

Completato 200 OK in 475ms (Viste: 196.5ms | ActiveRecord: 34.5ms)

Completato 200 OK in 480ms (Viste: 200.4ms | ActiveRecord: 36.4ms)

Completato 200 OK in 434ms (Viste: 198.2ms | ActiveRecord: 35.8ms)

Completato 200 OK in 475ms (Viste: 194.2ms | ActiveRecord: 36.4ms)

Completato 200 OK in 475ms (Viste: 195.0ms | ActiveRecord: 35.4ms)

Quindi ...

A parte la leggibilità, quello che sta per essere vinta da affinando la query con un ambito? Ha fine diventano più veloce quando non ci sono più record?

È stato utile?

Soluzione

In primo luogo, io non sono sicuro io capisco come una domanda può essere che unica, quindi mi piacerebbe guardare cercando di rimuovere questo. Non conosco la logica dei dati, in modo che potrebbe non essere applicabile, ma è un passo in più che si può essere in grado di evitare.

Ecco come vorrei affrontarlo:

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

Questo sposta la parte TOP della query al database in cui essa appartiene, piuttosto che andare a prendere tutti delle righe e poi scartando tutti, ma 10. A seconda delle criteri uniquing, si potrebbe anche utilizzare un ambito come

scope :unique, select('DISTINCT column_name')

e quindi è possibile utilizzare Question.cats.unique.recent e ottenere tutto in una query veloce che sfrutta l'algebra relazionale che sistemi di database sono progettati per.

Altri suggerimenti

Penso che la ragione gli ambiti sono più lenti in questo caso è perché risultano in 3 query di database separati, mentre l'altro approccio utilizza la consapevolezza che tutti e tre i risultati possono essere soddisfatte dalla singola query si utilizza.

Supponendo che è il caso, non è sorprendente scopi stanno facendo 3 query separate in quanto il sistema non sa quando si chiama il primo che si sta andando a chiamare gli altri subito dopo. Forse c'è una strategia di ottimizzazione che sarebbe ragionevole per questo scenario, ma non so che di ActiveRecord implementa.

In ogni caso, questo è uno svantaggio del campo di applicazione in questo caso particolare. Mi piace ambiti perché sono pulito / trasparente, flessibile ed incapsulati un'astrazione di nome per una query. AFAICT, in molti scenari non sono sensibilmente più lento rispetto alla query diretta equivalente.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top