2012-04-07 13 views
1

Ich habe ein Modell Produkt und es gehört zu einer Kategorie (category_id in products table). Ich möchte eine Abfrage schreiben, die die ersten 20 Produkte mit ihrem Kategorienamen aufnimmt. Ich habe 2 Möglichkeiten, es zu holen:Welche ist bevorzugt,: enthält oder: verbindet?

  1. Verwenden includes, wie folgt aus:

    Product.includes(:category). 
         order(:updated_at). 
         limit(20) 
    

    und in den Ansichten wie diese den Kategorienamen nehmen:

    <%= product.category.name if product.category %> 
    

    Dies wird Abfrage erstellen wie folgt:

    SELECT `products`.* from `products` ORDER BY `products`.updated_at LIMIT 20 
    SELECT `categories`.* from `categories` WHERE `categories`.id IN (1,2,3,4,5..,25) 
    
  2. Verwenden joins wie folgt aus:

    Product.joins("LEFT JOIN categories ON categories.id = products.category_id"). 
         select("products.*, categories.name as category_name"). 
         order(:updated_at). 
         limit(20) 
    

    und es in Ansichten wie diese verwenden:

    SELECT products.*, categories.name as category_name from `products` LEFT JOIN categories ON categories.id = products.category_id ORDER BY `products`.updated_at LIMIT 20 
    

Methode 1 hat die:

<%= product.category_name %> 

Dies wird Abfrage wie folgt erzeugen Vorteil, dass wir Model-Level-Methoden verwenden können, die auf dem Category-Modell geschrieben wurden, und der Code ist m Erz pflegbar. Aber es hat den Nachteil, dass es eine separate Abfrage verwendet, um die Kategorien zu finden, die die IN-Klausel verwenden.

Welcher ist der bevorzugte Weg?

+2

Es gibt auch Methode 3: Product.Eager_load (: Kategorien) –

+0

@FrederickCheung ..Ich kann keine Dokumentation zu dieser Methode finden .. was macht es? – rubyprince

+0

Derselbe Effekt wie includes (Sie erhalten vollständige Instanzen der Fledge-Kategorie bereit), aber mit einer Joins-basierten Abfrage. –

Antwort

0

Für Ihr Beispiel könnte ich mit Option 1 gehen, weil es einfacher und einfacher zu lesen ist und Sie nicht so viele Objekte laden, so glaube ich nicht, dass der Leistungseinbruch zu streng sein wird.

In einem Fall, in dem Sie möglicherweise mehr Daten laden würden (z. B. wenn Sie den limit(20) Teil entfernt haben), würde ich mit Option 2 gehen, weil Sie die Kategorieobjekte nicht instanziieren, wenn Sie nur ihre Namen benötigen. In kleineren Listen kann dieser Overhead vernachlässigbar sein, aber wenn die Liste lang wird, kann sie bedeutsam werden.

0

Die bevorzugte Weg ist, was immer Sie persönlich bevorzugen.

In aller Ehrlichkeit, aber ich sehe nicht, dass die Verwendung eines includes ist so groß von einem Deal. Vor allem bei der Entwicklung einer App, bei der sich das, was Sie auf die Seite setzen, ändern wird.

Meiner Meinung nach nur includes die meiste Zeit in dieser Situation. Es sei denn, Sie speichern viele text in Ihren Zeilen oder Sie erhalten die Produktion und diese Abfrage endet als Flaschenhals, dann sollten Sie wahrscheinlich die Zeit nehmen und optimieren.

2

Es ist nicht nur Vorliebe, es ist eine Frage der Leistung vs. Wartbarkeit. Ich würde zuerst die wartungsfreundlichere Route für Ihre Abfragen gehen. Wenn Ihre Leistung bei bestimmten Abfragen zu leiden beginnt, optimieren Sie sie mithilfe der Join-Syntax oder schreiben Sie einfach alte SQL-Dateien von Grund auf neu. Nicht vorzeitig optimieren. Optimieren Sie, wo Sie einen tatsächlichen Bedarf finden.

Verwandte Themen