提高 Rails 控制器方法的性能,returns 序列化哈希
Improving performance of a Rails controller method that returns a serialized hash
是否有人愿意就如何提高以下控制器方法的性能给我建议?
def index
@contacts = Hash[current_user.company.contacts.map {|contact| [contact.id, ContactSerializer.new(contact).as_json[:contact]] }]
respond_to do |format|
format.json { render json: { contacts: @contacts } }
end
end
这 return 具有以下数据结构:
{
contacts: {
79: {
id: 79,
first_name: "Foo",
last_name: "Bar",
email: "t@t.co",
engagement: "0%",
company_id: 94,
created_at: " 9:41AM Jan 30, 2016",
updated_at: "10:57AM Feb 23, 2016",
published_response_count: 0,
groups: {
test: true,
test23: false,
Test222: false,
Last: false
},
invites: [
{
id: 112,
email: "t@t.co",
status: "Requested",
created_at: "Jan 30, 2016, 8:48 PM",
date_submitted: null,
response: null
}
],
responses: [ ],
promotions: [
{
id: 26,
company_id: 94,
key: "e5cb3bc80b58c29df8a61231d0",
updated_at: "Feb 11, 2016, 2:45 PM",
read: null,
social_media_posts: [ ]
}
]
},
81: {
id: 81,
first_name: "Foo2",
last_name: "Bar2",
email: "foobar2@foobar.com",
engagement: "0%",
company_id: 94,
created_at: "12:55PM Feb 04, 2016",
updated_at: " 4:25PM Feb 19, 2016",
published_response_count: 0,
groups: {
test: true,
test23: true,
Test222: false,
Last: false
},
invites: [
{
id: 116,
email: "foobar2@foobar.com",
status: "Requested",
created_at: "Feb 22, 2016, 9:10 PM",
date_submitted: null,
response: null
}
],
responses: [ ],
promotions: [
{
id: 26,
company_id: 94,
key: "e5cb3bc80b58c29df8a61231d0",
updated_at: "Feb 11, 2016, 2:45 PM",
read: null,
social_media_posts: [ ]
}
]
}
}
}
我需要 index
方法来 return 散列,其中键是联系人 ID,而不是通常 returned 的数组。此外,我通过序列化程序传递每个联系人,以便我获得客户需要的所有关联数据。
只有几个联系人时,此方法工作正常,但是当我有 100 或 1000 个联系人时,它确实变慢了。我用 100 个联系人对它进行了基准测试,花了 4 秒才完成,这太糟糕了。我想知道如何改进我的代码,以更高效的方式获得 完全相同的 输出。这里的关键是输出需要保持不变。我对修改客户端代码没有兴趣(许多应用程序都依赖于此数据结构),因此所有更改都需要在服务器端进行。
这是我的ContactSerializer
供参考:
class ContactSerializer < ActiveModel::Serializer
attributes :id, :first_name, :last_name, :email, :engagement, :company_id, :created_at, :updated_at, :published_response_count, :groups
has_many :invites
has_many :responses
has_many :promotions
def groups
Hash[object.company.groups.map {|group| [group.name, object.groups.include?(group)] }]
end
def published_response_count
object.responses.where(published: true).count
end
def created_at
object.created_at.in_time_zone("Eastern Time (US & Canada)").strftime("%l:%M%p %b %d, %Y")
end
def updated_at
object.updated_at.in_time_zone("Eastern Time (US & Canada)").strftime("%l:%M%p %b %d, %Y")
end
def engagement
object.engagement
end
end
对于它的价值,我完全意识到 returning JSON 来自 Rails 的数据并不是一个很好的做法,并且已经完全放弃了它。不幸的是,这段代码是很久以前写的,我没有时间完全重写客户端以使用标准输出,例如联系人数组。
我开始研究 ActiveRecord 生成的查询。
一段时间后我意识到查询只占总处理时间的几毫秒。我开始从基本查询 company.contacts
开始对代码进行基准测试,然后逐渐添加我拥有的方法,例如 map
然后将每个联系人传递到序列化程序中,最后调用 as_json[:contact]
ContactSerializer.new(contact)
返回的对象。
我发现在序列化对象上调用 as_json[:contact]
每次联系平均消耗大约 30 毫秒(平均超过 100 次运行)。我这样做的原因是从返回的 JSON 中删除根 contact
节点。
当我用 198 个联系人对我的原始代码进行基准测试时,10 次运行平均花费 10400 毫秒。当我删除 as_json[:contact]
并在 ContactSerializer
上设置 root false
时,如“Abusing ActiveModel::Serializers for HAL”所述,我能够将时间从 10400 毫秒减少到 87 毫秒,同时返回确切的与客户端相同的结构,这令人震惊。
通过一些查询优化可能会缩短几毫秒,但此时其他任何事情都只是锦上添花。
是否有人愿意就如何提高以下控制器方法的性能给我建议?
def index
@contacts = Hash[current_user.company.contacts.map {|contact| [contact.id, ContactSerializer.new(contact).as_json[:contact]] }]
respond_to do |format|
format.json { render json: { contacts: @contacts } }
end
end
这 return 具有以下数据结构:
{
contacts: {
79: {
id: 79,
first_name: "Foo",
last_name: "Bar",
email: "t@t.co",
engagement: "0%",
company_id: 94,
created_at: " 9:41AM Jan 30, 2016",
updated_at: "10:57AM Feb 23, 2016",
published_response_count: 0,
groups: {
test: true,
test23: false,
Test222: false,
Last: false
},
invites: [
{
id: 112,
email: "t@t.co",
status: "Requested",
created_at: "Jan 30, 2016, 8:48 PM",
date_submitted: null,
response: null
}
],
responses: [ ],
promotions: [
{
id: 26,
company_id: 94,
key: "e5cb3bc80b58c29df8a61231d0",
updated_at: "Feb 11, 2016, 2:45 PM",
read: null,
social_media_posts: [ ]
}
]
},
81: {
id: 81,
first_name: "Foo2",
last_name: "Bar2",
email: "foobar2@foobar.com",
engagement: "0%",
company_id: 94,
created_at: "12:55PM Feb 04, 2016",
updated_at: " 4:25PM Feb 19, 2016",
published_response_count: 0,
groups: {
test: true,
test23: true,
Test222: false,
Last: false
},
invites: [
{
id: 116,
email: "foobar2@foobar.com",
status: "Requested",
created_at: "Feb 22, 2016, 9:10 PM",
date_submitted: null,
response: null
}
],
responses: [ ],
promotions: [
{
id: 26,
company_id: 94,
key: "e5cb3bc80b58c29df8a61231d0",
updated_at: "Feb 11, 2016, 2:45 PM",
read: null,
social_media_posts: [ ]
}
]
}
}
}
我需要 index
方法来 return 散列,其中键是联系人 ID,而不是通常 returned 的数组。此外,我通过序列化程序传递每个联系人,以便我获得客户需要的所有关联数据。
只有几个联系人时,此方法工作正常,但是当我有 100 或 1000 个联系人时,它确实变慢了。我用 100 个联系人对它进行了基准测试,花了 4 秒才完成,这太糟糕了。我想知道如何改进我的代码,以更高效的方式获得 完全相同的 输出。这里的关键是输出需要保持不变。我对修改客户端代码没有兴趣(许多应用程序都依赖于此数据结构),因此所有更改都需要在服务器端进行。
这是我的ContactSerializer
供参考:
class ContactSerializer < ActiveModel::Serializer
attributes :id, :first_name, :last_name, :email, :engagement, :company_id, :created_at, :updated_at, :published_response_count, :groups
has_many :invites
has_many :responses
has_many :promotions
def groups
Hash[object.company.groups.map {|group| [group.name, object.groups.include?(group)] }]
end
def published_response_count
object.responses.where(published: true).count
end
def created_at
object.created_at.in_time_zone("Eastern Time (US & Canada)").strftime("%l:%M%p %b %d, %Y")
end
def updated_at
object.updated_at.in_time_zone("Eastern Time (US & Canada)").strftime("%l:%M%p %b %d, %Y")
end
def engagement
object.engagement
end
end
对于它的价值,我完全意识到 returning JSON 来自 Rails 的数据并不是一个很好的做法,并且已经完全放弃了它。不幸的是,这段代码是很久以前写的,我没有时间完全重写客户端以使用标准输出,例如联系人数组。
我开始研究 ActiveRecord 生成的查询。
一段时间后我意识到查询只占总处理时间的几毫秒。我开始从基本查询 company.contacts
开始对代码进行基准测试,然后逐渐添加我拥有的方法,例如 map
然后将每个联系人传递到序列化程序中,最后调用 as_json[:contact]
ContactSerializer.new(contact)
返回的对象。
我发现在序列化对象上调用 as_json[:contact]
每次联系平均消耗大约 30 毫秒(平均超过 100 次运行)。我这样做的原因是从返回的 JSON 中删除根 contact
节点。
当我用 198 个联系人对我的原始代码进行基准测试时,10 次运行平均花费 10400 毫秒。当我删除 as_json[:contact]
并在 ContactSerializer
上设置 root false
时,如“Abusing ActiveModel::Serializers for HAL”所述,我能够将时间从 10400 毫秒减少到 87 毫秒,同时返回确切的与客户端相同的结构,这令人震惊。
通过一些查询优化可能会缩短几毫秒,但此时其他任何事情都只是锦上添花。