私のRailsアプリでは、特にモデルごとにインプレッションをログに記録するときに、データベースに余分な呼び出しを行って関連データを何度も取得するというN + 1の問題があります。
例えば:
Started GET "/" for 127.0.0.1 at 2018-12-02 16:21:05 -0500
Processing by JobsController#index as HTML
Job Load (4.4ms) SELECT "jobs".* FROM "jobs" WHERE "jobs"."published_at" IS NOT NULL ORDER BY "jobs"."published_at" DESC LIMIT $1 OFFSET $2 [["LIMIT", 30], ["OFFSET", 0]]
↳ app/controllers/jobs_controller.rb:22
User Load (1.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 13], ["LIMIT", 1]]
↳ app/controllers/jobs_controller.rb:24
Impression Exists (1.3ms) SELECT 1 AS one FROM "impressions" WHERE "impressions"."impressionable_id" = $1 AND "impressions"."impressionable_type" = $2 AND "impressions"."session_hash" = $3 LIMIT $4 [["impressionable_id", 705], ["impressionable_type", "Job"], ["session_hash", "d80d52dd401011a626d600167140e49f"], ["LIMIT", 1]]
↳ app/controllers/jobs_controller.rb:24
Impression Exists (0.6ms) SELECT 1 AS one FROM "impressions" WHERE "impressions"."impressionable_id" = $1 AND "impressions"."impressionable_type" = $2 AND "impressions"."session_hash" = $3 LIMIT $4 [["impressionable_id", 704], ["impressionable_type", "Job"], ["session_hash", "d80d52dd401011a626d600167140e49f"], ["LIMIT", 1]]
↳ app/controllers/jobs_controller.rb:24
Impression Exists (0.4ms) SELECT 1 AS one FROM "impressions" WHERE "impressions"."impressionable_id" = $1 AND "impressions"."impressionable_type" = $2 AND "impressions"."session_hash" = $3 LIMIT $4 [["impressionable_id", 703], ["impressionable_type", "Job"], ["session_hash", "d80d52dd401011a626d600167140e49f"], ["LIMIT", 1]]
↳ app/controllers/jobs_controller.rb:24
私は印象派の宝石を使用し、impressionist
メソッドを直接使用Jobs
して、ページ上のすべてを取得し、印象を記録しています。問題は、一意のインプレッションのみを記録しているためです。既に があるレコードの場合impression
、これらの追加の呼び出しは冗長です。@jobs.includes(:impressions).each
Rails がどのレコードが存在するかを判断するのに十分なほどスマートであることを期待して、関連付けられたデータをプリロードするために を使用しようとしましたが、Rails は依然として多数のImpression Exists
クエリを出力します。
@jobs.each{|job| impressionist(job,'', :unique => [:session_hash])}