Problembehandlung für mssql-python

Diagnostizieren und beheben Sie häufige Probleme, wenn Sie den mssql-python-Treiber verwenden, um sich mit SQL Server, Azure SQL-Datenbank, Azure SQL Managed Instance und SQL Database in Microsoft Fabric zu verbinden.

Installationsprobleme

pip install schlägt fehl oder erstellt aus dem Quellcode

Symptome:

error: Microsoft Visual C++ 14.0 or greater is required
ERROR: Failed building wheel for mssql-python

Mögliche Ursachen und Lösungen:

  • Kein vorgefertigtes Lenkrad für deine Plattform

    • Überprüfe, ob du eine unterstützte Python-Version (ab Version 3.10) und Plattform betreibst. Siehe Support-Lebenszyklus für die Kompatibilitätsmatrix. Aktualisieren Sie pip, bevor Sie mit pip install --upgrade pip installieren. Für reproduzierbare Teamumgebungen verwenden Sie den fixierten Workflow in Wiederholbare Deployments oder die Containermuster in Containern und lokaler Entwicklung, um Abweichungen zwischen lokalen Rechnern zu reduzieren.
  • Virtuelle Umgebung nicht aktiviert

    • Aktiviere zuerst deine virtuelle Umgebung. Die Installation von Python im System kann zu Berechtigungsfehlern oder -konflikten führen.
    python -m venv .venv
    .venv\Scripts\activate
    pip install mssql-python
    

  • Fehlende Linux-Systembibliotheken

Widersprüchliche Treiberinstallationen

Symptome:

Importfehler oder unerwartetes Verhalten nach der Installation von mssql-python zusammen mit pyodbc in derselben Umgebung.

Lösung:

mssql-python und pyodbc koexistieren können. Wenn Sie Konflikte sehen, schaffen Sie eine saubere virtuelle Umgebung:

python -m venv .venv --clear
.venv\Scripts\activate
pip install mssql-python

Verbindungsprobleme

Keine Verbindung zum Server möglich

Symptome:

OperationalError: [08001] (0) Client unable to establish connection

Mögliche Ursachen und Lösungen:

  • Server nicht erreichbar

    • Überprüfen Sie, ob der Servername und der Port korrekt sind.
    • Überprüfen Sie die Netzwerkverbindung: ping servername oder telnet servername 1433.
    • Stellen Sie sicher, dass die Firewall ausgehende Verbindungen am Port 1433 erlaubt.
  • SQL Server läuft nicht

    • Überprüfen Sie, ob der SQL Server-Dienst gestartet wurde.
    • Für benannte Instanzen überprüfen Sie, ob der SQL Server Browser-Dienst läuft.
  • Azure SQL firewall rules

    • Füge deine Client-IP den Azure SQL-Firewall-Regeln im Azure-Portal hinzu.
    • Für Azure SQL Managed Instance solltest du sicherstellen, dass du dich über ein erlaubtes Netzwerk verbindest.
# Test basic connectivity
import socket
try:
    sock = socket.create_connection(("<server>.database.windows.net", 1433), timeout=5)
    print("TCP connection successful")
    sock.close()
except Exception as e:
    print(f"Cannot reach server: {e}")

Fehler bei der Anmeldung

Symptome:

OperationalError: [28000] (18456) Login failed for user 'username'.

Mögliche Ursachen und Lösungen:

  • Authentifizierungsmodus-Fehlanpassung

    • Für Azure SQL-Datenbank, Azure SQL Managed Instance und SQL Database in Fabric bevorzugen Sie einen Microsoft Entra-Modus wie Authentication=ActiveDirectoryDefault.
    • Wenn du absichtlich SQL-Authentifizierung verwendest, prüfe, ob der Server sie erlaubt und dass du das korrekte Anmeldeformat für diesen Endpunkt verwendest.
  • Falsche SQL-Authentifizierungsdaten

    • Überprüfen Sie Benutzername und Passwort.
    • Für Azure SQL geben Sie den vollständigen Benutzernamen an: username@servername.
  • User existiert nicht in der Datenbank

    • Überprüfen Sie, ob der Benutzer Zugriff auf die angegebene Datenbank hat.
    • Überprüfen Sie, ob die Anmeldung einem Datenbankbenutzer zugeordnet ist.
  • Authentifizierung nicht konfiguriert

    • Verwenden Sie Microsoft Entra-Authentifizierung (empfohlen): Authentication=ActiveDirectoryDefault.
    • Wenn du Fehler bei einem lokalen SQL Server behebst, der die SQL-Authentifizierung akzeptieren sollte, vergewissere dich, dass SQL Server die Authentifizierung im gemischten Modus verwendet.

Verbindungstimeout

Symptome:

OperationalError: [HYT00] (0) Timeout expired
OperationalError: [HYT01] (0) Connection timeout expired

Mögliche Ursachen und Lösungen:

  • Der Server reagiert langsam

    • Erhöhen Sie das Verbindungs-Timeout:
    conn = mssql_python.connect(connection_string, timeout=60)
    
  • Netzwerklatenz

    • Überprüfe den Netzwerkpfad zum Server.
    • Erwägen Sie, einen kürzeren Netzwerkweg oder ein VPN zu verwenden.
  • Server unter hoher Last

    • Versuche, dich außerhalb der Hauptverkehrszeiten zu verbinden.
    • Kontaktieren Sie Ihren Datenbankadministrator.

SSL-Zertifikatfehler

Symptome:

OperationalError: [08001] SSL Provider: The certificate chain was issued by an authority that is not trusted

Lösungen :

Zunächst sollten Sie ein vertrauenswürdiges Zertifikat oder die lokalen Entwicklungsmuster in Container und lokaler Entwicklung bevorzugen. Verwenden Sie TrustServerCertificate=yes es nur für lokale Entwicklung gegen einen Server, den Sie steuern.

Für Entwicklung und Tests mit einem selbstsignierten Zertifikat:

conn = mssql_python.connect(
    "Server=<server>.database.windows.net;"
    "Database=<database>;"
    "Authentication=ActiveDirectoryDefault;"
    "Encrypt=yes;"
    "TrustServerCertificate=yes;"  # Don't use in production
)

Caution

TrustServerCertificate=yes ist ein nur lokal verfügbares Fallback. Trage es nicht in gemeinsame Devcontainer, CI-Pipelines oder Produktionsdeployments ein. Für eine umfassendere Orientierung siehe Verschlüsselung und Zertifikate.

Für die Produktion stellen Sie sicher, dass die richtigen Zertifikate installiert sind, und verwenden Sie:

conn = mssql_python.connect(
    "Server=<server>.database.windows.net;"
    "Database=<database>;"
    "Authentication=ActiveDirectoryDefault;"
    "Encrypt=yes;"
    "HostnameInCertificate=<server>.domain.com;"
)

Abfrageausführungsprobleme

Tabelle oder Objekt nicht gefunden

Symptome:

ProgrammingError: [42S02] (208) Invalid object name 'TableName'.

Mögliche Ursachen und Lösungen:

  • Falscher Datenbankkontext

    # Ensure you're connected to the correct database
    cursor.execute("SELECT DB_NAME()")
    print(cursor.fetchone()[0])
    
  • Schema nicht spezifiziert

    # Use fully qualified name
    cursor.execute("SELECT * FROM dbo.TableName")
    
  • Tabelle existiert nicht

    # Check if table exists
    cursor.execute("""
         SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES 
         WHERE TABLE_NAME = 'TableName'
    """)
    

Syntaxfehler

Symptome:

ProgrammingError: [42000] (102) Incorrect syntax near '...'.

Lösungen :

  1. Teste SQL zuerst in SSMS, um die Syntax zu überprüfen

  2. Überprüfen Sie das Entkommen von Zeichenketten – verwenden Sie parametrisierte Abfragen:

    # Wrong - vulnerable to syntax issues and SQL injection
    cursor.execute(f"SELECT * FROM Production.Product WHERE Name = '{name}'")
    
    # Correct - use parameters
    cursor.execute("SELECT * FROM Production.Product WHERE Name = %(name)s", {"name": name})
    

Parameterfehler

Symptome:

ProgrammingError: [07001] Wrong number of parameters

Lösungen :

  1. Zähle Platzhalter und Parameter – sie müssen übereinstimmen

  2. Wählen Sie den richtigen Parameterstil:

    # Qmark style - positional
    cursor.execute("SELECT * FROM Production.Product WHERE ProductID = ? AND Name LIKE ?", (1, "Adjustable%"))
    print(cursor.fetchone())
    
    # Pyformat style - named
    cursor.execute("SELECT * FROM Production.Product WHERE ProductID = %(id)s AND Name LIKE %(name)s", {"id": 1, "name": "Adjustable%"})
    print(cursor.fetchone())
    

Probleme mit Datentypen

Fehler bei Date-Time-Umrechnungen

Symptome:

DataError: [22007] Invalid datetime format

Lösungen :

Verwenden Sie Python Datetime-Objekte anstelle von Strings:

from datetime import datetime

cursor.execute("CREATE TABLE #Events (EventDate DATETIME)")

# Wrong - this raises an error for invalid dates
try:
    cursor.execute("INSERT INTO #Events (EventDate) VALUES (%(event_date)s)", {"event_date": "2024-13-45"})
except Exception as e:
    print(f"Expected error: {e}")

# Correct - use Python datetime objects
cursor.execute("INSERT INTO #Events (EventDate) VALUES (%(event_date)s)", {"event_date": datetime(2024, 3, 15)})
cursor.execute("SELECT EventDate FROM #Events")
print(cursor.fetchone())

Dezimalpräzisionsprobleme

Symptome:

Zahlen erscheinen abgeschnitten oder falsch gerundet.

Lösungen :

Verwendung decimal.Decimal für präzise Zahlenwerte:

from decimal import Decimal

cursor.execute("CREATE TABLE #PriceDemo (ListPrice DECIMAL(10,2))")
# Preserve full precision
cursor.execute(
    "INSERT INTO #PriceDemo (ListPrice) VALUES (%(list_price)s)",
    {"list_price": Decimal("19.99")}
)

Unicode-Codierungsprobleme

Symptome:

Spezialzeichen erscheinen verwirrt oder verursachen Fehler.

Lösungen :

  1. Verwenden Sie NVARCHAR-Spalten für Unicode-Daten in Ihrer Datenbank

  2. Strings direkt übergeben – der Treiber übernimmt die Kodierung:

    cursor.execute("CREATE TABLE #UnicodeDemo (Name NVARCHAR(50))")
    cursor.execute("INSERT INTO #UnicodeDemo (Name) VALUES (%(name)s)", {"name": "日本語"})
    cursor.execute("SELECT Name FROM #UnicodeDemo")
    print(cursor.fetchone())
    

Leistungsprobleme

Langsame Abfrageausführung

Mögliche Ursachen und Lösungen:

  • Fehlende Indizes: Überprüfen Sie den Abfrageausführungsplan in SSMS.

  • Große Ergebnismengen: Verwenden Sie fetchmany() anstelle von fetchall():

    cursor.arraysize = 1000
    while True:
         rows = cursor.fetchmany()
         if not rows:
             break
         process_rows(rows)
    
  • Verbindungspooling deaktiviert: Pooling aktivieren:

    import mssql_python
    mssql_python.pooling(max_size=20, idle_timeout=300)
    

Speicherprobleme bei großen Ergebnismengen

Symptome:

Der Python-Prozess geht dem Speicher aus.

Lösungen :

  1. Stromergebnisse statt alle in den Speicher zu laden:

    cursor.execute("SELECT * FROM LargeTable")
    for row in cursor:  # Iterates one row at a time
        process_row(row)
    
  2. Verwenden Sie serverseitige Paginierung:

    page_size = 1000
    offset = 0
    while True:
        cursor.execute(
            "SELECT * FROM LargeTable ORDER BY ID "
            "OFFSET ? ROWS FETCH NEXT ? ROWS ONLY",
            (offset, page_size)
        )
        rows = cursor.fetchall()
        if not rows:
            break
        process_rows(rows)
        offset += page_size
    

Transaktionsprobleme

Gültigkeitsbereich temporärer Tabellen mit Autocommit

Temporäre Tabellen (#tablename) innerhalb einer Transaktion verschwinden, wenn die Transaktion zurückgesetzt wird. Dies ist eine häufige Quelle für Verwirrung, wenn Autocommit deaktiviert ist (der Standardmodus):

conn = mssql_python.connect(connection_string)  # autocommit=False by default
cursor = conn.cursor()

cursor.execute("CREATE TABLE #TempData (ID INT, Name NVARCHAR(50))")
cursor.execute("INSERT INTO #TempData VALUES (1, 'test')")

# If the connection rolls back (explicit or on error), #TempData disappears
conn.rollback()

# This fails: Invalid object name '#TempData'
cursor.execute("SELECT * FROM #TempData")

Behebung: Führen Sie unmittelbar nach der Erstellung einer temporären Tabelle einen Commit durch, oder verwenden Sie den Autocommit-Modus:

cursor.execute("CREATE TABLE #TempData (ID INT, Name NVARCHAR(50))")
conn.commit()  # Lock in the table definition

cursor.execute("INSERT INTO #TempData VALUES (1, 'test')")
conn.commit()

DDL-Anweisungen, die den Autocommit-Modus erfordern, wie CREATE DATABASE, schlagen innerhalb einer offenen Transaktion fehl. Setze Autocommit ein, bevor du sie ausführst:

conn.autocommit = True
cursor.execute("CREATE DATABASE TestDB")
conn.autocommit = False

Transaktion nicht abgeschlossen

Symptome:

Datenänderungen bleiben nach dem Schließen der Verbindung nicht bestehen.

Solution:

Mit autocommit=False (Standardeinstellung) müssen Sie commit() aufrufen:

cursor.execute("CREATE TABLE #Products (Name NVARCHAR(100))")
cursor.execute("INSERT INTO #Products (Name) VALUES (%(name)s)", {"name": "Widget"})
conn.commit()  # Don't forget this!

Oder benutze den Autocommit-Modus:

conn = mssql_python.connect(connection_string, autocommit=True)

Deadlock-Fehler

Symptome:

OperationalError: [40001] (1205) Transaction ... was deadlocked on lock resources with another process

Solution:

Wiederholungslogik (siehe Wiederholungslogik) übernimmt das unmittelbare Scheitern, aber wiederkehrende Deadlocks deuten auf ein Designproblem hin. Um die Ursache zu beheben, erfassen Sie den Deadlock-Graphen und analysieren, welche Anweisungen und Sperrtypen beteiligt sind. Gängige Lösungen umfassen die Neuordnung von Operationen, sodass konkurrierende Transaktionen in derselben Reihenfolge Sperren erhalten, die Verringerung des Transaktionsumfangs sowie das Hinzufügen geeigneter Indizes zur Verkürzung der Sperrdauer.

Eine vollständige Anleitung zur Deadlock-Analyse finden Sie im Leitfaden zu Deadlocks. Wenn Sie Azure SQL-Datenbank verwenden, lesen Sie Deadlocks analysieren und verhindern.

Probleme mit der Großladung

Verstöße gegen Einschränkungen während des Bulk Copy-Vorgangs

Symptome:

RuntimeError: CHECK constraint ... Conflict occurred in database ...
RuntimeError: Cannot insert duplicate key ... violation of PRIMARY KEY constraint

Ursache:

Die Daten in Ihrem Batch verstoßen gegen die Tabellenbeschränkungen (Primärschlüssel, eindeutig, CHECK oder Fremdschlüssel).

Lösung:

Validiere die Daten vor dem Laden. Für große Datensätze laden Sie die Daten zunächst in eine Staging-Tabelle und führen sie dann in die Zieltabelle zusammen:

# Load into staging, then validate
cursor.execute("CREATE TABLE ##Staging (ID INT, Name NVARCHAR(100))")
cursor.bulkcopy("##Staging", rows)

# Check for duplicates before merging
cursor.execute("""
    SELECT s.ID FROM ##Staging s
    INNER JOIN dbo.Target t ON s.ID = t.ID
""")
dupes = cursor.fetchall()
if dupes:
    print(f"Skipping {len(dupes)} duplicate rows")

# Insert only non-duplicate rows
cursor.execute("""
    INSERT INTO dbo.Target (ID, Name)
    SELECT s.ID, s.Name FROM ##Staging s
    WHERE NOT EXISTS (SELECT 1 FROM dbo.Target t WHERE t.ID = s.ID)
""")
conn.commit()

Für Upsertmuster mit Staging-Tabellen siehe Muster für das Laden und Verschieben von Daten.

Spaltenabbildungsfehler

Symptome:

RuntimeError: Bulk copy failure - column count mismatch

Ursache:

Die Anzahl der Spalten in deinen Daten entspricht nicht der Spaltenanzahl der Zieltabelle, oder die Spalten sind in der falschen Reihenfolge.

Lösung:

Stellen Sie sicher, dass Ihre Daten exakt mit dem Tabellenschema in Reihenfolge und Anzahl übereinstimmen:

# Check the target table schema
cursor.execute("""
    SELECT COLUMN_NAME, DATA_TYPE
    FROM INFORMATION_SCHEMA.COLUMNS
    WHERE TABLE_NAME = 'MyTable'
    ORDER BY ORDINAL_POSITION
""")
for col in cursor.fetchall():
    print(col)

# Match your data to the column order
rows = [
    (1, "Widget", Decimal("19.99")),  # Must match table column order
    (2, "Gadget", Decimal("29.99")),
]
cursor.bulkcopy("dbo.MyTable", rows)

Typabweichungen beim Massenkopieren

Symptome:

Die Daten werden zwar geladen, aber die Werte sind abgeschnitten, abgerundet oder falsch.

Ursache:

Python-Werte werden nicht sauber auf die Ziel-Spaltentypen abgebildet. Häufige Fälle: in decimal-Spalten geladene float-Werte (Präzisionsverlust) oder zu lange Zeichenfolgen, die in Festlängenspalten geladen werden.

Lösung:

Verwenden Sie die richtigen Python-Typen, die zu Ihrem Schema passen:

from decimal import Decimal

# Use Decimal for decimal/numeric columns, not float
rows = [
    (1, "Widget", Decimal("19.99")),  # Correct
    # (1, "Widget", 19.99),           # Avoid: float loses precision
]
cursor.bulkcopy("dbo.Products", rows)

Fehler bei der NumPy-Typbindung

Symptome:

Parameter versagen lautlos oder verursachen Datentypfehler, wenn Numpy-Ganzzahl- oder Gleitwerttypen verwendet werden.

Ursache:

NumPy-Typen wie numpy.int64 und numpy.int32 bestehen isinstance(x, int) in NumPy 2.x nicht. Die Typinferenz des Fahrers erkennt sie nicht, was zu unerwartetem Verhalten führt.

Lösung:

Konvertiere Numpy-Werte vor der Bindung in native Python-Typen:

import numpy as np

# Convert individual values
cursor.execute("SELECT * FROM Production.Product WHERE ProductID = %(product_id)s", {"product_id": int(np.int64(42))})

# Convert DataFrame values
for _, row in df.iterrows():
    cursor.execute(
        "INSERT INTO #Orders (ProductID, Qty) VALUES (%(product_id)s, %(qty)s)",
        {"product_id": int(row["ProductID"]), "qty": int(row["Qty"])}
    )

Für größere Datensätze verwenden Sie stattdessen die Arrow - oder pandas-Integrationspfade , die die Typkonvertierung intern übernehmen.

Bulkcopy mit temporären Tabellen

Symptome:

cursor.bulkcopy("#TempTable", data) ergibt RuntimeError: Invalid object name '#TempTable'.

Ursache:

bulkcopy() kann temporäre Sitzungstabellen (#tablename) aufgrund von Einschränkungen bei der Metadatensuche nicht auflösen. Globale temporäre Tabellen (##tablename) und permanente Tabellen funktionieren.

Lösung:

Verwenden Sie eine globale temporäre Tabelle oder eine reguläre Stagingtabelle:

# Global temp table (visible to all sessions, dropped when last session disconnects)
cursor.execute("CREATE TABLE ##Staging (ID INT, Name NVARCHAR(50))")
cursor.bulkcopy("##Staging", rows)

# Or use a permanent staging table
cursor.execute("CREATE TABLE dbo.Staging (ID INT, Name NVARCHAR(50))")
cursor.bulkcopy("dbo.Staging", rows)

Für kleine Datensätze, bei denen eine Sitzungs-Temp-Tabelle bevorzugt wird, verwenden executemany() Sie stattdessen:

cursor.execute("CREATE TABLE #Staging (ID INT, Name NVARCHAR(50))")
cursor.executemany("INSERT INTO #Staging (ID, Name) VALUES (?, ?)", rows)

Container- und CI-Probleme

Fehlende Systembibliotheken unter Linux

Symptome:

ImportError: libltdl.so.7: cannot open shared object file: No such file or directory
ImportError: libkrb5.so.3: cannot open shared object file

Lösung:

Installieren Sie die erforderlichen Systempakete. Die Pakete unterscheiden sich je nach Verteilung:

Verteilung Installationsbefehl
Ubuntu/Debian sudo apt-get install libltdl7 libkrb5-3 libgssapi-krb5-2
Red Hat / Fedora sudo dnf install libtool-ltdl krb5-libs
Alpine apk add libltdl krb5-libs

Für Dockerfile-Beispiele siehe Container und lokale Entwicklung.

macOS SSL-Fehler nach der Installation

Symptome:

SSL-bezogene Fehler bei Verbindungen unter macOS, insbesondere auf Apple-Silicon-Systemen.

Lösung:

Installiere OpenSSL über Homebrew und setze die Linker-Flags:

brew install openssl
export LDFLAGS="-L/opt/homebrew/opt/openssl/lib"
export CPPFLAGS="-I/opt/homebrew/opt/openssl/include"

Diagnosewerkzeuge

Treiberprotokollierung aktivieren

Verwenden Sie mssql_python.setup_logging(), um eine umfassende DEBUG-Protokollierung zur Fehlerbehebung zu aktivieren. Alle Treiberoperationen werden protokolliert, einschließlich SQL-Anweisungen, Parameter, interne ODBC-Operationen und Änderungen des Verbindungszustands.

import mssql_python

# Enable logging to file (default)
mssql_python.setup_logging()

# Output to stdout (useful for CI/CD and containers)
mssql_python.setup_logging(output='stdout')

# Output to both file and stdout
mssql_python.setup_logging(output='both')

# Custom log file path (must use .txt, .log, or .csv extension)
mssql_python.setup_logging(log_file_path="/var/log/myapp/mssql.log")

Logdateien werden im CSV-Format geschrieben und rotieren automatisch bei 512 MB mit fünf Backups. Sensible Daten wie Passwörter und Zugriffstoken werden automatisch in der Logausgabe bereinigt.

Um eigene Logeinträge neben Treiberprotokollen hinzuzufügen, verwenden Sie driver_logger:

from mssql_python.logging import driver_logger

mssql_python.setup_logging()

driver_logger.debug("[App] Starting data processing")
driver_logger.error("[App] Failed to process record")
# Your entries appear in the same file with the same format

Caution

Logging hat einen Performance-Overhead. Aktiviere es nur bei der Fehlersuche, nicht standardmäßig in der Produktion.

Erhalte Fahrerinformationen

Rufen Sie die Treiberversion und Serverdetails von einer aktiven Verbindung ab:

import mssql_python

conn = mssql_python.connect(connection_string)

# Driver version
print(f"Version: {mssql_python.__version__}")

# Server information
print(f"Server name: {conn.getinfo(mssql_python.SQL_SERVER_NAME)}")
print(f"Database name: {conn.getinfo(mssql_python.SQL_DATABASE_NAME)}")

Überprüfen des Verbindungszustands

Testen Sie, ob eine Verbindung noch offen ist, bevor Sie die Operationen versuchen:

try:
    cursor = conn.cursor()
    cursor.execute("SELECT 1")
    print("Connection is open")
except mssql_python.Error:
    print("Connection is closed or broken")

Schnellreferenz: Häufige Fehler

Fehler SQLSTATE Übliche Ursache Schnelle Problembehebung
Client kann keine Verbindung herstellen 08001 Server nicht erreichbar Überprüfe Servernamen/Port
Fehler bei der Anmeldung 28000 Falsche Qualifikationen Benutzername/Passwort überprüfen
Timeout überschritten HYT00/HYT01 Langsames Netzwerk Timeout erhöhen
Ungültiger Objektname 42S02 Falsche Tabelle/Schema Verwenden Sie vollständig qualifizierte Namen
Syntaxfehler 42000 SQL-Fehler Verwenden parametrisierter Abfragen
Verstoß gegen eine Einschränkung 23000 FK/PK-Verstoß Überprüfen Sie die Datenintegrität
Deadlock 40001 Sperrkonflikt Versuchen Sie es erneut und analysieren Sie dann den Deadlock-Graphen