Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В этой статье приведены рекомендации по миграции приложений Django с PostgreSQL, MySQL или SQLite на SQL Server с помощью серверного модуля mssql-django.
Overview
ORM Django абстрагирует большинство различий между СУБД, но некоторые аспекты поведения и диалекты SQL различаются в зависимости от используемой СУБД. В этом руководстве рассматриваются основные различия, которые возникают при миграции на SQL Server.
Шаг 1. Установка mssql-django
Установите пакет mssql-django и его зависимости:
pip install mssql-django
Убедитесь, что установлен драйвер ODBC Microsoft для 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-процесса. Не пытайтесь запускать файлы миграции для PostgreSQL или MySQL на SQL Server.
Основные отличия от PostgreSQL
| Feature | PostgreSQL | SQL Server (mssql-django) |
|---|---|---|
| Автоматическое увеличение | SERIAL / BIGSERIAL |
IDENTITY(1,1) |
| Тип Boolean | Родной boolean |
bit (0 или 1) |
| Текстовые поля |
text (неограниченно) |
nvarchar(max) |
| Поддержка JSON | Нативный jsonb |
nvarchar(max) с функциями JSON (SQL Server 2016+) |
| Поля массива | ArrayField |
Не поддерживается. Используйте связанную таблицу или JSON. |
| Поля HStore | HStoreField |
Не поддерживается. Вместо этого используйте JSONField. |
| Поля диапазона |
IntegerRangeField, BigIntegerRangeField, DateRangeField, DateTimeRangeField |
Не поддерживается. Используйте два отдельных поля. |
| Полнотекстовый поиск |
SearchVector, SearchRank |
Используйте необработанные SQL-запросы для полнотекстового поиска SQL Server. |
DISTINCT ON |
Поддерживается | Не поддерживается. Используйте GROUP BY или подзапросы. |
DateTimeField с часовым поясом |
timestamp with time zone |
datetimeoffset (когда USE_TZ=True) или datetime2 |
Специфичные для PostgreSQL возможности для замены
Если в коде используются специальные функции django.contrib.postgresPostgreSQL, замените их:
# 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
| Feature | MySQL | SQL Server (mssql-django) |
|---|---|---|
| Автоматическое увеличение | AUTO_INCREMENT |
IDENTITY(1,1) |
| Тип Boolean | tinyint(1) |
bit |
| Текстовые поля | longtext |
nvarchar(max) |
| Поддержка JSON | Нативная JSON (5.7 и выше) |
nvarchar(max) с функциями JSON |
| Collation | Настройка для каждого столбца | Уровень экземпляра или базы данных (переопределяется параметром COLLATE) |
DateTimeField |
datetime(6) | datetimeoffset или datetime2 |
Основные отличия от SQLite
| Feature | SQLite | SQL Server (mssql-django) |
|---|---|---|
| Проверка типов | Гибкая типизация | Строгая типизация |
| Одновременные операции записи | Limited | Полная поддержка параллелизма |
| Максимальное количество соединений | Фактически 1 автор | Пул подключений с большим количеством одновременных подключений |
DateTimeField |
Хранящийся в виде текста | datetimeoffset или datetime2 |
Различия в параметрах сортировки
Сортировка определяет, как SQL Server сравнивает и сортирует текст. Это один из наиболее распространенных источников неожиданного поведения при миграции из PostgreSQL или MySQL.
Чувствительность к регистру
Параметры сортировки 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")
Если приложение зависит от сравнения с учетом регистра, у вас есть два варианта:
Измените параметры сортировки базы данных или столбца на вариант с учетом регистра:
-- 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 по умолчанию чувствительны к диакритическим знакам (AS), что соответствует поведению PostgreSQL. Символы, как é и 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 определяет правила сортировки, используемые в LIKE и операциях сравнения, генерируемых lookup-выражениями ORM Django. Он не изменяет параметры сортировки существующих столбцов в базе данных. Чтобы изменить правила сортировки для хранимых столбцов, используйте операторы 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:
| Операция | 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 (многоверсионное управление параллелизмом) для своего уровня изоляции READ COMMITTED. Читатели никогда не блокируют писателей и писателей никогда не блокируют читателей.
по умолчанию READ COMMITTED SQL Server использует блокировку, что означает, что запросы чтения могут блокироваться при ожидании завершения транзакций записи. Если после миграции в приложении наблюдается усиление блокировок, рассмотрите возможность включения READ COMMITTED SNAPSHOT в базе данных:
ALTER DATABASE [<your-database>]
SET READ_COMMITTED_SNAPSHOT ON;
Это приводит к тому, что SQL Server READ COMMITTED использует версионирование строк (аналогично MVCC в PostgreSQL) вместо блокировок. Читатели видят последнюю зафиксированную версию строки, не дожидаясь завершения активных процессов записи.
Note
READ COMMITTED SNAPSHOT требует дополнительного tempdb пространства для версий строк. Проведите тестирование под реалистичной нагрузкой перед включением в производственной среде. Дополнительные сведения см. в разделе "Управление транзакциями" в mssql-django.
Шаг 5. Перенос данных
Стратегия миграции данных зависит от размера набора данных:
Небольшие наборы данных (<500 МБ)
Используйте 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 МБ)
Для больших миграций используйте специализированные средства, чтобы избежать проблем с нехваткой памяти и временем ожидания. ORM в Django — не подходящий инструмент для массовой загрузки данных при таком масштабе. Не используйте его при переносе данных, а затем позвольте Django управлять схемой и логикой приложения.
| Tool | лучше всего подходит для |
|---|---|
| мастер импорта и экспорта SQL Server | Миграции из локальной среды в локальную среду с графическим интерфейсом |
| Фабрика данных Azure | Любой источник Azure SQL, включая гибридные сценарии |
| Azure Database Migration Service | Крупномасштабные миграции со встроенной проверкой и откатом |
| массовая копия mssql-python с помощью Apache Arrow | Пользовательские конвейеры Python, требующие максимальной пропускной способности между SQL Server, База данных SQL Azure и базой данных SQL в Fabric |
Проверка после миграции
После миграции проверьте согласованность начального значения identity для столбцов с автоинкрементом:
-- 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);