Vous pouvez faire du SQL direct pour avoir une seule requête pour les deux tables. Je vais fournir un exemple de requête aseptisée pour éviter que les gens ne mettent des variables directement dans la chaîne elle-même (danger d'injection SQL), même si cet exemple n'en a pas besoin :
@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
Modifier comme l'a dit Huy, un moyen simple est de ActiveRecord::Base.connection.execute("...")
. Un autre moyen est ActiveRecord::Base.connection.exec_query('...').rows
. Et vous pouvez utiliser des instructions préparées natives, par exemple si vous utilisez postgres, l'instruction préparée peut être faite avec raw_connection, prepare, et exec_prepared comme décrit dans https://stackoverflow.com/a/13806512/178651
Vous pouvez également mettre des fragments SQL bruts dans des requêtes relationnelles ActiveRecord : http://guides.rubyonrails.org/active_record_querying.html et dans les associations, les portées, etc. Vous pourriez probablement construire le même SQL avec les requêtes relationnelles d'ActiveRecord et faire des choses sympas avec ARel comme Ernie le mentionne dans http://erniemiller.org/2010/03/28/advanced-activerecord-3-queries-with-arel/ . Et, bien sûr, il existe d'autres ORM, des gemmes, etc.
Si cette fonction est utilisée fréquemment et que l'ajout d'index ne pose pas de problèmes de performance ou de ressources, envisagez d'ajouter un index dans la base de données pour payment_details.created_at et pour payment_errors.created_at.
Si de nombreux enregistrements ne doivent pas tous s'afficher en même temps, pensez à utiliser la pagination :
Si vous avez besoin de paginer, envisagez de créer d'abord une vue dans la BD appelée payment_records qui combine les tables payment_details et payment_errors, puis créez un modèle pour la vue (qui sera en lecture seule). Certaines bases de données prennent en charge les vues matérialisées, ce qui peut être une bonne idée pour les performances.
Considérez également les spécifications du matériel ou de la VM sur le serveur Rails et le serveur de base de données, la configuration, l'espace disque, la vitesse/latence/etc. du réseau, la proximité, etc. Envisagez également de placer la base de données sur un serveur/VM différent de celui de l'application Rails si vous ne l'avez pas fait, etc.
3 votes
Pourquoi pensez-vous que le SQL brut sera plus rapide ? Comment savez-vous que c'est un problème de SQL ?
0 votes
Sans voir le plan de requête, je suppose que le problème que vous rencontrez est le classement par created_at. Vous êtes probablement en train de faire un seq scan sur l'ensemble de ces tables (en y ajoutant la table des projets). En faisant deux de ces requêtes en une seule fois avec la méthode du contrôleur sur une grande table et une base de données sous-puissante (les bases de données Heroku sont réglées de manière générique et relativement sous-puissantes pour les dollars que vous dépensez), vous risquez d'obtenir des délais d'attente. Si vous ne faites pas beaucoup d'insertions dans ces tables, vous pouvez utiliser un index trié : devcenter.heroku.com/articles/postgresql-index#sorted-index
1 votes
Il serait toujours plus rapide de couper le code SQL à la main (si vous savez ce que vous faites). Rails fait du sql vraiment méchant. Il fonctionne bien mais pour être général, il doit... être général. Ceci dit, Jim a probablement raison... créer une indexation serait mieux. Essayez d'exécuter votre requête dans pgadmin (contre votre base de données).