Identity-map reads vs. explicit expire/refresh when verifying externally restored rows in SQLAlchemy ORM
0 reputation · 25 Sept 2023, 20:24 UTC
After restoring a database externally, an application needs to confirm that a specific row recovered from backup matches the restored database. SQLAlchemy ORM Sessions cache loaded instances in an identity map, so session.query(Model).get(pk) can return a pre-restore object without issuing a SELECT. Two documented approaches exist: rely on the identity-map read for speed, or force a fresh read using session.expire(instance) or session.refresh(instance).
The trade-off is not obvious. A cached read may silently return stale data, while refresh() immediately issues a SELECT and overwrites in-memory attributes, discarding uncommitted local changes. Calling session.expire_all() forces fresh reads on next access but can trigger a burst of SELECT statements for large object graphs. Core Connection.execute(select(...)) results bypass ORM identity-map caching and always reflect the current database state, but they do not update the ORM instance. Exact session API behavior varies between SQLAlchemy 1.4 and 2.0, so the installed major version matters.
For a post-restore verification step that must not disturb unsaved working objects, is it safer to compare a Core result row against the ORM instance, or to expire/refresh the instance and accept the query cost? Does the answer change between SQLAlchemy 1.4 and 2.0 session APIs?