この記事では、mssql-django バックエンドを使用して、Django アプリケーションを PostgreSQL、MySQL、または SQLite からSQL Serverに移行するためのガイダンスを提供します。
Overview
Django の ORM はほとんどのデータベースの違いを抽象化しますが、一部の動作と SQL 言語はバックエンドによって異なります。 このガイドでは、SQL Serverに移行するときに発生する主な違いについて説明します。
手順 1: mssql-django をインストールする
mssql-django パッケージとその依存関係をインストールします。
pip install mssql-django
Microsoft ODBC Driver for SQL Serverがインストールされていることを確認します。 プラットフォーム固有の手順については、 mssql-django のインストール を参照してください。
手順 2: DATABASE 構成を更新する
settings.pyで既存のデータベース構成を置き換えます。
# Example: From PostgreSQL
# DATABASES = {
# "default": {
# "ENGINE": "django.db.backends.postgresql",
# "NAME": "mydb",
# },
# }
# To SQL Server
DATABASES = {
"default": {
"ENGINE": "mssql",
"NAME": "<your-database>",
"USER": "<your-username>",
"PASSWORD": "<your-password>",
"HOST": "<your-server>",
"PORT": "1433",
"OPTIONS": {
"driver": "ODBC Driver 18 for SQL Server",
},
},
}
手順 3: 新しい移行を作成する
SQL Serverのクリーンな移行履歴から始めます。
# Remove existing migration files (keep __init__.py)
# Then regenerate
python manage.py makemigrations
python manage.py migrate
Important
データ移行または個別の ETL プロセスを使用してデータを転送します。 SQL Serverに対して PostgreSQL または MySQL 移行ファイルを実行しないでください。
PostgreSQL との主な違い
| 特徴 | PostgreSQL | SQL Server (mssql-django) |
|---|---|---|
| 自動インクリメント | SERIAL / BIGSERIAL |
IDENTITY(1,1) |
| ブール型 | ネイティブ boolean |
bit (0 または 1) |
| テキスト フィールド |
text (無制限) |
nvarchar(max) |
| JSON のサポート | ネイティブ jsonb |
JSON 関数を使用した nvarchar(max) (SQL Server 2016 以降) |
| 配列フィールド | ArrayField |
サポートされていません。 関連するテーブルまたは JSON を使用します。 |
| HStore フィールド | HStoreField |
サポートされていません。
JSONField を代わりに使用します。 |
| 範囲フィールド |
IntegerRangeField、BigIntegerRangeField、DateRangeField、DateTimeRangeField |
サポートされていません。 2 つの異なるフィールドを使用します。 |
| フルテキスト検索 |
SearchVector、SearchRank |
SQL Serverフルテキスト検索で生 SQL を使用します。 |
DISTINCT ON |
サポートされています | サポートされていません。
GROUP BYまたはサブクエリを使用します。 |
DateTimeField タイム ゾーン付き |
timestamp with time zone |
datetimeoffset ( USE_TZ=Trueの場合) または datetime2 |
置き換える PostgreSQL 固有機能
django.contrib.postgresの PostgreSQL 固有の機能をコードで使用する場合は、それらを置き換えます。
# PostgreSQL ArrayField - replace with JSONField or related table
# Before
from django.contrib.postgres.fields import ArrayField
tags = ArrayField(models.CharField(max_length=50))
# After (using JSONField)
tags = models.JSONField(default=list)
# PostgreSQL HStoreField - replace with JSONField
# Before
from django.contrib.postgres.fields import HStoreField
metadata = HStoreField()
# After
metadata = models.JSONField(default=dict)
MySQL との主な違い
| 特徴 | MySQL | SQL Server (mssql-django) |
|---|---|---|
| 自動インクリメント | AUTO_INCREMENT |
IDENTITY(1,1) |
| ブール型 | tinyint(1) |
bit |
| テキスト フィールド | longtext |
nvarchar(max) |
| JSON のサポート | ネイティブ JSON (5.7 以降) |
JSON 関数を含む nvarchar(max) |
| Collation | 列単位で構成可能 | インスタンスまたはデータベース レベル ( COLLATE オプションでオーバーライド) |
DateTimeField |
datetime(6) | datetimeoffset または datetime2 |
SQLite との主な違い
| 特徴 | SQLite | SQL Server (mssql-django) |
|---|---|---|
| 型の強制 | 柔軟な入力 | 厳密な型チェックの強制 |
| 同時書き込み | 制限付き | 並行処理の完全対応 |
| 最大接続数 | 実質的に 1 つのライター | 多数の同時接続に対応する接続プーリング |
DateTimeField |
テキストとして保存 | datetimeoffset または datetime2 |
照合順序の違い
照合順序は、SQL Server でテキストを比較および並べ替えする方法を制御します。 これは、PostgreSQL または MySQL から移行するときの予期しない動作の最も一般的な原因の 1 つです。
大文字小文字の区別
SQL Serverの既定の照合順序 (SQL_Latin1_General_CP1_CI_AS) では大文字と小文字が区別されません。 PostgreSQL では、既定では大文字と小文字が区別されます。
この動作は、移行後、以前に "Smith" と "smith" を区別したクエリが、それらを等しいものとして扱うことを意味します。
# On PostgreSQL: returns only exact case matches
# On SQL Server (default collation): returns both "Smith" and "smith"
User.objects.filter(last_name="Smith")
アプリケーションが大文字と小文字を区別する比較に依存している場合、次の 2 つのオプションがあります。
データベースまたは列の照合順序を大文字と 小文字を区別するバリアントに変更します。
-- Database-level (affects all new columns) ALTER DATABASE [<your-database>] COLLATE Latin1_General_CS_AS; -- Column-level (for specific columns) ALTER TABLE [<your-table>] ALTER COLUMN [<column-name>] NVARCHAR (150) COLLATE Latin1_General_CS_AS;対象を絞ったクエリのために、生の SQL で照合順序のオーバーライドを使用して Django の
__exactルックアップを使用します
アクセント感度
既定のSQL Server照合順序は、PostgreSQL の動作と一致するアクセントセンシティブ (AS) です。
éやeなどの文字は、異なるものとして扱われます。 アクセントを区別しない比較が必要な場合は、 _AIで終わる照合順序を使用します。
mssql-django で照合順序を構成する
データベース構成のテキスト フィールド参照の既定の照合順序をオーバーライドします。
DATABASES = {
"default": {
"ENGINE": "mssql",
"NAME": "<your-database>",
"OPTIONS": {
"driver": "ODBC Driver 18 for SQL Server",
"collation": "Latin1_General_CS_AS", # Case-sensitive
},
},
}
Note
collationのmssql-django オプションは、Django の ORM 参照によって生成されるLIKEおよび比較操作で使用される照合順序を制御します。 データベース内の既存の列の照合順序は変更されません。 格納されている列の照合順序を変更するには、 ALTER TABLE / ALTER COLUMN ステートメントを使用します。 詳細については、SQL Server の照合順序に関するドキュメントを参照してください。
手順 4: カスタム SQL を更新する
コードに生の SQL が含まれている場合は、SQL Server構文用に更新します。
# PostgreSQL syntax
# cursor.execute("SELECT * FROM products LIMIT 10 OFFSET 20")
# SQL Server syntax
cursor.execute("SELECT * FROM products ORDER BY id OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY")
SQL 構文の一般的な違い:
| Operation | PostgreSQL/MySQL | SQL Server |
|---|---|---|
| 結果を制限する | LIMIT 10 |
TOP 10 または OFFSET ... FETCH NEXT ... |
| 文字列連結 |
\|\| (PG) / CONCAT() |
+ または CONCAT() |
| ブール型リテラル | TRUE / FALSE |
1 / 0 |
| 現在のタイムスタンプ | NOW() |
タイムゾーン対応の値には、GETDATE()、SYSDATETIME()、または SYSDATETIMEOFFSET() |
| 存在しない場合 | CREATE TABLE IF NOT EXISTS |
sys.objects確認または使用IF NOT EXISTS |
トランザクション分離の違い
PostgreSQL では、分離レベルに MVCC (複数バージョンのコンカレンシー制御) が使用されます。 リーダーがライターをブロックしたり、ライターがリーダーをブロックしたりすることはありません。
SQL Serverの既定のREAD COMMITTEDではロックが使用されます。つまり、書き込みトランザクションの完了を待機している間に読み取りクエリがブロックされる可能性があります。 移行後にアプリケーションのブロックが増加する場合は、データベースで READ COMMITTED SNAPSHOT を有効にすることを検討してください。
ALTER DATABASE [<your-database>]
SET READ_COMMITTED_SNAPSHOT ON;
これによりSQL ServerのREAD COMMITTEDが、ロックの代わりに行のバージョン管理 (PostgreSQL の MVCC と同様) を使用するように変更されます。 閲覧者は、アクティブなライターを待たずに、行の最後にコミットされたバージョンを表示します。
Note
READ COMMITTED SNAPSHOT には、行バージョン用の追加の tempdb 領域が必要です。 運用環境で有効にする前に、現実的な負荷でテストします。 詳細については、「 mssql-django でのトランザクション管理」を参照してください。
手順 5: データを移行する
データ移行戦略は、データセットのサイズによって異なります。
小さなデータセット (<500 MB)
Django の dumpdata/loaddataを使用します。
# On the source database
python manage.py dumpdata --natural-foreign --natural-primary -o data.json
# Switch settings.py to SQL Server, then:
python manage.py migrate
python manage.py loaddata data.json
大規模なデータセット (>500 MB)
大規模な移行の場合は、特殊なツールを使用して、メモリの枯渇とタイムアウトの問題を回避します。 Django の ORM は、この規模での一括読み込みの適切なツールではありません。 データ移動のためにそれをバイパスし、後で Django がスキーマとアプリケーション ロジックを管理できるようにします。
| ツール | 最適な用途 |
|---|---|
| SQL Server インポートおよびエクスポート ウィザード | GUI を使用したオンプレミスからオンプレミスへの移行 |
| Azureデータファクトリー | ハイブリッド シナリオを含め、任意のソースから Azure SQL へ |
| Azure Database Migration Service | 検証とロールバックが組み込まれた大規模な移行 |
| Apache Arrow を使用した mssql-python の一括コピー | FabricのSQL Server、Azure SQL Database、SQL データベース間の最大スループットを必要とするカスタム Python パイプライン |
移行後の検証
移行後、自動インクリメント列の ID シード整合性を検証します。
-- Check identity seed and current value for all tables
SELECT
TABLE_NAME,
IDENT_SEED(TABLE_SCHEMA + '.' + TABLE_NAME) AS IdentitySeed,
IDENT_INCR(TABLE_SCHEMA + '.' + TABLE_NAME) AS IdentityIncrement,
IDENT_CURRENT(TABLE_SCHEMA + '.' + TABLE_NAME) AS CurrentIdentity
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
AND OBJECTPROPERTY(OBJECT_ID(TABLE_SCHEMA + '.' + TABLE_NAME), 'TableHasIdentity') = 1
ORDER BY TABLE_NAME;
CurrentIdentity が IdentitySeed + record_count を超えた場合: 再シードしてください。
DBCC CHECKIDENT ('your_table', RESEED, new_seed);