Použijte mssql-python s Apache Arrow

Ovladač mssql-python poskytuje metody načítání Apache Arrow pro vysoce výkonné sloupcové získávání dat z Microsoft SQL a Azure SQL Database.

Apache Arrow je vývojová platforma pro různé programovací jazyky určená pro sloupcová data v paměti. Ovladač převádí výsledky ODBC přímo do formátu Arrow v C++, čímž obchází tvorbu objektů v Python pro lepší výkon.

Integrace se šipkami umožňuje:

  • Přenos dat bez kopírování do Polars, Pandas a DuckDB. „Zero-copy“ znamená, že data zůstávají v jediném paměťovém bufferu, do kterého ovladač zapisuje a ze kterého knihovny, které data využívají, čtou přímo, takže se žádné řádky neduplikují do mezilehlých objektů Pythonu.
  • Streamování sad výsledků prostřednictvím RecordBatchReader bez načtení všeho do paměti.
  • Sloupcový datový formát ideální pro analytické a strojové učení.
  • Snížená spotřeba paměti ve srovnání s tvorbou objektů po řádcích v Python.

Metody kurzoru

Balíček pyarrow je vyžadován k použití metod načítání Arrow. Nainstalujte ho pomocí pip install pyarrow. Pokud pyarrow není nainstalován, při volání jakékoli metody Arrow dojde k vyvolání ImportError.

Ovladač mssql-python přidává tři metody k objektu kurzoru pro přístup k datům Arrow. Všechny tři metody převádějí výsledky ODBC do formátu Arrow ve vrstvě C++ ovladače, což zabraňuje vytváření mezilehlých Python objektů.

  • arrow() vrací celou množinu výsledků jako jednu tabulku v paměti. Nejjednodušší na používání.
  • arrow_batch() vrací jednu várku řádků najednou, takže máte manuální kontrolu nad smyčkou.
  • arrow_reader() vrací iterátor, který automaticky vrací dávky. Nejlepší pro streamování rozsáhlých výsledků.

Pomocí cursor.arrow(batch_size=8192)

Získejte celou množinu výsledků jako jednu pyarrow.Table. Tato metoda je nejjednodušší a dobře funguje, když se celá množina výsledků vejde do paměti.

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

Pokud váš připojovací řetězec používá Authentication=ActiveDirectoryDefault, ovladač používá DefaultAzureCredential, který zkouší více poskytovatelů přihlašovacích údajů za sebou. První spojení může být pomalé, protože SDK prochází řetězec, dokud nenajde funkčního poskytovatele. V produkci, pokud víte, jaký typ přihlašovacích údajů vaše prostředí používá, zadejte ho přímo (například ActiveDirectoryMSI pro spravovanou identitu), abyste se vyhnuli tzv. chain walk. Další informace naleznete v tématu ověřování Microsoft Entra.

Pomocí cursor.arrow_batch(batch_size=8192)

Získejte jediný pyarrow.RecordBatch obsah obsahující až batch_size řadu řádků. Použijte tuto metodu pro vlastní smyčky dávkového zpracování, kde potřebujete podrobnou kontrolu nad tím, kolik řádků se má najednou načíst.

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

Pomocí cursor.arrow_reader(batch_size=8192)

Vraťte pyarrow.RecordBatchReader, které vrací objekty RecordBatch, dokud se nevyčerpá sada výsledků. Tato metoda je nejefektivnější z hlediska paměti pro velké množiny výsledků.

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

Obvyklé scénáře

Tabulky šipek se přímo integrují s populárními Python datovými knihovnami. Následující příklady ukazují, jak předávat data ze Arrow do pandas, Polars, DuckDB a souborových formátů bez kopírování dat.

Načtěte výsledky do 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())

Načíst výsledky do Polars

import polars as pl

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

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

Výsledky dotazů pomocí DuckDB

DuckDB může dotazovat tabulky Arrow přímo v SQL bez kopírování dat. Tato schopnost je užitečná, když potřebujete SQL analýzu na výsledcích, které už jsou ve formátu 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())

Průběžně exportujte velké sady výsledků ve formátu Parquet

Pro velké sady výsledků streamujte Arrow batchy přímo do souboru Parquet, aniž byste museli načítat celý dataset do paměti. ParquetWriter zapisuje každou dávku inkrementálně.

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

Export do jiných formátů

PyArrow poskytuje vestavěné zapisovače pro CSV a formát Arrow IPC (známý také jako Feather V2). Soubory Arrow IPC přesně zachovávají datové typy Arrow a lze je rychle načíst zpět.

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)

Mapování datových typů

Metody načítání Arrow mapují typy Microsoft SQL na typy Arrow na úrovni C++.

Microsoft SQL typ Typ šipky
int, smallint, tinyint, bigint int32, int16, , int8int64
float, real float64, float32
Desetinné, číselné decimal128
bit bool
Char, Varchar, Nchar, Nvarchar utf8
text, ntext large_utf8
Binární, varbinární binary, large_binary
date date32
time time64[us]
Datetime, datetime2, smalldatetime timestamp[us]
datetimeoffset timestamp[us, tz=UTC]
uniqueidentifier utf8 (velká písmena)
xml utf8

Note

Ovladač převede datetimeoffset typ na UTC, protože sloupce Arrow vyžadují pevné časové pásmo. Ovladač normalizuje informace o časových pásmech jednotlivých buněk z Microsoft SQL do UTC během konverze.

Tento sql_variant typ není podporován metodami načítání Arrow a vytváří výjimku pro nepodporovaný datový typ. Použijte standardní fetchone(), fetchmany() nebo fetchall() pro dotazy, které vracejí sloupce sql_variant.

Důležité informace o výkonu

Metody načítání šipkami jsou nejrychlejší pro analytiku a operace s hromadnými daty, zatímco standardní metody kurzoru jsou vhodnější pro transakční vzory s malými sadami výsledků.

Kdy použít Arrow oproti standardnímu načítání

Scenario Doporučený přístup
Přineste pár řad na vystavení fetchone() / fetchall()
Načítání dat do pandy nebo polárů cursor.arrow()
Zpracování velkých datových sad v částech cursor.arrow_reader()
Vyhledávání v jednom řádku nebo malé množiny výsledků fetchone() / fetchval()
Analytické nebo agregační kanály cursor.arrow() + Polars/DuckDB
Zapisujte výsledky do Parquet nebo Arrow IPC cursor.arrow_reader() + PyArrow I/O

Správa paměti pro velké datové sady

Pro množiny výsledků, které mohou překročit dostupnou paměť, použijte arrow_reader() s rozumnou batch_sizehodnotou .

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

Upravte velikost dávky

Parametr batch_size určuje, kolik řádků je načteno v každé dávce. Optimální velikost závisí na šířce řádku a dostupné paměti. Širší řádky s velkými sloupci jako nvarchar(max) nebo varbinary(max) těží z menších velikostí dávek, zatímco úzké řádky těží z větších.

  • Výchozí (8192): Dobrá rovnováha pro většinu pracovních zátěží.
  • Menší (1000-5000): Použijte pro široké tabulky s velkými sloupci.
  • Větší (50000-100000): Použití pro úzké tabulky nebo když je propustnost důležitější než paměť.
# 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)