mssql-python ile bir veri erişimi ve analiz modeli seçin

Sürücü, mssql-python Microsoft SQL'den veri okumak için birden fazla yol sağlar. Her yol farklı iş yüklerine uyuyor. Bu rehber, veri boyutunuza, analiz ihtiyaçlarınıza ve performans gereksinimlerinize göre doğru olanı seçmenize yardımcı olur.

İş yüküne göre karar verin

Başlangıç noktanızı bulmak için bu tabloyu kullanın:

İş yükü Önerilen yol Neden?
Uygulama satırına erişim (web API, CRUD) İmleç alma yöntemleri Düşük ek yük, satır satır işleme, ek bağımlılık yok.
Küçük ve orta ölçekli raporlama sorguları pandas Filtreleme, gruplama ve görselleştirme için tanıdık API.
Büyük sonuç setleri veya geniş tablolar Ok çıkarımı Sıfır kopya sütunlu transfer, minimum bellek yükü.
Yüksek performans analizi Arrow ile Polars Sütun bazlı veriler üzerinde çok iş parçacıklı çalıştırma, GIL çekişmesi olmadan.
Yerel ve uzak veri üzerinden ad hoc SQL Arrow ile DuckDB Arrow tablolarında SQL analitiği, yerel CSV/Parquet dosyalarıyla birleştir.
Not defteri incelemesi pandalar veya oklu kutuplar Takım aşinalığı ve veri büyüklüğüne göre seçim yapın.

İmleç getirme yöntemleri

Ek bağımlılık olmadan satır odaklı erişim ihtiyacınız olduğunda standart imleç yöntemlerini kullanın. Bu yöntem, bir satır bir satırda işleyen, API yanıtlarını döndüren veya uygulama mantığı besleyen uygulama kodu için doğru seçimdir.

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

Büyük sonuç kümelerinin bellek açısından verimli toplu işlenmesi için fetchmany() kullanın. Tek bir değere ihtiyaç duyduğunuzda, sayım, maksimum veya varlık denetimi gibi durumlar için fetchval() kullanın.

Tam fetch yöntemi dokümantasyonu için bkz. Veri al.

Ok çıkarımı

Analitik, DataFrame oluşturma veya Parquet'e aktarma için sütunlu veriye ihtiyacınız olduğunda Arrow extraction kullanın. Arrow, sürücüden sıfır kopya veri aktarımı sağlar; bu da fetchall() öğesinden bir DataFrame oluşturmanın satır satır dönüştürme ek yükünü önler.

Columnstore indekslerine sahip tablolar zaten veritabanı motorunda sütunlu formatta saklanıyor, bu da Arrow çıkarımı bu iş yükleri için doğal bir uyum haline getiriyor.

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

Büyük sonuç kümeleri için, her şeyi belleğe yüklemeden toplu akış yapmak için kullanın arrow_reader() :

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

Ok tabloları pandalar, Polarlar ve DuckDB için başlangıç noktasıdır. Bir kez çıkar, sonra dönüştür:

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)

Tam Arrow dokümantasyonu için Apache Arrow entegrasyonuna bakınız.

pandas

Raporlama, geçici analiz veya veri temizliği için tanıdık bir DataFrame API'sine ihtiyacınız olduğunda pandas kullanın. Pandas, hafızaya sığan sonuç setleriyle en iyi çalışır (sütun genişliğine bağlı olarak birkaç milyon satıra kadar).

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

Daha büyük sonuç kümeleri için DataFrame'i fetchall() yerine Arrow'dan oluşturun:

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

ETL, zaman serisi ve geri yazma dahil olmak üzere tam pandas kalıpları için pandas entegrasyonuna bakınız.

Arrow ile Polars

Daha büyük sonuç setlerinde daha hızlı DataFrame işlemlerine ihtiyacınız olduğunda Polars kullanın. Polars, bellek biçimi olarak Apache Arrow kullanır; bu nedenle cursor.arrow() üzerinden yapılan aktarım sıfır kopyalıdır. Polars ayrıca birden fazla iş parçacığında işlemler yapar, bu da CPU ağırlıklı dönüşümlerde GIL rekabetini önler.

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)

Büyük sonuç setlerini yayınlamak için:

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)

Tam Polar desenleri için bkz. Polars entegrasyonu.

Arrow ile DuckDB

Çıkarılmış verilerde SQL analitiği çalıştırmak, sunucu verilerini yerel CSV veya Parquet dosyalarıyla birleştirmek veya sonuçları dosya formatlarına dışa aktarmak gerektiğinde DuckDB kullanın. DuckDB, sıfır kopya erişimi olan Ok tabloları üzerinde çalışır.

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

Sunucu verilerini yerel bir dosyayla birleştirin:

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

Parquet'e Dışa Aktar:

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

duckdb.sql("COPY orders TO 'orders.parquet' (FORMAT PARQUET)")

Tam DuckDB desenleri için DuckDB entegrasyonuna bakınız.

Okuma yolu kararlarını etkileyen Microsoft SQL özellikleri

Veritabanı motoru, hangi okuma yolunun en iyi çalıştığını doğrudan etkileyen özelliklere sahiptir. Yaklaşımınızı seçerken şu özellikleri göz önünde bulundurun:

Columnstore dizinleri

Columnstore indeksli tablolar verileri sütunlu formatta saklar. Arrow’a aktarma, bu tablolar için doğal bir aktarım yöntemidir çünkü veriler motor içinde zaten sütunlu biçimdedir. Eğer analitik sorgularınız milyonlarca satırdan oluşan geniş tabloları tarıyorsa, sunucu tarafında kümelenmiş olmayan columnstore indeksi ile istemci tarafındaki Arrow çıkarımı en iyi uçtan uca veri verimliliği sağlar.

İndekslenmiş görünümler

Indekslenen görünümler, toplu veya birleştirilmiş sonuçları önceden hesaplar ve sunucuda saklar. Pandas veya Polars analiziniz aynı toplamayı tekrar tekrar hesaplıyorsa, indeksli bir görünüm oluşturup o görünümü sorgulamayı düşünün. Sunucu, temel veri değiştikçe görünümü otomatik olarak korur.

Sorgu Mağazası

Query Store, sorgu yürütme istatistiklerini zaman içinde takip eder. Hangi sorguların doğrudan imleç okuması yerine Arrow çıkarımı ve yerel DataFrame analizini haklı çıkaracak kadar pahalı olduğunu belirlemek için kullanın. Bir sorgu milisaniyeler içinde çalışıyorsa, cursor fetch uygundur. Milyonlarca satır taranıyorsa, Arrow ile veri çıkarma ve verilerin yerel olarak analiz edilmesi sunucu yükünü azaltabilir.

Akıllı sorgu işleme

Microsoft SQL'in adaptif birleştirmeler, rowstore'da toplu mod ve bellek geri bildirimi gibi akıllı sorgu işleme özellikleri, sorgu yürütülmesini otomatik olarak optimize eder. Bu özellikler, hangi istemci okuma yolunu seçerseniz seçin çalışır; ancak en çok büyük analitik sorgulara yarar sağlar. Çoğu iş yükü için ipuçlarını veya uygulama planlarını ayarlamanıza gerek yok.

Büyük sonuç kümelerini akışla

Belleğe sığmayan sonuç kümeleri için akış desenleri kullanın:

İmleç tabanlı akış ile 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

Parquet'e Arrow tabanlı yayın:

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

Kaçınılması gereken anti-desenler

Desenden koruma Sorun Daha iyi bir yaklaşım
fetchall() sonra pd.DataFrame() büyük tablolar için Tüm satırları belleğe iki kez yükler (bir kez tuple olarak, bir kez DataFrame olarak). O zaman cursor.arrow()kullanınarrow_table.to_pandas().
Yalnızca satırları filtrelemek için Arrow’u pandas’a dönüştürme pandas'ın tam kopyası için bellek israf eder. SQL'de filtreleyin (WHERE madde) veya doğrudan Ok tablosunda Polars/DuckDB kullanın.
SELECT * Üç sütuna ihtiyacınız olduğunda Gereksiz verileri sunucudan aktarır. Sadece ihtiyacınız olan sütunları listeleyin.
Hesaplama için Bir DataFrame Oluşturma COUNT(*) Sunucu, Python'dan daha hızlı toplu hesaplar yapar. SELECT COUNT(*) ve fetchval() kullanın.
Sorgu başına yeni bağlantı açma Bağlantı oluşturmak, havuzlama yükü olsa bile pahalıdır. Mantıksal bir iş birimi içinde bağlantıları yeniden kullanın.
Zincirleme Oku -> pandalar -> kutuplar Her dönüşüm verileri kopyalıyor. Doğrudan hedef biçiminize gidin: Arrow -> Polars veya Arrow -> pandas.