Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Nutzen Sie diesen Artikel, um Probleme mit der Abfrageausführung, Datentyp, Performance, Transaktionen und Massenkopien mit dem mssql-python Treiber zu diagnostizieren.
Abfrageausführungsprobleme
Tabelle oder Objekt nicht gefunden
Symptome:
ProgrammingError: [42S02] (208) Invalid object name 'TableName'.
Mögliche Ursachen und Lösungen:
Falscher Datenbankkontext
cursor.execute("SELECT DB_NAME()") print(cursor.fetchone()[0])Schema nicht spezifiziert
cursor.execute("SELECT * FROM dbo.TableName")Tabelle existiert nicht
cursor.execute(""" SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'TableName' """)
Syntaxfehler
Symptome:
ProgrammingError: [42000] (102) Incorrect syntax near '...'.
Lösungen :
Testen Sie die SQL-Anweisung in SQL Server Management Studio (SSMS), um die Syntax zu überprüfen.
Verwenden Sie eine parametrisierte Abfrage anstelle von String-Interpolation:
# Don't use string interpolation for query parameters. cursor.execute(f"SELECT * FROM Production.Product WHERE Name = '{name}'") # Use parameters. cursor.execute( "SELECT * FROM Production.Product WHERE Name = %(name)s", {"name": name}, )
Parameterfehler
Symptome:
ProgrammingError: [07001] Wrong number of parameters
Lösungen :
Zähle die Platzhalter und Parameter. Die Zählungen müssen übereinstimmen.
Wählen Sie den richtigen Parameterstil:
# Qmark style: positional parameters cursor.execute( "SELECT * FROM Production.Product " "WHERE ProductID = ? AND Name LIKE ?", (1, "Adjustable%"), ) print(cursor.fetchone()) # Pyformat style: named parameters 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
Solution:
Verwende Python-Objekte datetime statt Strings.
from datetime import datetime
cursor.execute("CREATE TABLE #Events (EventDate DATETIME)")
# This value raises an error because the date is invalid.
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}")
# Use a Python datetime object.
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.
Solution:
Verwendung decimal.Decimal für präzise Zahlenwerte:
from decimal import Decimal
cursor.execute("CREATE TABLE #PriceDemo (ListPrice DECIMAL(10, 2))")
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 :
Verwenden Sie für Unicode-Daten in Ihrer Datenbank Spalten vom Typ nvarchar.
Übergeben Sie Zeichenfolgen direkt. Der Treiber übernimmt die Codierung:
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
fetchmany()Sie statt :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 :
Streame Ergebnisse, anstatt alle Zeilen in den Speicher zu laden.
cursor.execute("SELECT * FROM LargeTable") for row in cursor: process_row(row)Verwende 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 von temporären Tabellen mit Autocommit
Sitzungstemporäre Tabellen (#tablename), die du innerhalb einer Transaktion erstellst, verschwinden, wenn die Transaktion zurückrollt. Dieses Verhalten führt häufig zu Verwirrung, wenn Autocommit deaktiviert ist, was standardmäßig der Fall ist:
conn = mssql_python.connect(connection_string)
cursor = conn.cursor()
cursor.execute("CREATE TABLE #TempData (ID INT, Name NVARCHAR(50))")
cursor.execute("INSERT INTO #TempData VALUES (1, 'test')")
# An explicit rollback or an error removes #TempData.
conn.rollback()
# This statement fails with "Invalid object name '#TempData'".
cursor.execute("SELECT * FROM #TempData")
Commit unmittelbar, nachdem du eine temporäre Tabelle erstellt hast, oder nutze den Autocommit-Modus:
cursor.execute("CREATE TABLE #TempData (ID INT, Name NVARCHAR(50))")
conn.commit()
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 nicht bestehen, nachdem du die Verbindung geschlossen hast.
Solution:
Mit autocommit=False, was die Standardeinstellung ist, rufen Sie commit() auf:
cursor.execute("CREATE TABLE #Products (Name NVARCHAR(100))")
cursor.execute(
"INSERT INTO #Products (Name) VALUES (%(name)s)",
{"name": "Widget"},
)
conn.commit()
Alternativ verwenden Sie 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:
Die Wiederholungslogik übernimmt das unmittelbare Scheitern, aber wiederkehrende Deadlocks deuten auf ein Designproblem hin. Erfassen Sie den Deadlock-Graphen und analysieren Sie die Anweisungen und Sperrtypen. Häufige Korrekturen umfassen folgende Änderungen:
- Ordnen Sie die Operationen so neu, dass konkurrierende Transaktionen Sperren in derselben Reihenfolge anfordern.
- Reduzieren Sie den Transaktionsumfang.
- Fügen Sie passende Indizes hinzu, um die Sperrdauer zu verkürzen.
Eine vollständige Anleitung zur Deadlock-Analyse finden Sie im Leitfaden zu Deadlocks. Wenn Sie eine Azure SQL-Datenbank verwenden, siehe Analysieren und Deadlocks verhindern.
Probleme beim Massenladen
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 Tabellenbedingungen wie Primärschlüssel-, Unique-, Check- oder Fremdschlüssel-Constraints.
Solution:
Validiere die Daten, bevor du es lädst. Für große Datensätze laden Sie die Daten in eine Staging-Tabelle und führen Sie sie dann in das Ziel ein:
cursor.execute("CREATE TABLE ##Staging (ID INT, Name NVARCHAR(100))")
cursor.bulkcopy("##Staging", rows)
# Check for duplicate rows before the merge.
cursor.execute("""
SELECT s.ID
FROM ##Staging AS s
INNER JOIN dbo.Target AS t
ON s.ID = t.ID
""")
dupes = cursor.fetchall()
if dupes:
print(f"Skipping {len(dupes)} duplicate rows")
# Insert rows that don't exist in the target.
cursor.execute("""
INSERT INTO dbo.Target (ID, Name)
SELECT s.ID, s.Name
FROM ##Staging AS s
WHERE NOT EXISTS (
SELECT 1
FROM dbo.Target AS 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 Anzahl der Kolonnen in der Zieltabelle, oder die Spalten sind in der falschen Reihenfolge.
Solution:
Stellen Sie sicher, dass Ihre Daten in der Reihenfolge und Anzahl mit dem Tabellenschema übereinstimmen:
from decimal import Decimal
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)
rows = [
(1, "Widget", Decimal("19.99")),
(2, "Gadget", Decimal("29.99")),
]
cursor.bulkcopy("dbo.MyTable", rows)
Typabweichungen beim Massenkopieren
Symptome:
Die Daten werden geladen, aber die Werte sind gekürzt, gerundet oder falsch.
Ursache:
Python-Werte werden nicht sauber auf die Ziel-Spaltentypen abgebildet. Gängige Beispiele sind float Werte, die in Dezimalspalten geladen werden und an Präzision verlieren können, sowie übergroße Strings, die in feste Spalten geladen werden.
Solution:
Verwenden Sie Python-Typen, die zu Ihrem Schema passen:
from decimal import Decimal
rows = [
# Use Decimal for decimal and numeric columns.
(1, "Widget", Decimal("19.99")),
# Avoid float values because they can lose precision.
# (1, "Widget", 19.99),
]
cursor.bulkcopy("dbo.Products", rows)
NumPy-Typbindungsfehler
Symptome:
Parameter schlagen lautlos fehl oder verursachen Datentypfehler, wenn du NumPy-Ganzzahl- oder Gleitmein-Typen verwendest.
Ursache:
NumPy-Typen wie numpy.int64 und numpy.int32 bestehen in NumPy 2.x isinstance(x, int) nicht. Die Typinferenz des Fahrers erkennt sie nicht, was zu unerwartetem Verhalten führt.
Solution:
Konvertiere NumPy-Werte in native Python-Typen, bevor du sie bindest:
import numpy as np
cursor.execute(
"SELECT * FROM Production.Product WHERE ProductID = %(product_id)s",
{"product_id": int(np.int64(42))},
)
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 die Arrow- oder Pandas-Integrationspfade. Diese Pfade übernehmen die Typumwandlung intern.
Massenkopieren 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.
Solution:
Verwenden Sie eine globale temporäre Tabelle oder eine reguläre Stagingtabelle:
# A global temp table is visible to all sessions and is dropped
# when the last session disconnects.
cursor.execute("CREATE TABLE ##Staging (ID INT, Name NVARCHAR(50))")
cursor.bulkcopy("##Staging", rows)
# Alternatively, 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 Sie eine temporäre Sitzungstabelle bevorzugen, verwenden Sie executemany():
cursor.execute("CREATE TABLE #Staging (ID INT, Name NVARCHAR(50))")
cursor.executemany(
"INSERT INTO #Staging (ID, Name) VALUES (?, ?)",
rows,
)