Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
De mssql-python-driver bevat een bulkkopieerfunctie die efficiënt grote hoeveelheden data invoert in SQL Server, Azure SQL Database, Azure SQL Managed Instance en SQL database in Microsoft Fabric.
De cursor.bulkcopy() methode biedt een high-performance pad voor het laden van grote datasets:
- Minimaliseert netwerk-retourreizen.
- Omzeilt optioneel de controle van beperkingen tijdens het laden.
- Gebruikt het geoptimaliseerde TDS bulk insert-protocol.
- Bereikt een doorvoer vergelijkbaar met
bcp.exeenSqlBulkCopy.
De op Rust gebaseerde mssql_py_core native extensie ondersteunt de bulkkopieerfunctie. Het werkt buiten de normale cursor-execute()pipeline.
Basaal gebruik
Roep bulkcopy() aan op een cursor en geef de naam van de doeltabel en een iterable van rijtuples of Row-objecten door:
Important
Als je de doel-tabel in dezelfde sessie aanmaakt of aanpast, roep conn.commit() dan vóór bulkcopy(). Het bulk-copyprotocol gebruikt een apart intern kanaal om tabelmetadata te lezen, dus een niet-doorgevoerde DDL-wijziging kan een deadlock of time-out veroorzaken.
import mssql_python
conn = mssql_python.connect(connection_string)
cursor = conn.cursor()
# Create a temp table for the demo
cursor.execute("""
CREATE TABLE ##BulkDemo (
ID INT,
Name NVARCHAR(50),
Amount MONEY
)
""")
conn.commit()
data = [
(1, "Alice", 50000.00),
(2, "Bob", 60000.00),
(3, "Carol", 55000.00),
]
result = cursor.bulkcopy("##BulkDemo", data)
print(f"Copied {result['rows_copied']} rows in {result['batch_count']} batch(es)")
print(f"Elapsed: {result['elapsed_time']}")
Retourwaarde
bulkcopy() Geeft een woordenboek terug:
| Sleutel | Type | Beschrijving |
|---|---|---|
rows_copied |
int | Aantal rijen succesvol gekopieerd. |
batch_count |
int | Aantal verwerkte batches. |
elapsed_time |
float | De tijd die de operatie in seconden kostte. |
Methodesignatuur
cursor.bulkcopy(
table_name, # str – target table (can include schema, e.g. "dbo.MyTable")
data, # Iterable[Tuple | Row] – rows to insert
batch_size=0, # int – rows per batch; 0 = server optimal
timeout=30, # int – operation timeout in seconds
column_mappings=None, # List[str] | List[Tuple[int,str]] | None
keep_identity=False, # bool – preserve identity values from source
check_constraints=False, # bool – check constraints during load
table_lock=False, # bool – use table-level lock
keep_nulls=False, # bool – preserve NULLs instead of defaults
fire_triggers=False, # bool – fire INSERT triggers on target
use_internal_transaction=False, # bool – use internal transaction per batch
)
Kolomtoewijzingen
Standaard brengt bulkcopy() kolommen in kaart op basis van hun positie. Elke datakolom wordt gekoppeld aan de tabelkolom in dezelfde index. Gebruik de column_mappings parameter om dit gedrag te overrulen.
Lijst van kolomnamen
Elke positie in de lijst komt overeen met de brondata-index:
result = cursor.bulkcopy(
"##BulkDemo",
data,
column_mappings=["ID", "Name", "Amount"],
)
Geavanceerd formaat: expliciete indexmapping
Elke tuple heeft de vorm (source_index, target_column_name). Gebruik dit formaat om kolommen over te slaan of te herschikken:
result = cursor.bulkcopy(
"##BulkDemo",
data,
column_mappings=[(0, "ID"), (1, "Name"), (2, "Amount")],
)
Laden vanuit bestanden
Je kunt gegevens laden uit CSV-bestanden en andere bestandsformaten door een generator aan bulkcopy()te geven.
CSV-bestand
import csv
import io
import mssql_python
# In production, replace io.StringIO with open("data.csv", "r", ...)
csv_data = """ID,Name,Value
1,Widget,9.99
2,Gadget,24.50
3,Gizmo,4.75
"""
def csv_row_generator(file_obj):
"""Generator that yields tuples from a CSV file object."""
reader = csv.reader(file_obj)
next(reader) # Skip header
for row in reader:
if row: # skip blank lines
yield (
int(row[0]), # ID
row[1], # Name
float(row[2]), # Value
)
conn = mssql_python.connect(connection_string)
cursor = conn.cursor()
cursor.execute("""
CREATE TABLE ##CSVImport (ID INT, Name NVARCHAR(100), Value FLOAT)
""")
conn.commit()
result = cursor.bulkcopy("##CSVImport", csv_row_generator(io.StringIO(csv_data)))
print(f"Imported {result['rows_copied']} rows from CSV")
Grote bestanden met batching
Stel de batch_size parameter in om te bepalen hoeveel rijen de driver per batch verzendt. Deze aanpak werkt goed voor grote bestanden:
import csv
import io
import mssql_python
# In production, replace io.StringIO with open("large_file.csv", "r", ...)
csv_data = "\n".join(
["ID,Name,Value"] + [f"{i},Item {i},{i * 1.5}" for i in range(1, 201)]
)
def csv_rows(file_obj):
reader = csv.reader(file_obj)
next(reader) # Skip header
for row in reader:
if row:
yield (int(row[0]), row[1], float(row[2]))
conn = mssql_python.connect(connection_string)
cursor = conn.cursor()
cursor.execute("""
CREATE TABLE ##LargeCSV (ID INT, Name NVARCHAR(100), Value FLOAT)
""")
conn.commit()
result = cursor.bulkcopy(
"##LargeCSV",
csv_rows(io.StringIO(csv_data)),
batch_size=50,
)
print(f"Imported {result['rows_copied']} rows in {result['batch_count']} batches")
Laad pandas DataFrames
Converteer een pandas DataFrame naar een lijst van tuples voordat je het doorgeeft aan bulkcopy():
import pandas as pd
import mssql_python
df = pd.DataFrame({
'ID': [1, 2, 3],
'Name': ['Alice', 'Bob', 'Carol'],
'Amount': [50000.0, 60000.0, 55000.0],
})
conn = mssql_python.connect(connection_string)
cursor = conn.cursor()
cursor.execute("""
CREATE TABLE ##PandasDemo (ID INT, Name NVARCHAR(50), Amount MONEY)
""")
conn.commit()
data = [tuple(row) for row in df.itertuples(index=False, name=None)]
result = cursor.bulkcopy("##PandasDemo", data)
NULL-waarden verwerken
Geef None een willekeurige kolompositie door om een SQL-waarde NULL in te voegen:
cursor.execute("""
CREATE TABLE ##NullDemo (ID INT, Name NVARCHAR(50), Amount MONEY)
""")
conn.commit()
data = [
(1, "Alice", 50000.00),
(2, "Bob", None), # NULL Amount
(3, None, 55000.00), # NULL Name
]
cursor.bulkcopy("##NullDemo", data)
ID-kolommen
Om expliciete identiteitswaarden in te voegen, stelt u keep_identity=True in:
cursor.execute("""
CREATE TABLE ##IdentDemo (ID INT, Name NVARCHAR(50), Amount MONEY)
""")
conn.commit()
data = [
(100, "Alice", 50000.00),
(200, "Bob", 60000.00),
]
cursor.bulkcopy("##IdentDemo", data, keep_identity=True)
Wanneer keep_identity=False is ingesteld (standaard), laat u de identiteitskolom weg uit uw gegevens en gebruikt u column_mappings om de niet-identiteitskolommen te selecteren.
Bulkkopieeropties
| Parameter | Default | Beschrijving |
|---|---|---|
batch_size |
0 |
Rijen per partij.
0 laat de server de optimale grootte kiezen. |
timeout |
30 |
Operatie time-out over enkele seconden. |
keep_identity |
False |
Behoud identiteitswaarden uit brondata. |
check_constraints |
False |
Controleer de tabelbeperkingen tijdens het laden. |
table_lock |
False |
Gebruik een vergrendeling op tabelniveau in plaats van vergrendelingen op rijniveau. |
keep_nulls |
False |
Behoud NULL-waarden in plaats van de standaardwaarden van kolommen in te voegen. |
fire_triggers |
False |
Vuurtriggers INSERT op de doeltafel. |
use_internal_transaction |
False |
Voer elke batch uit binnen een interne transactie. |
Afhandeling van fouten
bulkcopy() Genereert een uitzondering als de load faalt, dus wikkel de aanroep in een try/except blok om fouten te vangen. Houd er rekening mee dat het bulkcopy() op zijn eigen interne verbinding draait en de gekopieerde rijen onafhankelijk commit, dus een conn.rollback() op je hoofdverbinding kan ze niet ongedaan maken. Om een batch atomair te maken, stel use_internal_transaction=True, die elke batch in een eigen transactie wikkelt die automatisch terugrolt als de batch faalt:
import mssql_python
conn = mssql_python.connect(connection_string)
cursor = conn.cursor()
cursor.execute("""
CREATE TABLE ##ImportDemo (ID INT, Name NVARCHAR(50), Value FLOAT)
""")
conn.commit()
data = [
(1, "Alice", 50000.00),
(2, "Bob", 60000.00),
(3, "Carol", 55000.00),
]
try:
result = cursor.bulkcopy("##ImportDemo", data, use_internal_transaction=True)
print(f"Successfully copied {result['rows_copied']} rows")
except (mssql_python.DatabaseError, ValueError) as e:
# bulkcopy() commits on its own connection, so there's nothing to roll back
# here. With use_internal_transaction=True, a failed batch is already rolled
# back on the bulk copy connection.
print(f"Bulk copy failed: {e}")
Om het laden van gegevens te laten afhangen van je eigen validatielogica, kopieer je de gegevens eerst in bulk naar een stagingtabel en verplaats je de rijen vervolgens naar de doeltabel met een INSERT ... SELECT binnen een transactie via je hoofdverbinding. Dit INSERT draait via je verbinding, dus conn.rollback() maakt het ongedaan als de validatie mislukt.
Authentication
Bulkcopy gebruikt een apart intern kanaal dat een eigen token vereist. De driver verwerkt automatisch tokenverwerving voor de ondersteunde authenticatiemethoden.
Beheerde identiteit (ActiveDirectoryMSI)
Gebruik Authentication=ActiveDirectoryMSI voor systeem- of door de gebruiker toegewezen beheerde identiteit. Deze authenticatiemethode wordt aanbevolen voor door Azure gehoste diensten zoals Azure VM's, App Service, Functions en AKS.
import mssql_python
# System-assigned managed identity
conn = mssql_python.connect(
"Server=<server>.database.windows.net;"
"Database=<database>;"
"Authentication=ActiveDirectoryMSI;"
"Encrypt=yes"
)
cursor = conn.cursor()
cursor.execute("CREATE TABLE ##MsiDemo (ID INT, Name NVARCHAR(50))")
conn.commit()
result = cursor.bulkcopy("##MsiDemo", [(1, "Alice"), (2, "Bob")])
print(f"Copied {result['rows_copied']} rows")
Voor een door de gebruiker toegewezen beheerde identiteit geef je de client-ID door in de verbindingsreeks:
conn = mssql_python.connect(
"Server=<server>.database.windows.net;"
"Database=<database>;"
"Authentication=ActiveDirectoryMSI;"
"UID=<client-id>;"
"Encrypt=yes"
)
Service principal (ActiveDirectoryServicePrincipal)
Gebruik Authentication=ActiveDirectoryServicePrincipal voor service principal (clientgegevens) authenticatie.
conn = mssql_python.connect(
"Server=<server>.database.windows.net;"
"Database=<database>;"
"Authentication=ActiveDirectoryServicePrincipal;"
"UID=<application-client-id>;"
"PWD=<client-secret>;"
"Encrypt=yes"
)
cursor = conn.cursor()
cursor.execute("CREATE TABLE ##SpDemo (ID INT, Value FLOAT)")
conn.commit()
result = cursor.bulkcopy("##SpDemo", [(1, 1.5), (2, 2.5)])
print(f"Copied {result['rows_copied']} rows")
Standaard inloggegevensketen (ActiveDirectoryDefault)
ActiveDirectoryDefault probeert meerdere referentieproviders opeenvolgend uit, zoals omgevingsvariabelen, workloadidentiteit, beheerde identiteit en meer. Het werkt zowel voor lokale ontwikkeling als voor Azure-gehoste diensten zonder codewijzigingen.
Voor meer informatie over authenticatie, zie Microsoft Entra authenticatie.
Tips voor prestaties
De volgende technieken helpen je om de bulk-kopieerdoorvoer te maximaliseren.
Gebruik generatoren voor grote datasets
Generatoren minimaliseren het geheugenverbruik omdat bulkcopy() elk itereerbaar object accepteert:
def data_generator(count):
"""Generate rows without loading all into memory."""
for i in range(count):
yield (i, f"Item {i}", i * 1.5)
cursor = conn.cursor()
cursor.execute("""
CREATE TABLE ##LargeDemo (ID INT, Name NVARCHAR(50), Value FLOAT)
""")
conn.commit()
result = cursor.bulkcopy("##LargeDemo", data_generator(1000))
Gebruik tabelvergrendelingen voor snellere laadbewerkingen
Als je geen gelijktijdige lezers hebt, stel table_lock=True dan in om de vergrendelingsoverhead tijdens grote initiële ladingen te verminderen.
result = cursor.bulkcopy(
"##LargeDemo",
data,
table_lock=True,
batch_size=100000,
)
Schakel indexen uit tijdens het laden
Schakel niet-geclusterde indexen tijdelijk uit vóór de bulkbelasting en bouw ze daarna opnieuw op voor betere prestaties:
cursor = conn.cursor()
cursor.execute("""
CREATE TABLE ##IndexDemo (ID INT, Name NVARCHAR(50), Value FLOAT)
""")
cursor.execute("CREATE NONCLUSTERED INDEX IX_Name ON ##IndexDemo(Name)")
conn.commit()
cursor.execute("ALTER INDEX IX_Name ON ##IndexDemo DISABLE")
conn.commit()
result = cursor.bulkcopy("##IndexDemo", data)
conn.commit()
cursor.execute("ALTER INDEX IX_Name ON ##IndexDemo REBUILD")
conn.commit()
Laad tabellen parallel
Open voor elke tabel een aparte verbinding en voer de laadbewerkingen parallel uit.
import concurrent.futures
def load_table(table_name, rows):
conn = mssql_python.connect(connection_string)
cursor = conn.cursor()
cursor.execute(f"CREATE TABLE {table_name} (ID INT, Name NVARCHAR(50), Value FLOAT)")
conn.commit()
result = cursor.bulkcopy(table_name, rows)
conn.commit()
conn.close()
return result["rows_copied"]
data = [(i, f"Item {i}", i * 1.5) for i in range(100)]
with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
futures = [
executor.submit(load_table, "##Load1", data),
executor.submit(load_table, "##Load2", data),
executor.submit(load_table, "##Load3", data),
]
for future in concurrent.futures.as_completed(futures):
print(f"Loaded {future.result()} rows")
Vergelijking met alternatieven
De volgende tabel vergelijkt bulkkopieën met andere methoden voor gegevensinvoeging.
| Methode | Gebruiksituatie | prestatie |
|---|---|---|
cursor.bulkcopy() |
Grote datasets (meer dan 1.000 rijen). | Snelst |
cursor.executemany() |
Middelgrote datasets met parameters. | Moderate |
cursor.execute() In een lus |
Kleine datasets met eenvoudige logica. | Langzaamst |