Memigrasikan aplikasi Django dari database lain ke SQL Server

Artikel ini menyediakan panduan untuk memigrasikan aplikasi Django dari PostgreSQL, MySQL, atau SQLite ke SQL Server menggunakan mssql-django backend.

Overview

ORM Django mengabstraksi sebagian besar perbedaan database, tetapi beberapa perilaku dan dialek SQL bervariasi di antara backend. Panduan ini mencakup perbedaan utama yang Anda temui saat bermigrasi ke SQL Server.

Langkah 1: Instal mssql-django

mssql-django Instal paket dan dependensinya:

pip install mssql-django

Pastikan Driver Microsoft ODBC untuk SQL Server diinstal. Lihat Menginstal mssql-django untuk instruksi khusus platform.

Langkah 2: Memperbarui DATABASE konfigurasi

Ganti konfigurasi database Anda yang sudah ada di 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",
        },
    },
}

Langkah 3: Membuat migrasi baru

Mulailah dengan riwayat migrasi yang bersih untuk SQL Server:

# Remove existing migration files (keep __init__.py)
# Then regenerate
python manage.py makemigrations
python manage.py migrate

Important

Transfer data Anda menggunakan migrasi data atau proses ETL terpisah. Jangan mencoba menjalankan file migrasi PostgreSQL atau MySQL terhadap SQL Server.

Perbedaan utama dari PostgreSQL

Fitur PostgreSQL SQL Server (mssql-django)
Pertambahan otomatis SERIAL / BIGSERIAL IDENTITY(1,1)
Jenis Boolean Bawaan boolean bit (0 atau 1)
Bidang teks text (tidak terbatas) nvarchar(max)
Dukungan JSON Native jsonb nvarchar(max) dengan fungsi JSON (SQL Server 2016+)
Bidang array ArrayField Tidak didukung. Gunakan tabel terkait atau JSON.
Bidang HStore HStoreField Tidak didukung. Gunakan JSONField sebagai gantinya.
Bidang rentang IntegerRangeField,BigIntegerRangeField,DateRangeField,DateTimeRangeField Tidak didukung. Gunakan dua bidang terpisah.
Pencarian teks lengkap SearchVector, SearchRank Gunakan SQL mentah dengan SQL Server pencarian teks lengkap.
DISTINCT ON Didukung Tidak didukung. Gunakan GROUP BY atau subkueri.
DateTimeField dengan zona waktu timestamp with time zone datetimeoffset (ketika USE_TZ=True) atau datetime2

Fitur khusus PostgreSQL yang perlu diganti

Jika kode Anda menggunakan fitur khusus PostgreSQL dari django.contrib.postgres, ganti:

# 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)

Perbedaan utama dari MySQL

Fitur MySQL SQL Server (mssql-django)
Inkrementasi otomatis AUTO_INCREMENT IDENTITY(1,1)
Jenis Boolean tinyint(1) bit
Bidang teks longtext nvarchar(max)
Dukungan JSON JSON Asli (5.7 dan yang lebih baru) nvarchar(max) dengan fungsi JSON
Collation Dapat dikonfigurasi per kolom Tingkat instans atau database (ditimpa dengan opsi COLLATE)
DateTimeField datetime(6) datetimeoffset atau datetime2

Perbedaan utama dari SQLite

Fitur SQLite SQL Server (mssql-django)
Penerapan tipe Pengetikan fleksibel Penegakan jenis yang ketat
Penulisan serentak Limited Dukungan konkurensi penuh
Koneksi maksimum Praktis 1 penulis Pengumpulan koneksi dengan banyak koneksi bersamaan
DateTimeField Disimpan sebagai teks datetimeoffset atau datetime2

Perbedaan kolasi

Kolasi menentukan cara SQL Server membandingkan dan mengurutkan teks. Ini adalah salah satu sumber perilaku tak terduga yang paling umum saat bermigrasi dari PostgreSQL atau MySQL.

Peka huruf besar/kecil

Kolasi bawaan SQL Server (SQL_Latin1_General_CP1_CI_AS) tidak peka terhadap huruf besar/kecil. PostgreSQL peka terhadap huruf besar/kecil secara bawaan.

Perilaku ini berarti bahwa setelah migrasi, kueri yang sebelumnya dibedakan antara "Smith" dan "smith" memperlakukannya sebagai sama:

# On PostgreSQL: returns only exact case matches
# On SQL Server (default collation): returns both "Smith" and "smith"
User.objects.filter(last_name="Smith")

Jika aplikasi Anda bergantung pada perbandingan peka huruf besar/kecil, Anda memiliki dua opsi:

  • Ubah basis data atau kolasi kolom menjadi varian yang peka terhadap huruf besar/kecil:

    -- 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;
    
  • Gunakan lookup Django __exact dengan penggantian kolasi dalam SQL mentah untuk kueri yang ditargetkan secara spesifik.

Sensitivitas aksen

Kolasi bawaan SQL Server peka aksen (AS), yang sesuai dengan perilaku PostgreSQL. Karakter seperti é dan e diperlakukan berbeda. Jika Anda memerlukan perbandingan yang tidak peka terhadap aksen, gunakan kolasi yang berakhiran _AI.

Mengonfigurasi kolase dalam mssql-django

Ubah kolasi bawaan untuk pencarian field teks dalam konfigurasi basis data Anda:

DATABASES = {
    "default": {
        "ENGINE": "mssql",
        "NAME": "<your-database>",
        "OPTIONS": {
            "driver": "ODBC Driver 18 for SQL Server",
            "collation": "Latin1_General_CS_AS",  # Case-sensitive
        },
    },
}

Note

Opsi collation dalam mssql-django mengatur kolasi yang digunakan dalam LIKE dan operasi perbandingan yang dihasilkan oleh lookups ORM Django. Ini tidak mengubah kolatasi kolom yang ada dalam database. Untuk mengubah kolasi kolom tersimpan, gunakan pernyataan ALTER TABLE / ALTER COLUMN. Untuk informasi selengkapnya, lihat dokumentasi kolasi SQL Server.

Langkah 4: Memperbarui SQL kustom

Jika kode Anda berisi SQL mentah, perbarui untuk sintaks 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")

Perbedaan sintaks SQL umum:

Pengoperasian PostgreSQL/MySQL SQL Server
Membatasi hasil LIMIT 10 TOP 10 atau OFFSET ... FETCH NEXT ...
Penggabungan string \|\| (PG) / CONCAT() + atau CONCAT()
Literal Boolean TRUE / FALSE 1 / 0
Tanda waktu saat ini NOW() GETDATE(), SYSDATETIME(), atau SYSDATETIMEOFFSET() untuk nilai sadar zona waktu
JIKA TIDAK ADA CREATE TABLE IF NOT EXISTS Periksa sys.objects atau gunakan IF NOT EXISTS

Perbedaan isolasi transaksi

PostgreSQL menggunakan MVCC (Kontrol Konkurensi Multi-Versi) untuk tingkat isolasinya READ COMMITTED . Pembaca tidak pernah memblokir penulis dan penulis tidak pernah memblokir pembaca.

default SQL Server READ COMMITTED menggunakan penguncian, yang berarti kueri baca dapat terblokir saat menunggu transaksi tulis selesai. Jika aplikasi Anda mengalami peningkatan pemblokiran setelah migrasi, pertimbangkan untuk mengaktifkan READ COMMITTED SNAPSHOT pada basis data:

ALTER DATABASE [<your-database>]
SET READ_COMMITTED_SNAPSHOT ON;

Ini mengubah SQL Server READ COMMITTED agar menggunakan pembuatan versi baris (mirip dengan MVCC PostgreSQL) alih-alih mekanisme penguncian. Pembaca melihat versi terakhir dari sebuah baris yang telah dikomit tanpa menunggu proses tulis yang aktif.

Note

READ COMMITTED SNAPSHOT memerlukan ruang tambahan tempdb untuk versi baris. Uji dengan beban yang realistis sebelum menerapkannya di lingkungan produksi. Untuk informasi selengkapnya, lihat Manajemen transaksi di mssql-django.

Langkah 5: Memigrasikan data

Strategi migrasi data bergantung pada ukuran himpunan data:

Himpunan data kecil (<500 MB)

Gunakan 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

Himpunan data besar (>500 MB)

Untuk migrasi besar, gunakan alat khusus untuk menghindari kehabisan memori dan masalah batas waktu. ORM Django bukanlah alat yang tepat untuk beban massal pada skala ini. Lewati untuk pemindahan data dan biarkan Django mengelola skema dan logika aplikasi setelahnya.

Tool Paling cocok untuk
Wizard Impor dan Ekspor SQL Server Migrasi on-premises ke on-premises dengan GUI
Azure Data Factory Sumber apa pun untuk Azure SQL, termasuk skenario hibrid
Layanan Migrasi Basis Data Azure Migrasi skala besar dengan validasi dan rollback bawaan
mssql-python salinan massal dengan Apache Arrow Alur Python kustom yang membutuhkan throughput maksimum antara database SQL Server, Azure SQL Database, dan SQL di Fabric

Validasi pascamigrasi

Setelah migrasi, validasi konsistensi benih identitas untuk kolom peningkatan otomatis:

-- 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;

Jika CurrentIdentity melebihi IdentitySeed + record_count, lakukan penyemaian ulang:

DBCC CHECKIDENT ('your_table', RESEED, new_seed);