Řešení potíží s mssql-python

Diagnostikujte a vyřešte běžné problémy při použití ovladače mssql-python pro připojení k SQL Server, Azure SQL Database, Azure SQL Managed Instance a SQL databázi v Microsoft Fabric.

Problémy s instalací

Instalace PIP selže nebo se sestaví ze zdrojového kódu

Příznaky:

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

Možné příčiny a řešení:

  • Pro vaši platformu není k dispozici žádný předem sestavený balíček wheel

    • Zkontrolujte, že používáte podporovanou verzi Python (verze 3.10 a vyšší) a platformu. Viz Životní cyklus podpory, kde najdete matici kompatibility. Před instalací pomocí pip install --upgrade pip aktualizujte pip. Pro opakovatelná prostředí pro týmy použijte uzamčený workflow v Opakovatelných nasazeních nebo kontejnerové postupy v Kontejnerech a místním vývoji, abyste omezili odchylky v konfiguraci místních počítačů.
  • Virtuální prostředí neaktivováno

    • Nejprve aktivujte své virtuální prostředí. Instalace Python do systému může způsobit chyby oprávnění nebo konflikty.
    python -m venv .venv
    .venv\Scripts\activate
    pip install mssql-python
    

Konfliktní instalace ovladačů

Příznaky:

Chyby při importu nebo neočekávané chování po instalaci mssql-python spolu s pyodbc ve stejném prostředí.

Oprava:

mssql-python a pyodbc mohou koexistovat. Pokud vidíte konflikty, vytvořte čisté virtuální prostředí:

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

Problémy s připojením

Nelze se připojit k serveru

Příznaky:

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

Možné příčiny a řešení:

  • Server není dostupný

    • Ověřte, že název serveru a port jsou správné.
    • Zkontrolujte síťové připojení: ping servername nebo telnet servername 1433.
    • Ujistěte se, že firewall umožňuje odchozí připojení na portu 1433.
  • SQL Server neběží

    • Ověřte, že služba SQL Server je spuštěna.
    • Pro pojmenované instance ověřte, že služba SQL Server Browser běží.
  • Azure SQL firewall rules

    • Přidejte IP klienta do pravidel Azure SQL firewallu v Azure portálu.
    • Pro Azure SQL Managed Instance se ujistěte, že se připojujete z povolené sítě.
# 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}")

Přihlášení se nezdařilo.

Příznaky:

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

Možné příčiny a řešení:

  • Nesoulad autentizačního režimu

    • Pro Azure SQL Database, Azure SQL Managed Instance a SQL database in Fabric preferují režim Microsoft Entra, například Authentication=ActiveDirectoryDefault.
    • Pokud používáte SQL autentizaci záměrně, ověřte, že server to umožňuje a že používáte správný přihlašovací formát pro daný endpoint.
  • Nesprávné SQL autentizační údaje

    • Ověřte uživatelské jméno a heslo.
    • Pro Azure SQL zahrňte celé uživatelské jméno: username@servername.
  • Uživatel v databázi neexistuje

    • Ověřte, že uživatel má přístup ke specifikované databázi.
    • Zkontrolujte, zda je přihlášení přiřazeno uživateli databáze.
  • Autentizace není nakonfigurována

    • Používejte Microsoft Entra autentizaci (doporučeno): Authentication=ActiveDirectoryDefault.
    • Pokud řešíte problém s lokálním SQL Server, který by měl přijímat SQL autentizaci, ověřte, že SQL Server používá smíšené režimy autentizace.

Časový limit připojení vypršel

Příznaky:

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

Možné příčiny a řešení:

  • Server reaguje pomalu

    • Zvyšte časový limit připojení:
    conn = mssql_python.connect(connection_string, timeout=60)
    
  • Latence sítě

    • Zkontrolujte síťovou cestu na server.
    • Zvažte použití kratší síťové cesty nebo VPN.
  • Server pod velkým zatížením

    • Zkuste se připojit mimo špičku.
    • Kontaktujte správce své databáze.

Chyby certifikátu SSL

Příznaky:

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

Řešení:

Za prvé, preferujte důvěryhodný certifikát nebo místní vývojové vzorce v kontejnerech a lokálním rozvoji. Používejte TrustServerCertificate=yes pouze pro lokální vývoj na serveru, který ovládáte.

Pro vývoj a testování s vlastním podpisem certifikátu:

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 je to záložní varianta pouze pro místní obyvatele. Nepřenášej to do sdílených vývojových kontejnerů, kanálů CI ani produkčních nasazení. Pro širší pokyny viz Šifrování a certifikáty.

Pro výrobu zajistěte instalaci správných certifikátů a použijte:

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

Problémy s prováděním dotazů

Tabulka nebo objekt nenalezený

Příznaky:

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

Možné příčiny a řešení:

  • Špatný kontext databáze

    # Ensure you're connected to the correct database
    cursor.execute("SELECT DB_NAME()")
    print(cursor.fetchone()[0])
    
  • Schéma nespecifikované

    # Use fully qualified name
    cursor.execute("SELECT * FROM dbo.TableName")
    
  • Tabulka neexistuje

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

Chyba syntaxe

Příznaky:

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

Řešení:

  1. Nejprve otestujte SQL v SSMS, abyste ověřili syntaxi

  2. Zkontrolujte escapování řetězců – použijte parametrizované dotazy:

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

Chyby parametrů

Příznaky:

ProgrammingError: [07001] Wrong number of parameters

Řešení:

  1. Počítejte zástupné znaky a parametry – musí se shodovat

  2. Vyberte správný styl parametrů:

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

Problémy s datovými typy

Chyby při převodu data a času

Příznaky:

DataError: [22007] Invalid datetime format

Řešení:

Používejte Python datetime objekty místo řetězců:

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

Problémy s desetinnou přesností

Příznaky:

Čísla se zobrazují oříznutá nebo nesprávně zaokrouhlená.

Řešení:

Použití decimal.Decimal pro přesné číselné hodnoty:

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

Problémy s kódováním v Unicode

Příznaky:

Speciální znaky se objevují zkresleně nebo způsobují chyby.

Řešení:

  1. Používejte sloupce NVARCHAR pro Unicode data ve vaší databázi

  2. Předávejte řetězce přímo – ovladač zajišťuje kódování:

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

Problémy s výkonem

Pomalé provádění dotazů

Možné příčiny a řešení:

  • Chybějící indexy: Zkontrolujte plán provádění dotazů v SSMS.

  • Velké množiny výsledků: Použijte fetchmany() místo :fetchall()

    cursor.arraysize = 1000
    while True:
         rows = cursor.fetchmany()
         if not rows:
             break
         process_rows(rows)
    
  • Sdružování připojení je zakázáno: Povolte sdružování připojení:

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

Problémy s pamětí při velkých výsledcích

Příznaky:

Procesu Python dochází paměť.

Řešení:

  1. Výsledky streamu místo načítání všeho do paměti:

    cursor.execute("SELECT * FROM LargeTable")
    for row in cursor:  # Iterates one row at a time
        process_row(row)
    
  2. Použijte stránkování na straně serveru:

    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
    

Problémy s transakcí

Rozsah platnosti dočasné tabulky s autocommit režimem

Dočasné tabulky (#tablename) vytvořené uvnitř transakce zmizí, když je transakce vrácena zpět. To je častý zdroj zmatku, když je automatický commit vypnutý (výchozí):

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

Oprava: Potvrďte transakci ihned po vytvoření dočasné tabulky nebo použijte režim automatického potvrzování:

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 příkazy, které vyžadují automatický commit režim, například CREATE DATABASE, selžou uvnitř otevřené transakce. Nastavte automatický commit před jejich spuštěním:

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

Transakce neprovedena

Příznaky:

Změny dat se po uzavření připojení nepřetrvávají.

Solution:

S autocommit=False (výchozí) musíte zavolat 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!

Nebo použijte režim automatického závazku:

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

Chyby zablokování

Příznaky:

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

Solution:

Logika opakování (viz logika opakování) řeší okamžité selhání, ale opakující se patové situace naznačují problém v návrhu. Chcete-li odstranit hlavní příčinu, zachyťte graf uváznutí a analyzujte, které příkazy a typy zámků se na něm podílejí. Běžné opravy zahrnují přeuspořádání operací, aby konkurenční transakce získaly zámky ve stejné sekvenci, což omezuje rozsah transakcí a přidává vhodné indexy ke zkrácení doby zámku.

Podrobný návod k analýze deadlocků najdete v článku Průvodce deadlocky. Pokud používáte Azure SQL Database, podívejte se na Analyzovat a předcházet zablokování.

Problémy s hromadným zatížením

Porušení omezení během hromadného kopírování

Příznaky:

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

Příčina:

Data ve vaší dávce porušují omezení tabulky (primární klíč, omezení jedinečnosti, CHECK nebo cizí klíč).

Oprava:

Před načtením ověřte data. Pro velké datové sady je nejprve načtěte do pracovní tabulky a poté je sloučte do cílové tabulky:

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

Vzory pro operace upsert s přípravnými tabulkami najdete v tématu Vzory načítání a přesunu dat.

Chyby při mapování sloupců

Příznaky:

RuntimeError: Bulk copy failure - column count mismatch

Příčina:

Počet sloupců ve vašich datech neodpovídá počtu sloupců v cílové tabulce, nebo jsou sloupce ve špatném pořadí.

Oprava:

Ujistěte se, že vaše data přesně odpovídají schématu tabulky v pořadí a počtu:

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

Typové neshody během hromadné kopie

Příznaky:

Data se načítají, ale hodnoty jsou zkrácené, zaokrouhlené nebo nesprávné.

Příčina:

Hodnoty Pythonu nelze jednoznačně mapovat na typy cílových sloupců. Běžné případy: float hodnoty načtené do decimal sloupců (ztráta přesnosti) nebo nadměrně velké řetězce načtené do sloupců s pevnou délkou.

Oprava:

Použijte správné typy Python, které odpovídají vašemu schématu:

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)

Selhání vázání typu Numpy

Příznaky:

Parametry při použití celočíselných typů NumPy nebo typů s plovoucí desetinnou čárkou buď tiše selžou, nebo vyvolají chyby datového typu.

Příčina:

Typy NumPy, jako numpy.int64 a numpy.int32, neprojdou přes isinstance(x, int) v NumPy 2.x. Typová inference řidiče je nerozpozná, což způsobuje neočekávané chování.

Oprava:

Převeďte hodnoty NumPy na nativní typy jazyka Python před navázáním:

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

Pro větší datové sady použijte integrační cesty Arrow nebo pandas , které interně řeší převod typů.

Bulkcopy s dočasnými tabulkami

Příznaky:

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

Příčina:

bulkcopy() nelze rozpoznat dočasné tabulky relace (#tablename) kvůli omezením při vyhledávání metadat. Globální dočasné tabulky (##tablename) a trvalé tabulky fungují.

Oprava:

Použijte globální dočasnou tabulku nebo běžnou pracovní tabulku:

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

Pro malé datové sady, kde je preferována tabulka session temp, použijte executemany() místo toho:

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

Problémy s kontejnery a CI

Chybějící systémové knihovny na Linuxu

Příznaky:

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

Oprava:

Nainstalujte potřebné systémové balíčky. Balíčky se liší podle rozdělení:

Distribution Instalační příkaz
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

Pro příklady Dockerfile viz Container a lokální vývoj.

Chyby macOS SSL po instalaci

Příznaky:

Chyby související se SSL při připojení z macOS, zejména na Apple Silicon.

Oprava:

Nainstalujte OpenSSL pomocí Homebrew a nastavte příznaky pro linker:

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

Diagnostické nástroje

Povolit logování ovladačů

Použijte mssql_python.setup_logging() pro povolení komplexního DEBUG logování pro řešení problémů. Všechny operace ovladačů jsou zaznamenány, včetně SQL příkazů, parametrů, interních operací ODBC a změn stavu spojení.

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

Protokolové soubory se ukládají ve formátu CSV a při dosažení velikosti 512 MB se automaticky rotují s uchováním pěti záložních souborů. Citlivá data jako hesla a přístupové tokeny jsou automaticky sanitizována ve výstupu z logu.

Pro přidání vlastních záznamů v logu vedle záznamů řidičů použijte 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

Logování má dopad na výkon. Zapněte ho pouze při řešení problémů, ne ve výchozím nastavení v produkci.

Získejte informace o řidiči

Získejte verzi ovladače a detaily serveru z aktivního připojení:

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

Kontrola stavu připojení

Otestujte, zda je spojení stále otevřené, než se pokusíte o operace:

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

Rychlá reference: Běžné chyby

Error SQLSTATE Obvyklá příčina Rychlá oprava
Klient nedokáže navázat spojení 08001 Nedostupný server Zkontrolujte název serveru/port
Přihlášení se nezdařilo. 28000 Špatné kvalifikace Ověřte uživatelské jméno/heslo
Vypršel časový limit. HYT00/HYT01 Pomalá síť Zvyšte časový limit
Neplatný název objektu 42S02 Špatná tabulka/schéma Používejte plně kvalifikovaná jména
Chyba syntaxe 42000 SQL chyba Použití parametrizovaných dotazů
Porušení omezení 23000 Porušení FK/PK Zkontrolujte integritu dat
Vzájemné zablokování 40001 Soutěž o zámky Zkuste to znovu a poté analyzujte graf uváznutí