PERF: Optimize execute() hot path: soft reset, prepare caching, and guarded diagnostics #528
Merged
bewithgaurav merged 4 commits intomainfrom Apr 29, 2026
Merged
Conversation
📊 Code Coverage Report
Diff CoverageDiff: main...HEAD, staged and unstaged changes
Summary
mssql_python/cursor.pyLines 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 themssql_python/pybind/ddbc_bindings.cppLines 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
|
ab57bb8 to
6703b85
Compare
2ee0f68 to
c113a03
Compare
970ce4d to
0604fc5
Compare
Contributor
There was a problem hiding this comment.
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
DDBCSQLResetStmtpybind 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 formssql-pythonwhen 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.
saurabh500
reviewed
Apr 28, 2026
612c063 to
c529bc9
Compare
saurabh500
reviewed
Apr 28, 2026
c529bc9 to
536cde1
Compare
- 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
536cde1 to
88329a0
Compare
gargsaumya
reviewed
Apr 28, 2026
gargsaumya
approved these changes
Apr 29, 2026
saurabh500
approved these changes
Apr 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Work Item / Issue Reference
Summary
This pull request introduces performance benchmarking infrastructure improvements and optimizations to the
mssql_pythondriver, as well as documentation and workflow updates to support a newPERF:pull request prefix. The most significant changes are grouped below.Driver Performance Optimizations:
_soft_reset_cursorincursor.pyto 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]DDBCSQLResetStmtbinding in the C++ layer to support the lightweight reset operation, and exposed it to Python. [1] [2]