Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Driver mssql-python menyediakan beberapa jalur untuk membaca data dari Microsoft SQL. Setiap jalur sesuai dengan beban kerja yang berbeda. Panduan ini membantu Anda memilih yang tepat berdasarkan ukuran data, kebutuhan analisis, dan persyaratan performa.
Tentukan berdasarkan beban kerja
Gunakan tabel ini untuk menemukan titik awal Anda:
| Beban Kerja | Jalur yang direkomendasikan | Mengapa |
|---|---|---|
| Akses baris pada aplikasi (API web, CRUD) | Metode pengambilan kursor | Beban tambahan rendah, pemrosesan per baris, tanpa dependensi tambahan. |
| Permintaan pelaporan kecil hingga menengah | pandas | API yang sudah dikenal untuk pemfilteran, pengelompokan, dan visualisasi. |
| Set hasil besar atau tabel lebar | Ekstraksi panah | Transfer kolom tanpa salinan, overhead memori minimal. |
| Analitik berperforma tinggi | Polars dengan Arrow | Eksekusi multithread pada data kolom, tidak ada perselisihan GIL. |
| SQL ad hoc pada data lokal dan data jarak jauh | DuckDB dengan Arrow | Analisis SQL pada tabel Arrow, gabungkan dengan file CSV/Parquet lokal. |
| Eksplorasi buku catatan | pandas atau Polars with Arrow | Pilih berdasarkan keakraban tim dan ukuran data. |
Metode pengambilan kursor
Gunakan metode kursor standar saat Anda memerlukan akses berorientasi baris tanpa dependensi tambahan. Metode ini adalah pilihan yang tepat untuk kode aplikasi yang memproses satu baris pada satu waktu, mengembalikan respons API, atau memberi makan logika aplikasi.
import mssql_python
conn = mssql_python.connect(
server="<server>.database.windows.net",
database="<database>",
authentication="ActiveDirectoryDefault",
encrypt="yes"
)
cursor = conn.cursor()
# fetchone(): Process rows one at a time
cursor.execute("SELECT ProductID, Name, ListPrice FROM Production.Product WHERE ListPrice > %(threshold)s", {"threshold": 100})
row = cursor.fetchone()
while row:
print(f"{row.Name}: ${row.ListPrice:.2f}")
row = cursor.fetchone()
# fetchmany(): Process in batches
cursor.execute("SELECT ProductID, Name FROM Production.Product")
while True:
batch = cursor.fetchmany(100)
if not batch:
break
for row in batch:
print(row.Name)
# fetchval(): Get a single scalar value
cursor.execute("SELECT COUNT(*) FROM Production.Product")
count = cursor.fetchval()
Gunakan fetchmany() untuk pemrosesan batch yang hemat memori dari kumpulan hasil besar. Gunakan fetchval() saat Anda memerlukan satu nilai seperti jumlah, maksimum, atau pemeriksaan keberadaan.
Untuk dokumentasi metode pengambilan lengkap, lihat Mengambil data.
Ekstraksi panah
Gunakan ekstraksi Arrow saat Anda memerlukan data kolumnar untuk analitik, pembuatan DataFrame, atau ekspor ke Parquet. Arrow menyediakan transfer data tanpa salinan dari driver, yang menghindari overhead konversi baris demi baris untuk membangun DataFrame dari fetchall().
Tabel dengan indeks columnstore sudah disimpan dalam format kolumnar di mesin basis data, sehingga ekstraksi Arrow menjadi sangat sesuai untuk beban kerja tersebut.
cursor.execute("""
SELECT ProductID, Name, ListPrice, Color
FROM Production.Product
WHERE ListPrice > 0
""")
# Get a single Arrow table
arrow_table = cursor.arrow()
print(f"{arrow_table.num_rows} rows, {arrow_table.num_columns} columns")
Untuk kumpulan hasil besar, gunakan arrow_reader() untuk mengalirkan batch tanpa memuat semuanya ke dalam memori:
cursor.execute("SELECT * FROM Sales.SalesOrderHeader")
# Stream Arrow record batches
reader = cursor.arrow_reader(batch_size=10000)
for batch in reader:
# Each batch is a pyarrow.RecordBatch
print(f"Batch: {batch.num_rows} rows")
Tabel Arrow adalah titik awal untuk pandas, Polars, dan DuckDB. Ekstrak sekali, lalu konversikan:
cursor.execute("""
SELECT ProductID, Name, ListPrice, Color
FROM Production.Product
WHERE ListPrice > 0
""")
arrow_table = cursor.arrow()
# Arrow -> pandas
df = arrow_table.to_pandas()
# Arrow -> Polars (zero-copy)
import polars as pl
df = pl.from_arrow(arrow_table)
Untuk dokumentasi Arrow lengkap, lihat Integrasi Apache Arrow.
pandas
Gunakan panda saat Anda memerlukan DataFrame API yang sudah dikenal untuk pelaporan, analisis ad hoc, atau pembersihan data. pandas berfungsi paling baik dengan set hasil yang muat dalam memori (hingga beberapa juta baris, tergantung pada lebar kolom).
cursor.execute("""
SELECT p.Name, p.ListPrice, pc.Name AS Category
FROM Production.Product p
JOIN Production.ProductSubcategory ps ON p.ProductSubcategoryID = ps.ProductSubcategoryID
JOIN Production.ProductCategory pc ON ps.ProductCategoryID = pc.ProductCategoryID
WHERE p.ListPrice > 0
""")
import pandas as pd
rows = cursor.fetchall()
columns = [desc[0] for desc in cursor.description]
df = pd.DataFrame.from_records(rows, columns=columns)
# Analyze
print(df.groupby("Category")["ListPrice"].agg(["mean", "count"]))
Untuk kumpulan hasil yang lebih besar, buat DataFrame dari Arrow, bukan fetchall():
cursor.execute("SELECT * FROM Sales.SalesOrderHeader")
arrow_table = cursor.arrow()
df = arrow_table.to_pandas()
Untuk pola penggunaan pandas yang lengkap, termasuk ETL, deret waktu, dan penulisan kembali, lihat integrasi pandas.
Polars dengan Arrow
Gunakan Polar saat Anda membutuhkan operasi DataFrame yang lebih cepat pada kumpulan hasil yang lebih besar. Polars menggunakan Apache Arrow sebagai format memorinya, sehingga transfer dari cursor.arrow() adalah zero-copy. Polars juga menjalankan operasi pada beberapa utas, yang menghindari perselisihan GIL pada transformasi berat CPU.
import polars as pl
cursor.execute("""
SELECT ProductID, Name, ListPrice, Color
FROM Production.Product
WHERE ListPrice > 0
""")
arrow_table = cursor.arrow()
df = pl.from_arrow(arrow_table)
# Filter and aggregate
result = (
df.filter(pl.col("ListPrice") > 100)
.group_by("Color")
.agg(pl.col("ListPrice").mean().alias("AvgPrice"))
.sort("AvgPrice", descending=True)
)
print(result)
Untuk streaming kumpulan hasil besar:
cursor.execute("SELECT * FROM Sales.SalesOrderHeader")
reader = cursor.arrow_reader(batch_size=50000)
frames = []
for batch in reader:
frames.append(pl.from_arrow(batch))
df = pl.concat(frames)
Untuk pola Kutub lengkap, lihat Integrasi Kutub.
DuckDB dengan Arrow
Gunakan DuckDB saat Anda perlu menjalankan analitik SQL pada data yang diekstrak, menggabungkan data server dengan file CSV atau Parquet lokal, atau mengekspor hasil ke format file. DuckDB bekerja dengan tabel Arrow dengan akses zero-copy.
import duckdb
cursor.execute("""
SELECT ProductID, Name, ListPrice, Color
FROM Production.Product
WHERE ListPrice > 0
""")
products = cursor.arrow()
# Run DuckDB SQL on the Arrow table
result = duckdb.sql("""
SELECT Color, AVG(ListPrice) AS AvgPrice, COUNT(*) AS Count
FROM products
WHERE Color IS NOT NULL
GROUP BY Color
ORDER BY AvgPrice DESC
""")
print(result.fetchdf())
Gabungkan data server dengan file lokal:
cursor.execute("SELECT CustomerID, TerritoryID FROM Sales.Customer")
customers = cursor.arrow()
# Join with a local CSV file
result = duckdb.sql("""
SELECT c.CustomerID, c.TerritoryID, l.Region
FROM customers c
JOIN read_csv_auto('regions.csv') l ON c.TerritoryID = l.TerritoryID
""")
Ekspor ke Parket:
cursor.execute("SELECT * FROM Sales.SalesOrderHeader")
orders = cursor.arrow()
duckdb.sql("COPY orders TO 'orders.parquet' (FORMAT PARQUET)")
Untuk pola DuckDB lengkap, lihat Integrasi DuckDB.
Fitur Microsoft SQL yang memengaruhi keputusan jalur baca
Mesin database memiliki fitur yang secara langsung memengaruhi jalur baca mana yang paling berfungsi. Pertimbangkan fitur-fitur ini saat memilih pendekatan Anda:
Indeks penyimpanan kolom
Tabel dengan indeks penyimpan kolom menyimpan data dalam format kolom. Ekstraksi Arrow adalah pilihan yang paling alami untuk tabel-tabel ini karena data sudah berformat kolumnar di dalam mesin. Jika kueri analitik Anda memindai tabel lebar dengan jutaan baris, indeks columnstore nonkluster di sisi server yang dipadukan dengan ekstraksi Arrow di sisi klien memberikan throughput menyeluruh terbaik.
Pandangan terindeks
Tampilan yang diindeks menghitung terlebih dahulu dan menyimpan hasil agregat atau gabungan di server. Jika analisis pandas atau Polars Anda berulang kali menghitung agregasi yang sama, pertimbangkan untuk membuat tampilan terindeks dan melakukan kueri pada tampilan tersebut sebagai gantinya. Server secara otomatis mempertahankan tampilan saat data yang mendasarinya berubah.
Toko Permintaan (Query Store)
Query Store melacak statistik eksekusi kueri dari waktu ke waktu. Gunakan ini untuk mengidentifikasi kueri mana yang cukup mahal sehingga layak dilakukan ekstraksi Arrow dan analisis DataFrame lokal, dibandingkan dengan pembacaan langsung melalui kursor. Jika kueri berjalan dalam hitungan milidetik, fetch kursor tidak masalah. Jika proses ini memindai jutaan baris, ekstraksi Arrow dan analisis lokal dapat mengurangi beban server.
Pemrosesan kueri pintar
Fitur pemrosesan kueri cerdas Microsoft SQL, seperti gabungan adaptif, mode batch di rowstore, dan umpan balik peruntukan memori, secara otomatis mengoptimalkan eksekusi kueri. Fitur-fitur ini berfungsi terlepas dari jalur baca klien mana yang Anda pilih, tetapi fitur ini paling menguntungkan kueri analitik besar. Anda tidak perlu menyetel petunjuk atau rencana eksekusi untuk sebagian besar beban kerja.
Alirkan set hasil berukuran besar
Untuk kumpulan hasil yang tidak muat dalam memori, gunakan pola streaming:
Streaming berbasis kursor dengan fetchmany():
cursor.execute("SELECT * FROM Sales.SalesOrderHeader")
while True:
batch = cursor.fetchmany(5000)
if not batch:
break
for row in batch:
print(row[0]) # Process each row
Streaming berbasis panah ke Parquet:
import pyarrow.parquet as pq
cursor.execute("SELECT * FROM Sales.SalesOrderHeader")
reader = cursor.arrow_reader(batch_size=50000)
writer = None
for batch in reader:
if writer is None:
writer = pq.ParquetWriter("orders.parquet", batch.schema)
writer.write_batch(batch)
if writer:
writer.close()
Anti-pola yang harus dihindari
| Anti-pola praktek | Problem | Pendekatan yang lebih baik |
|---|---|---|
fetchall() kemudian pd.DataFrame() untuk tabel besar |
Memuat semua baris ke dalam memori dua kali (sekali sebagai tuple, sekali sebagai DataFrame). | Gunakan cursor.arrow() kemudian arrow_table.to_pandas(). |
| Mengonversi Arrow ke pandas hanya untuk memfilter baris | Memboroskan memori untuk salinan penuh pandas. | Lakukan pemfilteran di SQL (klausa WHERE) atau gunakan Polars/DuckDB langsung pada tabel Arrow. |
SELECT * Saat Anda membutuhkan tiga kolom |
Mentransfer data yang tidak perlu dari server. | Cantumkan hanya kolom yang Anda butuhkan. |
Membangun DataFrame untuk menghitung COUNT(*) |
Server menghitung agregat lebih cepat daripada Python. | Gunakan SELECT COUNT(*) dan fetchval(). |
| Membuka koneksi baru per kueri | Pembuatan koneksi memerlukan biaya besar bahkan jika overhead pooling diperhitungkan. | Gunakan kembali koneksi dalam satu unit kerja logis. |
| Panah Rantai -> panda -> Kutub | Setiap konversi menyalin data. | Langsung ke format target Anda: Arrow -> Polars atau Arrow -> pandas. |