如何加快简单rails数据库查询的速度



我在ruby 2.6.3 上使用轨道4.2.11.1

我使用rails的请求非常慢,所以我对代码进行了基准测试,找到了罪魁祸首。大部分减速发生在数据库调用中,我从数据库中的表中选择一行。我已经尝试了几个不同版本的相同想法

使用此版本

Rails.logger.info Benchmark.measure{
result = Record.find_by_sql(['SELECT column FROM table WHERE condition']).first.column
}

rails的输出显示sql需要54.5ms,但基准测试输出0.043427 0.006294 0.049721(1.795859(,总请求需要1.81秒。当我直接在postgres终端中运行上面的sql时,它需要42ms。

显然问题不在于我的sql速度慢。42毫秒并不明显。但是1.79秒的速度太慢了,造成了糟糕的用户体验。

我读了一些书,得出的结论是,速度减慢是由rails的对象创建引起的(这看起来很奇怪,但显然可能非常慢(,所以我尝试使用pull来最大限度地减少创建的对象数量:

Rails.logger.info Benchmark.measure{
result = Record.where(condition).pluck(column).first
}

现在rails说sql耗时29.3ms,基准测试给出0.017989 0.006119 0.024108(0.713973(整个请求耗时0.731秒。这是一个巨大的改进,但0.7秒的速度仍然很慢,仍然会破坏我的应用程序的可用性。

我做错了什么?如此简单的事情竟然会出现如此巨大的放缓,这在我看来简直是疯了。如果rails就是这样工作的,我无法想象有人会把它用于严肃的应用程序!

find_by_sql对数据库执行自定义SQL查询并返回所有结果。

这意味着数据库中的所有记录都将被返回并实例化。只有这样,您才能通过对结果调用first来从该数组中选择第一个。

当您在ActiveRecord::Relation上调用first时,它将为您的查询添加一个限制,并只选择该限制,这就是您想要的行为。

这意味着你应该自己限制查询:

result = Record.find_by_sql(['SELECT column FROM table WHERE condition LIMIT 1']).first.column

我确信你的请求会很快,因为ruby不需要实例化所有的结果行。

正如我上面提到的,如果你只想要第一个,不确定为什么要要求所有匹配。

如果我这样做:

Rails.logger.info Benchmark.measure{
result = User.where(email: 'foo@bar.com').pluck(:email).first 
}
(9.6ms)  SELECT "users"."email" FROM "users" WHERE "users"."email" = $1  [["email", "foo@bar.com"]]
#<Benchmark::Tms:0x00007fc2ce4b7998 @label="", @real=0.6364280000561848,     @cstime=0.00364, @cutime=0.000661, @stime=0.1469640000000001, @utime=0.1646029999999996, @total=0.3158679999999997>
Rails.logger.info Benchmark.measure{
result = User.where(email: 'foo@bar.com').limit(1).pluck(:email) 
}
(1.8ms)  SELECT  "users"."email" FROM "users" WHERE "users"."email" = $1 LIMIT $2  [["email", "foo@bar.com.com"], ["LIMIT", 1]]
#<Benchmark::Tms:0x00007fc2ce4cd838 @label="", @real=0.004004000045824796, @cstime=0.0, @cutime=0.0, @stime=0.0005539999999997214, @utime=0.0013550000000002171, @total=0.0019089999999999385>

Rails也提供现金服务。如果再次运行查询,第二次应该会更快。你的where状况有多复杂?这可能是其中的一部分。

最新更新