如何加快简单的Rails数据库查询?

问题描述

我在ruby 2.6.3上使用rails 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时,需要42毫秒。

显然,问题不是我的sql很慢。 42毫秒并不明显。但是1.79秒太慢了,并且创造了可怕的用户体验。

我做了一些阅读,得出的结论是,速度下降是由Rails的对象创建引起的(这看起来很奇怪,但显然可能非常慢),所以我尝试使用pluck来最大程度地减少创建的对象数量:>

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条件有多复杂?那可能是其中的一部分。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...