Skip to content

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

Merged
Gaurav Sharma (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
Gaurav Sharma (bewithgaurav) merged 4 commits into
mainfrom
bewithgaurav/insertmany-perf-python-fixes

Conversation

@bewithgaurav

@bewithgauravGaurav Sharma (bewithgaurav) commented Apr 17, 2026

Copy link
Copy Markdown
Collaborator

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

github-actionsBot commented Apr 17, 2026

Copy link
Copy Markdown

📊 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

759ifself.hstmt:
760ret=ddbc_bindings.DDBCSQLResetStmt(self.hstmt)
761try:
762check_error(ddbc_sql_const.SQL_HANDLE_STMT.value, self.hstmt, ret)
! 763exceptException:
764logger.warning("_soft_reset_cursor failed; falling back to full reset")
! 765self._reset_cursor()
! 766self.last_executed_stmt=""
! 767return768self._clear_rownumber()
769770defclose(self) ->None:
771 """

Lines 1384-1392

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

mssql_python/pybind/ddbc_bindings.cpp

Lines 1379-1394

1379 }
13801381SQLRETURNSQLResetStmt_wrap(SqlHandlePtr statementHandle) {
1382if (!statementHandle || !statementHandle->get()) {
! 1383returnSQL_INVALID_HANDLE;
! 1384 }
1385if (statementHandle->isImplicitlyFreed()) {
! 1386returnSQL_INVALID_HANDLE;
! 1387 }
1388if (!SQLFreeStmt_ptr) {
! 1389DriverLoader::getInstance().loadDriver();
! 1390 }
1391SQLHANDLE hStmt = statementHandle->get();
13921393SQLRETURN 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
Gaurav Sharma (bewithgaurav)force-pushed the bewithgaurav/insertmany-perf-python-fixes branch from ab57bb8 to 6703b85CompareApril 20, 2026 08:01
Comment threadeng/pipelines/pr-validation-pipeline.yml Dismissed
Comment threadeng/pipelines/pr-validation-pipeline.yml Dismissed
@bewithgaurav
Gaurav Sharma (bewithgaurav)force-pushed the bewithgaurav/insertmany-perf-python-fixes branch 2 times, most recently from 2ee0f68 to c113a03CompareApril 20, 2026 09:59
@github-actionsgithub-actionsBot added the pr-size: large Substantial code update label Apr 20, 2026
@bewithgaurav
Gaurav Sharma (bewithgaurav)force-pushed the bewithgaurav/insertmany-perf-python-fixes branch 3 times, most recently from 970ce4d to 0604fc5CompareApril 24, 2026 11:13
@github-actionsgithub-actionsBot added pr-size: medium Moderate update size and removed pr-size: large Substantial code update labels Apr 24, 2026
@bewithgaurav
Gaurav Sharma (bewithgaurav) marked this pull request as ready for review April 28, 2026 05:03
CopilotAI review requested due to automatic review settings April 28, 2026 05:03

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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.

FileDescription
mssql_python/pybind/ddbc_bindings.cppAdds SQLResetStmt_wrap and exports DDBCSQLResetStmt to Python.
mssql_python/cursor.pyUses soft reset + prepare caching and optimizes parameter conversion/logging/diagnostics in execute().
benchmarks/perf-benchmarking.pyNormalizes 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 threadmssql_python/cursor.py
Comment threadmssql_python/cursor.py Outdated
Comment threadmssql_python/cursor.py Outdated
Comment threadmssql_python/pybind/ddbc_bindings.cpp Outdated
Comment threadmssql_python/pybind/ddbc_bindings.cpp Outdated
Comment threadmssql_python/cursor.py
@bewithgaurav
Gaurav Sharma (bewithgaurav)force-pushed the bewithgaurav/insertmany-perf-python-fixes branch 2 times, most recently from 612c063 to c529bc9CompareApril 28, 2026 05:31
Comment threadmssql_python/pybind/ddbc_bindings.cpp Outdated
Comment threadmssql_python/pybind/ddbc_bindings.cpp Outdated
Comment threadmssql_python/cursor.py
Comment threadmssql_python/cursor.py
Comment threadbenchmarks/perf-benchmarking.py Outdated
Comment threadmssql_python/cursor.py
@bewithgaurav
Gaurav Sharma (bewithgaurav)force-pushed the bewithgaurav/insertmany-perf-python-fixes branch from c529bc9 to 536cde1CompareApril 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
Gaurav Sharma (bewithgaurav)force-pushed the bewithgaurav/insertmany-perf-python-fixes branch from 536cde1 to 88329a0CompareApril 28, 2026 05:46
Comment threadmssql_python/pybind/ddbc_bindings.cpp
@bewithgaurav
Gaurav Sharma (bewithgaurav) merged commit 44afe09 into mainApr 29, 2026
34 checks passed
@gargsaumyagargsaumya mentioned this pull request May 15, 2026
@gargsaumyagargsaumya mentioned this pull request May 20, 2026
gargsaumya added a commit that referenced this pull request May 20, 2026
### Work Item / Issue Reference
>
[AB#45159](https://sqlclientdrivers.visualstudio.com/mssql-python/_sprints/taskboard/mssql-python%20Team/mssql-python/Rubidium/May%202026?workitem=45159)
-------------------------------------------------------------------
### Summary
**Enhancements**
- #548 — manylinux_2_28 build targets for RHEL 8 / glibc 2.28
- #542 — macOS universal2 wheel for Python 3.10
- #526 — UTF-16 string handling via simdutf
- #528 — Optimized execute() hot path
- #567 — Azure Linux installation docs
**Bug Fixes**
- #562 — Login failures now raise mssql_python exception instead of
RuntimeError
- #568 — GIL released during blocking SQLSetConnectAttr calls
- #541 — GIL released during blocking ODBC statement/fetch/transaction
calls
- #560 — executemany RuntimeError when decimals change signs
- #495 — Inconsistent CP1252 VARCHAR retrieval Windows vs Linux
- #559 — BulkCopy empty string in NVARCHAR(MAX)/VARCHAR(MAX) (via
mssql_py_core 0.1.4)
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-size: mediumModerate update size

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@bewithgaurav@saurabh500@github-advanced-security@gargsaumya