Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 53 additions & 5 deletions benchmarks/perf-benchmarking.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
"""
Performance Benchmarking: mssql-python vs pyodbc

Runs scenarios (fetch queries + insertmanyvalues), compares mssql-python against pyodbc,
and optionally against a baseline JSON from the main branch.
Runs scenarios (fetch queries + insertmanyvalues, with and without setinputsizes),
compares mssql-python against pyodbc, and optionally against a baseline JSON from
the main branch.

Usage:
python benchmarks/perf-benchmarking.py # 2-col: PR vs pyodbc
Expand Down Expand Up @@ -38,7 +39,7 @@
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))

import pyodbc
from mssql_python import connect
from mssql_python import SQL_INTEGER, SQL_VARCHAR, connect

# Configuration
CONN_STR = os.getenv("DB_CONNECTION_STRING")
Expand Down Expand Up @@ -76,7 +77,6 @@ def _init_conn_strings():
CONN_STR = ";".join(parts)



class BenchmarkResult:
def __init__(self, name: str):
self.name = name
Expand Down Expand Up @@ -185,7 +185,13 @@ def _generate_rows(total: int) -> list:
return [(i, f"value_{i}") for i in range(total)]


def _run_insertmany(conn_factory, conn_str, name: str, iterations: int) -> BenchmarkResult:
def _run_insertmany(
conn_factory,
conn_str,
name: str,
iterations: int,
input_sizes: Optional[List[tuple]] = None,
) -> BenchmarkResult:
result = BenchmarkResult(name)
batch_sql = _build_batch_sql(INSERTMANY_BATCH_SIZE)
all_rows = _generate_rows(INSERTMANY_ROWS)
Expand All @@ -211,6 +217,8 @@ def _run_insertmany(conn_factory, conn_str, name: str, iterations: int) -> Bench

start = time.perf_counter()
for flat_params in batches:
if input_sizes:
cursor.setinputsizes(input_sizes)
cursor.execute(batch_sql, flat_params)
elapsed = time.perf_counter() - start

Expand Down Expand Up @@ -241,6 +249,28 @@ def run_insertmany_mssql(iterations: int) -> BenchmarkResult:
)


def run_setinputsizes_pyodbc(iterations: int) -> BenchmarkResult:
input_sizes = [(pyodbc.SQL_INTEGER, 0, 0), (pyodbc.SQL_VARCHAR, 100, 0)]
return _run_insertmany(
lambda cs: pyodbc.connect(cs),
CONN_STR_PYODBC,
"Setinputsizes (100K rows)",
iterations,
input_sizes * INSERTMANY_BATCH_SIZE,
)


def run_setinputsizes_mssql(iterations: int) -> BenchmarkResult:
input_sizes = [(SQL_INTEGER, 0, 0), (SQL_VARCHAR, 100, 0)]
Comment thread
bewithgaurav marked this conversation as resolved.
return _run_insertmany(
lambda cs: connect(cs),
CONN_STR,
"Setinputsizes (100K rows)",
iterations,
input_sizes * INSERTMANY_BATCH_SIZE,
)


# ---------------------------------------------------------------------------
# Output formatting
# ---------------------------------------------------------------------------
Expand Down Expand Up @@ -574,6 +604,24 @@ def main():

all_results.append((insert_name, ms_insert, py_insert))

setinputsizes_name = "Setinputsizes (100K rows)"
print(f"\nRunning: {setinputsizes_name}")
print(f" pyodbc... ", end="", flush=True)
py_setinputsizes = run_setinputsizes_pyodbc(NUM_ITERATIONS)
if py_setinputsizes.times:
print(f"OK ({py_setinputsizes.median:.4f}s)")
else:
print("FAILED")

print(f" mssql-python... ", end="", flush=True)
ms_setinputsizes = run_setinputsizes_mssql(NUM_ITERATIONS)
if ms_setinputsizes.times:
print(f"OK ({ms_setinputsizes.median:.4f}s)")
else:
print("FAILED")

all_results.append((setinputsizes_name, ms_setinputsizes, py_setinputsizes))

# Output
print_results(all_results, baseline)

Expand Down
Loading