mssql-django 故障排查

诊断并解决Microsoft Fabric中SQL Server、Azure SQL 数据库、Azure SQL 托管实例和 SQL 数据库的后端常见问题mssql-django

连接问题

本部分介绍最常见的连接错误以及如何解决这些问题。

找不到 ODBC 驱动程序

症状

django.core.exceptions.ImproperlyConfigured: 'ODBC Driver 18 for SQL Server' is not a recognized ODBC driver

或者:

Error: ('01000', "[01000] [unixODBC][Driver Manager]Can't open lib 'ODBC Driver 18 for SQL Server'")

可能的原因和解决方案

  • 未安装 ODBC 驱动程序

    安装 Microsoft ODBC Driver for SQL Server。 有关下载链接,请参阅下载 ODBC Driver for SQL Server

  • 已安装多个驱动程序版本

    在 : 中 settings.py指定确切的驱动程序名称或路径:

    DATABASES = {
        "default": {
            "ENGINE": "mssql",
            "NAME": "<your-database>",
            "USER": "<your-username>",
            "PASSWORD": "<your-password>",
            "HOST": "<your-server>",
            "PORT": "1433",
            "OPTIONS": {
                "driver": "ODBC Driver 17 for SQL Server",
            },
        },
    }
    

    在 Linux 上,指定完整路径:

    "OPTIONS": {
        "driver": "/opt/microsoft/msodbcsql17/lib64/libmsodbcsql-17.10.so.6.1",
    },
    
  • 检查已安装的驱动程序

    • 在 Linux/macOS 上,运行 odbcinst -q -d
    • 在Windows,在管理工具中检查 ODBC 数据源

连接被拒绝

症状

django.db.utils.OperationalError: ('08001', '[08001] ... TCP Provider: Error code 0x2749 ...')

可能的原因和解决方案

  • SQL Server上未启用 TCP/IP

    • 打开 SQL Server 配置管理器
    • “SQL Server网络配置”下,启用 TCP/IP
    • TCP/IP 属性中,激活用于连接的 IP 地址。
    • 重启 SQL Server 服务。
  • 防火墙阻止端口 1433

    • 验证防火墙规则是否允许端口 1433 上的入站连接。
    • 对于Azure SQL,请在Azure门户防火墙设置中添加客户端 IP。
  • 服务器名称或端口错误

    验证配置中的 HOSTPORT 值。

登录失败

症状

django.db.utils.OperationalError: ('28000', "[28000] [Microsoft][ODBC Driver 18 for SQL Server][SQL Server]Login failed for user '<username>'.")

可能的原因和解决方案

  • 凭据不正确

    验证用户名和密码。

  • 用户不存在

    确认登录名已映射到目标数据库中的用户。

  • 已禁用SQL Server身份验证

    启用混合模式身份验证,或使用Windows或Microsoft Entra身份验证。

连接超时

症状

django.db.utils.OperationalError: ('HYT00', '[HYT00] [Microsoft][ODBC Driver 18 for SQL Server]Login timeout expired')

可能的原因和解决方案

  • 网络延迟

    在 OPTIONS 中增大 connection_timeout

  • 服务器重载

    增加 connection_retriesconnection_retry_backoff_time

    "OPTIONS": {
        "driver": "ODBC Driver 18 for SQL Server",
        "connection_timeout": 30,
        "connection_retries": 5,
        "connection_retry_backoff_time": 10,
    },
    

迁移问题

在针对 SQL Server 的 Django 迁移操作期间发生这些错误。

日期和时间问题

Now() 值在 USE_TZ=True 时会发生偏移

症状

当 SQL Server 主机时区不是 UTC 时,使用 Django Now()auto_nowauto_now_add 写入的时间戳会发生偏移。

解决方案:升级到 mssql-django 1.7.2 或更高版本。 版本 1.7.2 修复了支持时区的 Now() SQL 生成和 datetimeoffset 偏移量处理的问题。

AttributeError 调用 .explain()

症状

AttributeError: ... explain_format ...

解决方案:升级到 mssql-django 1.7.2 或更高版本。 版本 1.7.2 修复了 Django 4.0 及更高版本中 explain 元数据的编译器兼容性问题。

无法修改 AutoField

症状

django.db.utils.ProgrammingError: Cannot alter column to or from an IDENTITY column

解决方案:SQL Server 不支持将字段类型更改为 AutoField 或从 AutoField 更改。 使用所需的字段类型创建新模型,手动迁移数据,然后删除旧表。 有关解决方法,请参阅 使用 mssql-django 进行数据库迁移

重命名因外键约束而失败

症状

django.db.utils.ProgrammingError: ... could not drop constraint ...

解决方案:SQL Server在重命名列之前需要删除外键约束。 在迁移过程中使用 SeparateDatabaseAndState。 有关示例,请参阅 使用 mssql-django 进行数据库迁移

编码问题

在错误解释来自SQL Server的字符数据时pyodbc,通常会发生编码错误。

Unicode 编码错误

症状

UnicodeDecodeError: 'utf-8' codec can't decode byte ...

解决方案:在pyodbc字典中配置OPTIONS编码:

"OPTIONS": {
    "driver": "ODBC Driver 18 for SQL Server",
    "unicode_results": True,
},

FreeTDS 问题

FreeTDS 需要与 Microsoft ODBC 驱动程序不同的特定配置。

host_is_server错误

症状

使用 FreeTDS 而不指定 host_is_server时连接失败。

解决方案:使用 FreeTDS 时,将 host_is_server 设置为 True

"OPTIONS": {
    "driver": "FreeTDS",
    "host_is_server": True,
},

有关 FreeTDS 配置的详细信息,请参阅 mssql-django 的连接选项

测试数据库问题

测试数据库创建和销毁可能会失败,具体取决于身份验证方法。

无法使用托管标识创建测试数据库

症状

django.db.utils.DatabaseError: ('42000', '[42000] ... EXECUTE permission denied on object ...')

或者:

django.db.utils.OperationalError: ('28000', ... login failed ...)

使用 ActiveDirectoryMsi (托管标识)身份验证时,测试运行程序无法创建或销毁测试数据库。 存在此限制是因为:

  • 托管标识凭据是从主机环境(例如Azure VM 和应用服务)获取的。

  • 测试运行器在清理阶段尝试使用 test 数据库凭据进行连接。

  • 可以向托管标识授予数据库级角色,但创建和删除测试数据库通常需要测试运行器通常不具备的服务器级权限。

受影响的身份验证方法

  • ActiveDirectoryMsi(Azure托管标识)
  • ActiveDirectoryServicePrincipal (仅在服务器范围内配置)

支持的身份验证方法 (测试数据库创建工作):

  • ActiveDirectoryPassword
  • ActiveDirectoryIntegrated
  • SQL 身份验证(用户名/密码)

测试环境中的身份验证取舍

方法 无机密 支持自动创建/删除测试数据库 典型用法
ActiveDirectoryMsi Yes 通常不(除非授予服务器级权限) Azure托管的生产工作负荷
ActiveDirectoryServicePrincipal 否(客户端密码/证书) 取决于授予的服务器级权限 采用显式身份管理的 CI/CD
ActiveDirectoryPassword No 是(具有足够的 SQL 权限) 开发人员和受控的 CI 环境
SQL 身份验证 No 是(具有足够的 SQL 权限) 本地或隔离的测试环境

解决方法

  • 在开发环境中:使用 --keepdb 标志跳过测试数据库清理:

    python manage.py test --keepdb
    
  • 对于 CI/CD 管道:预先创建专用测试数据库并授予托管标识 CREATE TABLEALTER 权限:

    -- Connect as a server admin, then:
    USE [test_database_name];
    
    -- Grant permissions for managed identity (replace with your identity name)
    CREATE USER [your-app-identity] FROM EXTERNAL PROVIDER;
    GRANT CREATE TABLE TO [your-app-identity];
    GRANT ALTER ON SCHEMA::dbo TO [your-app-identity];
    
  • 替代方法:对测试环境使用 SQL 身份验证,或切换到 ActiveDirectoryPassword CI/CD 测试运行程序。

回滚流程

当迁移在中途失败时,请使用此回滚顺序将系统恢复到已知正常状态:

  1. 停止应用程序写入以避免其他架构偏移。

  2. 检查迁移状态:

    python manage.py showmigrations
    python manage.py sqlmigrate <app_label> <migration_number>
    
  3. 回滚到最后一个已知正常的迁移:

    python manage.py migrate <app_label> <previous_migration>
    
  4. 如果模式与迁移历史记录不一致,请仅在核实数据库的实际模式后,谨慎使用 --fake 修复状态。

  5. 首先在过渡环境中重新运行迁移,然后重试生产。

Important

对于破坏性的迁移(如删除、重命名和列类型更改),请在部署之前执行经过测试的备份。 如果无法通过迁移回滚,请从备份还原并重新应用已验证的迁移。

Docker 和容器问题

容器镜像需要显式安装 ODBC 驱动程序以及构建依赖项。

容器中找不到 ODBC 驱动程序

症状

Error: ('01000', "[01000] [unixODBC][Driver Manager]Can't open lib 'ODBC Driver 18 for SQL Server'")

可能的原因和解决方案

  • 容器映像中未安装 ODBC 驱动程序

    Slim 或 Alpine 基础镜像不包含 ODBC 驱动程序。 添加 Microsoft APT 存储库并在 Dockerfile 中安装msodbcsql18。 有关完整的 Dockerfile 示例,请参阅 “部署到应用服务 ”。

  • 缺少 unixodbc-dev

    pyodbc wheel 链接到 libodbc.so。 在安装Python包之前安装 unixodbc-dev (Debian/Ubuntu) 或 unixODBC-devel (RHEL/Fedora)。

pyodbc 无法基于精简映像进行生成

症状

error: command 'gcc' failed: No such file or directory

或者:

fatal error: sql.h: No such file or directory

解决方案:先安装构建依赖项,再执行 pip install

RUN apt-get update && apt-get install -y --no-install-recommends \
    gcc \
    g++ \
    unixodbc-dev

或者,使用多阶段生成来保持最终映像较小:

# Build stage
FROM python:3.12-slim AS builder
RUN apt-get update && apt-get install -y --no-install-recommends gcc g++ unixodbc-dev
COPY requirements.txt .
RUN pip wheel --no-cache-dir --wheel-dir /wheels -r requirements.txt

# Runtime stage
FROM python:3.12-slim
RUN apt-get update && apt-get install -y --no-install-recommends \
    curl gnupg2 unixodbc \
    && curl -fsSL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor -o /usr/share/keyrings/microsoft-prod.gpg \
    && curl -fsSL https://packages.microsoft.com/config/debian/12/prod.list > /etc/apt/sources.list.d/mssql-release.list \
    && apt-get update \
    && ACCEPT_EULA=Y apt-get install -y --no-install-recommends msodbcsql18 \
    && apt-get purge -y --auto-remove curl gnupg2 \
    && rm -rf /var/lib/apt/lists/*
COPY --from=builder /wheels /wheels
RUN pip install --no-cache-dir /wheels/*

容器无法连接到SQL Server

症状

django.db.utils.OperationalError: ('08001', '... TCP Provider: Error code 0x2749 ...')

可能的原因和解决方案

  • Docker Compose 服务名称未被用作主机名

    使用 Docker Compose 时,设置为 DB_HOST 服务名称(例如, db而不是 localhost127.0.0.1)。

  • SQL Server容器未就绪

    SQL Server容器需要几秒钟才能启动。 添加健康检查或启动延迟:

    services:
      db:
        image: mcr.microsoft.com/mssql/server:2022-latest
        healthcheck:
          test: /opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P "$$MSSQL_SA_PASSWORD" -No -Q "SELECT 1" || exit 1
          # $$ escapes the $ sign in Docker Compose YAML
          interval: 10s
          retries: 10
          start_period: 10s
      web:
        depends_on:
          db:
            condition: service_healthy
    
  • 端口映射冲突

    如果主机上运行SQL Server的另一个实例,请更改公开的端口(例如1434:1433),并相应地更新 Django 配置。

Azure SQL暂时性错误恢复

后端mssql-django通过查询SERVERPROPERTY('EngineEdition')自动检测Azure SQL 数据库和Azure SQL 托管实例连接。 针对Azure SQL运行时,后端会针对暂时性错误(例如临时资源限制或短暂的网络中断)重试连接。

您可以使用 connection_retriesconnection_retry_backoff_time 选项来调整这种行为:

"OPTIONS": {
    "driver": "ODBC Driver 18 for SQL Server",
    "connection_retries": 5,
    "connection_retry_backoff_time": 5,
},

这些设置仅适用于初始连接建立。 后端不会重试失败的查询。 如果在建立连接后查询失败并出现暂时性错误,则异常将传播到应用程序代码。 使用应用程序级重试逻辑(例如 django-retry-db 或自定义中间件)进行查询级复原。

慢查询和执行计划回归

这些问题通常需要服务器端分析以及 Django 级查询评审。

查询变慢或开始超时

症状

随着时间推移,相同的查询集会变慢,或者在部署、索引更改或统计信息更新后开始超时。

可能的原因和解决方案

  • 从内置性能报告开始

    对于SQL Server和Azure SQL 托管实例,请在SQL Server Management Studio中打开性能仪表板。 对于 Azure SQL 数据库,请打开Azure SQL 数据库的查询性能见解。 这些工具通常是比临时 DMV 查询更好的第一步,因为它们可以快速呈现昂贵的查询、等待和资源压力。

  • 计划回归

    使用查询存储查找慢速查询,并检查它是否具有多个计划。 从Regressed QueriesTop Resource Consuming Queries视图入手,如 使用 查询存储 监视工作负载的最佳做法 中所述。

  • 低效的执行计划

    打开该语句的实际执行计划,并检查是否存在表扫描或索引扫描、大量键查找、哈希溢出或行数估计不准确的问题。 有关背景信息,请参阅 执行计划概述

  • 识别出错误的瓶颈

    如果查询没有 CPU 绑定,请使用查询存储等待统计信息并识别瓶颈来区分 CPU、内存、磁盘 I/O、阻塞和连接压力。

  • 修复被应用在错误的层

    采取最小且有效的修复措施:添加或调整索引、更新统计信息、减少所选的列数和行数,或将大型写入分批进行。 如果需要应急缓解措施,DBA 可以在修复根本原因的同时,暂时在 查询存储 中强制使用一个已知良好的计划。

将 dbshell 用于交互式查询

Django 的 dbshell 管理命令会打开一个连接到你的数据库的交互式 SQL shell:

python manage.py dbshell

配置 Microsoft ODBC 驱动程序时,后端使用 sqlcmd;使用 FreeTDS 时,后端使用 isql。 验证该工具是否在 PATH 上:

  • Windowssqlcmd包含在SQL Server工具中,也可以单独下载。
  • Linux 和 macOS:从Microsoft存储库安装mssql-tools18