eager_load + find_by에서 쿼리가 두 번 발행되는 경우
14438 단어 Rails6RailsActiveRecordRails5루비
결론
일반적인 1:N Relation이 있을 때
class User < ApplicationRecord
has_many :comments
end
class Comment < ApplicationRecord
belongs_to :user
end
User.eager_load(:comments).find_by(id: 1)
빗질하면
1. User.find_by(id: 1) SQL
2. User.eager_load(:comments) SQL
두 번 SQL 발급
User.eager_load(:comments).where(id: 1).load.first
라고 하면 쿼리가 1회가 된다.
(
.load
는 .to_a
라든지 OK)ruby 2.5.1
rails 5.0.6/6.0.1(下記ログは6.0.1のものです)
에서 확인됨.
상세
보통 해 보았지만, 아무래도 단순한 find 같은 쿼리와,
함께 정보를 얻는 쿼리의 두 번이 발행되었습니다.
User.eager_load(:comments).find(1)
# SELECT DISTINCT `users`.`id` FROM `users` LEFT OUTER JOIN `comments` ON `comments`.`user_id` = `users`.`id` WHERE `users`.`id` = 1 LIMIT 1
# SELECT `users`.`id` AS t0_r0, `users`.`name` AS t0_r1, `users`.`created_at` AS t0_r2, `users`.`updated_at` AS t0_r3, `comments`.`id` AS t1_r0, `comments`.`user_id` AS t1_r1, `comments`.`created_at` AS t1_r2, `comments`.`updated_at` AS t1_r3 FROM `users` LEFT OUTER JOIN `comments` ON `comments`.`user_id` = `users`.`id` WHERE `users`.`id` = 1 AND `users`.`id` = 1
User.eager_load(:comments).find_by(id: 1)
# SELECT DISTINCT `users`.`id` FROM `users` LEFT OUTER JOIN `comments` ON `comments`.`user_id` = `users`.`id` WHERE `users`.`id` = 1 LIMIT 1
# SELECT `users`.`id` AS t0_r0, `users`.`name` AS t0_r1, `users`.`created_at` AS t0_r2, `users`.`updated_at` AS t0_r3, `comments`.`id` AS t1_r0, `comments`.`user_id` AS t1_r1, `comments`.`created_at` AS t1_r2, `comments`.`updated_at` AS t1_r3 FROM `users` LEFT OUTER JOIN `comments` ON `comments`.`user_id` = `users`.`id` WHERE `users`.`id` = 1 AND `users`.`id` = 1
User.eager_load(:comments).where(id: 1).first
# SELECT DISTINCT `users`.`id` AS alias_0, `users`.`id` FROM `users` LEFT OUTER JOIN `comments` ON `comments`.`user_id` = `users`.`id` WHERE `users`.`id` = 1 ORDER BY `users`.`id` ASC LIMIT 1
# SELECT `users`.`id` AS t0_r0, `users`.`name` AS t0_r1, `users`.`created_at` AS t0_r2, `users`.`updated_at` AS t0_r3, `comments`.`id` AS t1_r0, `comments`.`user_id` AS t1_r1, `comments`.`created_at` AS t1_r2, `comments`.`updated_at` AS t1_r3 FROM `users` LEFT OUTER JOIN `comments` ON `comments`.`user_id` = `users`.`id` WHERE `users`.`id` = 1 AND `users`.`id` = 1 ORDER BY `users`.`id` ASC
WHERE `users`.`id` = 1 AND `users`.`id` = 1
라든지 엄청 중복 같은 쿼리가 있다.두 번째 쿼리만으로 원하는 정보를 얻을 수 있어야합니다.
어떻게든 한 번의 쿼리로 만들고 싶습니다
User.eager_load(:comments).where(id: 1)
의 경우 쿼리가 한 번이므로,이 시점에서 쿼리를 무리하게 발화시키고 나서, first를 취하면 좋을까?
User.eager_load(:comments).where(id: 1).load.first
# SELECT `users`.`id` AS t0_r0, `users`.`name` AS t0_r1, `users`.`created_at` AS t0_r2, `users`.`updated_at` AS t0_r3, `comments`.`id` AS t1_r0, `comments`.`user_id` AS t1_r1, `comments`.`created_at` AS t1_r2, `comments`.`updated_at` AS t1_r3 FROM `users` LEFT OUTER JOIN `comments` ON `comments`.`user_id` = `users`.`id` WHERE `users`.`id` = 1
키타━━━━(゚∀゚)━━━━!!
끝.
쿼리 정형ver
User.eager_load(:comments).find(1)
# SQL (4.0ms) SELECT DISTINCT `users`.`id` FROM `users` LEFT OUTER JOIN `comments` ON `comments`.`user_id` = `users`.`id` WHERE `users`.`id` = 1 LIMIT 1
# SQL (2.8ms) SELECT `users`.`id` AS t0_r0, `users`.`name` AS t0_r1, `users`.`created_at` AS t0_r2, `users`.`updated_at` AS t0_r3, `comments`.`id` AS t1_r0, `comments`.`user_id` AS t1_r1, `comments`.`created_at` AS t1_r2, `comments`.`updated_at` AS t1_r3 FROM `users` LEFT OUTER JOIN `comments` ON `comments`.`user_id` = `users`.`id` WHERE `users`.`id` = 1 AND `users`.`id` = 1
# -- pretty format.
# SELECT
# DISTINCT `users`.`id`
# FROM
# `users`
# LEFT OUTER JOIN `comments` ON `comments`.`user_id` = `users`.`id`
# WHERE
# `users`.`id` = 1
# LIMIT
# 1;
#
# SELECT
# `users`.`id` AS t0_r0,
# `users`.`name` AS t0_r1,
# `users`.`created_at` AS t0_r2,
# `users`.`updated_at` AS t0_r3,
# `comments`.`id` AS t1_r0,
# `comments`.`user_id` AS t1_r1,
# `comments`.`created_at` AS t1_r2,
# `comments`.`updated_at` AS t1_r3
# FROM
# `users`
# LEFT OUTER JOIN `comments` ON `comments`.`user_id` = `users`.`id`
# WHERE
# `users`.`id` = 1
# AND `users`.`id` = 1;
#=> #<User id: 1, name: "hogehoge", created_at: "2019-11-15 04:54:42", updated_at: "2019-11-15 04:54:42">
User.eager_load(:comments).find_by(id: 1)
# SQL (1.0ms) SELECT DISTINCT `users`.`id` FROM `users` LEFT OUTER JOIN `comments` ON `comments`.`user_id` = `users`.`id` WHERE `users`.`id` = 1 LIMIT 1
# SQL (2.7ms) SELECT `users`.`id` AS t0_r0, `users`.`name` AS t0_r1, `users`.`created_at` AS t0_r2, `users`.`updated_at` AS t0_r3, `comments`.`id` AS t1_r0, `comments`.`user_id` AS t1_r1, `comments`.`created_at` AS t1_r2, `comments`.`updated_at` AS t1_r3 FROM `users` LEFT OUTER JOIN `comments` ON `comments`.`user_id` = `users`.`id` WHERE `users`.`id` = 1 AND `users`.`id` = 1
# SELECT
# DISTINCT `users`.`id`
# FROM
# `users`
# LEFT OUTER JOIN `comments` ON `comments`.`user_id` = `users`.`id`
# WHERE
# `users`.`id` = 1
# LIMIT
# 1;
#
# SELECT
# `users`.`id` AS t0_r0,
# `users`.`name` AS t0_r1,
# `users`.`created_at` AS t0_r2,
# `users`.`updated_at` AS t0_r3,
# `comments`.`id` AS t1_r0,
# `comments`.`user_id` AS t1_r1,
# `comments`.`created_at` AS t1_r2,
# `comments`.`updated_at` AS t1_r3
# FROM
# `users`
# LEFT OUTER JOIN `comments` ON `comments`.`user_id` = `users`.`id`
# WHERE
# `users`.`id` = 1
# AND `users`.`id` = 1;
#
#=> #<User id: 1, name: "hogehoge", created_at: "2019-11-15 04:54:42", updated_at: "2019-11-15 04:54:42">
User.eager_load(:comments).where(id: 1).first
# SQL (0.6ms) SELECT DISTINCT `users`.`id` AS alias_0, `users`.`id` FROM `users` LEFT OUTER JOIN `comments` ON `comments`.`user_id` = `users`.`id` WHERE `users`.`id` = 1 ORDER BY `users`.`id` ASC LIMIT 1
# SQL (0.6ms) SELECT `users`.`id` AS t0_r0, `users`.`name` AS t0_r1, `users`.`created_at` AS t0_r2, `users`.`updated_at` AS t0_r3, `comments`.`id` AS t1_r0, `comments`.`user_id` AS t1_r1, `comments`.`created_at` AS t1_r2, `comments`.`updated_at` AS t1_r3 FROM `users` LEFT OUTER JOIN `comments` ON `comments`.`user_id` = `users`.`id` WHERE `users`.`id` = 1 AND `users`.`id` = 1 ORDER BY `users`.`id` ASC
#
# SELECT
# DISTINCT `users`.`id` AS alias_0,
# `users`.`id`
# FROM
# `users`
# LEFT OUTER JOIN `comments` ON `comments`.`user_id` = `users`.`id`
# WHERE
# `users`.`id` = 1
# ORDER BY
# `users`.`id` ASC
# LIMIT
# 1;
#
# SELECT
# `users`.`id` AS t0_r0,
# `users`.`name` AS t0_r1,
# `users`.`created_at` AS t0_r2,
# `users`.`updated_at` AS t0_r3,
# `comments`.`id` AS t1_r0,
# `comments`.`user_id` AS t1_r1,
# `comments`.`created_at` AS t1_r2,
# `comments`.`updated_at` AS t1_r3
# FROM
# `users`
# LEFT OUTER JOIN `comments` ON `comments`.`user_id` = `users`.`id`
# WHERE
# `users`.`id` = 1
# AND `users`.`id` = 1
# ORDER BY
# `users`.`id` ASC;
#=> #<User id: 1, name: "hogehoge", created_at: "2019-11-15 04:54:42", updated_at: "2019-11-15 04:54:42">
User.eager_load(:comments).where(id: 1).load.first
# SQL (1.0ms) SELECT `users`.`id` AS t0_r0, `users`.`name` AS t0_r1, `users`.`created_at` AS t0_r2, `users`.`updated_at` AS t0_r3, `comments`.`id` AS t1_r0, `comments`.`user_id` AS t1_r1, `comments`.`created_at` AS t1_r2, `comments`.`updated_at` AS t1_r3 FROM `users` LEFT OUTER JOIN `comments` ON `comments`.`user_id` = `users`.`id` WHERE `users`.`id` = 1
# SELECT
# `users`.`id` AS t0_r0,
# `users`.`name` AS t0_r1,
# `users`.`created_at` AS t0_r2,
# `users`.`updated_at` AS t0_r3,
# `comments`.`id` AS t1_r0,
# `comments`.`user_id` AS t1_r1,
# `comments`.`created_at` AS t1_r2,
# `comments`.`updated_at` AS t1_r3
# FROM
# `users`
# LEFT OUTER JOIN `comments` ON `comments`.`user_id` = `users`.`id`
# WHERE
# `users`.`id` = 1;
#=> #<User id: 1, name: "hogehoge", created_at: "2019-11-15 04:54:42", updated_at: "2019-11-15 04:54:42">
Reference
이 문제에 관하여(eager_load + find_by에서 쿼리가 두 번 발행되는 경우), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/k_karen/items/cb4a2c762554ab257751텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)