Solucionar problemas no mssql-python

Diagnostice e resolva problemas comuns ao usar o driver mssql-python para conectar ao SQL Server, Banco de Dados SQL do Azure, Instância Gerenciada de SQL do Azure e banco de dados SQL no Microsoft Fabric.

Problemas de instalação

o pip falha ao instalar ou compila a partir do código-fonte

Sintomas:

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

Possíveis causas e soluções:

  • Sem volante pré-montado para sua plataforma

    • Verifique se você está usando uma versão de Python suportada (versões 3.10 e posteriores) e uma plataforma. Veja ciclo de vida de suporte para a matriz de compatibilidade. Atualize o pip antes de instalar com pip install --upgrade pip. Para ambientes reproduzíveis para a equipe, use o fluxo de trabalho bloqueado em Implantações reproduzíveis ou os padrões de contêiner em Contêineres e desenvolvimento local para reduzir a divergência entre máquinas locais.
  • Ambiente virtual não ativado

    • Ative seu ambiente virtual primeiro. Instalar Python no sistema pode causar erros ou conflitos de permissões.
    python -m venv .venv
    .venv\Scripts\activate
    pip install mssql-python
    

Instalações conflitantes de drivers

Sintomas:

Erros de importação ou comportamento inesperado após instalar mssql-python ao lado pyodbc no mesmo ambiente.

Correção:

mssql-python e pyodbc podem coexistir. Se você perceber conflitos, crie um ambiente virtual limpo:

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

Problemas de conexão

Não consigo conectar ao servidor

Sintomas:

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

Possíveis causas e soluções:

  • Servidor não acessível

    • Verifique se o nome do servidor e a porta estão corretos.
    • Verifique conectividade de rede: ping servername ou telnet servername 1433.
    • Certifique-se de que o firewall permita conexões de saída na porta 1433.
  • SQL Server não está rodando

    • Verifique se o serviço do SQL Server foi iniciado.
    • Para instâncias nomeadas, verifique se o serviço SQL Server Browser está em execução.
  • Regras de firewall do SQL do Azure

    • Adicione o IP do seu cliente às regras do firewall SQL do Azure no portal do Azure.
    • Para Instância Gerenciada de SQL do Azure, certifique-se de estar conectando a partir de uma rede permitida.
# 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}")

Falha no logon

Sintomas:

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

Possíveis causas e soluções:

  • Incompatibilidade no modo de autenticação

    • Para Banco de Dados SQL do Azure, Instância Gerenciada de SQL do Azure e SQL Database em Fabric, dê preferência a um modo do Microsoft Entra, como Authentication=ActiveDirectoryDefault.
    • Se você está usando autenticação SQL intencionalmente, verifique se o servidor permite e se você está usando o formato de login correto para aquele endpoint.
  • Credenciais de autenticação SQL incorretas

    • Verifique nome de usuário e senha.
    • Para SQL do Azure, inclua o nome de usuário completo: username@servername.
  • O usuário não existe no banco de dados

    • Verifique se o usuário tem acesso ao banco de dados especificado.
    • Verifique se o login está mapeado para um usuário do banco de dados.
  • Autenticação não configurada

    • Use a autenticação Microsoft Entra (recomendada): Authentication=ActiveDirectoryDefault.
    • Se você está tentando solucionar problemas em um SQL Server local que deveria aceitar autenticação SQL, verifique se o SQL Server usa autenticação em modo misto.

Tempo de espera da conexão esgotado

Sintomas:

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

Possíveis causas e soluções:

  • O servidor demora a responder

    • Aumente o tempo limite da conexão:
    conn = mssql_python.connect(connection_string, timeout=60)
    
  • Latência da rede

    • Verifique o caminho da rede até o servidor.
    • Considere usar um caminho de rede mais curto ou VPN.
  • Servidor sob carga pesada

    • Tente se conectar durante os horários de menor movimento.
    • Entre em contato com o administrador do seu banco de dados.

Erros de certificado SSL

Sintomas:

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

Soluções:

Primeiro, prefira um certificado confiável ou os padrões de desenvolvimento local em Contêiner e desenvolvimento local. Use TrustServerCertificate=yes apenas para desenvolvimento local em um servidor que você controla.

Para desenvolvimento e testes com um certificado autoassinado:

conn = mssql_python.connect(
    "Server=<server>.database.windows.net;"
    "Database=<database>;"
    "Authentication=ActiveDirectoryDefault;"
    "Encrypt=yes;"
    "TrustServerCertificate=yes;"  # Don't use in production
)

Cuidado

TrustServerCertificate=yes é um recurso reservado apenas local. Não leve isso para devcontainers compartilhados, pipelines de CI ou implantações de produção. Para orientações mais amplas, veja Criptografia e certificados.

Para produção, certifique-se de que os certificados adequados estejam instalados e utilize:

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

Problemas de execução de consultas

Tabela ou objeto não encontrado

Sintomas:

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

Possíveis causas e soluções:

  • Contexto errado do banco de dados

    # Ensure you're connected to the correct database
    cursor.execute("SELECT DB_NAME()")
    print(cursor.fetchone()[0])
    
  • Esquema não especificado

    # Use fully qualified name
    cursor.execute("SELECT * FROM dbo.TableName")
    
  • A tabela não existe

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

Erro de sintaxe

Sintomas:

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

Soluções:

  1. Teste o SQL no SSMS primeiro para verificar a sintaxe

  2. Verifique o escape de string - use consultas parametrizadas:

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

Erros de parâmetros

Sintomas:

ProgrammingError: [07001] Wrong number of parameters

Soluções:

  1. Conte os marcadores de posição e os parâmetros - eles devem corresponder

  2. Escolha o estilo de parâmetros correto:

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

Questões com tipos de dados

Erros de conversão de data e hora

Sintomas:

DataError: [22007] Invalid datetime format

Soluções:

Use objetos data-hora em Python em vez de strings:

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

Questões de precisão decimal

Sintomas:

Os números parecem truncados ou arredondados incorretamente.

Soluções:

decimal.Decimal Use para valores numéricos precisos:

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

Problemas de codificação Unicode

Sintomas:

Caracteres especiais aparecem distorcidos ou causam erros.

Soluções:

  1. Use colunas do tipo NVARCHAR para dados Unicode no seu banco de dados

  2. Passe as cadeias diretamente - o driver cuida da codificação:

    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 desempenho

Execução lenta da consulta

Possíveis causas e soluções:

  • Índices faltando: Verifique o plano de execução da consulta no SSMS.

  • Grandes conjuntos de resultados: Use fetchmany() em vez de fetchall():

    cursor.arraysize = 1000
    while True:
         rows = cursor.fetchmany()
         if not rows:
             break
         process_rows(rows)
    
  • Pooling de conexão desativado: Ativar o pooling:

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

Problemas de memória com resultados grandes

Sintomas:

O processo Python fica sem memória.

Soluções:

  1. Resultados do fluxo em vez de carregar tudo na memória:

    cursor.execute("SELECT * FROM LargeTable")
    for row in cursor:  # Iterates one row at a time
        process_row(row)
    
  2. Use a paginação no lado do 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
    

Questões de transação

Escopo de tabelas temporárias com autocommit

Tabelas temporárias (#tablename) criadas dentro de uma transação desaparecem quando a transação é revertida. Essa é uma fonte comum de confusão quando o autocommit está desligado (o padrão):

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

Correção: Faça commit imediatamente após criar uma tabela temporária, ou use o modo de autocommit:

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

Instruções DDL que exigem modo autocommit, como CREATE DATABASE, falham dentro de uma transação aberta. Defina a confirmação automática antes de executá-las:

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

Transação não comprometida

Sintomas:

As alterações nos dados não persistem após o fechamento da conexão.

Solution:

Com autocommit=False (padrão), você deve chamar 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!

Ou use o modo autocommit:

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

Erros de deadlock

Sintomas:

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

Solution:

A lógica de nova tentativa (veja lógica de nova tentativa) lida com a falha imediata, mas impasses recorrentes indicam um problema de projeto. Para corrigir a causa raiz, capture o grafo de deadlock e analise quais comandos e tipos de bloqueio estão envolvidos. Correções comuns incluem reordenação das operações para que transações concorrentes adquiram bloqueios na mesma sequência, redução do escopo da transação e adição de índices apropriados para diminuir a duração do bloqueio.

Para uma análise completa de deadlocks, consulte o guia de deadlocks. Se você está usando o Banco de Dados SQL do Azure, veja Analisar e prevenir bloqueios.

Problemas de carregamento em massa

Violações de restrições durante a cópia em massa

Sintomas:

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

Causa:

Os dados no seu lote violam as restrições da tabela (chave primária, única, CHECK ou chave estrangeira).

Correção:

Valide os dados antes de carregar. Para grandes conjuntos de dados, carregue primeiro para uma tabela de preparação e depois mescle na tabela de destino:

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

Para padrões upsert com tabelas de staging, veja Padrões de carregamento e movimento de dados.

Erros de mapeamento de colunas

Sintomas:

RuntimeError: Bulk copy failure - column count mismatch

Causa:

O número de colunas nos seus dados não corresponde ao número de colunas da tabela alvo, ou as colunas estão na ordem errada.

Correção:

Certifique-se de que seus dados correspondam exatamente ao esquema da tabela, na ordem e na quantidade:

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

Incompatibilidade de tipos durante a cópia em massa

Sintomas:

Os dados são carregados, mas os valores são truncados, arredondados ou incorretos.

Causa:

Os valores de Python não correspondem diretamente aos tipos de dados da coluna de destino. Casos comuns: float valores carregados em colunas decimal (perda de precisão) ou cadeias de caracteres longas demais carregadas em colunas de comprimento fixo.

Correção:

Use os tipos corretos de Python que combinem com seu esquema:

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)

Falhas de vinculação de tipos do NumPy

Sintomas:

Os parâmetros falham silenciosamente ou geram erros de tipo de dados ao usar tipos inteiros ou de ponto flutuante do NumPy.

Causa:

Tipos do NumPy como numpy.int64 e numpy.int32 não são aprovados em isinstance(x, int) no NumPy 2.x. A inferência de tipo do motorista não os reconhece, o que causa comportamentos inesperados.

Correção:

Converta valores numpy para tipos nativos de Python antes de vincular:

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

Para conjuntos de dados maiores, use os caminhos de integração Arrow ou pandas, que fazem a conversão de tipos internamente.

Cópia em massa com tabelas temporárias

Sintomas:

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

Causa:

bulkcopy() Não é possível resolver tabelas temporárias de sessão (#tablename) devido a limitações na consulta de metadados. Tabelas temporárias globais (##tablename) e tabelas permanentes funcionam.

Correção:

Use uma tabela temporária global ou uma tabela de preparação regular:

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

Para conjuntos de dados pequenos onde uma tabela temporária de sessão é preferida, use executemany() em vez disso:

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

Questões de contêiner e CI

Bibliotecas de sistema ausentes no Linux

Sintomas:

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

Correção:

Instale os pacotes de sistema necessários. Os pacotes diferem pela distribuição:

Distribution Comando de Instalação
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

Para exemplos de Dockerfile, veja Container e desenvolvimento local.

Erros SSL do macOS após a instalação

Sintomas:

Erros relacionados a SSL ao conectar pelo macOS, especialmente no Apple Silicon.

Correção:

Instale o OpenSSL via Homebrew e defina as bandeiras de linker:

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

Ferramentas de diagnóstico

Ativar o log do driver

Use mssql_python.setup_logging() para habilitar um registro DEBUG abrangente para resolução de problemas. Todas as operações de driver são registradas, incluindo instruções SQL, parâmetros, operações ODBC internas e mudanças no estado da conexão.

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

Os arquivos de log são gravados em formato CSV e são rotacionados automaticamente ao atingirem 512 MB, com cinco backups. Dados sensíveis como senhas e tokens de acesso são automaticamente higienizados na saída de log.

Para adicionar suas próprias entradas de registro junto com os registros dos motoristas, use 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

Cuidado

O registro em log gera impacto no desempenho. Ative isso apenas durante a resolução de problemas, não em produção por padrão.

Obtenha informações sobre o motorista

Recupere a versão do driver e os detalhes do servidor de uma conexão ativa:

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

Verificar o estado da conexão

Teste se uma conexão ainda está aberta antes de tentar operações:

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

Referência rápida: Erros comuns

Erro SQLSTATE Causa comum Correção rápida
O cliente não consegue estabelecer conexão 08001 Servidor inacessível Verifique nome/porta do servidor
Falha no logon 28000 Credenciais erradas Verifique nome de usuário/senha
Tempo limite expirado HYT00/HYT01 Rede lenta Aumentar o tempo limite
Nome de objeto inválido 42S02 Tabela/esquema errado Use nomes totalmente qualificados
Erro de sintaxe 42000 Erro SQL Usar consultas parametrizadas
Violação de restrição 23000 Violação FK/PK Verifique a integridade dos dados
Deadlock 40001 Contenção de bloqueio Tente novamente, em seguida analise o gráfico de deadlock