2015-02-23 1 views
1

Utilisation ActiveRecord 4.2 avec MySQL 5.5ActiveRecord .last et ActiveRecord .last (1) renvoient des résultats différents

J'ai un modèle appelé produit.

Exécution Product.last dans la console - je reçois le Premier enregistrement dans le tableau (avec id 1 et updated_at en 2013)

Courir Product.last(1) - Je reçois le dernier enregistrement dans le tableau avec identifiant (122039) et updated_at en février 2015.

J'avais l'impression qu'ils devraient retourner la même chose. Pourquoi Product.last renvoie le résultat de Product.first?

P.S .: Il s'agit d'une base de données de développement. Alors je l'ai détruit et l'ai ré-migré et j'ai réensemencé toutes les données. Je ne sais pas si cela importe, mais pour accélérer les processus d'ensemencement (depuis que je sème quelques tables avec 100,000s de lignes de données de qualité de production) - I Les graines de fichiers .sql à l'aide insertion en bloc & ActiveRecord::Base.connection.execute(sql_from_file)

MISE À JOUR Après avoir fait une comparaison (voir 2 modifications ci-dessous), il semble que Product.last ne fasse pas order by id desc, tandis que le Product.last (1) le fait réellement. Des idées pourquoi?

EDIT 1 De grumes:

Product.last (1)

SELECT DISTINCT 
    `products`.`id` 
FROM 
    `products` 
    LEFT OUTER JOIN `restrictions` 
    ON `restrictions`.`id` = `products`.`distribution_restriction_id` 
    AND `restrictions`.`type` IN ('DistributionRestriction') 
    LEFT OUTER JOIN `vendors` 
    ON `vendors`.`id` = `products`.`vendor_id` 
    LEFT OUTER JOIN `manufacturers` 
    ON `manufacturers`.`id` = `products`.`manufacturer_id` 
    LEFT OUTER JOIN `categories` 
    ON `categories`.`id` = `products`.`category_id` 
    AND `categories`.`type` IN ('ProductCategory') 
    LEFT OUTER JOIN `products_restrictions` 
    ON `products_restrictions`.`product_id` = `products`.`id` 
    LEFT OUTER JOIN `restrictions` `restrictions_products` 
    ON `restrictions_products`.`id` = `products_restrictions`.`restriction_id` 
    AND `restrictions_products`.`type` IN ('ProductRestriction') 
    LEFT OUTER JOIN `categories` `departments_products` 
    ON `departments_products`.`id` = `products`.`department_id` 
    AND `departments_products`.`type` IN ('Department') 
    LEFT OUTER JOIN `comments` 
    ON `comments`.`commentable_id` = `products`.`id` 
    AND `comments`.`commentable_type` = 'Product' 
    LEFT OUTER JOIN `pictures` 
    ON `pictures`.`picturable_id` = `products`.`id` 
    AND `pictures`.`picturable_type` = 'Product' 
ORDER BY `products`.`id` DESC 
LIMIT 1 ; 

SELECT 
    `products`.`id` AS t0_r0, 
    `products`.`name` AS t0_r1, 
    `products`.`client_number` AS t0_r2, 
    `products`.`client_reference_string` AS t0_r3, 
    `products`.`client_id` AS t0_r4, 
    `products`.`vendor_number` AS t0_r5, 
    `products`.`vendor_reference_string` AS t0_r6, 
    `products`.`vendor_id` AS t0_r7, 
    `products`.`manufacturer_number` AS t0_r8, 
    `products`.`manufacturer_reference_string` AS t0_r9, 
    `products`.`manufacturer_id` AS t0_r10, 
    `products`.`reman_number` AS t0_r11, 
    `products`.`superseded_by_id` AS t0_r12, 
    `products`.`description` AS t0_r13, 
    `products`.`category_id` AS t0_r14, 
    `products`.`first_year_used` AS t0_r15, 
    `products`.`last_year_used` AS t0_r16, 
    `products`.`reorder_level` AS t0_r17, 
    `products`.`minimum_order_quantity` AS t0_r18, 
    `products`.`total_stock` AS t0_r19, 
    `products`.`stock_details` AS t0_r20, 
    `products`.`status` AS t0_r21, 
    `products`.`discontinued_at` AS t0_r22, 
    `products`.`currency` AS t0_r23, 
    `products`.`dealer_exchange_amount_cents` AS t0_r24, 
    `products`.`dealer_sale_amount_cents` AS t0_r25, 
    `products`.`retail_exchange_amount_cents` AS t0_r26, 
    `products`.`retail_sale_amount_cents` AS t0_r27, 
    `products`.`cost_amount_cents` AS t0_r28, 
    `products`.`core_charge_amount_cents` AS t0_r29, 
    `products`.`reman_amount_cents` AS t0_r30, 
    `products`.`out_of_warranty` AS t0_r31, 
    `products`.`backordered_till` AS t0_r32, 
    `products`.`repair_only` AS t0_r33, 
    `products`.`publicly_visible` AS t0_r34, 
    `products`.`period_usage` AS t0_r35, 
    `products`.`distribution_restriction_id` AS t0_r36, 
    `products`.`department_id` AS t0_r37, 
    `products`.`stats` AS t0_r38, 
    `products`.`announcement_date` AS t0_r39, 
    `products`.`status_with_vendor` AS t0_r40, 
    `products`.`masterfile_details` AS t0_r41, 
    `products`.`created_at` AS t0_r42, 
    `products`.`updated_at` AS t0_r43, 
    `restrictions`.`id` AS t1_r0, 
    `restrictions`.`name` AS t1_r1, 
    `restrictions`.`code` AS t1_r2, 
    `restrictions`.`description` AS t1_r3, 
    `restrictions`.`severity` AS t1_r4, 
    `restrictions`.`begins_at` AS t1_r5, 
    `restrictions`.`expires_at` AS t1_r6, 
    `restrictions`.`type` AS t1_r7, 
    `restrictions`.`created_at` AS t1_r8, 
    `restrictions`.`updated_at` AS t1_r9, 
    `vendors`.`id` AS t2_r0, 
    `vendors`.`name` AS t2_r1, 
    `vendors`.`code` AS t2_r2, 
    `vendors`.`created_at` AS t2_r3, 
    `vendors`.`updated_at` AS t2_r4, 
    `manufacturers`.`id` AS t3_r0, 
    `manufacturers`.`name` AS t3_r1, 
    `manufacturers`.`code` AS t3_r2, 
    `manufacturers`.`created_at` AS t3_r3, 
    `manufacturers`.`updated_at` AS t3_r4, 
    `categories`.`id` AS t4_r0, 
    `categories`.`name` AS t4_r1, 
    `categories`.`code` AS t4_r2, 
    `categories`.`description` AS t4_r3, 
    `categories`.`type` AS t4_r4, 
    `categories`.`category_id` AS t4_r5, 
    `categories`.`created_at` AS t4_r6, 
    `categories`.`updated_at` AS t4_r7, 
    `restrictions_products`.`id` AS t5_r0, 
    `restrictions_products`.`name` AS t5_r1, 
    `restrictions_products`.`code` AS t5_r2, 
    `restrictions_products`.`description` AS t5_r3, 
    `restrictions_products`.`severity` AS t5_r4, 
    `restrictions_products`.`begins_at` AS t5_r5, 
    `restrictions_products`.`expires_at` AS t5_r6, 
    `restrictions_products`.`type` AS t5_r7, 
    `restrictions_products`.`created_at` AS t5_r8, 
    `restrictions_products`.`updated_at` AS t5_r9, 
    `departments_products`.`id` AS t6_r0, 
    `departments_products`.`name` AS t6_r1, 
    `departments_products`.`code` AS t6_r2, 
    `departments_products`.`description` AS t6_r3, 
    `departments_products`.`type` AS t6_r4, 
    `departments_products`.`category_id` AS t6_r5, 
    `departments_products`.`created_at` AS t6_r6, 
    `departments_products`.`updated_at` AS t6_r7, 
    `comments`.`id` AS t7_r0, 
    `comments`.`title` AS t7_r1, 
    `comments`.`body` AS t7_r2, 
    `comments`.`author_id` AS t7_r3, 
    `comments`.`category` AS t7_r4, 
    `comments`.`commentable_id` AS t7_r5, 
    `comments`.`commentable_type` AS t7_r6, 
    `comments`.`created_at` AS t7_r7, 
    `comments`.`updated_at` AS t7_r8, 
    `pictures`.`id` AS t8_r0, 
    `pictures`.`name` AS t8_r1, 
    `pictures`.`title` AS t8_r2, 
    `pictures`.`path` AS t8_r3, 
    `pictures`.`picturable_id` AS t8_r4, 
    `pictures`.`picturable_type` AS t8_r5, 
    `pictures`.`category` AS t8_r6, 
    `pictures`.`created_at` AS t8_r7, 
    `pictures`.`updated_at` AS t8_r8 
FROM 
    `products` 
    LEFT OUTER JOIN `restrictions` 
    ON `restrictions`.`id` = `products`.`distribution_restriction_id` 
    AND `restrictions`.`type` IN ('DistributionRestriction') 
    LEFT OUTER JOIN `vendors` 
    ON `vendors`.`id` = `products`.`vendor_id` 
    LEFT OUTER JOIN `manufacturers` 
    ON `manufacturers`.`id` = `products`.`manufacturer_id` 
    LEFT OUTER JOIN `categories` 
    ON `categories`.`id` = `products`.`category_id` 
    AND `categories`.`type` IN ('ProductCategory') 
    LEFT OUTER JOIN `products_restrictions` 
    ON `products_restrictions`.`product_id` = `products`.`id` 
    LEFT OUTER JOIN `restrictions` `restrictions_products` 
    ON `restrictions_products`.`id` = `products_restrictions`.`restriction_id` 
    AND `restrictions_products`.`type` IN ('ProductRestriction') 
    LEFT OUTER JOIN `categories` `departments_products` 
    ON `departments_products`.`id` = `products`.`department_id` 
    AND `departments_products`.`type` IN ('Department') 
    LEFT OUTER JOIN `comments` 
    ON `comments`.`commentable_id` = `products`.`id` 
    AND `comments`.`commentable_type` = 'Product' 
    LEFT OUTER JOIN `pictures` 
    ON `pictures`.`picturable_id` = `products`.`id` 
    AND `pictures`.`picturable_type` = 'Product' 
WHERE `products`.`id` IN (122039) 
ORDER BY `products`.`id` DESC 

vs deuxième Product.last

SQL (2.1 ms) 
SELECT DISTINCT 
    `products`.`id` 
FROM 
    `products` 
    LEFT OUTER JOIN `restrictions` 
    ON `restrictions`.`id` = `products`.`distribution_restriction_id` 
    AND `restrictions`.`type` IN ('DistributionRestriction') 
    LEFT OUTER JOIN `vendors` 
    ON `vendors`.`id` = `products`.`vendor_id` 
    LEFT OUTER JOIN `manufacturers` 
    ON `manufacturers`.`id` = `products`.`manufacturer_id` 
    LEFT OUTER JOIN `categories` 
    ON `categories`.`id` = `products`.`category_id` 
    AND `categories`.`type` IN ('ProductCategory') 
    LEFT OUTER JOIN `products_restrictions` 
    ON `products_restrictions`.`product_id` = `products`.`id` 
    LEFT OUTER JOIN `restrictions` `restrictions_products` 
    ON `restrictions_products`.`id` = `products_restrictions`.`restriction_id` 
    AND `restrictions_products`.`type` IN ('ProductRestriction') 
    LEFT OUTER JOIN `categories` `departments_products` 
    ON `departments_products`.`id` = `products`.`department_id` 
    AND `departments_products`.`type` IN ('Department') 
    LEFT OUTER JOIN `comments` 
    ON `comments`.`commentable_id` = `products`.`id` 
    AND `comments`.`commentable_type` = 'Product' 
    LEFT OUTER JOIN `pictures` 
    ON `pictures`.`picturable_id` = `products`.`id` 
    AND `pictures`.`picturable_type` = 'Product' 
LIMIT 1 ; 

SELECT 
    `products`.`id` AS t0_r0, 
    `products`.`name` AS t0_r1, 
    `products`.`client_number` AS t0_r2, 
    `products`.`client_reference_string` AS t0_r3, 
    `products`.`client_id` AS t0_r4, 
    `products`.`vendor_number` AS t0_r5, 
    `products`.`vendor_reference_string` AS t0_r6, 
    `products`.`vendor_id` AS t0_r7, 
    `products`.`manufacturer_number` AS t0_r8, 
    `products`.`manufacturer_reference_string` AS t0_r9, 
    `products`.`manufacturer_id` AS t0_r10, 
    `products`.`reman_number` AS t0_r11, 
    `products`.`superseded_by_id` AS t0_r12, 
    `products`.`description` AS t0_r13, 
    `products`.`category_id` AS t0_r14, 
    `products`.`first_year_used` AS t0_r15, 
    `products`.`last_year_used` AS t0_r16, 
    `products`.`reorder_level` AS t0_r17, 
    `products`.`minimum_order_quantity` AS t0_r18, 
    `products`.`total_stock` AS t0_r19, 
    `products`.`stock_details` AS t0_r20, 
    `products`.`status` AS t0_r21, 
    `products`.`discontinued_at` AS t0_r22, 
    `products`.`currency` AS t0_r23, 
    `products`.`dealer_exchange_amount_cents` AS t0_r24, 
    `products`.`dealer_sale_amount_cents` AS t0_r25, 
    `products`.`retail_exchange_amount_cents` AS t0_r26, 
    `products`.`retail_sale_amount_cents` AS t0_r27, 
    `products`.`cost_amount_cents` AS t0_r28, 
    `products`.`core_charge_amount_cents` AS t0_r29, 
    `products`.`reman_amount_cents` AS t0_r30, 
    `products`.`out_of_warranty` AS t0_r31, 
    `products`.`backordered_till` AS t0_r32, 
    `products`.`repair_only` AS t0_r33, 
    `products`.`publicly_visible` AS t0_r34, 
    `products`.`period_usage` AS t0_r35, 
    `products`.`distribution_restriction_id` AS t0_r36, 
    `products`.`department_id` AS t0_r37, 
    `products`.`stats` AS t0_r38, 
    `products`.`announcement_date` AS t0_r39, 
    `products`.`status_with_vendor` AS t0_r40, 
    `products`.`masterfile_details` AS t0_r41, 
    `products`.`created_at` AS t0_r42, 
    `products`.`updated_at` AS t0_r43, 
    `restrictions`.`id` AS t1_r0, 
    `restrictions`.`name` AS t1_r1, 
    `restrictions`.`code` AS t1_r2, 
    `restrictions`.`description` AS t1_r3, 
    `restrictions`.`severity` AS t1_r4, 
    `restrictions`.`begins_at` AS t1_r5, 
    `restrictions`.`expires_at` AS t1_r6, 
    `restrictions`.`type` AS t1_r7, 
    `restrictions`.`created_at` AS t1_r8, 
    `restrictions`.`updated_at` AS t1_r9, 
    `vendors`.`id` AS t2_r0, 
    `vendors`.`name` AS t2_r1, 
    `vendors`.`code` AS t2_r2, 
    `vendors`.`created_at` AS t2_r3, 
    `vendors`.`updated_at` AS t2_r4, 
    `manufacturers`.`id` AS t3_r0, 
    `manufacturers`.`name` AS t3_r1, 
    `manufacturers`.`code` AS t3_r2, 
    `manufacturers`.`created_at` AS t3_r3, 
    `manufacturers`.`updated_at` AS t3_r4, 
    `categories`.`id` AS t4_r0, 
    `categories`.`name` AS t4_r1, 
    `categories`.`code` AS t4_r2, 
    `categories`.`description` AS t4_r3, 
    `categories`.`type` AS t4_r4, 
    `categories`.`category_id` AS t4_r5, 
    `categories`.`created_at` AS t4_r6, 
    `categories`.`updated_at` AS t4_r7, 
    `restrictions_products`.`id` AS t5_r0, 
    `restrictions_products`.`name` AS t5_r1, 
    `restrictions_products`.`code` AS t5_r2, 
    `restrictions_products`.`description` AS t5_r3, 
    `restrictions_products`.`severity` AS t5_r4, 
    `restrictions_products`.`begins_at` AS t5_r5, 
    `restrictions_products`.`expires_at` AS t5_r6, 
    `restrictions_products`.`type` AS t5_r7, 
    `restrictions_products`.`created_at` AS t5_r8, 
    `restrictions_products`.`updated_at` AS t5_r9, 
    `departments_products`.`id` AS t6_r0, 
    `departments_products`.`name` AS t6_r1, 
    `departments_products`.`code` AS t6_r2, 
    `departments_products`.`description` AS t6_r3, 
    `departments_products`.`type` AS t6_r4, 
    `departments_products`.`category_id` AS t6_r5, 
    `departments_products`.`created_at` AS t6_r6, 
    `departments_products`.`updated_at` AS t6_r7, 
    `comments`.`id` AS t7_r0, 
    `comments`.`title` AS t7_r1, 
    `comments`.`body` AS t7_r2, 
    `comments`.`author_id` AS t7_r3, 
    `comments`.`category` AS t7_r4, 
    `comments`.`commentable_id` AS t7_r5, 
    `comments`.`commentable_type` AS t7_r6, 
    `comments`.`created_at` AS t7_r7, 
    `comments`.`updated_at` AS t7_r8, 
    `pictures`.`id` AS t8_r0, 
    `pictures`.`name` AS t8_r1, 
    `pictures`.`title` AS t8_r2, 
    `pictures`.`path` AS t8_r3, 
    `pictures`.`picturable_id` AS t8_r4, 
    `pictures`.`picturable_type` AS t8_r5, 
    `pictures`.`category` AS t8_r6, 
    `pictures`.`created_at` AS t8_r7, 
    `pictures`.`updated_at` AS t8_r8 
FROM 
    `products` 
    LEFT OUTER JOIN `restrictions` 
    ON `restrictions`.`id` = `products`.`distribution_restriction_id` 
    AND `restrictions`.`type` IN ('DistributionRestriction') 
    LEFT OUTER JOIN `vendors` 
    ON `vendors`.`id` = `products`.`vendor_id` 
    LEFT OUTER JOIN `manufacturers` 
    ON `manufacturers`.`id` = `products`.`manufacturer_id` 
    LEFT OUTER JOIN `categories` 
    ON `categories`.`id` = `products`.`category_id` 
    AND `categories`.`type` IN ('ProductCategory') 
    LEFT OUTER JOIN `products_restrictions` 
    ON `products_restrictions`.`product_id` = `products`.`id` 
    LEFT OUTER JOIN `restrictions` `restrictions_products` 
    ON `restrictions_products`.`id` = `products_restrictions`.`restriction_id` 
    AND `restrictions_products`.`type` IN ('ProductRestriction') 
    LEFT OUTER JOIN `categories` `departments_products` 
    ON `departments_products`.`id` = `products`.`department_id` 
    AND `departments_products`.`type` IN ('Department') 
    LEFT OUTER JOIN `comments` 
    ON `comments`.`commentable_id` = `products`.`id` 
    AND `comments`.`commentable_type` = 'Product' 
    LEFT OUTER JOIN `pictures` 
    ON `pictures`.`picturable_id` = `products`.`id` 
    AND `pictures`.`picturable_type` = 'Product' 
WHERE `products`.`id` IN (1) 

** 2 ** EDIT

default_scope {eager_load([:distribution_restriction, :vendor, :manufacturer, :category, :restrictions, :department, :comments, :pictures])} 
+0

S'il vous plaît montrer le SQL de vos journaux que chaque déclaration produit. – smathy

+0

Pourriez-vous poster le SQL qui résulte dans chacun de ceux? Dans ma base de données, ils résultent tous les deux en 'ORDER BY id DESC' et retournent les mêmes résultats. La seule différence étant 'last' renvoie un enregistrement et' last (1) 'renvoie un tableau. – evanbikes

+0

Exécutez simplement 'ActiveRecord :: Base.logger = Logger.new (STDOUT)' et vous verrez la sortie du journal dans votre console. – smathy

Répondre

0

Le coupable est eager_loading dans mon modèle.

Ok, donc il semble que quelque chose doit être gardé à l'esprit et peut-être mentionné dans la documentation, que eager_loading bousille commande dans .last()

J'ai essayé

scope :include_all, -> {eager_load([:distribution_restriction, :vendor, :manufacturer, :category, :restrictions, :department, :comments, :pictures])}

Et puis Product.include_all.last & Product.include_all.last(1)

Comme mon problème d'origine eager_loading - foiré dans la commande fi premier cas.

1

#first et #last d'ActiveRecord n'ont aucune commande implicite, et il est laissé à votre base de données à remplir.

Dans la plupart des cas, ils reviendront dans l'ordre avec la clé primaire, mais pas toujours.

Il est préférable d'être explicite sur votre commande lorsque vous en avez vraiment besoin.

+0

Pas tout à fait correct. De docs: "Trouver le dernier enregistrement (ou N derniers enregistrements si un paramètre est fourni) .Si aucun ordre n'est défini il passera commande par clé primaire (id dans ce cas)." Comme je l'ai lu - pour moi cela signifie qu'il va saisir l'ensemble (toutes les lignes) et retourner le dernier en fonction de l'ID. J'ai 30K enregistrements dans la table, mais il continue de retourner le premier enregistrement - avec l'ID 1. S'il n'est pas censé retourner le dernier enregistrement, alors il devrait être nommé random() :-) – konung

+0

Basé sur les docs - toutes choses étant égal last() & last (1) devrait retourner la même chose. http://api.rubyonrails.org/classes/ActiveRecord/FinderMethods.html#method-i-last – konung