Oharra
Baimena behar duzu orria atzitzeko. Direktorioetan saioa has dezakezu edo haiek alda ditzakezu.
Baimena behar duzu orria atzitzeko. Direktorioak alda ditzakezu.
Utiliza este artículo para diagnosticar problemas de ejecución de consultas, tipo de datos, rendimiento, transacciones y copias masivas con el mssql-python controlador.
Problemas de ejecución de consultas
Tabla u objeto no encontrado
Síntomas:
ProgrammingError: [42S02] (208) Invalid object name 'TableName'.
Posibles causas y soluciones:
Contexto incorrecto de la base de datos
cursor.execute("SELECT DB_NAME()") print(cursor.fetchone()[0])Esquema no especificado
cursor.execute("SELECT * FROM dbo.TableName")La tabla no existe
cursor.execute(""" SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'TableName' """)
Error de sintaxis
Síntomas:
ProgrammingError: [42000] (102) Incorrect syntax near '...'.
Soluciones:
Prueba la sentencia SQL en SQL Server Management Studio (SSMS) para verificar la sintaxis.
Utiliza una consulta parametrizada en lugar de interpolación de cadenas:
# 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}, )
Errores de parámetros
Síntomas:
ProgrammingError: [07001] Wrong number of parameters
Soluciones:
Cuenta los marcadores de posición y los parámetros. Los conteos deben coincidir.
Elige el estilo de parámetro correcto:
# 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())
Problemas con el tipo de datos
Errores de conversión de fecha y hora
Síntomas:
DataError: [22007] Invalid datetime format
Solution:
Usa objetos en Python datetime en lugar de cadenas.
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())
Problemas de precisión decimal
Síntomas:
Los números aparecen truncados o redondeados incorrectamente.
Solution:
Uso decimal.Decimal para valores numéricos precisos:
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")},
)
Problemas de codificación Unicode
Síntomas:
Los caracteres especiales aparecen distorsionados o causan errores.
Soluciones:
Usa columnas nvarchar para los datos Unicode en tu base de datos.
Pasa las cadenas directamente. El controlador gestiona la codificació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())
Problemas de rendimiento
Ejecución lenta de consultas
Posibles causas y soluciones:
Índices faltantes: Revisa el plan de ejecución de consultas en SSMS.
Conjuntos de resultados grandes: Usar
fetchmany()en lugar defetchall():cursor.arraysize = 1000 while True: rows = cursor.fetchmany() if not rows: break process_rows(rows)Agrupación de conexiones desactivada: Habilitar agrupación:
import mssql_python mssql_python.pooling(max_size=20, idle_timeout=300)
Problemas de memoria con resultados grandes
Síntomas:
El proceso de Python se queda sin memoria.
Soluciones:
Transmita los resultados en flujo en lugar de cargar todas las filas en la memoria.
cursor.execute("SELECT * FROM LargeTable") for row in cursor: process_row(row)Usa la paginación del lado del servidor.
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
Problemas de transacciones
Alcance de tablas temporales con autocommit
Las tablas temporales de sesión (#tablename) que creas dentro de una transacción desaparecen cuando la transacción se revierte. Este comportamiento suele causar confusión cuando el autocommit está apagado, que es el valor predeterminado:
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")
Confirma inmediatamente después de crear una tabla temporal, o usa el modo autocommit:
cursor.execute("CREATE TABLE #TempData (ID INT, Name NVARCHAR(50))")
conn.commit()
cursor.execute("INSERT INTO #TempData VALUES (1, 'test')")
conn.commit()
Las sentencias DDL que requieren modo de compromiso automático, como CREATE DATABASE, fallan dentro de una transacción abierta. Establece el autocommit antes de ejecutarlos:
conn.autocommit = True
cursor.execute("CREATE DATABASE TestDB")
conn.autocommit = False
Transacción no comprometida
Síntomas:
Los cambios en los datos no persisten después de cerrar la conexión.
Solution:
Con autocommit=False, que es el valor predeterminado, llama a commit():
cursor.execute("CREATE TABLE #Products (Name NVARCHAR(100))")
cursor.execute(
"INSERT INTO #Products (Name) VALUES (%(name)s)",
{"name": "Widget"},
)
conn.commit()
Alternativamente, utiliza el modo de auto-commit:
conn = mssql_python.connect(connection_string, autocommit=True)
Errores de interbloqueo
Síntomas:
OperationalError: [40001] (1205) Transaction ... was deadlocked on lock resources with another process
Solution:
La lógica de reintentos gestiona el fallo inmediato, pero los bloqueos recurrentes indican un problema de diseño. Captura el gráfico de bloqueos y analiza las sentencias y tipos de bloqueo. Las soluciones más comunes incluyen estos cambios:
- Reordene las operaciones para que las transacciones en conflicto adquieran los bloqueos en la misma secuencia.
- Reducir el alcance de la transacción.
- Añadir índices apropiados para reducir la duración de los bloqueos.
Para una guía completa del análisis de bloqueos, consulta la guía de bloqueos. Si usas Azure SQL Database, consulta Analizar y prevenir bloqueos.
Problemas de carga masiva
Infracciones de restricciones durante la copia masiva
Síntomas:
RuntimeError: CHECK constraint ... Conflict occurred in database ...
RuntimeError: Cannot insert duplicate key ... violation of PRIMARY KEY constraint
Causa:
Los datos de tu lote incumplen las restricciones de la tabla, como las restricciones de clave primaria, de unicidad, de comprobación o de clave externa.
Solution:
Valida los datos antes de cargarlos. Para conjuntos de datos grandes, carga los datos en una tabla de staging y luego combínalos en el destino:
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()
Para patrones actualizar/insertar (upsert) con tablas de etapas, consulte Patrones de carga y movimiento de datos.
Errores de mapeo de columnas
Síntomas:
RuntimeError: Bulk copy failure - column count mismatch
Causa:
El número de columnas en tus datos no coincide con el número de columnas de la tabla objetivo, o las columnas están en el orden incorrecto.
Solution:
Asegúrate de que tus datos coincidan con el esquema de la tabla en el orden y la cantidad:
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)
Desajustes de tipo durante la copia en bloque
Síntomas:
Los datos se cargan, pero los valores están truncados, redondeados o son incorrectos.
Causa:
Los valores de Python no se corresponden claramente con los tipos de columna destino. Ejemplos comunes incluyen float valores cargados en columnas decimales , que pueden perder precisión, y cadenas sobredimensionadas cargadas en columnas de longitud fija.
Solution:
Usa tipos de Python que coincidan con tu esquema:
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)
Errores de vinculación de tipos de NumPy
Síntomas:
Los parámetros fallan silenciosamente o generan errores de tipo de datos cuando usas enteros o tipos flotantes NumPy.
Causa:
Tipos de NumPy como numpy.int64 y numpy.int32 no pasan isinstance(x, int) en NumPy 2.x. La inferencia de tipo del conductor no los reconoce, lo que provoca un comportamiento inesperado.
Solution:
Convierte los valores de NumPy a tipos nativos de Python antes de asignarlos:
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"]),
},
)
Para conjuntos de datos más grandes, utiliza las rutas de integración de Arrow o pandas . Estas rutas gestionan la conversión de tipos internamente.
Copia masiva con tablas temporales
Síntomas:
cursor.bulkcopy("#TempTable", data) genera RuntimeError: Invalid object name '#TempTable'.
Causa:
bulkcopy() No se pueden resolver las tablas temporales de sesión (#tablename) debido a las limitaciones de búsqueda de metadatos. Las tablas temporales globales (##tablename) y las tablas permanentes funcionan.
Solution:
Utiliza una tabla temporal global o una tabla de ensayo normal:
# 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)
Para conjuntos de datos pequeños donde prefieras una tabla temporal de sesión, usa executemany():
cursor.execute("CREATE TABLE #Staging (ID INT, Name NVARCHAR(50))")
cursor.executemany(
"INSERT INTO #Staging (ID, Name) VALUES (?, ?)",
rows,
)