Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Does not work with includes or eager_loads #4

Closed
westonganger opened this issue Jul 13, 2017 · 4 comments
Closed

Does not work with includes or eager_loads #4

westonganger opened this issue Jul 13, 2017 · 4 comments

Comments

@westonganger
Copy link

westonganger commented Jul 13, 2017

I found out that it doesn't work when using includes or eager_loads, however joins and preload works correctly. This is not a problem because the performance improvements are so great that I am able to work around these. But if this can't be fixed it would be nice to note this in the readme.

@Liooo
Copy link

Liooo commented Nov 2, 2017

Bit outdated but for the record.
preload/includes isn't working as well, you can confirm N+1 happening even when preloading association.

@Paxa
Copy link
Owner

Paxa commented Nov 2, 2017

I don't know what is right solution would be. I don't want to reproduce rails' logic for includes.
I guess you should write custom sql to include needed rows or some logic for one-to-many relations

For one to one / belongs to:

User.select("users.*, (select name from cities where user.hometown_id = cities.id) as hometown_name")....

For one to many / many to many:

users = User.all.light_records
photos = Photo.where(user_id: users.map(&:id)).light_records

users.each do |user|
  user_photos = photos.select {|ph| ph.user_id = user.id }
  ...
end

If your volumes are really big then can process in batches:

batch = []
User.all.light_records_each do |user|
  batch << user
  if batch.size >= 1000
    photos = Photo.where(user_id: batch.map(&:id)).light_records
    process_batch(batch, photos)
  end
end

photos = Photo.where(user_id: batch.map(&:id)).light_records
process_batch(batch, photos)

If you want to have same interface as rails associations then can make attr_accessor:

class User < ActiveRecord::Base
  module LightRecord
    attr_accessor :photos
  end
end

users = User.all.light_records
photos = Photo.where(user_id: users.map(&:id)).light_records

users.each do |user|
  # to make same interface as rails' preloading
  user.photos = photos.select {|ph| ph.user_id = user.id }
  ...
end

@Liooo
Copy link

Liooo commented Nov 2, 2017

@Paxa Right, thank you.
I was just searching if this lib works with loaders and came across this issue. Just added clarification for guys coming later.

@Paxa
Copy link
Owner

Paxa commented Aug 19, 2019

includes(..) still not supported and no plans to do it. (contributions are welcome)

Method light_records_each provides streaming result from mysql. Mysql start to send data before query is complete, so we can't know what will be all foreign keys without interacting through results.

I can suggest you to rewrite code to load relations manually, like this:

articles = Article.all.light_records
users = {}
User.find_by(id: articles.map(&:user_id).uniq).light_records_each do |user|
  users[user.id] = user
end

articles.each do |article|
  user = users[article.user_id]
  ...
end

@Paxa Paxa closed this as completed Feb 26, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants