Rails Grape api:获取更多数据时的性能
Rails Grape api: performannce when getting more data
我在使用 grape api 时遇到了性能问题。
我有以下型号:
class Profile
has_many :transitive_user_profiles
end
class TransitiveUserProfile < ApplicationRecord
belongs_to :profile
belongs_to :user
belongs_to :client
结束
class DefaultAddress
belongs_to :user
end
我正在通过 rest-api 使用 grape
获取所有用户和各自的配置文件
@all_profiles = @all_profiles ||
TransitiveUserProfile.includes(:profile).where(
"profile_id IN (?)", application.profile_ids)
present @users, with: Identity::V3::UserEntity, all_profiles: @all_profiles #@user = User.all - around 700 users
我写了 UserEntity class
class UserEntity < Grape::Entity
expose :id, as: :uniqueId
expose :trimmed_userid, as: :userId
expose :nachname, as: :lastName
expose :vorname, as: :firstName
expose :is_valid, as: :isValid
expose :is_system_user, as: :isSystemUser
expose :email
expose :utc_updated_at, as: :updatedAt
expose :applications_and_profiles
def email
object.default_address_email
end
def applications_and_profiles
app_profiles = @all_app_profiles.where(user_id: object.id).collect{|t| {name: t.profile.unique_id, rights: t.profile.profilrechte} }
[{:appl_id=>"test", :profiles=>app_profiles}]
end
end
我遇到了问题,当我尝试获取所有用户和配置文件时需要超过 15 秒。在以下代码中面临问题(花时间获取关联对象)。
def email
object.default_address_email
end
def applications_and_profiles
app_profiles = @all_app_profiles.where(user_id: object.id).collect{|t| {name: t.profile.unique_id, rights: t.profile.profilrechte} }
[{:appl_id=>"test", :profiles=>app_profiles}]
end
如何高效解决(通常少于5秒)
app_profiles = @all_app_profiles.where(user_id: object.id).collect{|t| {姓名:t.profile.unique_id,权利:t.profile.profilrechte}}
上面的sql造成了N+1的问题,会导致性能变慢。您可以检查有关此的日志。解决此问题的更好方法是使用预加载,如下所示(如@max pleaner 和@anothermh 所建议)
app_profiles = @all_app_profiles.where(user_id: object.id).includes(:profile).collect{|t| {姓名:t.profile.unique_id,权利:t.profile.profilrechte}}
有关预加载的更多信息,您可以关注以下内容link:
1) https://medium.com/@codenode/10-tips-for-eager-loading-to-avoid-n-1-queries-in-rails-2bad54456a3f
谢谢大家,是的,这是 N+1 问题。最后我能够使用 @all_app_profiles.select {|i| i.user_id == object.id}.collect {|t| {name: t.profile.unique_id, unique_id: t.profile.unique_id, rights: t.profile.profilrechte} }
而不是 @all_app_profiles.where(user_id: object.id).collect{|t| {name: t.profile.unique_id, rights: t.profile.profilrechte} }
[{:appl_id=>"test", :profiles=>app_profiles}]
来解决
我在使用 grape api 时遇到了性能问题。 我有以下型号:
class Profile
has_many :transitive_user_profiles
end
class TransitiveUserProfile < ApplicationRecord
belongs_to :profile
belongs_to :user
belongs_to :client
结束
class DefaultAddress
belongs_to :user
end
我正在通过 rest-api 使用 grape
获取所有用户和各自的配置文件@all_profiles = @all_profiles ||
TransitiveUserProfile.includes(:profile).where(
"profile_id IN (?)", application.profile_ids)
present @users, with: Identity::V3::UserEntity, all_profiles: @all_profiles #@user = User.all - around 700 users
我写了 UserEntity class
class UserEntity < Grape::Entity
expose :id, as: :uniqueId
expose :trimmed_userid, as: :userId
expose :nachname, as: :lastName
expose :vorname, as: :firstName
expose :is_valid, as: :isValid
expose :is_system_user, as: :isSystemUser
expose :email
expose :utc_updated_at, as: :updatedAt
expose :applications_and_profiles
def email
object.default_address_email
end
def applications_and_profiles
app_profiles = @all_app_profiles.where(user_id: object.id).collect{|t| {name: t.profile.unique_id, rights: t.profile.profilrechte} }
[{:appl_id=>"test", :profiles=>app_profiles}]
end
end
我遇到了问题,当我尝试获取所有用户和配置文件时需要超过 15 秒。在以下代码中面临问题(花时间获取关联对象)。
def email
object.default_address_email
end
def applications_and_profiles
app_profiles = @all_app_profiles.where(user_id: object.id).collect{|t| {name: t.profile.unique_id, rights: t.profile.profilrechte} }
[{:appl_id=>"test", :profiles=>app_profiles}]
end
如何高效解决(通常少于5秒)
app_profiles = @all_app_profiles.where(user_id: object.id).collect{|t| {姓名:t.profile.unique_id,权利:t.profile.profilrechte}}
上面的sql造成了N+1的问题,会导致性能变慢。您可以检查有关此的日志。解决此问题的更好方法是使用预加载,如下所示(如@max pleaner 和@anothermh 所建议)
app_profiles = @all_app_profiles.where(user_id: object.id).includes(:profile).collect{|t| {姓名:t.profile.unique_id,权利:t.profile.profilrechte}}
有关预加载的更多信息,您可以关注以下内容link:
1) https://medium.com/@codenode/10-tips-for-eager-loading-to-avoid-n-1-queries-in-rails-2bad54456a3f
谢谢大家,是的,这是 N+1 问题。最后我能够使用 @all_app_profiles.select {|i| i.user_id == object.id}.collect {|t| {name: t.profile.unique_id, unique_id: t.profile.unique_id, rights: t.profile.profilrechte} }
而不是 @all_app_profiles.where(user_id: object.id).collect{|t| {name: t.profile.unique_id, rights: t.profile.profilrechte} }
[{:appl_id=>"test", :profiles=>app_profiles}]