Memecahkan masalah mssql-python

Mendiagnosis dan menyelesaikan masalah umum saat menggunakan driver mssql-python untuk terhubung ke SQL Server, Azure SQL Database, Azure SQL Managed Instance, dan database SQL di Microsoft Fabric.

Masalah penginstalan

pip gagal diinstal atau dikompilasi dari kode sumber

Gejala:

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

Kemungkinan penyebab dan solusi:

  • Tidak ada roda bawaan untuk platform Anda

    • Periksa apakah Anda menjalankan versi Python yang didukung (versi 3.10 dan versi yang lebih baru) dan platform. Lihat Siklus hidup dukungan untuk matriks kompatibilitas. Perbarui pip sebelum menginstal dengan pip install --upgrade pip. Untuk lingkungan tim yang dapat diulang, gunakan alur kerja terkunci di Penyebaran yang dapat diulang atau pola kontainer di Kontainer dan pengembangan lokal untuk mengurangi penyimpangan mesin lokal.
  • Lingkungan virtual tidak diaktifkan

    • Aktifkan lingkungan virtual Anda terlebih dahulu. Menginstal ke dalam sistem Python dapat menyebabkan kesalahan atau konflik izin.
    python -m venv .venv
    .venv\Scripts\activate
    pip install mssql-python
    

  • Pustaka sistem Linux yang hilang

Penginstalan driver yang bertentangan

Gejala:

Impor kesalahan atau perilaku tak terduga setelah menginstal mssql-python bersama pyodbc di lingkungan yang sama.

Perbaikan pada :

mssql-python dan pyodbc dapat hidup berdampingan. Jika Anda melihat konflik, buat lingkungan virtual yang bersih:

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

Masalah koneksi

Tidak dapat terhubung ke server

Gejala:

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

Kemungkinan penyebab dan solusi:

  • Server tidak dapat dijangkau

    • Pastikan nama server dan port sudah benar.
    • Periksa konektivitas jaringan: ping servername atau telnet servername 1433.
    • Pastikan firewall mengizinkan koneksi keluar pada port 1433.
  • SQL Server tidak berjalan

    • Verifikasi layanan SQL Server dimulai.
    • Untuk instans bernama, pastikan bahwa layanan SQL Server Browser sedang berjalan.
  • Aturan firewall Azure SQL

    • Tambahkan IP klien Anda ke aturan firewall Azure SQL di portal Azure.
    • Untuk Azure SQL Managed Instance, pastikan Anda terhubung dari jaringan yang diizinkan.
# 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}")

Gagal masuk

Gejala:

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

Kemungkinan penyebab dan solusi:

  • Ketidakcocokan mode autentikasi

    • Untuk Azure SQL Database, Azure SQL Managed Instance, dan database SQL dalam Fabric, sebaiknya gunakan mode autentikasi Microsoft Entra seperti Authentication=ActiveDirectoryDefault.
    • Jika Anda menggunakan autentikasi SQL dengan sengaja, verifikasi bahwa server mengizinkannya dan Anda menggunakan format login yang benar untuk titik akhir tersebut.
  • Kredensial autentikasi SQL yang salah

    • Verifikasi nama pengguna dan kata sandi.
    • Untuk Azure SQL, sertakan nama pengguna lengkap: username@servername.
  • Pengguna tidak ada dalam database

    • Verifikasi pengguna memiliki akses ke database yang ditentukan.
    • Periksa apakah proses masuk dipetakan ke pengguna basis data.
  • Autentikasi tidak dikonfigurasi

    • Gunakan autentikasi Microsoft Entra (disarankan): Authentication=ActiveDirectoryDefault.
    • Jika Anda memecahkan masalah SQL Server lokal yang harus menerima autentikasi SQL, verifikasi bahwa SQL Server menggunakan autentikasi mode campuran.

Waktu koneksi habis

Gejala:

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

Kemungkinan penyebab dan solusi:

  • Server lambat merespons

    • Tingkatkan batas waktu koneksi:
    conn = mssql_python.connect(connection_string, timeout=60)
    
  • Latensi jaringan

    • Periksa jalur jaringan ke server.
    • Pertimbangkan untuk menggunakan jalur jaringan atau VPN yang lebih pendek.
  • Server di bawah beban berat

    • Cobalah terhubung di luar jam sibuk.
    • Hubungi administrator database Anda.

Kesalahan sertifikat SSL

Gejala:

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

Solusi:

Pertama, utamakan sertifikat tepercaya atau pola pengembangan lokal di Container dan pengembangan lokal. Gunakan TrustServerCertificate=yes hanya untuk pengembangan lokal terhadap server yang Anda kendalikan.

Untuk pengembangan dan pengujian dengan sertifikat yang ditandatangani sendiri:

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 adalah cadangan yang hanya bersifat lokal. Jangan membawanya ke devcontainer bersama, alur CI, atau penyebaran produksi. Untuk panduan yang lebih luas, lihat Enkripsi dan sertifikat.

Untuk produksi, pastikan sertifikat yang tepat dipasang dan gunakan:

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

Masalah eksekusi kueri

Tabel atau objek tidak ditemukan

Gejala:

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

Kemungkinan penyebab dan solusi:

  • Konteks database yang salah

    # Ensure you're connected to the correct database
    cursor.execute("SELECT DB_NAME()")
    print(cursor.fetchone()[0])
    
  • Skema tidak ditentukan

    # Use fully qualified name
    cursor.execute("SELECT * FROM dbo.TableName")
    
  • Tabel tidak ada

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

Kesalahan sintaks

Gejala:

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

Solusi:

  1. Uji SQL di SSMS terlebih dahulu untuk memverifikasi sintaks

  2. Periksa escape string - gunakan kueri berparameter:

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

Kesalahan parameter

Gejala:

ProgrammingError: [07001] Wrong number of parameters

Solusi:

  1. Hitung placeholder dan parameter - jumlahnya harus sama

  2. Pilih gaya parameter yang tepat:

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

Masalah jenis data

Kesalahan konversi tanggal dan waktu

Gejala:

DataError: [22007] Invalid datetime format

Solusi:

Gunakan objek datetime Python alih-alih string:

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

Masalah presisi desimal

Gejala:

Angka tampak terpotong atau dibulatkan dengan tidak benar.

Solusi:

Gunakan decimal.Decimal untuk nilai numerik yang tepat:

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

Masalah pengkodean Unicode

Gejala:

Karakter khusus muncul kacau atau menyebabkan kesalahan.

Solusi:

  1. Menggunakan kolom NVARCHAR untuk data Unicode dalam database Anda

  2. Teruskan string secara langsung - driver menangani pengkodean:

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

Masalah performa

Eksekusi kueri yang lambat

Kemungkinan penyebab dan solusi:

  • Indeks yang hilang: Periksa rencana eksekusi kueri di SSMS.

  • Kumpulan hasil besar: Gunakan fetchmany() alih-alih fetchall():

    cursor.arraysize = 1000
    while True:
         rows = cursor.fetchmany()
         if not rows:
             break
         process_rows(rows)
    
  • Pengumpulan koneksi dinonaktifkan: Aktifkan pengumpulan:

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

Masalah memori dengan hasil yang besar

Gejala:

Proses Python kehabisan memori.

Solusi:

  1. Tampilkan hasil secara streaming alih-alih memuat semuanya ke memori:

    cursor.execute("SELECT * FROM LargeTable")
    for row in cursor:  # Iterates one row at a time
        process_row(row)
    
  2. Gunakan paginasi sisi server:

    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
    

Masalah transaksi

Ruang lingkup tabel temporer dengan autocommit

Tabel sementara (#tablename) yang dibuat di dalam transaksi menghilang saat transaksi diputar kembali. Hal ini adalah sumber kebingungan yang umum saat autocommit dinonaktifkan (setelan bawaan):

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

Perbaiki: Terapkan segera setelah membuat tabel sementara, atau gunakan mode penerapan otomatis:

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

Pernyataan DDL yang memerlukan mode penerapan otomatis, seperti CREATE DATABASE, gagal di dalam transaksi terbuka. Atur autocommit sebelum menjalankannya:

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

Transaksi tidak dilakukan

Gejala:

Perubahan data tidak akan tetap ada setelah menutup koneksi.

Solution:

Dengan autocommit=False (default), Anda harus memanggil 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!

Atau gunakan mode komit otomatis:

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

Kesalahan deadlock

Gejala:

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

Solution:

Logika coba lagi (lihat Logika coba ulang) menangani kegagalan langsung, tetapi kebuntuan berulang menunjukkan masalah desain. Untuk memperbaiki akar penyebabnya, tangkap grafik kebuntuan dan analisis pernyataan dan jenis kunci mana yang terlibat. Perbaikan umum mencakup mengubah urutan operasi agar transaksi yang saling bersaing memperoleh kunci dalam urutan yang sama, mengurangi ruang lingkup transaksi, dan menambahkan indeks yang sesuai untuk mengurangi durasi penguncian.

Untuk panduan lengkap analisis kebuntuan, lihat Panduan kebuntuan. Jika Anda menggunakan Azure SQL Database, lihat Menganalisis dan mencegah kebuntuan.

Masalah pemuatan massal

Pelanggaran batasan selama salinan massal

Gejala:

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

Penyebab:

Data dalam batch Anda melanggar batasan tabel (kunci utama, unik, CHECK, atau kunci asing).

Perbaikan pada :

Validasi data sebelum memuat. Untuk dataset besar, muat terlebih dahulu ke tabel staging, lalu gabungkan ke tabel target:

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

Untuk pola upsert dengan tabel staging, lihat Pola pemuatan dan pemindahan data.

Kesalahan pemetaan kolom

Gejala:

RuntimeError: Bulk copy failure - column count mismatch

Penyebab:

Jumlah kolom dalam data Anda tidak cocok dengan jumlah kolom tabel target, atau kolom dalam urutan yang salah.

Perbaikan pada :

Pastikan data Anda cocok dengan skema tabel secara tepat dalam urutan dan jumlah:

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

Ketidakcocokan tipe data selama bulk copy

Gejala:

Data dimuat tetapi nilai dipotong, dibulatkan, atau salah.

Penyebab:

Nilai Python tidak cocok secara langsung dengan tipe kolom target. Kasus umum: nilai float yang dimuat ke kolom decimal (hilangnya presisi), atau string yang terlalu panjang yang dimuat ke kolom dengan panjang tetap.

Perbaikan pada :

Gunakan jenis Python yang benar yang cocok dengan skema Anda:

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)

Kegagalan binding tipe NumPy

Gejala:

Parameter gagal tanpa peringatan atau memunculkan kesalahan tipe data saat menggunakan tipe bilangan bulat atau floating point NumPy.

Penyebab:

Tipe NumPy seperti numpy.int64 dan numpy.int32 tidak lolos isinstance(x, int) di NumPy 2.x. Inferensi tipe pada driver tidak dapat mengenalinya, yang menyebabkan perilaku tak terduga.

Perbaikan pada :

Konversi nilai numpy ke jenis Python asli sebelum mengikat:

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

Untuk himpunan data yang lebih besar, gunakan opsi integrasi Arrow atau pandas, yang menangani konversi tipe secara internal.

Salin massal dengan tabel sementara

Gejala:

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

Penyebab:

bulkcopy() Tidak dapat menyelesaikan tabel sementara sesi (#tablename) karena batasan pencarian metadata. Tabel suhu global (##tablename) dan tabel permanen berfungsi.

Perbaikan pada :

Gunakan tabel temp global atau tabel pementasan reguler:

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

Untuk himpunan data kecil di mana tabel sementara sesi lebih disukai, gunakan executemany() sebagai gantinya:

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

Masalah kontainer dan CI

Pustaka sistem yang hilang di Linux

Gejala:

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

Perbaikan pada :

Instal paket sistem yang diperlukan. Paketnya berbeda berdasarkan distribusi:

Distribution Perintah instalasi
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

Untuk contoh Dockerfile, lihat Kontainer dan pengembangan lokal.

Kesalahan SSL macOS setelah penginstalan

Gejala:

Kesalahan terkait SSL saat menyambungkan dari macOS, terutama di Apple Silicon.

Perbaikan pada :

Instal OpenSSL melalui Homebrew dan atur bendera linker:

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

Alat diagnostik

Aktifkan pencatatan log driver

Gunakan mssql_python.setup_logging() untuk mengaktifkan pengelogan DEBUG yang komprehensif untuk pemecahan masalah. Semua operasi driver dicatat, termasuk pernyataan SQL, parameter, operasi ODBC internal, dan perubahan status koneksi.

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

File log ditulis dalam format CSV dan secara otomatis dirotasi saat mencapai 512 MB dengan lima file cadangan. Data sensitif seperti kata sandi dan token akses secara otomatis dibersihkan dalam output log.

Untuk menambahkan entri log Anda sendiri di samping log driver, gunakan 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

Pencatatan log menimbulkan overhead pada kinerja. Aktifkan hanya saat pemecahan masalah, bukan dalam produksi secara default.

Dapatkan informasi pengemudi

Ambil versi driver dan detail server dari koneksi aktif:

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

Periksa status koneksi

Menguji apakah koneksi masih terbuka sebelum mencoba operasi:

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

Referensi cepat: Kesalahan umum

Kesalahan SQLSTATE Penyebab umum Perbaikan cepat
Klien tidak dapat membuat koneksi 08001 Server tidak dapat dijangkau Periksa nama server/port
Gagal masuk 28000 Kredensial tidak valid Verifikasi nama pengguna/kata sandi
Waktu tunggu habis HYT00 / HYT01 Jaringan lambat Meningkatkan batas waktu
Nama objek tidak valid 42S02 Tabel/skema yang salah Gunakan nama yang sepenuhnya memenuhi syarat
Kesalahan sintaks 42000 Kesalahan SQL Menggunakan kueri berparameter
Pelanggaran batasan 23000 Pelanggaran FK/PK Periksa integritas data
Kebuntuan 40001 Mengunci ketidaksesuaian Coba lagi, lalu analisis grafik kebuntuan