🧚 お知らせ!Beekeeper Studio は高速でモダンなオープンソースのデータベース GUI です ダウンロード
2025年4月25日 著者:Matthew Rathbone

ActiveRecord だけでは物足りないこともあります。複数の JOIN を含む複雑なクエリが必要な場合や、データベースのパフォーマンスを限界まで引き出したい場合です。そんなときに役立つのが生の SQL です。

ここでは、Rails で生の SQL を実行するために知っておくべきことを、基本からよくある落とし穴の回避まで、すべて解説します。

生の SQL が本当に必要になるとき

ほとんどの場合、ActiveRecord で十分です。しかし、実際の現場で生の SQL が適しているのは次のようなケースです。

  • 複雑な集計 - ウィンドウ関数、CTE、複雑な GROUP BY 操作が必要な場合
  • パフォーマンスが重要なクエリ - ActiveRecord が生成する SQL が非効率な場合
  • データベース固有の機能 - PostgreSQL の JSONB 演算子や MySQL の FULLTEXT 検索などを使う場合
  • 一括操作 - ActiveRecord を個別に呼び出すと遅くなる大量更新

では、実践的な内容に入りましょう。

実例:ユーザー分析

ユーザー分析機能を作っていて、過去7日間に登録したユーザーとその投稿数を取得する必要があるとします。その場合は次のようになります。

生の SQL を実行する3つの方法

Rails には生の SQL を実行する方法がいくつかあります。主なものは次のとおりです。

1. connection.execute - 生の結果を取得する

データベースの結果をそのまま取得したい場合に使います。

sql = <<~SQL
  SELECT 
    u.id, u.name, u.email,
    COUNT(p.id) as post_count
  FROM users u
  LEFT JOIN posts p ON p.user_id = u.id
  WHERE u.created_at >= NOW() - INTERVAL '7 days'
  GROUP BY u.id, u.name, u.email
  ORDER BY post_count DESC
SQL

result = ActiveRecord::Base.connection.execute(sql)
result.each do |row|
  puts "#{row['name']}: #{row['post_count']} posts"
end

2. find_by_sql - モデルオブジェクトを取得する

実際の ActiveRecord オブジェクトを返してほしい場合に使います。

users = User.find_by_sql([
  "SELECT * FROM users WHERE created_at >= ? AND status = ?",
  7.days.ago, 'active'
])

users.each { |user| puts user.email }

3. Arel と pluck - ハイブリッドなアプローチ

シンプルなケースでは、ActiveRecord と組み合わせて生の SQL を部分的に使うこともできます。

User.where("created_at >= ?", 7.days.ago)
    .pluck("name, email, DATE(created_at) as signup_date")

ハッキングを防ぐ:SQL インジェクション対策

これは非常に重要です。ユーザー入力を SQL 文字列に直接埋め込むことは絶対にしないでください。間違った例はこちらです。

# DON'T DO THIS - vulnerable to SQL injection
email = params[:email]
User.find_by_sql("SELECT * FROM users WHERE email = '#{email}'")

代わりに、パラメータ化クエリを使いましょう。

# Safe approach with parameters
email = params[:email]
User.find_by_sql(["SELECT * FROM users WHERE email = ?", email])

# Or use connection.quote for raw execute
email = params[:email]
sanitized_email = ActiveRecord::Base.connection.quote(email)
result = ActiveRecord::Base.connection.execute("SELECT * FROM users WHERE email = #{sanitized_email}")

パラメータは自動的にエスケープされるため安全です。必ず使うようにしましょう。

パフォーマンスのヒント

生の SQL を使う目的はパフォーマンスであることが多いので、プロのヒントをいくつか紹介します。

Beekeeper Studio でクエリを分析する - Rails アプリに組み込む前に SQL をテスト・最適化するのに最適です。

フィルタや JOIN に使うカラムにはインデックスを追加しましょう。

# In a migration
add_index :users, :created_at
add_index :posts, [:user_id, :status]

EXPLAIN を使ってクエリのパフォーマンスを把握しましょう。

ActiveRecord::Base.connection.execute("EXPLAIN ANALYZE #{your_sql}")

複雑で再利用するクエリは、生の SQL をあちこちで繰り返す代わりにデータベースビューの利用を検討しましょう。

まとめ

Rails における生の SQL は、鋭いナイフのようなものです。必要なときには強力ですが、取り扱いには注意が必要です。ActiveRecord では対応できない複雑なクエリ、パフォーマンス最適化、データベース固有の機能に使いましょう。

覚えておきたいポイント:

  • SQL インジェクションを防ぐため、必ずパラメータ化クエリを使う
  • まずは Beekeeper Studio などのツールでクエリをテストする
  • ActiveRecord を完全に捨てず、生の SQL は戦略的に使う

関連資料

データベース管理や SQL の最適化について疑問がありますか?Beekeeper Studio なら、デプロイ前にデータを簡単に探索し、クエリを磨き上げることができます。

Beekeeper Studioは無料のオープンソースのデータベースGUIです

これまで使った中で最高のSQLクエリ&エディタツールです。データベースの管理に必要なものがすべて揃っています。 - ⭐⭐⭐⭐⭐ Mit

Beekeeper Studioは高速で直感的、そして使いやすいツールです。多数のデータベースに対応し、Windows、Mac、Linuxで快適に動作します。

BeekeeperのLinux版は100%フル機能。手抜きも機能の妥協も一切ありません。

Beekeeper Studio 利用者の声

★★★★★
「Beekeeper Studio で以前の SQL ワークフローが完全に置き換わりました。高速で直感的で、データベース作業がまた楽しくなりました。」
— Alex K.、データベース開発者
★★★★★
「多くのデータベース GUI を試してきましたが、Beekeeper は機能とシンプルさのバランスが完璧です。とにかくちゃんと動きます。」
— Sarah M.、フルスタックエンジニア