Az mssql-python hibaelhárítása

Diagnosztizálni és megoldani a gyakori problémákat, amikor az mssql-python driverrel csatlakozunk az SQL Server-hez, Azure SQL Database-hez, Azure SQL Managed Instance-hoz és SQL database-hez a Microsoft Fabric-ben.

Telepítési problémák

A pip telepítése meghibásodik vagy forrásból épít

Tünetek:

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

Lehetséges okok és megoldások:

  • Nincs előre összeszerelt kerék a platformodhoz

    • Ellenőrizd, hogy támogatott Python verziót (3.10 és újabb verziók) és platformot használsz. A kompatibilitási mátrixot lásd a támogatási életciklusnál. Frissítsd a pip-et telepítés előtt .pip install --upgrade pip Az ismételhető csapatkörnyezetekhez használd a zárolt munkafolyamatot a Repeatable deployments részben, vagy a konténermintákat a Container and local development részben a helyi gépek közötti eltérések csökkentése érdekében.
  • Virtuális környezet nem aktiválva

    • Először aktiváld a virtuális környezetedet. A Python rendszerbe való telepítése jogosultsági hibákat vagy ütközéseket okozhat.
    python -m venv .venv
    .venv\Scripts\activate
    pip install mssql-python
    

  • Hiányzó Linux rendszerkönyvtárak

Ellentmondó illesztőprogram-telepítések

Tünetek:

Importálási hibák vagy váratlan működés, miután a(z) mssql-python és pyodbc ugyanabban a környezetben lett telepítve.

Javítás:

mssql-python és pyodbc együtt létezhetnek. Ha konfliktusokat látsz, hozz létre egy tiszta, virtuális környezetet:

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

Kapcsolódási problémák

Nem tudok csatlakozni a szerverhez

Tünetek:

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

Lehetséges okok és megoldások:

  • A szerver nem elérhető

    • Ellenőrizd a szerver neve és a port helyességét.
    • Ellenőrizze a hálózati kapcsolatot: ping servername vagy telnet servername 1433.
    • Győződj meg róla, hogy a tűzfal lehetővé teszi a kimenő kapcsolatokat a 1433-as porton.
  • SQL Server nem fut

    • Ellenőrizd, hogy az SQL Server szolgáltatás elindult.
    • Névos példányok esetén ellenőrizd, hogy az SQL Server böngésző szolgáltatás fut.
  • Azure SQL firewall rules

    • Adja hozzá az ügyfél IP-címét az Azure SQL tűzfal szabályaihoz az Azure portálban.
    • Azure SQL Managed Instance esetén győződj meg róla, hogy engedélyezett hálózatról csatlakozol.
# 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}")

A bejelentkezés sikertelen

Tünetek:

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

Lehetséges okok és megoldások:

  • Hitelesítési mód eltérése

    • Azure SQL Database, Azure SQL Managed Instance és SQL database in Fabric esetén előnyben részesítsünk egy Microsoft Entra módot, például Authentication=ActiveDirectoryDefault.
    • Ha szándékosan használod az SQL hitelesítést, ellenőrizd, hogy a szerver engedélyezi-e, és hogy a megfelelő bejelentkezési formátumot használod az adott végponthoz.
  • Hibás SQL hitelesítési adatok

    • Ellenőrizd a felhasználónevet és jelszót.
    • Azure SQL esetén add fel a teljes felhasználónevet: username@servername.
  • A felhasználó nem létezik az adatbázisban

    • Ellenőrizd, hogy a felhasználó hozzáfér a megadott adatbázishoz.
    • Ellenőrizd, hogy a bejelentkezés hozzá van-e rendelve egy adatbázis-felhasználóhoz.
  • Hitelesítés nem konfigurált

    • Használd a Microsoft Entra hitelesítést (ajánlott): Authentication=ActiveDirectoryDefault.
    • Ha egy helyi SQL Serveren végzel hibaelhárítást, amelynek engedélyeznie kell az SQL-hitelesítést, ellenőrizd, hogy az SQL Server vegyes módú hitelesítést használ.

Kapcsolati időkorlát

Tünetek:

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

Lehetséges okok és megoldások:

  • A szerver lassan válaszol

    • Növeld a kapcsolati időtúllépést:
    conn = mssql_python.connect(connection_string, timeout=60)
    
  • Hálózati késés

    • Ellenőrizd a szerver hálózati útvonalát.
    • Fontold meg rövidebb hálózati útvonal vagy VPN használatát.
  • Szerver nagy terhelés alatt

    • Próbálj meg csatlakozni csúcsidőn kívül.
    • Vegye fel a kapcsolatot az adatbázis-adminisztrátorával.

SSL-tanúsítványhibák

Tünetek:

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

Megoldások:

Először is, inkább megbízható tanúsítványt vagy a Container és helyi fejlesztési mintákat részesítse előnyben. TrustServerCertificate=yes Csak helyi fejlesztésre használd egy olyan szerver ellen, amit te irányítasz.

Önként aláírt tanúsítványsal történő fejlesztés és tesztelés:

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 csak helyi tartalékmegoldás. Ne vigye be megosztott fejlesztőkonténerekbe, CI pipeline-okba vagy termelési telepítésekbe. Szélesebb útmutatásért lásd: Titkosítás és tanúsítványok.

A gyártáshoz győződjön meg róla, hogy megfelelő tanúsítványok telepítve legyenek és használják:

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

Lekérdezés végrehajtási problémái

A tábla vagy objektum nem található

Tünetek:

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

Lehetséges okok és megoldások:

  • Rossz adatbázis-kontextus

    # Ensure you're connected to the correct database
    cursor.execute("SELECT DB_NAME()")
    print(cursor.fetchone()[0])
    
  • Nem meghatározott séma

    # Use fully qualified name
    cursor.execute("SELECT * FROM dbo.TableName")
    
  • A táblázat nem létezik

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

Szintaxishiba

Tünetek:

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

Megoldások:

  1. Először teszteld SQL-t SSMS-ben a szintaxis ellenőrzéséhez

  2. Ellenőrizd a karakterláncok escape-elését - használj paraméterezett lekérdezéseket:

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

Paraméterhibák

Tünetek:

ProgrammingError: [07001] Wrong number of parameters

Megoldások:

  1. Számold meg a helykitöltőket és paramétereket – egyezniük kell

  2. Válaszd ki a megfelelő paraméterstílust:

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

Adattípus-problémák

Dátumidő-átalakítási hibák

Tünetek:

DataError: [22007] Invalid datetime format

Megoldások:

Használj Python datetime objektumokat a stringek helyett:

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

Tizedes pontossági problémák

Tünetek:

A számok lerövidítettnek vagy helytelenül kerekítve jelennek meg.

Megoldások:

Pontos numerikus értékek felhasználása decimal.Decimal :

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 kódolási problémák

Tünetek:

A speciális karakterek zavarosnak tűnnek vagy hibákat okoznak.

Megoldások:

  1. Használj NVARCHAR oszlopokat Unicode adatokhoz az adatbázisodban

  2. Közvetlenül továbbítsa a stringeket – a meghajtó kezeli a kódolást:

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

Teljesítménnyel kapcsolatos problémák

Lassú lekérdezés végrehajtása

Lehetséges okok és megoldások:

  • Hiányzó indexek: Ellenőrizd a lekérdezés végrehajtási tervet az SSMS-ben.

  • Nagy eredményhalmazok: Használdfetchmany() helyettefetchall():

    cursor.arraysize = 1000
    while True:
         rows = cursor.fetchmany()
         if not rows:
             break
         process_rows(rows)
    
  • Kapcsolat-összevonás letiltva: Kapcsolja be a kapcsolat-összevonást:

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

Memóriaproblémák nagy méretű eredmények esetén

Tünetek:

A Python-folyamat kifogy a memóriából.

Megoldások:

  1. Az eredmények streamelése ahelyett, hogy mindent a memóriába töltene:

    cursor.execute("SELECT * FROM LargeTable")
    for row in cursor:  # Iterates one row at a time
        process_row(row)
    
  2. Használj szerveroldali oldali lapozást:

    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
    

Tranzakciós problémák

Ideiglenes táblák hatóköre automatikus véglegesítés mellett

A tranzakción belül létrehozott ideiglenes táblák (#tablename) eltűnnek, amikor a tranzakciót visszafordítják. Ez a gyakori félreértések forrása, amikor az automatikus véglegesítés ki van kapcsolva (ez az alapértelmezett):

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

Javítás: Azonnal commit egy ideiglenes tábla létrehozása után, vagy használj automatikus commit módot:

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 utasítások, amelyek automatikus commit módot igényelnek, például CREATE DATABASE, egy nyílt tranzakcióban meghibásodnak. Állítsd be az automatikus köteleződést, mielőtt futtatnád őket:

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

Nem végrehajtott tranzakció

Tünetek:

Az adatváltozások nem maradnak fenn a kapcsolat zárása után.

Solution:

A autocommit=False (alapértelmezett) esetén hívnod commit()kell:

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!

Vagy használj automatikus commit módot:

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

Holtzárhibák

Tünetek:

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

Solution:

Az újrapróbálkozás logikája (lásd Retry logika) kezeli az azonnali hibát, de az ismétlődő holtpontok tervezési problémára utalnak. A kiváltó ok elhárításához rögzítse a holtpontgráfot, és elemezze, mely utasítások és zárolási típusok érintettek. Gyakori megoldások közé tartozik a műveletek átrendezése, hogy a versengő tranzakciók ugyanabban a sorrendben szerezzék meg a zárokat, a tranzakciós hatókör csökkentése, valamint megfelelő indexek hozzáadása a zár időtartamának csökkentése érdekében.

A holthelyzet elemzésének teljes végigjátszásáért lásd a Deadlocks útmutatót. Ha az Azure SQL Database-t használja, lásd: A holtpontok elemzése és megelőzése.

Tömegterhelési problémák

Korlátok megsértése tömegmásolás során

Tünetek:

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

A probléma oka

A batch-ben lévő adatok megszegik a táblakorlátozásokat (elsődleges kulcs, egyedi, CHECK vagy idegen kulcs).

Javítás:

Ellenőrizd az adatokat betöltés előtt. Nagy adathalmazok esetén először töltsd be egy köztes táblába, majd egyesítsd a céltáblával:

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

Az átmeneti táblákat használó upsert mintákkal kapcsolatban lásd a következőt: Adatbetöltési és -mozgatási minták.

Oszlopleképezési hibák

Tünetek:

RuntimeError: Bulk copy failure - column count mismatch

A probléma oka

Az adatodban lévő oszlopok száma nem egyezik a céltáblás oszlopszámmal, vagy az oszlopok rossz sorrendben vannak.

Javítás:

Győződj meg róla, hogy adataid pontosan egyeznek a táblázat sémájával sorrendben és számban:

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

Típusütközések tömeges másolás során

Tünetek:

Az adat betöltődik, de az értékek lerövidítettek, kerekítettek vagy helytelenek.

A probléma oka

A Python értékek nem egyeznek tisztán a céloszlop típusokkal. Gyakori esetek: a float oszlopokba betöltött értékek (decimal miatti pontosságvesztés), illetve a rögzített hosszúságú oszlopokba betöltött túl hosszú karakterláncok.

Javítás:

Használd a megfelelő Python típusokat, amelyek illeszkednek a sémádhoz:

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)

Numpy típusú kötéshibák

Tünetek:

A paraméterek csendben hibásodnak vagy adattípus-hibákat okoznak, ha numpy egész vagy lebegő típusokat használnak.

A probléma oka

Az olyan NumPy-típusok, mint a numpy.int64 és a numpy.int32, nem mennek át a isinstance(x, int) ellenőrzésen a NumPy 2.x verzióban. A sofőr típuskövetkeztetése nem ismeri fel őket, ami váratlan viselkedést okoz.

Javítás:

A numpy értékeket natív Python típusokra konvertáljuk kötés előtt:

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

Nagyobb adathalmazoknál inkább az Arrow vagy a pandas integrációs útvonalakat használjuk, amelyek a típusváltást belsőleg kezelik.

Bulkcopy ideiglenes táblázatokkal

Tünetek:

cursor.bulkcopy("#TempTable", data) megemeli a(z) RuntimeError: Invalid object name '#TempTable' értékét.

A probléma oka

bulkcopy() Nem tudom megoldani a session temp táblákat (#tablename) a metaadat-lekérdezés korlátai miatt. A globális hőmérsékleti táblázatok (##tablename) és az állandó táblázatok működnek.

Javítás:

Használj globális temp táblát vagy hagyományos staging table-t:

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

Kis adathalmazok esetén, amikor a munkamenet-ideiglenes tábla az előnyben részesített, használja inkább ezt: executemany()

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

Konténer- és CI problémák

Hiányzó rendszerkönyvtárak Linuxon

Tünetek:

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

Javítás:

Telepítsd a szükséges rendszercsomagokat. A csomagok eloszlás szerint különböznek:

Distribution Parancs telepítése
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

Dockerfile példákért lásd: Container és helyi fejlesztés.

macOS SSL hibák telepítés után

Tünetek:

SSL-lel kapcsolatos hibák macOS rendszerből történő csatlakozáskor, különösen Apple Siliconon.

Javítás:

Telepítsd az OpenSSL-t Homebrew-en keresztül, és állítsd be a linker zászlókat:

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

Diagnosztikai eszközök

Illesztőprogram-naplózás engedélyezése

Használd mssql_python.setup_logging() az átfogó DEBUG naplózás engedélyezésére hibakereséshez. Minden driver műveletet naplóznak, beleértve az SQL utasításokat, paramétereket, belső ODBC műveleteket és a kapcsolati állapotváltozásokat.

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

A naplófájlok CSV formátumban íródnak, és automatikusan forgathatók 512 MB-nál öt biztonsági mentéssel. Az érzékeny adatokat, például a jelszavakat és a hozzáférési tokeneket, a rendszer automatikusan maszkolja a naplókimenetben.

Saját naplóbejegyzések hozzáadásához a driver-naplók mellé használd 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

A naplózás teljesítményterheléssel jár. Csak hibakeresés közben engedélyezze, nem a gyártásban alapértelmezettben.

Sofőrinformációk

A meghajtó verzió és a szerver adatai előhívása egy aktív kapcsolatról:

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

Kapcsolat állapotának ellenőrzése

Teszteljük, hogy a kapcsolat még nyitva van-e a műveletek megkezdése előtt:

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

Gyors hivatkozás: Gyakori hibák

Hiba SQLSTATE Közös ok Gyors javítás
Az ügyfél nem tudja kapcsolatot teremteni 08001 A kiszolgáló nem érhető el Ellenőrizd a szerver nevet/portot
A bejelentkezés sikertelen 28000 Rossz képesítések Ellenőrizd a felhasználónevet/jelszót
Időtúllépés történt HYT00/HYT01 Lassú hálózat Időtúllépés növelése
Érvénytelen objektumnév 42S02 Rossz táblázat/séma Teljesen minősített neveket használj
Szintaxishiba 42000 SQL hiba Paraméteres lekérdezések használata
Kényszer megsértése 23000 FK/PK-sértés Ellenőrizd az adatintegritást
Holtzár 40001 Zárolási ütközés Próbáld újra, majd elemezd a holtpont grafikont