Migrálás a pyodbc-ről az mssql-pythonra

Az mssql-python illesztőprogram a Microsoft első saját fejlesztésű Python-illesztőprogramja a Microsoft SQL-hez. Ha inkább egy Microsoft által karbantartott illesztőprogram-lehetőséget részesít előnyben, az a következőket kínálja:

  • Nincs külső ODBC illezőprogramfüggőség.
  • Beépített csatlakozási csoportosítás.
  • Modern Python 3.10+ támogatás.
  • Natív Microsoft Entra hitelesítés.

Főbb különbségek

Feature pyodbc mssql-python
Paraméterstílus qmark (?) qmark (?) és pyformat (%(name)s)
ODBC-illesztőprogram szükséges Yes No
Kapcsolatmegosztás Külső Beépített
Minimális Python-verzió 3.6 3.10
callproc() Támogatott Nincs implementálva
Autocommit alapértelmezett Off Off

Alapvető migrációs lépések

Az alábbi lépések lefedik a pyodbc alkalmazás mssql-pythonra történő migrálásához szükséges kulcsfontosságú változtatásokat.

1. Frissítsék az importokat

Az pyodbc importot helyettesítsük :mssql_python

Előtte (pyodbc):

import pyodbc

(mssql-python) után:

import mssql_python

2. Kapcsolódási láncok frissítése

Távolítsa el a DRIVER= kulcsszót, és frissítse a hitelesítési módszert:

Mielőtt (pyodbc, ODBC drivert igényel):

conn = pyodbc.connect(
    "DRIVER={ODBC Driver 18 for SQL Server};"
    "SERVER=localhost;"
    "DATABASE=AdventureWorks2022;"
    "Trusted_Connection=yes;"
)

Miután (mssql-python, nincs szükség driverre, Microsoft Entra auth-val):

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

3. Hagyd a lekérdezéseidet változatlanul

Az mssql-python illesztőprogram támogatja mind ? a (qmark), mind %(name)s (pyformat) paraméterstílusokat. A meglévő ? lekérdezéseid változtatás nélkül működnek:

Előtte (pyodbc):

cursor.execute("SELECT * FROM Production.Product WHERE ProductID = ? AND Color = ?", (1, "Red"))

Utána (mssql-python, ugyanaz a lekérdezés):

cursor.execute("SELECT * FROM Production.Product WHERE ProductID = ? AND Color = ?", (1, "Red"))

4. Tartsa meg az executemany elemet változatlanul

A meglévő executemany hívások tuple-okkal és ? jelölőkkel változtatás nélkül működnek:

Korábban (pyodbc):

cursor.execute("CREATE TABLE #MigrateDemo (ID INT, Name NVARCHAR(50))")
data = [(1, "Alice"), (2, "Bob"), (3, "Carol")]
cursor.executemany("INSERT INTO #MigrateDemo (ID, Name) VALUES (?, ?)", data)

Miután (mssql-python, ugyanaz a kód):

cursor.execute("DROP TABLE IF EXISTS #MigrateDemo")
cursor.execute("CREATE TABLE #MigrateDemo (ID INT, Name NVARCHAR(50))")
data = [(1, "Alice"), (2, "Bob"), (3, "Carol")]
cursor.executemany("INSERT INTO #MigrateDemo (ID, Name) VALUES (?, ?)", data)

Tárolt eljárás migráció

Az mssql-python illesztőprogram nem valósítja meg a callproc() elemet. A következő szakaszok bemutatják, hogyan kell helyette használni EXECUTE .

EXECUTE használata tárolt eljárásokhoz

A pyodbc illezser támogatja callproc(), de az mssql-python illesztőprogram nem. Használja inkább a következőt EXECUTE :

Mielőtt (pyodbc):

cursor.callproc("dbo.uspGetEmployeeManagers", (5,))
results = cursor.fetchall()

(mssql-python) után:

cursor.execute(
    "EXECUTE dbo.uspGetEmployeeManagers @BusinessEntityID = %(id)s",
    {"id": 5}
)
results = cursor.fetchall()
print(f"Got {len(results)} rows")

Kimeneti paraméterek

Használj T-SQL változókat a kimeneti értékek rögzítésére a callproc() kimeneti paraméterek helyett:

Mielőtt (pyodbc, callproc használatával):

params = (category_id, pyodbc.SQL_INTEGER)
cursor.callproc("dbo.GetProductCount", params)
count = params[1].value

Miután (mssql-python, T-SQL-változók használatával):

cursor.execute(
    """
    DECLARE @count INT;
    SELECT @count = COUNT(*) FROM Production.Product
    WHERE ProductSubcategoryID = %(cat_id)s;
    SELECT @count AS ProductCount;
    """,
    {"cat_id": 1}
)
product_count = cursor.fetchval()
print(f"Product count: {product_count}")

Jellemző-specifikus migrációk

Az alábbi szakaszok specifikus pyodbc jellemzőket és azok mssql-python megfelelőit tárgyalják.

Kapcsolódási karakterláncok

pyodbc kulcsszó mssql-python kulcsszó Jegyzetek
DRIVER={...} Nem szükséges Az ODBC illesztőprogram beépítve van a csomagban.
SERVER= Server= Nincs változás a viselkedésben.
DATABASE= Database= Nincs változás a viselkedésben.
Trusted_Connection= Trusted_Connection= Nincs változás a viselkedésben.
UID= / PWD= UID= / PWD= Nincs változás a viselkedésben.
Authentication= Authentication= Ugyanazokat az értékeket fogadja el.

Automatikus véglegesítés

Az automatikus elköteleződés viselkedése mindkét illesztőprogramban azonos:

pyodbc:

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

MSSQL-Python:

conn.autocommit = True

Tömeges beszúrás

A nagy INSERT adagok gyorsításához a pyodbc felhasználók beállítják fast_executemany = True. Az mssql-python illesztőprogram már optimalizálja a(z) executemany használatát paraméterezett kötegek esetén, így mérsékelt mennyiségű beszúrásokhoz nincs szükség külön kapcsolóra. Nagy mennyiségű adat betöltésekor inkább a bulkcopy() használata javasolt, amely a sorokat a tömeges másolási protokollon keresztül folyamatosan továbbítja, és sokkal gyorsabb, mint az egyes INSERT utasítások kiadása. A teljes munkafolyamatért lásd: Használj tömeges másolatot.

pyodbc:

cursor.fast_executemany = True
cursor.executemany(query, data)

A (mssql-python) után mérsékelt adag a következőkkel executemany:

cursor.execute("DROP TABLE IF EXISTS #BulkTarget")
cursor.execute("CREATE TABLE #BulkTarget (ID INT, Name NVARCHAR(50))")
data = [(i, f"Item {i}") for i in range(100)]
cursor.executemany("INSERT INTO #BulkTarget (ID, Name) VALUES (?, ?)", data)
conn.commit()

A(z) (mssql-python) után, nagy terhelés esetén bulkcopy (előnyben részesített):

cursor.execute("IF OBJECT_ID('##BulkTarget') IS NOT NULL DROP TABLE ##BulkTarget")
cursor.execute("CREATE TABLE ##BulkTarget (ID INT, Name NVARCHAR(50))")
conn.commit()  # Commit DDL before bulkcopy
data = [(i, f"Item {i}") for i in range(100)]
result = cursor.bulkcopy("##BulkTarget", data)
print(f"Bulk copied {result['rows_copied']} rows")
cursor.execute("DROP TABLE ##BulkTarget")
conn.commit()

Sorgyár

Az mssql-python illesztőprogram olyan objektumokat ad vissza Row , amelyek alapértelmezetten támogatják az attribútum-hozzáférést, anélkül, hogy egyedi sorgyárat kellene létrehozni:

PyoDBC (Custom Row Factory):

def namedtuple_row_factory(cursor):
    from collections import namedtuple
    columns = [col[0] for col in cursor.description]
    Row = namedtuple("Row", columns)
    return Row

MSSQL-python (attribútum-hozzáférés alapértelmezett):

cursor.execute("SELECT Name, ListPrice FROM Production.Product")
row = cursor.fetchone()
print(row.Name)   # Attribute access works directly
print(row[0])     # Index access also works

Hibakezelés

Az mssql-python illesztőprogram ugyanazt a kivételhierarchiát használja, mint a pyodbc, így a legtöbb kivételkezelő csak modulnévváltoztatást igényel.

Kivételhierarchia

A kivételosztályok nevei közvetlenül megfeleltethetők az illesztőprogramok között:

pyodbc:

try:
    cursor.execute(query)
except pyodbc.Error as e:
    pass
except pyodbc.DatabaseError as e:
    pass
except pyodbc.OperationalError as e:
    pass

MSSQL-Python:

try:
    cursor.execute("SELECT TOP 1 * FROM Production.Product")
    print(cursor.fetchone())
except mssql_python.Error as e:
    pass
except mssql_python.DatabaseError as e:
    pass
except mssql_python.OperationalError as e:
    pass

A hiba részletei

Mindkét illesztőprogram a kivétel argumentumain keresztül teszi elérhetővé a hiba részleteit:

pyodbc:

try:
    cursor.execute(query)
except pyodbc.Error as e:
    sqlstate = e.args[0]
    message = e.args[1]

MSSQL-Python:

try:
    cursor.execute("SELECT TOP 1 * FROM NonExistentTable_XYZ")
except mssql_python.Error as e:
    # Error message contains SQLSTATE and details
    print(str(e))

Kapcsolatmegosztás

Az mssql-python illesztőprogram alapértelmezetten tartalmazza a csatlakozási poolingot, így külső pooling könyvtárakra már nem lesz szükség.

Távolítsd el a külső készletezést

Ha külső poolingot használtál pyodbc-vel, az mssql-python driverben ez beépített:

Előtte (pyodbc külső pool):

from dbutils.pooled_db import PooledDB

pool = PooledDB(pyodbc, 5, driver="{ODBC Driver 18 for SQL Server}",
                server="your_server", database="your_database",
                uid="your_username", pwd="your_password")
conn = pool.connection()

A(z) mssql-python beépített kapcsolatkészlete után:

conn = mssql_python.connect(connection_string)
conn.close()

Pool konfigurálása

Felülírd az alapértelmezett medence méretét és időkorlátot a következőkkel:mssql_python.pooling()

import mssql_python

mssql_python.pooling()

Teljes migrálási példa

Az alábbiakban ugyanazt a függvényt mutatja pyodbc-vel írva, majd mssql-pythonnal újraírva.

Előtte (pyodbc)

Ez a verzió a pyodbc kapcsolati karakterlánc-et használja egy DRIVER kulcsszóval együtt:

import pyodbc
from datetime import date

def get_orders(customer_id: int, start_date: date):
    conn = pyodbc.connect(
        "DRIVER={ODBC Driver 18 for SQL Server};"
        "SERVER=localhost;"
        "DATABASE=AdventureWorks2022;"
        "Trusted_Connection=yes;"
    )
    cursor = conn.cursor()

    cursor.execute("""
        SELECT SalesOrderID, OrderDate, TotalDue
        FROM Sales.SalesOrderHeader
        WHERE CustomerID = ? AND OrderDate >= ?
        ORDER BY OrderDate DESC
    """, (customer_id, start_date))

    orders = []
    for row in cursor:
        orders.append({
            "id": row.SalesOrderID,
            "date": row.OrderDate,
            "total": row.TotalDue
        })

    cursor.close()
    conn.close()
    return orders

Miután (mssql-python)

Ez a verzió eltávolítja a DRIVER kulcsszót. Minden lekérdezés, paraméter és sorhozzáférési mintázat azonos marad:

import mssql_python
from datetime import date

def get_orders(customer_id: int, start_date: date):
    conn = mssql_python.connect(
        "Server=localhost;"
        "Database=AdventureWorks2022;"
        "Trusted_Connection=yes;"
    )
    cursor = conn.cursor()

    cursor.execute("""
        SELECT SalesOrderID, OrderDate, TotalDue
        FROM Sales.SalesOrderHeader
        WHERE CustomerID = ? AND OrderDate >= ?
        ORDER BY OrderDate DESC
    """, (customer_id, start_date))

    orders = []
    for row in cursor:
        orders.append({
            "id": row.SalesOrderID,
            "date": row.OrderDate,
            "total": row.TotalDue
        })

    cursor.close()
    conn.close()
    return orders

A módosítások csak az importálási utasítást és a kapcsolati sztringet érintik (nincs szükség a DRIVER kulcsszóra). Minden lekérdezés, paraméter, bevonási minta és sor hozzáférés ugyanaz marad.

A migráció tesztelése.

A migráció befejezése előtt ugyanazokat a lekérdezéseket futtatjuk mindkét meghajtón, és hasonlítsd össze az eredményeket, hogy megerősítsd az egyenlő viselkedést.

Ellenőrizze az egyenértékű működést

Használj egy összehasonlító függvényt, amely ugyanazt a lekérdezést futtatja mindkét meghajtóval szemben, és kiállítja, hogy az eredmények egyeznek:

import pyodbc
import mssql_python

def compare_results(pyodbc_conn_str: str, mssql_conn_str: str, query: str):
    """Compare results from both drivers."""
    # pyodbc query
    pyodbc_conn = pyodbc.connect(pyodbc_conn_str)
    pyodbc_cursor = pyodbc_conn.cursor()
    pyodbc_cursor.execute(query)
    pyodbc_results = pyodbc_cursor.fetchall()
    pyodbc_conn.close()
    
    # mssql-python query
    mssql_conn = mssql_python.connect(mssql_conn_str)
    mssql_cursor = mssql_conn.cursor()
    mssql_cursor.execute(query)
    mssql_results = mssql_cursor.fetchall()
    mssql_conn.close()
    
    # Compare
    assert len(pyodbc_results) == len(mssql_results)
    for p_row, m_row in zip(pyodbc_results, mssql_results):
        assert tuple(p_row) == tuple(m_row)
    
    print(f"Results match: {len(pyodbc_results)} rows")

Checklist

  • [ ] Frissítse az importokat a pyodbc -től -re mssql_python.
  • [ ] Távolítsd DRIVER= el a csatlakozási szálakat.
  • [ ] Tartsák meg a meglévő ? paraméterlekérdezéseket (működnek as-is).
  • [ ] Használj EXECUTE utasításokat tárolt eljáráshívásokhoz.
  • [ ] Távolítsd el a külső kapcsolatcsoportosítás konfigurációját.
  • [ ] Frissítse a kivételkezelő osztályneveket.
  • [ ] Teszteljük az összes lekérdezést és tárolt eljárást.
  • [ ] Ellenőrizd az adattípusok kezelését (különösen a tizedeseket és dátumokat).
  • [ ] Távolítsd el az ODBC illeperesítőt a telepítési követelményekből.