Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
O driver mssql-python fornece métodos de busca Apache Arrow para recuperação de dados colunares de alto desempenho a partir do Microsoft SQL e do Base de Dados SQL do Azure.
O Apache Arrow é uma plataforma de desenvolvimento multilinguagem para dados colunares em memória. O driver converte conjuntos de resultados ODBC diretamente para o formato Arrow em C++, contornando a criação de objetos em Python para melhorar o desempenho.
A integração com Arrow permite:
- Transferência de dados sem cópia para Polars, pandas e DuckDB. "Zero-copy" significa que os dados permanecem num único buffer de memória, escrito pelo driver e lido diretamente pelas bibliotecas consumidoras, pelo que nenhuma linha é duplicada em objetos Python intermédios.
- Transmitir conjuntos de resultados em fluxo através de
RecordBatchReadersem carregar tudo na memória. - Formato de dados colunar ideal para cargas de trabalho de análise e aprendizagem automática.
- Redução do uso de memória em comparação com a criação de objetos Python linha a linha.
Métodos de cursor
O pyarrow pacote é obrigatório para usar métodos de busca Arrow. Instale-o com pip install pyarrow. Se pyarrow não estiver instalado, chamar qualquer método Arrow gera um ImportError.
O driver mssql-python adiciona três métodos ao objeto cursor para o acesso aos dados do Arrow. Os três métodos convertem conjuntos de resultados ODBC para o formato Arrow na camada C++ do driver, o que evita criar objetos Python intermédios.
-
arrow()devolve todo o conjunto de resultados como uma tabela em memória. Mais simples de utilizar. -
arrow_batch()devolve um lote de linhas de cada vez, o que lhe dá controlo manual sobre o ciclo. -
arrow_reader()devolve um iterador que gera lotes automaticamente. Ideal para a transmissão em fluxo de grandes volumes de resultados.
Ao utilizar cursor.arrow(batch_size=8192)
Obtenha todo o conjunto de resultados num único pyarrow.Table. Este método é o mais simples e funciona bem quando o conjunto completo de resultados cabe na memória.
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
Se a sua cadeia de ligação usar Authentication=ActiveDirectoryDefault, o controlador usa DefaultAzureCredential, que tenta vários fornecedores de credenciais em sequência. A primeira conexão pode ser lenta porque o SDK percorre a cadeia até encontrar um provedor funcional. Em produção, se souber que tipo de credencial o seu ambiente utiliza, especifique-o diretamente (por exemplo, ActiveDirectoryMSI para identidade gerida) para evitar o chain walk. Para obter mais informações, consulte Autenticação do Microsoft Entra.
Ao utilizar cursor.arrow_batch(batch_size=8192)
Obtém um único pyarrow.RecordBatch com até batch_size linhas. Use este método para ciclos personalizados de processamento em lote, onde precisa de controlo detalhado sobre quantas linhas são obtidas de cada vez.
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")
Ao utilizar cursor.arrow_reader(batch_size=8192)
Retorna um pyarrow.RecordBatchReader que produz objetos RecordBatch até esgotar o conjunto de resultados. Este método é a opção mais eficiente em termos de memória para conjuntos de resultados grandes.
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")
Padrões comuns
As tabelas de seta integram-se diretamente com bibliotecas de dados Python populares. Os exemplos seguintes mostram como passar dados do Arrow para pandas, Polars, DuckDB e formatos de ficheiro sem copiar dados.
Carregar resultados para o 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())
Carregar resultados para o Polars
import polars as pl
cursor.execute("SELECT * FROM Production.Product")
table = cursor.arrow()
df = pl.from_arrow(table)
print(df)
Resultados da consulta com o DuckDB
O DuckDB pode consultar tabelas Arrow diretamente em SQL sem copiar dados. Esta funcionalidade é útil quando precisas de análise ao estilo SQL em conjuntos de resultados que já estão em formato 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())
Transmitir grandes conjuntos de resultados para Parquet
Para conjuntos de resultados grandes, transmita lotes do Arrow diretamente para um ficheiro Parquet sem carregar todo o conjunto de dados na memória. O ParquetWriter escreve cada lote incrementalmente.
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()
Exportação para outros formatos
O PyArrow fornece gravadores incorporados para CSV e o formato de ficheiro IPC Arrow (também conhecido como Feather V2). Os ficheiros Arrow IPC preservam exatamente os tipos de Arrow e são rápidos de ler.
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)
Mapeamentos de tipo de dados
Os métodos de obtenção do Arrow mapeiam os tipos SQL da Microsoft para tipos Arrow ao nível de C++.
| Tipo Microsoft SQL | Tipo de flecha |
|---|---|
| int, smallint, tinyint, bigint |
int32, int16, int8, int64 |
| float, real |
float64, float32 |
| decimal, numérico | decimal128 |
| bit | bool |
| char, varchar, nchar, nvarchar | utf8 |
| texto, ntext | large_utf8 |
| binário, varbinário |
binary, large_binary |
| date | date32 |
| time | time64[us] |
| datetime, datetime2, smalldatetime | timestamp[us] |
| datetimeoffset | timestamp[us, tz=UTC] |
| uniqueidentifier |
utf8 (corda maiúscula) |
| xml | utf8 |
Note
O driver converte o datetimeoffset tipo para UTC porque as colunas Arrow requerem um fuso horário fixo. O driver normaliza a informação por fuso horário por célula do Microsoft SQL para UTC durante a conversão.
O sql_variant tipo não é suportado pelos métodos Arrow fetch e gera uma exceção de tipo de dado não suportado. Use o padrão fetchone(), fetchmany(), ou fetchall() para consultas que devolvam sql_variant colunas.
Considerações sobre desempenho
Os métodos de busca por seta são os mais rápidos para análises e operações de dados em massa, enquanto os métodos padrão de cursor são mais adequados para padrões transacionais com conjuntos de resultados pequenos.
Quando usar Arrow em vez do fetch padrão
| Scenario | Abordagem recomendada |
|---|---|
| Obtém algumas linhas para apresentação | fetchone() / fetchall() |
| Carregar dados para pandas ou Polars | cursor.arrow() |
| Processar grandes conjuntos de dados em blocos | cursor.arrow_reader() |
| Consultas de linha única ou pequenos conjuntos de resultados | fetchone() / fetchval() |
| Cadeias de análise ou de agregação |
cursor.arrow() + Polars/DuckDB |
| Escrever resultados em Parquet ou Arrow IPC |
cursor.arrow_reader() + PyArrow I/O |
Gestão de memória para grandes conjuntos de dados
Para conjuntos de resultados que possam exceder a memória disponível, utilize arrow_reader() com um valor razoável para batch_size.
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")
Ajustar o tamanho do lote
O batch_size parâmetro controla quantas linhas são obtidas em cada lote. O tamanho ideal depende da largura da linha e da memória disponível. Linhas mais largas com colunas grandes como nvarchar(max) ou varbinary(max) beneficiam de tamanhos de lote mais pequenos, enquanto filas estreitas beneficiam de tamanhos maiores.
- Predefinição (8192): Bom equilíbrio para a maioria das cargas de trabalho.
- Mais pequeno (1000-5000): Utilize para tabelas largas com colunas largas.
- Maior (50000-100000): Uso para tabelas estreitas ou quando o throughput importa mais do que a memória.
# 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)