Skip to content

performance issues with linkage(always: true) #106

Open
@spencerroan

Description

@spencerroan

In our serializers we make liberal use of linkage(always: true). This fully renders the relationship including any calls out to new linkages. This is a performance issue and generates n+1 queries for objects we were not planning on loading. I'm going to build something that looks up what the include tree should be based on what we always include and what is asked for.

For instance:

class SerializableBar < JSONAPI::Serializable::Resource
  type 'bars'
  has_many :foos do
    linkage always: true
  end
end

class SerializableFoo < JSONAPI::Serializable::Resource
  type 'foos'
  # I do not expect any of this to be run except what is used to generate id/type info for the linkage.
  has_many :quxes do
    linkage always: true
  end
end

When rendering a Bar without including quxes, I don't expect the has_many quxes to be serialized.

In the short term I've made this monkey patch to avoid loading extra layers of relationships:

class JSONAPI::Serializable::Relationship
  def belongs_to_linkage(association)
    reflection = @object.class.reflect_on_association(association)
    foreign_key = @object.public_send(reflection.foreign_key)
    foreign_key && {
      id: foreign_key,
      type: reflection.plural_name
    }
  end

  def has_one_linkage(association, receiver = @object)
    associated = receiver.public_send(association)
    associated ? linkage_for(associated) : nil
  end

  def has_many_linkage(association)
    associated = @object.public_send(association)
    associated.map { |assoc| linkage_for(assoc) }
  end

  def linkage_for(associated)
    {
      id: associated.id,
      type: associated.class.table_name
    }
  end
end

I'll explore ways of not monkey patching like creating a sister to linkage() that does more of what I need performance wise.
This seems related to:
#91
#100
#49

I guess an additional issue I have is that the related object is loaded even on a belongs_to. I'd assume the reflection of the relationship could generate id and type without loading the object, but it does make for more conditional/brittle code.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions