Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Sürücü, mssql-python Microsoft SQL'e veri yazmak için birden fazla yol sağlar. Her yol farklı iş yüklerine uyuyor. Bu rehber, veri hacminize, kaynak formatınıza ve güncel anlam sisteminize göre doğru olanı seçmenize yardımcı olur.
İş yüküne göre karar verin
| İş yükü | Önerilen yol | Neden? |
|---|---|---|
| CSV dosyalarını bir tabloya yükleyin | CSV verilerini toplu kopya ile yükleyin |
bulkcopy() Jeneratör ile herhangi bir boyuttaki dosyaları belleğe yüklemeden işliyor. |
| Uygulama kodundan tek bir satır ekle | Tek satırlı eklemeler | Düşük yük, basit hata işleme, üretilen anahtarları geri göndermek için OUTPUT ile çalışır. |
| Uygulama kodundan küçük-orta ölçekli bir parti ekleyin | Toplu eklemeler | Tek tek eklemelere kıyasla gidiş gelişleri azaltır. |
| Herhangi bir kaynaktan yüzlerce veya daha fazla satır yükleyin | Toplu kopya | TDS toplu ekleme, büyük hacimler için en verimli yoldur. |
| Bir anahtara göre satır ekleme veya güncelleme | Upsert ile MERGE |
MERGE, INSERT, UPDATE ve DELETE öğelerini tek bir deyimde işler. |
| DataFrame'i tabloya yükle | Veri Çerçevelerini Yükle | pandas veya Polars'tan satırları alın ve bulkcopy() öğesine aktarın. |
| Parquet dosyaları aracılığıyla sahne verileri | Parquet hazırlama alanı | Ara dosya formatı gerektiğinde sistemler arası ETL için faydalıdır. |
CSV verilerini toplu kopya ile yükleyin
CSV verilerini yüklemek, Python veritabanı çalışmaları için en yaygın sorudur. Bir jeneratör beslemesiyle csv.reader kullanın bulkcopy():
import csv
import mssql_python
conn = mssql_python.connect(connection_string)
cursor = conn.cursor()
# Create a target table
cursor.execute("""
IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'ProductImport')
CREATE TABLE dbo.ProductImport (
Name nvarchar(100),
ProductNumber nvarchar(25),
ListPrice decimal(10,2)
)
""")
conn.commit()
def csv_rows(path):
with open(path, newline="", encoding="utf-8") as f:
reader = csv.reader(f)
next(reader) # Skip header
for row in reader:
yield (row[0], row[1], float(row[2]))
result = cursor.bulkcopy(
"dbo.ProductImport",
csv_rows("products.csv"),
batch_size=5000
)
print(f"Loaded {result['rows_copied']} rows")
conn.commit()
Üretici desen, dosya boyutu ne olursa olsun bellek kullanımını sabit tutar. Sütun eşlemesi ve kimlik işlemesi için bkz. Toplu kopyalama işlemleri.
Tek satırlı eklemeler
Her seferinde bir kaydı işlediğiniz uygulama düzeyindeki yazma işlemleri için tekli eklemeler kullanın. Oluşturulan anahtarları almak için OUTPUT INSERTED kullanın:
cursor.execute("""
INSERT INTO dbo.ProductImport (Name, ProductNumber, ListPrice)
OUTPUT INSERTED.Name
VALUES (%(name)s, %(product_number)s, %(list_price)s)
""", {"name": "Widget", "product_number": "WG-1000", "list_price": 19.99})
inserted_name = cursor.fetchval()
conn.commit()
Tekli insertler şu durumlarda doğru seçimdir:
- Her kullanıcı eylemi için bir satır eklersiniz (form gönderimi, API çağrısı).
- Eklemeden önce her satırı tek tek doğrulamanız veya dönüştürmeniz gerekir.
- Hemen eklenen ID veya diğer oluşturulan değerlere ihtiyacınız var.
Toplu eklemeler
Orta sayıda satırınız olduğunda ve toplu kopyalamanın sağladığı aktarım hızına ihtiyacınız olmadığında executemany() kullanın:
rows = [
{"name": "Widget A", "product_number": "WG-1001", "list_price": 19.99},
{"name": "Widget B", "product_number": "WG-1002", "list_price": 24.99},
{"name": "Widget C", "product_number": "WG-1003", "list_price": 29.99},
]
cursor.executemany(
"INSERT INTO dbo.ProductImport (Name, ProductNumber, ListPrice) VALUES (%(name)s, %(product_number)s, %(list_price)s)",
rows
)
conn.commit()
executemany() her satırı ayrı bir parametreli ifade olarak gönderir. Satır başına denetimden ziyade aktarım hızı daha önemli olduğunda, bulkcopy() TDS toplu ekleme protokolünü kullandığı için daha verimlidir. Geçiş noktası, satır genişliğine ve ağ gecikmesine bağlıdır; ancak genellikle birkaç yüz satırın alt sınırlarındadır.
Toplu kopya
İş hacmi satır bazında denetimden daha önemli olduğunda, bulkcopy() kullanın. Bu yöntem, satır satır eklemelerden çok daha verimli olan TDS toplu ekleme protokolünü kullanır:
rows = [
("Widget A", "WG-1001", 19.99),
("Widget B", "WG-1002", 24.99),
("Widget C", "WG-1003", 29.99),
]
result = cursor.bulkcopy("dbo.ProductImport", rows, batch_size=5000)
print(f"Loaded {result['rows_copied']} rows")
conn.commit()
Toplu kopyalama için performans ipuçları
- Bellek kullanımını sabit tutmak için büyük veri setleri için üreteçler kullanın.
- TDS toplu işlemi başına kaç satır gönderileceğini denetlemek için Set
batch_sizeseçeneğini ayarlayın. 5.000 ile başlayın ve sıra genişliğine göre ayarlayın. - Özel yükler için masa kilitleri kullanın:
cursor.bulkcopy("dbo.ProductImport", rows, table_lock=True). - Yüklemeden önce indeksleri devre dışı bırakın, sonra yeniden oluşturun. Bu dizi, yük sırasında indeks bakım yükünü önler.
Sütun eşlemeleri, kimlik sütunları, NULL işleme ve paralel yükleme için bkz. Toplu kopyalama işlemleri.
Upsert ile MERGE
MERGE, Microsoft SQL'de koşullu INSERT, UPDATE ve DELETE işlemlerini tek bir işlemde gerçekleştiren ifadedir. Python geliştiricilerinin sıkça ihtiyaç duyduğu "yeniyse ekle, varsa güncelle" desenini yönetiyor.
Tek satırlı upsert
Tek bir satır için, parametre takma adlarını tanımlayan bir USING yan tümcesiyle birlikte MERGE kullanın:
cursor.execute("""
MERGE dbo.ProductImport AS target
USING (SELECT %(name)s AS Name, %(product_number)s AS ProductNumber, %(list_price)s AS ListPrice) AS source
ON target.ProductNumber = source.ProductNumber
WHEN MATCHED THEN
UPDATE SET
Name = source.Name,
ListPrice = source.ListPrice
WHEN NOT MATCHED THEN
INSERT (Name, ProductNumber, ListPrice)
VALUES (source.Name, source.ProductNumber, source.ListPrice);
""", {"name": "Widget A", "product_number": "WG-1001", "list_price": 24.99})
conn.commit()
Sahneleme tablosu kullanarak toplu upsert
Toplu upsert işlemleri için, önce verileri geçici bir tabloya alın, ardından bu tablodan güncelleme yapmak için MERGE kullanın. DataFrame upsert işlemleri ve toplu güncellemeler için varsayılan kalıp olarak insert-or-update kullanın:
import csv
import mssql_python
conn = mssql_python.connect(connection_string)
cursor = conn.cursor()
# Step 1: Create a global temp table for staging
# Note: bulkcopy() requires global temp tables (##), not session temp tables (#)
cursor.execute("""
IF OBJECT_ID('tempdb..##ProductImportStage') IS NOT NULL
DROP TABLE ##ProductImportStage;
CREATE TABLE ##ProductImportStage (
Name nvarchar(100),
ProductNumber nvarchar(25),
ListPrice decimal(10,2)
)
""")
cursor.commit()
# Step 2: Bulk load into the staging table
def csv_rows(path):
with open(path, newline="", encoding="utf-8") as f:
reader = csv.reader(f)
next(reader)
for row in reader:
yield (row[0], row[1], float(row[2]))
cursor.bulkcopy("##ProductImportStage", csv_rows("products_update.csv"), batch_size=5000)
# Step 3: MERGE from staging into the target table
cursor.execute("""
MERGE dbo.ProductImport AS target
USING ##ProductImportStage AS source
ON target.ProductNumber = source.ProductNumber
WHEN MATCHED THEN
UPDATE SET
Name = source.Name,
ListPrice = source.ListPrice
WHEN NOT MATCHED BY TARGET THEN
INSERT (Name, ProductNumber, ListPrice)
VALUES (source.Name, source.ProductNumber, source.ListPrice)
OUTPUT $action, INSERTED.ProductNumber, DELETED.ProductNumber;
""")
# Step 4: Read the OUTPUT to see what changed
for row in cursor.fetchall():
print(f"{row[0]}: inserted={row[1]}, deleted={row[2]}")
conn.commit()
Bu örnek, varsayılan ekle-veya güncelle modelini göstermektedir:
-
INSERT Kaynakta bulunup hedefte bulunmayan satırlar (
WHEN NOT MATCHED BY TARGET). -
UPDATE her iki satırda da var olan satırlar (
WHEN MATCHED). - OUTPUT maddesi, her satırda hangi işlemlerin yapıldığını bildirir ve bu da denetim izleri için faydalıdır.
Caution
WHEN NOT MATCHED BY SOURCE THEN DELETE öğesini yalnızca hazırlama verileri hedefin esas alınan tam bir kopyası olduğunda ekleyin. Eğer toplu işlem yalnızca değiştirilmiş satırları içeriyorsa, bu yan tümce kaynak akışından kasıtlı olarak çıkarılmış satırları siler.
Tam uzlaştırmaya ihtiyacınız varsa, kaynağın hedef tablo için yetkili olduğunu doğruladıktan sonra uzatın MERGE :
WHEN NOT MATCHED BY SOURCE THEN
DELETE
Paylaşılan ortamlarda, eşzamanlı işler arasında çarpışmaları önlemek için her çalışma başına benzersiz bir küresel geçici tablo adı veya kalıcı bir aşamalama tablosu kullanın.
Bunun yerine ayrı UPDATE ve INSERT ifadelerinin ne zaman kullanılacağı
MERGE güçlüdür, ancak bazı uç durumlar içerir. Ayrı ifadeler kullanmayı düşünün:
- Mantığa ihtiyacın DELETE yok. Ayrı bir
UPDATEve ardındanINSERT WHERE NOT EXISTSkullanmak, daha okunaklıdır ve hata ayıklaması daha kolaydır. - Bu ifade
MERGEo kadar karmaşık ki, kilitlenme davranışını tahmin etmek zor. Ayrı ifadeler, kilitleme ayrıntı düzeyi üzerinde doğrudan denetim sağlar. -
MERGEkilit yükseltmesinin engellemeye neden olabileceği, yüksek eşzamanlılığa sahip bir tabloyu güncelliyorsunuz.
# Simpler alternative: UPDATE then INSERT
cursor.execute("""
UPDATE dbo.ProductImport
SET Name = %(name)s, ListPrice = %(list_price)s
WHERE ProductNumber = %(product_number)s
""", {"name": "Widget A", "list_price": 24.99, "product_number": "WG-1001"})
if cursor.rowcount == 0:
cursor.execute("""
INSERT INTO dbo.ProductImport (Name, ProductNumber, ListPrice)
VALUES (%(name)s, %(product_number)s, %(list_price)s)
""", {"name": "Widget A", "product_number": "WG-1001", "list_price": 24.99})
conn.commit()
Veri Çerçevelerini Yükle
Pandas veya Polars DataFrame’inden satırları ayıklayın ve bulkcopy() kullanarak yükleyin:
pandas
Bir pandas DataFrame'i tuple'lara dönüştürün ve şu adrese bulkcopy()aktarın:
import pandas as pd
df = pd.read_csv("products.csv")
# Convert DataFrame rows to tuples
rows = list(df[["Name", "ProductNumber", "ListPrice"]].itertuples(index=False, name=None))
cursor.bulkcopy("dbo.ProductImport", rows, batch_size=5000)
conn.commit()
Kutuplar
Bir Polars DataFrame'i şu .rows() yöntemle tuple'lara dönüştürebilirsiniz:
import polars as pl
df = pl.read_csv("products.csv")
# Convert Polars DataFrame to list of tuples
rows = df.select(["Name", "ProductNumber", "ListPrice"]).rows()
cursor.bulkcopy("dbo.ProductImport", rows, batch_size=5000)
conn.commit()
Tam DataFrame yükleme desenleri için pandas entegrasyonu ve Polars entegrasyonuna bakınız.
Parquet hazırlama
Sistemler arasında veri taşırken veya ETL boru hattınız zaten Parquet dosyaları üretirken ara format olarak Parquet'i kullanın:
import pyarrow.parquet as pq
# Read Parquet file
table = pq.read_table("products.parquet")
# Convert to rows for bulkcopy
rows = [tuple(row) for row in zip(*[col.to_pylist() for col in table.columns])]
cursor.bulkcopy("dbo.ProductImport", rows, batch_size=5000)
conn.commit()
Büyük Parquet dosyaları için, bellek kullanımını sabit tutmak için satır grupları halinde okuyun:
import pyarrow.parquet as pq
parquet_file = pq.ParquetFile("products.parquet")
for batch in parquet_file.iter_batches(batch_size=10000):
rows = [tuple(row) for row in zip(*[col.to_pylist() for col in batch.columns])]
cursor.bulkcopy("dbo.ProductImport", rows, batch_size=10000)
conn.commit()
Yüklü verileri doğrulama
Yüklendikten sonra sıra sayılarını doğrulayın ve verileri nokta kontrol edin:
cursor.execute("SELECT COUNT(*) FROM dbo.ProductImport")
count = cursor.fetchval()
print(f"Total rows: {count}")
cursor.execute("""
SELECT TOP 5 Name, ProductNumber, ListPrice
FROM dbo.ProductImport
ORDER BY Name
""")
for row in cursor:
print(f" {row.Name} ({row.ProductNumber}): ${row.ListPrice:.2f}")
Üretim yüklerinde, bulkcopy() çağrısını korumak için çağıran bağlantının işlemine güvenmeyin.
bulkcopy() kendi dahili bağlantısını açar ve kopyalanan satırları bağımsız olarak onaylar; bu nedenle ana bağlantınızdaki conn.rollback() bunları geri alamaz. İki yaklaşım atomikliği sağlar:
- Her partiyi kendi işlemine sarması için
use_internal_transaction=Truedeğerini ayarlayın. Yarı başarısız olan parti, o partiyi yarı yüklü bırakmak yerine geri çeker. - Verileri yükseltmeden önce doğrulamak için, verileri toplu olarak bir hazırlama tablosuna kopyalayın, doğrulayın ve ardından ana bağlantınızda bir işlem içinde
INSERT ... SELECTkullanarak satırları hedef tabloya taşıyın. Bu, bağlantınız üzerinden çalıştığı içinINSERT, doğrulama başarısız olursaconn.rollback()bunu geri alır.
# Stage the data. bulkcopy() runs on its own connection, so these rows
# persist regardless of the transaction below.
cursor.bulkcopy("dbo.ProductImport_Stage", rows, batch_size=5000)
try:
cursor.execute("SELECT COUNT(*) FROM dbo.ProductImport_Stage")
count = cursor.fetchval()
if count < expected_count:
raise ValueError(f"Expected {expected_count} rows, got {count}")
# This INSERT runs on your connection, so it's covered by the transaction.
cursor.execute("""
INSERT INTO dbo.ProductImport (Name, ProductNumber, ListPrice)
SELECT Name, ProductNumber, ListPrice FROM dbo.ProductImport_Stage
""")
conn.commit()
except Exception:
conn.rollback()
raise