From 319304e7c9e5c6c2e42513b81f85aa6b238495b5 Mon Sep 17 00:00:00 2001 From: Federico Caselli Date: Sat, 27 Apr 2024 13:06:03 +0200 Subject: [PATCH] improve fetchmany performance when using deque Change-Id: Id30e770eb44eafd3e939c4076b639e8e6962c54b --- lib/sqlalchemy/connectors/asyncio.py | 8 ++------ lib/sqlalchemy/engine/cursor.py | 22 ++++++++++++---------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/lib/sqlalchemy/connectors/asyncio.py b/lib/sqlalchemy/connectors/asyncio.py index 5add8e4a12..34820facb6 100644 --- a/lib/sqlalchemy/connectors/asyncio.py +++ b/lib/sqlalchemy/connectors/asyncio.py @@ -11,7 +11,6 @@ from __future__ import annotations import asyncio import collections -import itertools import sys from typing import Any from typing import Deque @@ -232,11 +231,8 @@ class AsyncAdapt_dbapi_cursor: def fetchmany(self, size: Optional[int] = None) -> Sequence[Any]: if size is None: size = self.arraysize - - rr = iter(self._rows) - retval = list(itertools.islice(rr, 0, size)) - self._rows = collections.deque(rr) - return retval + rr = self._rows + return [rr.popleft() for _ in range(min(size, len(rr)))] def fetchall(self) -> Sequence[Any]: retval = list(self._rows) diff --git a/lib/sqlalchemy/engine/cursor.py b/lib/sqlalchemy/engine/cursor.py index 004274ec5a..5d141feaa8 100644 --- a/lib/sqlalchemy/engine/cursor.py +++ b/lib/sqlalchemy/engine/cursor.py @@ -1252,8 +1252,9 @@ class BufferedRowCursorFetchStrategy(CursorFetchStrategy): if size is None: return self.fetchall(result, dbapi_cursor) - buf = list(self._rowbuffer) - lb = len(buf) + rb = self._rowbuffer + lb = len(rb) + close = False if size > lb: try: new = dbapi_cursor.fetchmany(size - lb) @@ -1261,13 +1262,15 @@ class BufferedRowCursorFetchStrategy(CursorFetchStrategy): self.handle_exception(result, dbapi_cursor, e) else: if not new: - result._soft_close() + # defer closing since it may clear the row buffer + close = True else: - buf.extend(new) + rb.extend(new) - result = buf[0:size] - self._rowbuffer = collections.deque(buf[size:]) - return result + res = [rb.popleft() for _ in range(min(size, len(rb)))] + if close: + result._soft_close() + return res def fetchall(self, result, dbapi_cursor): try: @@ -1321,9 +1324,8 @@ class FullyBufferedCursorFetchStrategy(CursorFetchStrategy): if size is None: return self.fetchall(result, dbapi_cursor) - buf = list(self._rowbuffer) - rows = buf[0:size] - self._rowbuffer = collections.deque(buf[size:]) + rb = self._rowbuffer + rows = [rb.popleft() for _ in range(min(size, len(rb)))] if not rows: result._soft_close() return rows -- 2.47.2