Utilisez mssql-python avec Apache Arrow

Le pilote mssql-python fournit des méthodes de récupération Apache Arrow pour la récupération de données columnaires haute performance depuis Microsoft SQL et Azure SQL Database.

Apache Arrow est une plateforme de développement multi-langages pour les données en colonnes en mémoire. Le pilote convertit directement les ensembles de résultats ODBC en format Arrow en C++, contournant la création d’objets Python pour améliorer les performances.

L’intégration de Arrow permet :

  • Transfert de données sans copie vers Polars, pandas et DuckDB. « Zero-copy » signifie que les données restent dans un seul tampon mémoire que le pilote écrit et que les bibliothèques consommantes lisent directement, de sorte qu’aucune ligne n’est dupliquée en objets Python intermédiaires.
  • Le résultat de streaming passe RecordBatchReader sans tout charger en mémoire.
  • Format de données en colonnes idéal pour les charges de travail analytiques et d’apprentissage automatique.
  • Réduction de la consommation de mémoire par rapport à la création d’objets Python ligne par ligne.

Méthodes de Curseur

Le pyarrow package doit utiliser des méthodes de récupération Arrow. Installez-le avec pip install pyarrow. Si pyarrow n’est pas installé, appeler n’importe quelle méthode Arrow génère un ImportError.

Le pilote mssql-python ajoute trois méthodes à l’objet curseur pour l’accès aux données Arrow. Les trois méthodes convertissent les ensembles de résultats ODBC au format Arrow dans la couche C++ du pilote, ce qui évite de créer des objets Python intermédiaires.

  • arrow() renvoie l’ensemble des résultats sous forme d’une seule table en mémoire. Les plus simples à utiliser.
  • arrow_batch() renvoie un lot de lignes à la fois, vous donnant le contrôle manuel de la boucle.
  • arrow_reader() renvoie un itérateur qui génère automatiquement des lots. Idéal pour diffuser de gros résultats.

Utilisation de cursor.arrow(batch_size=8192)

Récupérez l’ensemble des résultats comme un seul pyarrow.Table. Cette méthode est la plus simple et fonctionne bien lorsque l’ensemble complet des résultats tient en mémoire.

import mssql_python

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

cursor.execute("SELECT ProductID, Name, ListPrice FROM Production.Product")
table = cursor.arrow()

print(type(table))       # <class 'pyarrow.lib.Table'>
print(table.num_rows)    # Number of rows fetched
print(table.num_columns) # Number of columns
print(table.schema)      # Column names and Arrow types
print(table.to_pandas()) # Convert to pandas DataFrame

Note

Si votre chaîne de connexion utilise Authentication=ActiveDirectoryDefault, le pilote utilise DefaultAzureCredential, ce qui essaie plusieurs fournisseurs d’identifiants en séquence. La première connexion peut être lente car le SDK parcourt la chaîne jusqu’à ce qu’il trouve un fournisseur fonctionnel. En production, si vous savez quel type d’identifiant votre environnement utilise, spécifiez-le directement (par exemple, ActiveDirectoryMSI pour l’identité gérée) afin d’éviter la marche en chaîne. Pour plus d’informations, consultez Authentification Microsoft Entra.

Utilisation de cursor.arrow_batch(batch_size=8192)

Récupérez un seul pyarrow.RecordBatch contenant jusqu’à batch_size lignes. Utilisez cette méthode pour des boucles de traitement batch personnalisées où vous avez besoin d’un contrôle précis sur le nombre de lignes récupérées à la fois.

cursor.execute("SELECT * FROM Production.TransactionHistory")

while True:
    batch = cursor.arrow_batch(batch_size=10000)
    if batch.num_rows == 0:
        break
    # Process each batch
    print(f"Fetched {batch.num_rows} rows")

Utilisation de cursor.arrow_reader(batch_size=8192)

Retourner un pyarrow.RecordBatchReader qui renvoie des objets RecordBatch jusqu’à épuisement du jeu de résultats. Cette méthode est l’option la plus efficace en mémoire pour les grands ensembles de résultats.

cursor.execute("SELECT * FROM Production.TransactionHistory")
reader = cursor.arrow_reader(batch_size=50000)

for batch in reader:
    # Process streaming batches without loading all data
    print(f"Batch: {batch.num_rows} rows")

Modèles courants

Les tables de flèches s’intègrent directement avec les bibliothèques de données Python populaires. Les exemples suivants montrent comment transmettre les données Arrow aux pandas, Polars, DuckDB et formats de fichiers sans copier les données.

Charger les résultats dans pandas

cursor.execute("SELECT * FROM Production.Product")
table = cursor.arrow()

# Convert to pandas with zero-copy where possible
df = table.to_pandas()
print(df.head())

Charger les résultats dans Polars

import polars as pl

cursor.execute("SELECT * FROM Production.Product")
table = cursor.arrow()

df = pl.from_arrow(table)
print(df)

Résultats de requêtes avec DuckDB

DuckDB peut interroger directement les tables de flèches en SQL sans copier les données. Cette fonctionnalité est utile lorsque vous avez besoin d’une analyse de type SQL sur des ensembles de résultats déjà au format Arrow.

import duckdb

cursor.execute("SELECT * FROM Sales.SalesOrderHeader")
arrow_table = cursor.arrow()

# Query the Arrow table with DuckDB SQL
result = duckdb.sql("SELECT CustomerID, SUM(TotalDue) FROM arrow_table GROUP BY CustomerID")
print(result.fetchall())

Exporter en flux des jeux de résultats volumineux vers Parquet

Pour de grands ensembles de résultats, diffusez des lots Arrow directement vers un fichier Parquet sans charger l’ensemble de données en mémoire. Le ParquetWriter écrit chaque lot de façon incrémentale.

import pyarrow.parquet as pq

cursor.execute("SELECT * FROM Production.TransactionHistory")
reader = cursor.arrow_reader(batch_size=100000)

# Write streaming batches to a Parquet file
writer = None
for batch in reader:
    if writer is None:
        writer = pq.ParquetWriter("output.parquet", batch.schema)
    writer.write_batch(batch)

if writer:
    writer.close()

Exportation vers d’autres formats

PyArrow fournit des graveurs intégrés pour CSV et le format de fichier IPC Arrow (également connu sous le nom de Feather V2). Les fichiers Arrow IPC conservent exactement les types Arrow et peuvent être relus rapidement.

import pyarrow as pa
import pyarrow.csv as pcsv

cursor.execute("SELECT * FROM Production.Product")
table = cursor.arrow()

# Write to CSV
pcsv.write_csv(table, "products.csv")

# Write to an Arrow IPC file
with pa.ipc.new_file("products.arrow", table.schema) as writer:
    writer.write_table(table)

Mappages de types de données

Les méthodes de récupération Arrow associent les types SQL Microsoft aux types Arrow au niveau C++.

type SQL Microsoft Type de flèche
int, smallint, tinyint, bigint int32, int16, int8, int64
flottant, réel float64, float32
décimal, numérique decimal128
bit bool
Char, Varchar, Nchar, Nvarchar utf8
Texte, Ntext large_utf8
binaire, varbinaire binary, large_binary
date date32
time time64[us]
datetime, datetime2, smalldatetime timestamp[us]
datetimeoffset timestamp[us, tz=UTC]
uniqueidentifier utf8 (corde majuscule)
xml utf8

Note

Le pilote convertit le datetimeoffset type en UTC car les colonnes Arrow nécessitent un fuseau horaire fixe. Le pilote normalise les informations de fuseau horaire pour chaque cellule de Microsoft SQL en UTC lors de la conversion.

Ce sql_variant type n’est pas pris en charge par les méthodes Arrow Fetch et génère une exception de type de données non prise en charge. Utilisez la valeur standard fetchone(), fetchmany() ou fetchall() pour les requêtes qui renvoient sql_variant colonnes.

Considérations relatives aux performances

Les méthodes de récupération de flèches sont les plus rapides pour l’analytique et les opérations de données en masse, tandis que les méthodes de curseur standard conviennent mieux aux modèles transactionnels avec de petits ensembles de résultats.

Quand utiliser Arrow ou la récupération standard

Scénario Approche recommandée
Récupérez quelques rangées pour les afficher fetchone() / fetchall()
Charger les données dans les pandas ou les Polar cursor.arrow()
Traiter de grands ensembles de données par blocs cursor.arrow_reader()
Recherches à une seule ligne ou petits ensembles de résultats fetchone() / fetchval()
Analyse ou pipelines d’agrégation cursor.arrow() + Polars/DuckDB
Écrire les résultats sur Parquet ou Arrow IPC cursor.arrow_reader() + PyArrow E/S

Gestion de la mémoire pour de grands ensembles de données

Pour les jeux de résultats susceptibles de dépasser la mémoire disponible, utilisez arrow_reader() avec un batch_size raisonnable.

cursor.execute("SELECT * FROM Production.TransactionHistory")

# Process in batches of 100K rows
reader = cursor.arrow_reader(batch_size=100000)
total_rows = 0

for batch in reader:
    # Work with each batch individually
    total_rows += batch.num_rows
    # batch goes out of scope and memory is freed

print(f"Processed {total_rows} rows")

Ajuster la taille du lot

Le batch_size paramètre contrôle combien de lignes sont récupérées dans chaque lot. La taille optimale dépend de la largeur de votre ligne et de la mémoire disponible. Les rangées plus larges avec de grandes colonnes comme nvarchar(max) ou varbinary(max) bénéficient de tailles de lots plus petites, tandis que les rangées étroites bénéficient de plus grandes.

  • Par défaut (8192) : Bon équilibre pour la plupart des charges de travail.
  • Plus petits (1000-5000) : À utiliser pour de larges tables avec de grandes colonnes.
  • Plus grand (50000-100000) : Utilisation pour des tables étroites ou lorsque le débit compte plus que la mémoire.
# Narrow table with many rows - use larger batches
cursor.execute("SELECT ProductID, ListPrice FROM Production.Product")
table = cursor.arrow(batch_size=100000)

# Wide table with LOB columns - use smaller batches
cursor.execute("SELECT * FROM Production.Document")
table = cursor.arrow(batch_size=1000)