VillageSQL is a drop-in replacement for MySQL with extensions.
All examples on this page work on VillageSQL. Install Now →
どこでも重要な設定
フレームワークが何であれ、3 つのことが成り立っていなければなりません。- 接続が
utf8mb4を使っていること。そうでないと絵文字が転送中に壊れます。utf8mb4 と絵文字を参照してください。 - 厳格 SQL モードがオンであること (MySQL 8.x のデフォルトです)。不正なデータが黙って切り捨てられる代わりにエラーになります。
- プールサイズが意図的に決められていること。どのフレームワークもプロセスごとにプールを開きます。数値を選ぶ前にプロセス数を掛けてください。コネクションプーリングを参照してください。
Django
- Django のドキュメントが推奨する、保守されている C ドライバーの
mysqlclientを使ってください。 - Django は一部の制約を Python でエミュレートします。実際のデータベース制約も追加してください (
unique=Trueは実際の一意インデックスになりますが、チェック制約にはMetaのCheckConstraintが必要です)。 select_related()(JOIN) とprefetch_related()(2 番目のクエリ) が N+1 のためのツールです。使うべき場面は後述します。
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 はデフォルトで 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 をそのまま通すだけなので、これらの抜け道のどれを通しても動作します。
関連項目
- Next.js と Prisma で MySQL を使う — 設定だけでなく、Prisma 7 上の完全なアプリ
- Next.js と Drizzle で MySQL を使う — 上では扱わない、より軽量で SQL ファーストの代替である Drizzle 上の完全なアプリ
- Next.js で MySQL を使う — ORM を一切使わない接続設定とクエリパターン
- Rails 8 で MySQL を使う — Rails 8 が MySQL を選ぶために必要なスキャフォールドのフラグを含む完全なアプリ
- Laravel 12 で MySQL を使う — 上では扱わない、Laravel の Eloquent ORM 上の完全なアプリ
- Go と sqlc で MySQL を使う — ランタイム ORM の代わりに生成された型安全なクエリ
- コネクションプーリング — プロセスをまたいだプールのサイズ決定
- utf8mb4 と絵文字 — 上のすべての設定が設定している文字セット
- スロークエリログ — ORM が生成するものを捕まえる
- スキーママイグレーション — ORM が生成した DDL を安全に適用する