疑難排解 mssql-django

診斷並解決 SQL Server、Azure SQL Database、Azure SQL 受控執行個體 及 Microsoft Fabric 中 SQL 資料庫後端常見問題mssql-django

連接問題

本節將介紹最常見的連線錯誤及其解決方法。

找不到 ODBC 驅動程式

徵兆:

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

Or:

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

多個原因與解決方案

  • 未安裝 ODBC 驅動程式

    安裝 Microsoft 的 SQL Server ODBC 驅動程式。 欲下載連結,請參閱下載 SQL Server 的 ODBC 驅動程式

  • 安裝多個驅動程式版本

    請在 : 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 portal 防火牆設定中新增你的客戶端 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,
    },
    

移轉問題

這些錯誤發生在 Django 對 SQL Server 的遷移操作中。

日期與時間問題

Now() 值會在 USE_TZ=True 時位移

徵兆:

使用 Django Now()auto_nowauto_now_add 寫入的時間戳記,在 SQL Server 主機時區不是 UTC 時會發生位移。

解決方案:升級到 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 及以後版本的編譯器相容性,說明了元資料。

無法更改 AutoField

徵兆:

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

解決方案:SQL Server 不支援將欄位從或變更為 AutoField。 建立一個想要的欄位類型的新模型,手動遷移資料,然後丟棄舊資料表。 有關解決方法,請參見 mssql-django 的資料庫遷移

重命名在外鍵限制下失敗

徵兆:

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

解決方案:SQL Server 需要在重新命名欄位前先捨棄外鍵約束。 在您的遷移過程中使用 SeparateDatabaseAndState。 舉例來說,請參考 mssql-django 的資料庫遷移

編碼問題

編碼錯誤通常發生在pyodbc誤解 SQL Server 的字元資料時。

Unicode 編碼錯誤

徵兆:

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

解決方案:在 OPTIONS 字典中設定 pyodbc 編碼:

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

FreeTDS 問題

FreeTDS 需要與 Microsoft ODBC 驅動程式不同的特定設定。

host_is_server 錯誤

徵兆:

使用未指定 host_is_server的 FreeTDS 時連線失敗。

解決方案:設定 host_is_serverTrue 使用 FreeTDS 時:

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

欲了解更多 FreeTDS 設定資訊,請參閱 mssql-django 的連線選項

測試資料庫問題

測試資料庫的建立與銷毀可能會因你的認證方式而失敗。

無法建立使用管理身份的測試資料庫

徵兆:

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

Or:

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

當你使用 ActiveDirectoryMsi (管理身份)驗證時,測試執行者無法建立或銷毀測試資料庫。 此限制存在的原因在於:

  • 管理身份憑證是從主機環境(例如 Azure VM 和 App Service)取得的。

  • 測試執行器在 teardown 期間會嘗試使用 test 資料庫憑證進行連線。

  • 管理身份可以被賦予資料庫層級的角色,但測試資料庫的建立與刪除通常需要伺服器層級的權限,而測試執行者往往沒有這些權限。

受影響的認證方式

  • ActiveDirectoryMsi(Azure managed identity)
  • ActiveDirectoryServicePrincipal (僅在伺服器範圍內設定時)

支援的認證方法 (測試資料庫建立可行):

  • ActiveDirectoryPassword
  • ActiveDirectoryIntegrated
  • SQL 認證(使用者名稱/密碼)

測試環境中的身分驗證取捨

方法 無秘密 可配合自動建立/刪除測試資料庫運作 典型用途
ActiveDirectoryMsi Yes 通常不會(除非有伺服器層級的權限) Azure 託管的生產工作負載
ActiveDirectoryServicePrincipal 否(用戶端密碼/憑證) 這取決於被授予的伺服器層級權限 採用明確身分管理的 CI/CD
ActiveDirectoryPassword 是的(只要有足夠的 SQL 權限) 開發人員與受控的 CI 環境
SQL 驗證 是的(只要有足夠的 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 認證,或在 CI/CD 測試執行器中切換至 ActiveDirectoryPassword SQL 認證。

回退程序

當遷移中途失敗時,請使用此回滾序列回到已知良好狀態:

  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 範例請參見 Deploy to App Service

  • 遺失包裹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

Or:

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自動偵測 Azure SQL Database 與 Azure SQL 受控執行個體 連線,方法是查詢 SERVERPROPERTY('EngineEdition')。 在執行 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 Database,請開啟 Query Performance Insight for Azure SQL Database。 這些工具通常比臨時撰寫的 DMV 查詢更適合作為第一步,因為它們能迅速找出高成本查詢、等待情形及資源壓力。

  • 計畫迴歸

    使用 查詢存放區 找出慢速查詢,並檢查是否有多個方案。 從 使用 查詢存放區 監視工作負載的最佳做法 中所述的 回歸查詢最耗用資源的查詢 檢視開始。

  • 執行計畫效率低下

    開啟該語句的 實際執行計畫 ,檢查是否有資料表或索引掃描、大金鑰查詢、雜湊溢出或不準確的列估計。 背景請參見 執行計畫概述

  • 錯誤的瓶頸被識別

    如果查詢不受 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