メインコンテンツへスキップ

VillageSQL is a drop-in replacement for MySQL with extensions.

All examples on this page work on VillageSQL. Install Now →
ほとんどのアプリケーションは実際には ORM を通じて MySQL と通信しており、ORM の問題の大半は、ひと握りの設定行と 1 つのクエリパターンにたどり着きます。このガイドでは、Django、Rails、Prisma の MySQL 側の設定と、ORM が生成する SQL を製品の遅い部分にしないための習慣を扱います。VillageSQL は MySQL のドロップイン代替なので、ここにある設定はすべて変更なしで VillageSQL でも動作します。ORM には違いが分かりません。

どこでも重要な設定

フレームワークが何であれ、3 つのことが成り立っていなければなりません。
  • 接続が utf8mb4 を使っていること。そうでないと絵文字が転送中に壊れます。utf8mb4 と絵文字を参照してください。
  • 厳格 SQL モードがオンであること (MySQL 8.x のデフォルトです)。不正なデータが黙って切り捨てられる代わりにエラーになります。
  • プールサイズが意図的に決められていること。どのフレームワークもプロセスごとにプールを開きます。数値を選ぶ前にプロセス数を掛けてください。コネクションプーリングを参照してください。

Django

Django 固有の注意点:
  • Django のドキュメントが推奨する、保守されている C ドライバーの mysqlclient を使ってください。
  • Django は一部の制約を Python でエミュレートします。実際のデータベース制約も追加してください (unique=True は実際の一意インデックスになりますが、チェック制約には Meta の CheckConstraint が必要です)。
  • select_related() (JOIN) と prefetch_related() (2 番目のクエリ) が N+1 のためのツールです。使うべき場面は後述します。

Rails

Rails 固有の注意点:
  • database.yml の encoding: utf8mb4 は、接続の文字セットと rails db:create のデフォルトの両方を設定します。
  • ActiveRecord のバリデーション (validates_uniqueness_of) は並行実行で競合します。すべての一意性バリデーションを実際の一意インデックスで裏付け、1062 重複キーエラーを最後の防衛線にしてください。
  • includes が N+1 のためのツールです。strict_loading モードは遅延読み込みをエラーに変えるため、N+1 は出荷される代わりに開発中に失敗します。
  • Rails 8.1 は database.yml に、古いバージョンが pool を生成していた場所に max_connections を生成します。pool: キーは max_connections が読むフォールバックとして今も黙って動作します。両方を異なる値に設定すると起動時に例外が発生します。Rails 8 がもはや MySQL をデフォルトにしないために必要な --database=mysql フラグを含む完全なアプリについては、Rails 8 で MySQL を使うを参照してください。

Prisma

Prisma 固有の注意点:
  • Prisma はデフォルトで utf8mb4 を使います。注意すべき設定は URL の connection_limit で、デフォルトは低めです。
  • prisma migrate はスキーマの差分から DDL を生成します。手書きのマイグレーションと同じように、本番環境に適用する前に生成された SQL を読んでください。スキーママイグレーションを参照してください。
  • リレーションのクエリは include を使います。N+1 の形は、結果をループしてリレーションに 1 つずつアクセスするときに現れます。
  • Prisma 7 は、上の接続 URL を schema.prisma から別の設定ファイルへ移し、接続にはドライバーアダプターを必要とします。完全な Prisma 7 アプリについては、Next.js と Prisma で MySQL を使うを参照してください。

N+1 問題をまとめて解説

普遍的な ORM のパフォーマンスバグです。100 件の注文を読み込み、次に各注文の顧客を遅延読み込みすると、ORM は 101 回のクエリを発行します。修正はどのフレームワークでも同じ考え方です。必要なリレーションを前もって宣言し、ORM が 1 回か 2 回のクエリでそれらを取得するようにします (select_related / includes / include)。検出ツールも普遍的です。開発環境でクエリログをオンにして ORM が実際に送っているものを読むか、本番環境でスロークエリログを監視してください。

SQL に切り替えるべきとき

ORM は CRUD で元を取り、分析では元を取れません。ウィンドウ関数、CTE、一括 upsert、複数テーブルのレポートクエリは、それを表現しようとするクエリビルダーのチェーンよりも SQL のほうが明快です。どの ORM にも抜け道があります (Django の raw()、Rails の find_by_sql、Prisma の $queryRaw)。それに値する 5 パーセントのクエリにそれを使うのは、敗北ではなく良いエンジニアリングです。これは VillageSQL の拡張機能の関数が ORM アプリケーションに届く方法でもあります。SELECT UUID_V7() や ai_prompt(...) は、ORM が SQL をそのまま通すだけなので、これらの抜け道のどれを通しても動作します。

関連項目