Skip to content

PERF: Optimize execute() hot path: soft reset, prepare caching, and guarded diagnostics #528

Draft
bewithgaurav wants to merge 8 commits intomainfrom
bewithgaurav/insertmany-perf-python-fixes
Draft

PERF: Optimize execute() hot path: soft reset, prepare caching, and guarded diagnostics #528
bewithgaurav wants to merge 8 commits intomainfrom
bewithgaurav/insertmany-perf-python-fixes

Conversation

@bewithgaurav
Copy link
Copy Markdown
Collaborator

@bewithgaurav bewithgaurav commented Apr 17, 2026

Work Item / Issue Reference

AB#44166

GitHub Issue: #<ISSUE_NUMBER>


Summary

This pull request introduces performance benchmarking infrastructure improvements and optimizations to the mssql_python driver, as well as documentation and workflow updates to support a new PERF: pull request prefix. The most significant changes are grouped below.

Driver Performance Optimizations:

  • Implemented a lightweight _soft_reset_cursor in cursor.py to reuse prepared statement handles, avoiding unnecessary SQLPrepare calls when executing the same SQL repeatedly. This improves performance for repeated statement execution. [1] [2] [3] [4]
  • Optimized parameter conversion logic to skip redundant conversions when re-executing the same SQL with the same parameter style, further reducing overhead.
  • Added a new DDBCSQLResetStmt binding in the C++ layer to support the lightweight reset operation, and exposed it to Python. [1] [2]

…n, CI artifact pipeline

- Add insertmanyvalues scenario (100K rows, 1000/batch, GH #500 repro)
- Add --baseline flag for 3-way comparison (main vs PR vs pyodbc)
- Add --json flag to save results for pipeline artifact consumption
- Publish benchmark results as CI artifact on main merge
- Download baseline artifact on PR runs for automatic regression detection
- Fix timing: time.time() -> time.perf_counter()
- Move connection setup outside timing window (measure execute+fetch only)
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 17, 2026

📊 Code Coverage Report

🔥 Diff Coverage

87%


🎯 Overall Coverage

79%


📈 Total Lines Covered: 6708 out of 8482
📁 Project: mssql-python


Diff Coverage

Diff: main...HEAD, staged and unstaged changes

  • mssql_python/cursor.py (95.2%): Missing lines 1369
  • mssql_python/pybind/ddbc_bindings.cpp (77.8%): Missing lines 1367-1368,1371-1372

Summary

  • Total: 39 lines
  • Missing: 5 lines
  • Coverage: 87%

mssql_python/cursor.py

Lines 1365-1373

  1365         if reset_cursor:
  1366             if self.hstmt:
  1367                 self._soft_reset_cursor()
  1368             else:
! 1369                 self._reset_cursor()
  1370 
  1371         # Clear any previous messages
  1372         self.messages = []

mssql_python/pybind/ddbc_bindings.cpp

Lines 1363-1376

  1363 }
  1364 
  1365 SQLRETURN SQLResetStmt_wrap(SqlHandlePtr statementHandle) {
  1366     if (!SQLFreeStmt_ptr) {
! 1367         DriverLoader::getInstance().loadDriver();
! 1368     }
  1369     SQLHANDLE hStmt = statementHandle->get();
  1370     if (!hStmt) {
! 1371         return SQL_INVALID_HANDLE;
! 1372     }
  1373 
  1374     SQLRETURN rc = SQLFreeStmt_ptr(hStmt, SQL_CLOSE);
  1375     if (SQL_SUCCEEDED(rc)) {
  1376         rc = SQLFreeStmt_ptr(hStmt, SQL_RESET_PARAMS);


📋 Files Needing Attention

📉 Files with overall lowest coverage (click to expand)
mssql_python.pybind.logger_bridge.cpp: 59.2%
mssql_python.pybind.ddbc_bindings.h: 67.8%
mssql_python.row.py: 70.5%
mssql_python.pybind.logger_bridge.hpp: 70.8%
mssql_python.pybind.ddbc_bindings.cpp: 74.3%
mssql_python.pybind.connection.connection.cpp: 75.8%
mssql_python.__init__.py: 77.3%
mssql_python.ddbc_bindings.py: 79.6%
mssql_python.pybind.connection.connection_pool.cpp: 79.6%
mssql_python.connection.py: 85.2%

🔗 Quick Links

⚙️ Build Summary 📋 Coverage Details

View Azure DevOps Build

Browse Full Coverage Report

- Download and restore AdventureWorks2022 via docker cp + sqlcmd
- Install pyodbc and run perf-benchmarking.py with --baseline/--json
- Publish/download baseline artifacts (perf-baseline-macOS-SQL2022/SQL2025)
- Same pattern as Windows, adapted for Colima Docker
@bewithgaurav bewithgaurav force-pushed the bewithgaurav/insertmany-perf-python-fixes branch from ab57bb8 to 6703b85 Compare April 20, 2026 08:01
Comment thread eng/pipelines/pr-validation-pipeline.yml Dismissed
Comment thread eng/pipelines/pr-validation-pipeline.yml Dismissed
@bewithgaurav bewithgaurav force-pushed the bewithgaurav/insertmany-perf-python-fixes branch from 6703b85 to 2ee0f68 Compare April 20, 2026 09:40
@bewithgaurav bewithgaurav force-pushed the bewithgaurav/insertmany-perf-python-fixes branch from 2ee0f68 to c113a03 Compare April 20, 2026 09:59
@github-actions github-actions bot added the pr-size: large Substantial code update label Apr 20, 2026
@bewithgaurav bewithgaurav force-pushed the bewithgaurav/insertmany-perf-python-fixes branch from c113a03 to 9ed69e4 Compare April 20, 2026 10:33
- Add _soft_reset_cursor: SQL_CLOSE + SQL_RESET_PARAMS instead of
  full HSTMT free/realloc on each execute() call
- Add DDBCSQLResetStmt C++ wrapper exposing lightweight reset via pybind11
- Skip SQLPrepare when re-executing the same SQL (prepare caching)
- Skip detect_and_convert_parameters on repeated same-SQL calls
- Guard DDBCSQLGetAllDiagRecords behind SQL_SUCCESS_WITH_INFO check
- Guard per-parameter debug logging behind logger.isEnabledFor(DEBUG)
- Fix benchmark script to strip Driver= from mssql-python connection string
@bewithgaurav bewithgaurav force-pushed the bewithgaurav/insertmany-perf-python-fixes branch from 5b92dc7 to 970ce4d Compare April 20, 2026 10:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-size: large Substantial code update

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants