Skip to content

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

Merged
bewithgaurav merged 4 commits into
mainfrom
bewithgaurav/insertmany-perf-python-fixes
Apr 29, 2026
Merged

PERF: Optimize execute() hot path: soft reset, prepare caching, and guarded diagnostics #528
bewithgaurav merged 4 commits into
mainfrom
bewithgaurav/insertmany-perf-python-fixes

Conversation

@bewithgaurav
Copy link
Copy Markdown
Collaborator

@bewithgaurav bewithgaurav commented Apr 17, 2026

Work Item / Issue Reference

AB#44166

Related GitHub Issue: #500


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]

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 17, 2026

📊 Code Coverage Report

🔥 Diff Coverage

78%


🎯 Overall Coverage

79%


📈 Total Lines Covered: 6793 out of 8552
📁 Project: mssql-python


Diff Coverage

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

  • mssql_python/cursor.py (80.0%): Missing lines 763,765-767,1388
  • mssql_python/pybind/ddbc_bindings.cpp (76.0%): Missing lines 1383-1384,1386-1387,1389-1390
  • mssql_python/pybind/ddbc_bindings.h (100%)

Summary

  • Total: 51 lines
  • Missing: 11 lines
  • Coverage: 78%

mssql_python/cursor.py

Lines 759-771

  759         if self.hstmt:
  760             ret = ddbc_bindings.DDBCSQLResetStmt(self.hstmt)
  761             try:
  762                 check_error(ddbc_sql_const.SQL_HANDLE_STMT.value, self.hstmt, ret)
! 763             except Exception:
  764                 logger.warning("_soft_reset_cursor failed; falling back to full reset")
! 765                 self._reset_cursor()
! 766                 self.last_executed_stmt = ""
! 767                 return
  768         self._clear_rownumber()
  769 
  770     def close(self) -> None:
  771         """

Lines 1384-1392

  1384         if reset_cursor:
  1385             if self.hstmt:
  1386                 self._soft_reset_cursor()
  1387             else:
! 1388                 self._reset_cursor()
  1389         else:
  1390             # Close just the ODBC cursor (not the statement handle) so the
  1391             # prepared plan can be reused.  SQLFreeStmt(SQL_CLOSE) releases
  1392             # the cursor associated with hstmt without destroying the

mssql_python/pybind/ddbc_bindings.cpp

Lines 1379-1394

  1379 }
  1380 
  1381 SQLRETURN SQLResetStmt_wrap(SqlHandlePtr statementHandle) {
  1382     if (!statementHandle || !statementHandle->get()) {
! 1383         return SQL_INVALID_HANDLE;
! 1384     }
  1385     if (statementHandle->isImplicitlyFreed()) {
! 1386         return SQL_INVALID_HANDLE;
! 1387     }
  1388     if (!SQLFreeStmt_ptr) {
! 1389         DriverLoader::getInstance().loadDriver();
! 1390     }
  1391     SQLHANDLE hStmt = statementHandle->get();
  1392 
  1393     SQLRETURN rc;
  1394     {


📋 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.9%
mssql_python.row.py: 70.5%
mssql_python.pybind.logger_bridge.hpp: 70.8%
mssql_python.pybind.ddbc_bindings.cpp: 74.6%
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.3%

🔗 Quick Links

⚙️ Build Summary 📋 Coverage Details

View Azure DevOps Build

Browse Full Coverage Report

@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 2 times, most recently 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 3 times, most recently from 970ce4d to 0604fc5 Compare April 24, 2026 11:13
@github-actions github-actions Bot added pr-size: medium Moderate update size and removed pr-size: large Substantial code update labels Apr 24, 2026
@bewithgaurav bewithgaurav marked this pull request as ready for review April 28, 2026 05:03
Copilot AI review requested due to automatic review settings April 28, 2026 05:03
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a lightweight statement “reset” primitive to the pybind ODBC layer and uses it in Cursor.execute() to reduce overhead on the execute hot path (avoid full HSTMT reallocation, skip redundant parameter-style conversion on re-execution, and reduce diagnostic-record collection work).

Changes:

  • Add DDBCSQLResetStmt pybind export to close the cursor + reset parameter bindings without freeing the HSTMT.
  • Update Cursor.execute() to use _soft_reset_cursor() and introduce simple prepare caching + reduced conversion/log/diagnostic overhead.
  • Adjust the perf benchmark script to strip Driver= from the connection string for mssql-python when present.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.

File Description
mssql_python/pybind/ddbc_bindings.cpp Adds SQLResetStmt_wrap and exports DDBCSQLResetStmt to Python.
mssql_python/cursor.py Uses soft reset + prepare caching and optimizes parameter conversion/logging/diagnostics in execute().
benchmarks/perf-benchmarking.py Normalizes conn string for mssql-python by removing Driver= when present.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread mssql_python/cursor.py
Comment thread mssql_python/cursor.py Outdated
Comment thread mssql_python/cursor.py Outdated
Comment thread mssql_python/pybind/ddbc_bindings.cpp Outdated
Comment thread mssql_python/pybind/ddbc_bindings.cpp Outdated
Comment thread mssql_python/cursor.py
@bewithgaurav bewithgaurav force-pushed the bewithgaurav/insertmany-perf-python-fixes branch 2 times, most recently from 612c063 to c529bc9 Compare April 28, 2026 05:31
Comment thread mssql_python/pybind/ddbc_bindings.cpp Outdated
Comment thread mssql_python/pybind/ddbc_bindings.cpp Outdated
Comment thread mssql_python/cursor.py
Comment thread mssql_python/cursor.py
Comment thread benchmarks/perf-benchmarking.py Outdated
Comment thread mssql_python/cursor.py
@bewithgaurav bewithgaurav force-pushed the bewithgaurav/insertmany-perf-python-fixes branch from c529bc9 to 536cde1 Compare April 28, 2026 05:42
- 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 536cde1 to 88329a0 Compare April 28, 2026 05:46
Comment thread mssql_python/pybind/ddbc_bindings.cpp
@bewithgaurav bewithgaurav merged commit 44afe09 into main Apr 29, 2026
34 checks passed
@gargsaumya gargsaumya mentioned this pull request May 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-size: medium Moderate update size

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants