Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
DuckDB è un motore di analisi SQL in processo che può interrogare direttamente le tabelle Apache Arrow senza dover copiare dati. Combinando DuckDB con il driver mssql-python puoi farti:
- Esegui query SQL analitiche su set di risultati di Microsoft SQL senza caricare dati in pandas o Polars.
- Interroga le tabelle Arrow in memoria senza overhead di copia.
- Unisci i dati SQL Microsoft ai file locali (CSV, Parquet, JSON) in una singola query DuckDB.
- Esporta i dati Microsoft SQL su Parquet, CSV o altri formati tramite DuckDB.
Prerequisiti
- Python 3.10 o versione successiva.
- I pacchetti
mssql-python,duckdbepyarrow. Installa tutto conpip install mssql-python duckdb pyarrow. - Installare prerequisiti specifici del sistema operativo monouso. Gli utenti Windows possono saltare questo passaggio. Per dettagli completi sulla piattaforma, vedi Installa mssql-python.
Creare un database SQL
Crea o collegati a un database SQL su una delle seguenti piattaforme:
Gli esempi in questo articolo interrogano il AdventureWorks database di esempio. Se non lo possiedi già, consulta i database di esempio di AdventureWorks.
Installa le dipendenze
pip install mssql-python duckdb pyarrow
Consulta i dati SQL di Microsoft con DuckDB
Il flusso di lavoro base è: eseguire una query con mssql-python, recuperare i risultati come tabella delle frecce, poi interrogare quella tabella con DuckDB SQL.
Schema di base
Inizia stabilendo una connessione e recuperando i dati come tabella Arrow.
import duckdb
import mssql_python
conn = mssql_python.connect(
"Server=<server>.database.windows.net;"
"Database=<database>;"
"Authentication=ActiveDirectoryDefault;"
"Encrypt=yes"
)
cursor = conn.cursor()
# Fetch Microsoft SQL data as Arrow
cursor.execute("SELECT * FROM Production.Product WHERE ListPrice > 0")
products = cursor.arrow()
# Query the Arrow table with DuckDB
result = duckdb.sql("""
SELECT Color, COUNT(*) AS ProductCount, AVG(ListPrice) AS AvgPrice
FROM products
GROUP BY Color
ORDER BY ProductCount DESC
""")
print(result.fetchdf())
DuckDB fa riferimento alla products tabella Arrow con il nome della sua variabile Python. Nessun dato viene copiato nello storage di DuckDB.
Aggregato e filtro
Usa l'SQL di DuckDB per raggruppare e aggregare i dati Arrow.
cursor.execute("SELECT * FROM Sales.SalesOrderHeader")
orders = cursor.arrow()
# Top customers by total spend
top_customers = duckdb.sql("""
SELECT
CustomerID,
COUNT(*) AS OrderCount,
SUM(TotalDue) AS TotalSpent,
AVG(TotalDue) AS AvgOrderValue
FROM orders
GROUP BY CustomerID
HAVING SUM(TotalDue) > 10000
ORDER BY TotalSpent DESC
LIMIT 20
""")
print(top_customers.fetchdf())
Unire più risultati di Microsoft SQL
Prendi più tabelle da Microsoft SQL e uniscile in DuckDB senza scrivere una query cross-server.
# Fetch two tables
cursor.execute("SELECT * FROM Production.Product")
products = cursor.arrow()
cursor.execute("SELECT * FROM Production.ProductSubcategory")
subcategories = cursor.arrow()
# Join in DuckDB
result = duckdb.sql("""
SELECT
s.Name AS Subcategory,
COUNT(*) AS ProductCount,
ROUND(AVG(p.ListPrice), 2) AS AvgPrice
FROM products p
JOIN subcategories s ON p.ProductSubcategoryID = s.ProductSubcategoryID
GROUP BY s.Name
ORDER BY AvgPrice DESC
""")
print(result.fetchdf())
Unisci i dati SQL di Microsoft con file locali
DuckDB può leggere file CSV, Parquet e JSON nativamente. Combina i dati di SQL Server con i file locali in un'unica query.
Unisci con un file CSV
Carica un file CSV e uniscilo con i dati di Microsoft SQL.
import csv
from pathlib import Path
cursor.execute("SELECT CustomerID, PersonID FROM Sales.Customer")
customers = cursor.arrow()
csv_path = Path("customer_regions.csv")
with csv_path.open("w", newline="", encoding="utf-8") as file:
writer = csv.writer(file)
writer.writerow(["CustomerID", "Region", "Segment"])
writer.writerows([
(1, "West", "Premium"),
(2, "East", "Standard"),
(3, "Central", "Basic"),
])
try:
result = duckdb.sql("""
SELECT c.CustomerID, c.PersonID, f.Region, f.Segment
FROM customers c
JOIN read_csv_auto('customer_regions.csv') f ON c.CustomerID = f.CustomerID
""")
print(result.fetchdf())
finally:
csv_path.unlink(missing_ok=True)
Unisci a un file Parquet
Carica un file Parquet e uniscilo ai dati di Microsoft SQL.
from pathlib import Path
import pyarrow as pa
import pyarrow.parquet as pq
cursor.execute("SELECT ProductID, Name, ListPrice FROM Production.Product")
products = cursor.arrow()
parquet_path = Path("order_history.parquet")
order_history = pa.table({
"ProductID": [1, 2, 680],
"OrderDate": ["2024-06-01", "2024-03-15", "2024-01-10"],
"Quantity": [10, 5, 3],
})
pq.write_table(order_history, parquet_path)
try:
result = duckdb.sql("""
SELECT p.Name, p.ListPrice, h.OrderDate, h.Quantity
FROM products p
JOIN read_parquet('order_history.parquet') h ON p.ProductID = h.ProductID
WHERE h.OrderDate >= '2024-01-01'
""")
print(result.fetchdf())
finally:
parquet_path.unlink(missing_ok=True)
Esporta dati di Microsoft SQL
Usa la dichiarazione di COPY DuckDB per esportare i dati Microsoft SQL in vari formati file.
Esportazione in parquet
Esporta i dati in formato Apache Parquet.
cursor.execute("SELECT * FROM Production.Product")
products = cursor.arrow()
duckdb.sql("COPY products TO 'products.parquet' (FORMAT PARQUET)")
Esporta in CSV
Esporta i dati in un file di valori separati da virgole:
cursor.execute("SELECT * FROM Sales.SalesOrderHeader")
orders = cursor.arrow()
duckdb.sql("COPY orders TO 'orders.csv' (FORMAT CSV, HEADER)")
Esporta Parquet partizionato
Esporta i dati in file Parquet partizionati per l'analisi distribuita:
import shutil
from pathlib import Path
cursor.execute("SELECT * FROM Sales.SalesOrderHeader")
orders = cursor.arrow()
output_dir = Path("sales_data")
shutil.rmtree(output_dir, ignore_errors=True)
duckdb.sql("""
COPY (SELECT *, YEAR(OrderDate) AS OrderYear FROM orders)
TO 'sales_data'
(FORMAT PARQUET, PARTITION_BY (OrderYear))
""")
Trasmettere in streaming set di risultati di grandi dimensioni
Per grandi dataset, si usa arrow_reader() per elaborare dati in batch in streaming senza caricare tutte le righe in memoria contemporaneamente:
cursor.execute("SELECT * FROM Production.TransactionHistory")
reader = cursor.arrow_reader(batch_size=50000)
# Process each batch with DuckDB
total_rows = 0
for batch in reader:
result = duckdb.sql("""
SELECT ProductID, SUM(ActualCost) AS TotalCost
FROM batch
GROUP BY ProductID
""")
total_rows += batch.num_rows
print(f"Processed {total_rows} rows")
Accumula i risultati dello streaming
Per aggregare su tutti i lotti, registrare ogni batch in una connessione DuckDB persistente e accumulare i risultati in modo incrementale.
cursor.execute("SELECT * FROM Production.TransactionHistory")
reader = cursor.arrow_reader(batch_size=50000)
duck = duckdb.connect()
duck.execute("CREATE TABLE transactions (ProductID INT, ActualCost DOUBLE, Quantity INT)")
for batch in reader:
duck.execute("INSERT INTO transactions SELECT ProductID, ActualCost, Quantity FROM batch")
# Query the accumulated data
result = duck.sql("""
SELECT ProductID, SUM(ActualCost) AS TotalCost, SUM(Quantity) AS TotalQty
FROM transactions
GROUP BY ProductID
ORDER BY TotalCost DESC
LIMIT 10
""")
print(result.fetchdf())
duck.close()
Suggerimenti per le prestazioni
Lascia che Microsoft SQL si occupi del lavoro pesante
Microsoft SQL è più veloce per filtri, join e aggregazioni che per estrarre tutti i dati grezzi via wire. Usa DuckDB per l'analisi secondaria su set di risultati già recuperati, non come sostituto dell'ottimizzazione delle query di SQL Server.
# Suboptimal: Pull all rows, filter in DuckDB
cursor.execute("SELECT * FROM Sales.SalesOrderHeader")
orders = cursor.arrow()
result = duckdb.sql("SELECT * FROM orders WHERE TotalDue > 1000")
# Better: Filter in Microsoft SQL, analyze in DuckDB
cursor.execute("SELECT * FROM Sales.SalesOrderHeader WHERE TotalDue > 1000")
orders = cursor.arrow()
result = duckdb.sql("SELECT CustomerID, SUM(TotalDue) FROM orders GROUP BY CustomerID")
Usa Arrow per tutte le operazioni di lettura
Il trasferimento basato su frecce evita la creazione di oggetti Python intermedi, riducendo l'uso di memoria e migliorando la produttività. Preferisci cursor.arrow() alla conversione manuale riga per riga quando si passano dati a DuckDB.
Usa lo streaming per i grandi dataset
Per set di risultati più grandi della memoria disponibile, utilizzare arrow_reader() con un batch_size parametro per elaborare i dati in modo incrementale.