Risoluzione dei problemi mssql-python

Diagnostica e risolvi i problemi comuni quando usi il driver mssql-python per connetterti a SQL Server, database SQL di Azure, Istanza gestita di SQL di Azure e database SQL in Microsoft Fabric.

Problemi di installazione

Fallimento dell'installazione di PIP o compilazione dal sorgente

Sintomi:

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

Possibili cause e soluzioni:

  • Nessun volante preassemblato per la tua piattaforma

    • Controlla di avere una versione Python supportata (versioni 3.10 e successive) e una piattaforma. Vedi ciclo di vita del supporto per la matrice di compatibilità. Aggiorna pip prima di installare con pip install --upgrade pip. Per ambienti di team ripetibili, usa il flusso di lavoro bloccato nelle implementazioni ripetibili o i pattern container nel container e nello sviluppo locale per ridurre il drift locale della macchina.
  • Ambiente virtuale non attivato

    • Attiva prima il tuo ambiente virtuale. L'installazione di Python nel sistema può causare errori di permesso o conflitti.
    python -m venv .venv
    .venv\Scripts\activate
    pip install mssql-python
    

Installazioni di driver in conflitto

Sintomi:

Errori di importazione o comportamenti imprevisti dopo aver installato mssql-python accanto pyodbc allo stesso ambiente.

Correzione :

mssql-python e pyodbc possono coesistere. Se noti conflitti, crea un ambiente virtuale pulito:

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

Problemi di connessione

Impossibile connettersi al server

Sintomi:

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

Possibili cause e soluzioni:

  • Server non raggiungibile

    • Verifica che il nome del server e la porta siano corretti.
    • Controlla la connettività di rete: ping servername oppure telnet servername 1433.
    • Assicurati che il firewall consenta connessioni in uscita sulla porta 1433.
  • SQL Server non in esecuzione

    • Verifica che il servizio SQL Server sia stato avviato.
    • Per le istanze nominate, verifica che il servizio SQL Server Browser sia in esecuzione.
  • Azure SQL firewall rules

    • Aggiungi l'IP del tuo client alle regole firewall Azure SQL nel portale Azure.
    • Per Istanza gestita di SQL di Azure, assicurati di connetterti da una rete consentita.
# 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}")

Accesso non riuscito

Sintomi:

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

Possibili cause e soluzioni:

  • Disallineamento della modalità di autenticazione

    • Per database SQL di Azure, Istanza gestita di SQL di Azure e SQL database in Fabric, preferisci una modalità Microsoft Entra come Authentication=ActiveDirectoryDefault.
    • Se usi l'autenticazione SQL intenzionalmente, verifica che il server la consenta e che tu stia usando il formato di login corretto per quell'endpoint.
  • Credenziali di autenticazione SQL errate

    • Verifica nome utente e password.
    • Per Azure SQL, includere il nome utente completo: username@servername.
  • L'utente non esiste nel database

    • Verifica che l'utente abbia accesso al database specificato.
    • Controlla se l'accesso è mappato a un utente del database.
  • Autenticazione non configurata

    • Usa l'autenticazione Microsoft Entra (consigliata): Authentication=ActiveDirectoryDefault.
    • Se stai facendo una risoluzione di problemi su un SQL Server locale che dovrebbe accettare l'autenticazione SQL, verifica che SQL Server utilizzi l'autenticazione in modalità mista.

Timeout della connessione

Sintomi:

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

Possibili cause e soluzioni:

  • Il server risponde lentamente

    • Aumenta il timeout della connessione:
    conn = mssql_python.connect(connection_string, timeout=60)
    
  • Latenza di rete

    • Controlla il percorso di rete verso il server.
    • Considera di usare un percorso di rete più corto o una VPN.
  • Server sotto carico elevato

    • Prova a connetterti durante le ore di punta basse.
    • Contatta l'amministratore del tuo database.

Errori del certificato SSL

Sintomi:

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

Soluzioni:

Innanzitutto, privilegia un certificato attendibile o le configurazioni di sviluppo locale in Container e sviluppo locale. Usalo TrustServerCertificate=yes solo per lo sviluppo locale su un server che controlli.

Per sviluppo e test con certificato autofirmato:

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

Attenzione

TrustServerCertificate=yes è una soluzione di riserva solo locale. Non portarla in devcontainer condivisi, pipeline di CI o distribuzioni in produzione. Per indicazioni più generali, vedi Crittografia e certificati.

Per la produzione, assicurarsi che siano installati i certificati adeguati e utilizzare:

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

Problemi di esecuzione delle query

Tabella o oggetto non trovato

Sintomi:

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

Possibili cause e soluzioni:

  • Contesto sbagliato del database

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

    # Use fully qualified name
    cursor.execute("SELECT * FROM dbo.TableName")
    
  • Il tavolo non esiste

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

Errore di sintassi

Sintomi:

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

Soluzioni:

  1. Testa prima SQL in SSMS per verificare la sintassi

  2. Controlla la fuga delle stringhe - usa query parametrizzate:

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

Errori dei parametri

Sintomi:

ProgrammingError: [07001] Wrong number of parameters

Soluzioni:

  1. Conta i segnaposto e i parametri - devono corrispondere

  2. Scegli lo stile di parametro giusto:

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

Problemi con i tipi di dati

Errori di conversione di data e ora

Sintomi:

DataError: [22007] Invalid datetime format

Soluzioni:

Usa oggetti datetime in Python invece delle stringhe:

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

Problemi di precisione decimale

Sintomi:

I numeri appaiono troncati o arrotondati in modo errato.

Soluzioni:

Uso decimal.Decimal per valori numerici precisi:

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")}
)

Problemi di codifica Unicode

Sintomi:

I caratteri speciali appaiono distorti o causano errori.

Soluzioni:

  1. Usa le colonne NVARCHAR per i dati Unicode nel tuo database

  2. Passa le stringhe direttamente - il driver gestisce la codifica:

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

Problemi di prestazioni

Esecuzione lenta delle query

Possibili cause e soluzioni:

  • Indici mancanti: Controlla il piano di esecuzione delle query in SSMS.

  • Grandi set di risultati: Usa fetchmany() invece di fetchall():

    cursor.arraysize = 1000
    while True:
         rows = cursor.fetchmany()
         if not rows:
             break
         process_rows(rows)
    
  • Pooling delle connessioni disabilitato: Abilita il pooling delle connessioni:

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

Problemi di memoria con risultati grandi

Sintomi:

Il processo Python esaurisce la memoria.

Soluzioni:

  1. Risultati dello stream invece di caricare tutti in memoria:

    cursor.execute("SELECT * FROM LargeTable")
    for row in cursor:  # Iterates one row at a time
        process_row(row)
    
  2. Usa la paginazione lato server:

    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
    

Problemi di transazione

Visibilità delle tabelle temporanee con autocommit

Le tabelle temporanee (#tablename) create all'interno di una transazione scompaiono quando viene eseguito il rollback della transazione. Questa è una fonte comune di confusione quando l'autocommit è disattivato (il valore predefinito):

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

Correzione: Effettua il commit immediatamente dopo aver creato una tabella temporanea, oppure usa la modalità autocommit:

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

Le istruzioni DDL che richiedono la modalità autocommitto, come CREATE DATABASE, falliscono all'interno di una transazione aperta. Imposta l'autocommit prima di eseguirli:

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

Transazione non commessa

Sintomi:

I cambiamenti nei dati non persistono dopo la chiusura della connessione.

Soluzione:

Con autocommit=False (predefinito), devi chiamare commit():

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!

Oppure usa la modalità autocommit:

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

Errori di deadlock

Sintomi:

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

Soluzione:

La logica di ritentativi (vedi logica di ritento) gestisce il guasto immediato, ma blocchi ricorrenti indicano un problema di progettazione. Per risolvere la causa all’origine del problema, acquisisci il grafico del deadlock e analizza quali istruzioni e tipi di blocco sono coinvolti. Le correzioni comuni includono operazioni di riordinazione affinché le transazioni concorrenti acquisiscano lock nella stessa sequenza, la riduzione dell'ambito delle transazioni e l'aggiunta di indici appropriati per ridurre la durata dei lock.

Per una guida completa dell'analisi degli sblocchi, consulta la guida Deadlocks. Se usi database SQL di Azure, vedi Analizza e preveni blocchi.

Problemi di carico in blocco

Violazioni dei vincoli durante la copia di massa

Sintomi:

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

Causa:

I dati nel tuo batch violano i vincoli delle tabelle (chiave primaria, univoca, CHECK o chiave esterna).

Correzione :

Valida i dati prima di caricarli. Per grandi dataset, carichi prima una tabella di staging, poi unisci nel target:

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

Per i modelli di upsert con tabelle di staging, vedi i modelli di caricamento e spostamento dei dati.

Errori di mappatura delle colonne

Sintomi:

RuntimeError: Bulk copy failure - column count mismatch

Causa:

Il numero di colonne nei tuoi dati non corrisponde a quello della tabella di destinazione, oppure le colonne sono nell'ordine sbagliato.

Correzione :

Assicurati che i tuoi dati corrispondano esattamente allo schema della tabella per ordine e numero:

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

Discorrispondenze di tipo durante la copia di massa

Sintomi:

I dati si caricano ma i valori sono troncati, arrotondati o erratati.

Causa:

I valori di Python non corrispondono nettamente ai tipi di colonne di destinazione. Casi comuni: float valori caricati nelle decimal colonne (perdita di precisione), o stringhe sovradimensionate caricate in colonne di lunghezza fissa.

Correzione :

Usa i tipi di Python corretti che corrispondono al tuo schema:

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)

Errori di binding dei tipi NumPy

Sintomi:

I parametri falliscono silenziosamente o generano errori di tipo di dato quando si usano tipi interi o in virgola mobile di NumPy.

Causa:

I tipi di NumPy come numpy.int64 e numpy.int32 non superano isinstance(x, int) in NumPy 2.x. L'inferenza di tipo del conducente non li riconosce, il che provoca comportamenti inaspettati.

Correzione :

Converti i valori numpy in tipi nativi di Python prima di binding:

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"])}
    )

Per dataset più grandi, si usano invece i percorsi di integrazione Arrow o pandas , che gestiscono internamente la conversione dei tipi.

Copia di massa con tabelle temporanee

Sintomi:

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

Causa:

bulkcopy() Non è possibile risolvere le tabelle temporanee della sessione (#tablename) a causa delle limitazioni di ricerca dei metadati. Le tabelle temporanee globali (##tablename) e le tabelle permanenti funzionano.

Correzione :

Usa una tabella temporanea globale o una tabella di staging normale:

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

Per piccoli dataset in cui si preferisce una tabella temporanea di sessione, si usa executemany() invece:

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

Problemi di container e CI

Librerie di sistema mancanti su Linux

Sintomi:

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

Correzione :

Installa i pacchetti di sistema richiesti. I pacchetti differiscono per distribuzione:

Distribution Installa comando
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

Per esempi di Dockerfile, vedi Container e sviluppo locale.

Errori SSL di macOS dopo l'installazione

Sintomi:

Errori legati a SSL quando si connette da macOS, specialmente su Apple Silicon.

Correzione :

Installa OpenSSL tramite Homebrew e imposta i flag del linker:

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

Strumenti di diagnostica

Abilita il logging dei driver

Usa mssql_python.setup_logging() per abilitare una registrazione DEBUG completa per la diagnostica. Tutte le operazioni del driver sono registrate, inclusi istruzioni SQL, parametri, operazioni ODBC interne e cambiamenti dello stato della connessione.

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

I file di log sono scritti in formato CSV e ruotano automaticamente a 512 MB con cinque backup. I dati sensibili come password e token di accesso vengono automaticamente sanificati nell'output del log.

Per aggiungere le tue voci di log accanto ai log del driver, usa 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

Attenzione

Il logging ha un impatto sulle prestazioni. Attivalo solo durante la risoluzione dei problemi, non in produzione di default.

Ottieni informazioni sul conducente

Recupera la versione del driver e i dettagli del server da una connessione attiva:

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)}")

Controllare lo stato della connessione

Verifica se una connessione è ancora aperta prima di tentare le operazioni:

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

Riferimento rapido: Errori comuni

Error SQLSTATE Causa comune Correzione rapida
Il client non è in grado di stabilire la connessione 08001 Server non raggiungibile Controlla nome/porta server
Accesso non riuscito 28000 Credenziali sbagliate Verifica nome utente/password
Il timeout è scaduto HYT00/HYT01 Rete lenta Aumenta il timeout
Nome di oggetto non valido 42S02 Tabella/schema sbagliato Usa nomi pienamente qualificati
Errore di sintassi 42000 Errore SQL Usare query con parametri
Violazione del vincolo 23000 Violazione FK/PK Controlla l'integrità dei dati
Deadlock 40001 Conflitto di blocco Riprova, poi analizza il grafico dello stallo