Пример Rails raw SQL

Как я могу преобразовать этот код в raw sql и использовать в rails? Потому что, когда я развертываю этот код в heroku, возникает ошибка тайм-аута запроса.Я думаю, что это будет быстрее, если я использую raw 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)

5 ответов


вы можете сделать это:

sql = "Select * from ... your sql query here"
records_array = ActiveRecord::Base.connection.execute(sql)

records_array тогда будет результатом вашего 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">...]

Model.connection.select_all('sql').to_hash

если вы хотите просто хэш-значений:

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"}
]

результат объекта:

select_all возвращает


вы можете сделать direct SQL, чтобы иметь один запрос для обеих таблиц. Я приведу пример санированного запроса, чтобы, Надеюсь, люди не помещали переменные непосредственно в саму строку( опасность 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

редактировать: как сказал Хью, простой способ -ActiveRecord::Base.connection.execute("..."). Другой способ -ActiveRecord::Base.connection.exec_query('...').rows. И вы можете использовать собственные подготовленные операторы, например, если вы используете postgres, подготовленный оператор можно сделать с raw_connection, подготовка и exec_prepared как описано вhttps://stackoverflow.com/a/13806512/178651

вы также можете поместить необработанные фрагменты SQL в реляционные запросы ActiveRecord:http://guides.rubyonrails.org/active_record_querying.html и в ассоциациях, областях и т. д. Вероятно, вы могли бы построить тот же SQL с реляционными запросами ActiveRecord и можете делать классные вещи с ARel, как упоминает Эрни в http://erniemiller.org/2010/03/28/advanced-activerecord-3-queries-with-arel/. И, конечно, есть другие Ормы, драгоценные камни и т. д.

Если это будет использоваться много, и добавление индексов не вызовет других проблем с производительностью/ресурсами, рассмотрите возможность добавления индекса в БД для payment_details.created_at и payment_errors.created_at.

Если много записей и не все записи должны отображаться сразу, рассмотрите возможность использования разбиение на страницы:

Если вам нужно разбить на страницы, подумайте о создании представления в БД, которое сначала называется payment_records, которое объединяет таблицы payment_details и payment_errors, а затем имеет модель для представления (которая будет доступна только для чтения). Некоторые DBs поддерживают материализованные представления, что может быть хорошей идеей для спектакль.

также рассмотрите спецификации оборудования или VM на Rails server и DB server, config, дисковое пространство, скорость сети/задержка/и т. д. близость и т. д. И рассмотрите возможность размещения БД на другом сервере / виртуальной машине, чем приложение Rails, если у вас нет и т. д.


вы можете выполнить необработанный запрос, используя ActiveRecord. И я предложу пойти с SQL block

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)