Ceci n'est pas une réponse mais la comparaison de trois réponses à cette question. J'ai déjà donné ma réponse. Il y a confusion avec le fonctionnement de :joins
et :include
dans ActiveRecord.find
.J'ai donc passé du temps à analyser le journal SQL pour trouver trois solutions.
Approche 1: obtenir le nombre de ventes en utilisant count
#To return the sales count for each product
ps_count_hash = Product.count(:joins => [:sales], :group => "products.id") # sql 1.1
# To print the product id and sales count
ps_count_hash.each do | product_id, sales_count|
p "Product#{product_id} - (#{sales_count})"
end
# To print the product details and sales count
# get all the products associated
Product.find_all_by_id(ps_count_hash.keys).each |product| #sql 1.2
p "Product[id = #{product.id}, name = #{product.name}] - (#{ps_count_hash[product.id]})"
end
Approche 2: Obtenez les produits par un join
Product.find(:all, :joins=>[:sales]).each do |product| #sql 2.1
p "Product[id = #{product.id}, name = #{product.name}] - (#{product.sales.size})" # sql 2.2 - 2.(2+N)
end
Approche 3: Obtenez les produits à travers un include
Product.find(:all, :include=>[:sales]).each do |product| #sql 3.1 and 3.2
p "Product[id = #{product.id}, name = #{product.name}] - (#{product.sales.size})"
end
Maintenant, regardons les instructions SQL générées par ces trois approches
instructions SQL pour l'approche 1 - 2 SQL
SELECT count(*) AS count_all, products.id AS products_id FROM `products` INNER JOIN `sales` ON sales.product_id = products.id GROUP BY products.id
SELECT `products`.* FROM `products` WHERE (`products`.`id` IN (1,2))
instructions SQL pour l'approche 2 - 2 SQL
SELECT * FROM `products`
SELECT `sales`.* FROM `sales` WHERE (`sales`.product_id IN (1,2))
Instructions SQL pour l'approche 3 - N + 1 SQL
SELECT `products`.* FROM `products` INNER JOIN `sales` ON sales.product_id = products.id
SELECT * FROM `sales` WHERE (`sales`.product_id = 1)
SELECT * FROM `sales` WHERE (`sales`.product_id = 2)
Meilleure approche pour le comptage produit par les ventes (avec des détails sur les ventes): Approche 1
Meilleure approche pour le comptage produit par les ventes (avec des ventes de détails): Approche 2
Approche 3 a le problème N + 1. Donc, c'est hors de la contestation.
Et là, vous avez le problème «N + 1». –
Il n'y a aucune raison d'optimiser prématurément. Les associations sont The Rails Way et seront familiers à tous les développeurs de Rails qui regardent son code. Il peut toujours optimiser plus tard si cela devient un goulot d'étranglement. –
Ce n'est pas une optimisation prématurée. Utilisez simplement ': include' ou': join'. Vous ne passez pas de temps pour ça. Pourquoi devrions-nous écrire un mauvais code à l'avance sachant que c'est mauvais si nous pouvons écrire un meilleur code avec exactement le même effort maintenant. –