Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Gebruik dit artikel om problemen met query-uitvoering, datatype, prestaties, transacties en bulkkopieën met de mssql-python driver te diagnosticeren.
Problemen met de uitvoering van query's
Tabel of object niet gevonden
Symptomen:
ProgrammingError: [42S02] (208) Invalid object name 'TableName'.
Mogelijke oorzaken en oplossingen:
Onjuiste databasecontext
cursor.execute("SELECT DB_NAME()") print(cursor.fetchone()[0])Schema niet gespecificeerd
cursor.execute("SELECT * FROM dbo.TableName")Tabel bestaat niet
cursor.execute(""" SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'TableName' """)
Syntaxisfout
Symptomen:
ProgrammingError: [42000] (102) Incorrect syntax near '...'.
Oplossingen:
Test de SQL-instructie in SQL Server Management Studio (SSMS) om de syntaxis te controleren.
Gebruik een geparametriseerde query in plaats van stringinterpolatie:
# 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}, )
Parameterfouten
Symptomen:
ProgrammingError: [07001] Wrong number of parameters
Oplossingen:
Tel de tijdelijke en parameters mee. De tellingen moeten overeenkomen.
Kies de juiste parameterstijl:
# 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())
Onjuiste aantallen rijen in batches met meerdere resultsets
Als rowcount na nextset() het aantal van de eerste instructie opnieuw weergeeft, upgrade dan het stuurprogramma. Elke succesvolle nextset() update werkt het aantal voor het nieuwe resultaat bij. Een resultaat dat rijen oplevert start op -1 vóór het ophalen. Controleer cursor.description vóór het ophalen, omdat data-modificatieresultaten tellingen bevatten in plaats van rijen.
Laat SET NOCOUNT weg wanneer je resultaten van beïnvloede rijen nodig hebt. Voor een volledig voorbeeld, zie Elk resultaat in een batch bijhouden.
Datatypeproblemen
Fouten bij data-tijdconversie
Symptomen:
DataError: [22007] Invalid datetime format
Solution:
Gebruik Python-objecten datetime in plaats van 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())
De constructor van Timestamp vereist een microseconde-argument
Als Timestamp(year, month, day, hour, minute, second)microsecond genereert voor een ontbrekend TypeError-argument, upgrade dan mssql-python. De huidige driver accepteert de zes-arguments DB-API constructor en zet microsecond standaard op nul. Voor meer informatie, zie DB-API tijdstempelconstructor.
Decimale precisieproblemen
Symptomen:
Getallen lijken afgekapt of onjuist afgerond.
Solution:
Gebruik decimal.Decimal voor precieze numerieke waarden:
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-coderingsproblemen
Symptomen:
Speciale tekens lijken onverstaanbaar of veroorzaken fouten.
Oplossingen:
Gebruik nvarchar-kolommen voor Unicode-data in je database.
Geef de snaren direct door. De driver verzorgt de codering:
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())
Prestatieproblemen
Langzame query-uitvoering
Mogelijke oorzaken en oplossingen:
Ontbrekende indexen: Controleer het query-uitvoeringsplan in SSMS.
Grote resultaatsets: Gebruik
fetchmany()in plaats vanfetchall():cursor.arraysize = 1000 while True: rows = cursor.fetchmany() if not rows: break process_rows(rows)Verbindingspooling uitgeschakeld: Pooling inschakelen:
import mssql_python mssql_python.pooling(max_size=20, idle_timeout=300)
Geheugenproblemen met grote resultaten
Symptomen:
Het Python-proces heeft onvoldoende geheugen.
Oplossingen:
Stream resultaten in plaats van alle rijen in het geheugen te laden.
cursor.execute("SELECT * FROM LargeTable") for row in cursor: process_row(row)Gebruik server-side paginering.
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
Transactieproblemen
Bereik van tijdelijke tabellen met autocommit
Sessietijdelijke tabellen (#tablename) die je binnen een transactie aanmaakt, verdwijnen wanneer de transactie wordt teruggerold. Dit gedrag veroorzaakt vaak verwarring wanneer autocommit uit staat, wat standaard is:
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 direct nadat je een tijdelijke tabel hebt gemaakt, of gebruik de 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-instructies die autocommit vereisen, zoals CREATE DATABASE, falen binnen een open transactie. Stel autocommit in voordat je ze uitvoert:
conn.autocommit = True
cursor.execute("CREATE DATABASE TestDB")
conn.autocommit = False
Transactie niet gerealiseerd
Symptomen:
Datawijzigingen blijven niet bestaan nadat je de verbinding hebt gesloten.
Solution:
Met autocommit=False, wat de standaard is, roep commit():
cursor.execute("CREATE TABLE #Products (Name NVARCHAR(100))")
cursor.execute(
"INSERT INTO #Products (Name) VALUES (%(name)s)",
{"name": "Widget"},
)
conn.commit()
Alternatief kun je de autocommit-modus gebruiken:
conn = mssql_python.connect(connection_string, autocommit=True)
Deadlockfouten
Symptomen:
OperationalError: [40001] (1205) Transaction ... was deadlocked on lock resources with another process
Solution:
Herprobeerlogica zorgt voor het directe falen, maar terugkerende deadlocks wijzen op een ontwerpprobleem. Leg het deadlockdiagram vast en analyseer de instructies en vergrendelingstypen. Veelvoorkomende oplossingen zijn onder andere de volgende wijzigingen:
- Herordeningsoperaties zodat concurrerende transacties vergrendelingen in dezelfde volgorde krijgen.
- Verminder de reikwijdte van transacties.
- Voeg passende indexen toe om de duur van de vergrendeling te verkorten.
Voor een volledige walkthrough van deadlock-analyse, zie de Deadlocks-gids. Als je Azure SQL Database gebruikt, zie Deadlocks analyseren en voorkomen.
Problemen met bulklading
Bulkkopiëren mislukt na een upgrade van een pakket
Als reguliere queries werken maar bulkcopy() of bulkcopy_arrow() er niet in slagen de native bulk copy-module te importeren of te laden, upgrade dan de driver met afhankelijkheden:
python -m pip install --upgrade mssql-python
python -m pip check
De driver vereist een overeenkomende mssql-python-rs runtime. Een gedeeltelijke upgrade of installatie met --no-deps kan incompatibele pakketten geïnstalleerd laten. Als je een private package index gebruikt, spiegel dan beide companion packages en behoud de door de driver gedeclareerde vastgezette afhankelijkheidsversies. Voor de huidige vastgezette versies, zie Vereisten voor afhankelijkheden.
Niet-ondersteunde bestemmingsnamen
bulkcopy() en bulkcopy_arrow() accepteren maximaal drie identificatieonderdelen. Een vierdelige naam zoals server.database.schema.table veroorzaakt RuntimeError tijdens het opzoeken van metagegevens voordat er rijen worden verzonden. Maak direct verbinding met de bestemmingsserver en gebruik een tabelnaam van één deel, twee of drie delen. Voor haakjesontsnapping en fouten door ongeldige namen, zie namen van doeltabellen.
Unicode of fracties van seconden verloren tijdens bulkkopiëren
Upgrade de driver als bulkkopie UTF-8-tekst beschadigt of fracties van seconden afsnijdt bij het laden van compatibele datetime2-waarden . De huidige bulk-copy runtime verwerkt UTF-8 tekst en behoudt de datetime2 precisie beschikbaar in de bron- en bestemmingstypen.
Gebruik nvarchar of een UTF-8-collatie op varchar voor Unicode-tekst. Python-waarden datetime en de Arrow-ophaalmethoden van de driver zijn beperkt tot microseconden. Voor waarden in stappen van 100 nanoseconden die al in een Arrow-nanoseconde-tijdstempelkolom staan, laad je in datetime2(7) zonder eerst naar Python datetime te converteren. Voor meer informatie, zie Unicode en temporele precisie en Arrow temporele precisie.
Beperkingsovertredingen tijdens bulkcopy
Symptomen:
RuntimeError: CHECK constraint ... Conflict occurred in database ...
RuntimeError: Cannot insert duplicate key ... violation of PRIMARY KEY constraint
Oorzaak:
Data in je batch overtreedt tabelbeperkingen zoals primaire sleutel, unieke, controle- of vreemde sleutelbeperkingen.
Solution:
Valideer de data voordat je het laadt. Voor grote gegevenssets laad je de gegevens in een stagingtabel en voeg je deze vervolgens samen in de doeltabel:
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()
Voor upsert-patronen met stagingtabellen, zie Patronen voor het laden en verplaatsen van gegevens.
Kolomafbeeldingsfouten
Symptomen:
RuntimeError: Bulk copy failure - column count mismatch
Oorzaak:
Het aantal kolommen in je data komt niet overeen met het aantal kolommen in de doeltabel, of de kolommen staan in de verkeerde volgorde.
Solution:
Zorg ervoor dat je gegevens overeenkomen met het tabelschema in volgorde en aantal:
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)
Typeverschillen tijdens een bulkcopy
Symptomen:
Gegevens worden geladen, maar waarden worden afgekort, afgerond of incorrect.
Oorzaak:
Python-waarden worden niet netjes gekoppeld aan de doelkolomtypen. Veelvoorkomende voorbeelden zijn float waarden die in decimale kolommen worden geladen, die aan precisie kunnen verliezen, en oversized strings die in kolommen van vaste lengte worden geladen.
Solution:
Gebruik Python-types die bij je 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-type binding fouten
Symptomen:
Parameters falen stilletjes of veroorzaken datatypefouten wanneer je NumPy-integer- of float-types gebruikt.
Oorzaak:
NumPy-typen zoals numpy.int64 en numpy.int32 slagen niet door isinstance(x, int) in NumPy 2.x. De type-inferentie van de bestuurder herkent ze niet, wat onverwacht gedrag veroorzaakt.
Solution:
Converteer NumPy-waarden naar native Python-types voordat je ze bindt:
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"]),
},
)
Voor grotere datasets gebruik je de integratiepaden van Arrow of pandas . Deze paden verzorgen de typeconversie intern.
Bulk-kopiëren met tijdelijke tabellen
Symptomen:
cursor.bulkcopy("#TempTable", data) verhoogt RuntimeError: Invalid object name '#TempTable'.
Oorzaak:
bulkcopy() Kan sessie-tijdelijke tabellen (#tablename) niet oplossen vanwege beperkingen in metadata-opzoeken. Globale tijdelijke tabellen (##tablename) en permanente tabellen werken.
Solution:
Gebruik een globale tijdelijke tabel of een gewone stagingtabel:
# 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)
Voor kleine datasets waarbij je een sessie-tijdelijke tabel prefereert, gebruik executemany():
cursor.execute("CREATE TABLE #Staging (ID INT, Name NVARCHAR(50))")
cursor.executemany(
"INSERT INTO #Staging (ID, Name) VALUES (?, ?)",
rows,
)