Rails原始SQL示例

Rails原始SQL示例,sql,ruby-on-rails,Sql,Ruby On Rails,如何将此代码转换为原始sql并在rails中使用?因为当我在heroku中部署这段代码时,有一个请求超时错误。我认为如果我使用原始sql,这会更快 @payments = PaymentDetail.joins(:project).order('payment_details.created_at desc') @payment_errors = PaymentError.joins(:project).order('payment_errors.created_at desc') @all_

如何将此代码转换为原始sql并在rails中使用?因为当我在heroku中部署这段代码时,有一个请求超时错误。我认为如果我使用原始sql,这会更快

@payments = PaymentDetail.joins(:project).order('payment_details.created_at desc')
@payment_errors = PaymentError.joins(:project).order('payment_errors.created_at desc')

@all_payments = (@payments + @payment_errors)

可以使用直接SQL对两个表进行一次查询。我将提供一个经过清理的查询示例,希望能够防止人们将变量直接放入字符串本身,即使此示例没有指定需要它:

@results = []
ActiveRecord::Base.connection.select_all(
  ActiveRecord::Base.send(:sanitize_sql_array, 
   ["... your SQL query goes here and ?, ?, ? are replaced...;", a, b, c])
).each do |record|
  # instead of an array of hashes, you could put in a custom object with attributes
  @results << {col_a_name: record["col_a_name"], col_b_name: record["col_b_name"], ...}
end
编辑:正如Huy所说,一种简单的方法是ActiveRecord::Base.connection.execute。。。。另一种方法是ActiveRecord::Base.connection.exec_查询“…”行。您可以使用本机准备的语句,例如,如果使用postgres,准备的语句可以按照中所述使用原始连接、准备和执行准备来完成

您还可以将原始SQL片段放入ActiveRecord关系查询中: 在关联、作用域等方面,您可能可以使用ActiveRecord关系查询构造相同的SQL,并且可以使用ARel做一些很酷的事情,就像Ernie在中提到的那样。当然,还有其他的orm、gems等等

如果这将被大量使用,并且添加索引不会引起其他性能/资源问题,请考虑在DayPayStigelIs.CREDATION AT和PayTunsError中创建一个索引。

如果有大量的记录而不是所有的记录需要立即显示,请考虑使用分页:

如果需要进行分页,请考虑在DB中创建一个视图,首先称为PayMunsRead,它结合PayMeNeDebug细节和PayMunsError表,然后有一个只读视图的模型。有些数据库支持物化视图,这可能是一个提高性能的好主意

还考虑Rails服务器和DB服务器上的硬件或VM规范、配置、磁盘空间、网络速度/延迟等,以及邻近性等,并且考虑如果没有,则将DB放在不同的服务器/VM上,而不是Rails应用程序。 sql=从…中选择*。。。这里是您的sql查询 records\u array=ActiveRecord::Base.connection.executesql


记录数组将是sql查询在一个数组中的结果,您可以对该数组进行迭代。

我知道这是一个古老的数组。。。但我今天遇到了同样的问题,并找到了解决办法:

Model.find_by_sql
如果要实例化结果,请执行以下操作:

Client.find_by_sql("
  SELECT * FROM clients
  INNER JOIN orders ON clients.id = orders.client_id
  ORDER BY clients.created_at desc
")
# => [<Client id: 1, first_name: "Lucas" >, <Client id: 2, first_name: "Jan">...]
如果您只需要值的散列:

Client.connection.select_all("SELECT first_name, created_at FROM clients
   WHERE id = '1'").to_hash
# => [
  {"first_name"=>"Rafael", "created_at"=>"2012-11-10 23:23:45.281189"},
  {"first_name"=>"Eileen", "created_at"=>"2013-12-09 11:22:35.221282"}
]
结果对象:

全选返回一个结果对象。你可以用它做神奇的事情

result = Post.connection.select_all('SELECT id, title, body FROM posts')
# Get the column names of the result:
result.columns
# => ["id", "title", "body"]

# Get the record values of the result:
result.rows
# => [[1, "title_1", "body_1"],
      [2, "title_2", "body_2"],
      ...
     ]

# Get an array of hashes representing the result (column => value):
result.to_hash
# => [{"id" => 1, "title" => "title_1", "body" => "body_1"},
      {"id" => 2, "title" => "title_2", "body" => "body_2"},
      ...
     ]

# ActiveRecord::Result also includes Enumerable.
result.each do |row|
  puts row['title'] + " " + row['body']
end
资料来源:

. .
您可以使用ActiveRecord执行原始查询。我建议使用SQL块

query = <<-SQL 
  SELECT * 
  FROM payment_details
  INNER JOIN projects 
          ON projects.id = payment_details.project_id
  ORDER BY payment_details.created_at DESC
SQL

result = ActiveRecord::Base.connection.execute(query)

您还可以将原始SQL与ActiveRecord条件混合使用,例如,如果要在以下条件中调用函数:

my_instances = MyModel.where.not(attribute_a: nil) \
  .where('crc32(attribute_b) = ?', slot) \
  .select(:id)
我想使用ActiveRecord类的exec_查询,因为它返回查询转换为对象的映射,所以当主题是原始SQL时,使用对象进行迭代是非常实用和高效的

例如:

values = ActiveRecord::Base.connection.exec_query("select * from clients")
p values
并返回此完整查询:

[{"id": 1, "name": "user 1"}, {"id": 2, "name": "user 2"}, {"id": 3, "name": "user 3"}]
仅获取值列表的步骤

p values.rows

[[1, "user 1"], [2, "user 2"], [3, "user 3"]]
仅获取字段和列的步骤

p values.columns

["id", "name"]

为什么您认为原始SQL会更快?你怎么知道这是一个SQL问题呢?如果没有看到查询计划,我猜你现在遇到的问题是由。您可能正在对整个表进行seq扫描,并将项目表也带进来。在一个大表和动力不足的DB heroku数据库上执行其中两种一次性控制器方法,通常会对数据库进行调优,并且由于花费的$$而动力不足,很可能会导致超时。如果不在这些表中进行大量插入,可以进行排序索引:如果您知道自己在做什么,手动剪切sql总是会更快。Rails生成了一些非常糟糕的sql。它工作得很好,但一般来说,它必须。。。要笼统。那就是说吉姆可能是对的。。创建索引会更好。试着在pgadmin中对你的数据库运行你的查询,因为询问者是按日期排序的,我认为分页没有帮助?我对SQL不是最深入的,但我的理解是,原始帖子中的查询需要获取整个表才能对其进行排序,只有这样才能限制结果。我怀疑大部分查询计划都在order子句中。@JimWrubel澄清了关于分页的段落-措辞有点不合适。旁注:对于不同的数据库适配器,记录数组将具有不同的类型。如果您使用的是PG,它将是PG::Result的一个实例,而不是Array。然后您需要调用这个PG::Result对象上的值来获得结果array@baash05你赞成通过类访问它是什么意思这篇文章讨论了如何在没有模型的情况下访问表,实际上在OP中没有提到不使用模型,只是讨论了如何执行原始sql。PaymentDetail.executesql工作正常。我更喜欢ActiveRecord::Base.connection.exec_查询,因为它返回一个ActiveRecords::Result对象,该对象具有方便的方法,如.columns和.rows来访问标题和值。来自.execute的哈希数组可能很麻烦
当我使用SUM GROUP BY子句运行时,处理并给了我多余的结果。find_BY_sql正是我想要的,非常感谢。find_BY_sql就是它!!你好有没有办法将参数传递给此查询?@AkshayGoyal您可以在块内使用普通的ruby字符串插值。选择*FROM users WHERE users.id={user.id},这样做可能会使您暴露于SQL注入的可能性
p values.columns

["id", "name"]