]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Remove LRU warnings
authorMike Bayer <mike_mp@zzzcomputing.com>
Fri, 8 Sep 2017 00:38:00 +0000 (20:38 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sat, 9 Sep 2017 01:42:07 +0000 (21:42 -0400)
Removed the warnings that are emitted when the LRU caches employed
by the mapper as well as loader srtategies reach their threshold; the
purpose of this warning was at first a guard against excess cache keys
being generated but became basically a check on the "creating many
engines" antipattern.   While this is still an antipattern, the presense
of test suites which both create an engine per test as well as raise
on all warnings will be an inconvenience; it should not be critical
that such test suites change their architecture just for this warning
(though engine-per-test suite is always better).

Change-Id: I41ef8cd642d05a845f53119b196440f9d7879cd9
Fixes: #4071
doc/build/changelog/unreleased_12/4071.rst [new file with mode: 0644]
doc/build/faq/performance.rst
lib/sqlalchemy/orm/mapper.py
lib/sqlalchemy/orm/strategies.py
test/orm/test_mapper.py

diff --git a/doc/build/changelog/unreleased_12/4071.rst b/doc/build/changelog/unreleased_12/4071.rst
new file mode 100644 (file)
index 0000000..ff6fc1b
--- /dev/null
@@ -0,0 +1,13 @@
+.. change::
+       :tags: bug, orm
+       :tickets: 4071
+
+       Removed the warnings that are emitted when the LRU caches employed
+       by the mapper as well as loader srtategies reach their threshold; the
+       purpose of this warning was at first a guard against excess cache keys
+       being generated but became basically a check on the "creating many
+       engines" antipattern.   While this is still an antipattern, the presense
+       of test suites which both create an engine per test as well as raise
+       on all warnings will be an inconvenience; it should not be critical
+       that such test suites change their architecture just for this warning
+       (though engine-per-test suite is always better).
\ No newline at end of file
index c6f51ebb132ac46e364e944560814edef5db81e5..d6ee557ea42a557a0a39309c8bb940ce75362f5b 100644 (file)
@@ -460,53 +460,3 @@ Script::
         test_sqlite3(100000)
 
 
-.. _faq_compiled_cache_threshold:
-
-How do I deal with "compiled statement cache reaching its size threshhold"?
----------------------------------------------------------------------------
-
-Some parts of the ORM make use of a least-recently-used (LRU) cache in order
-to cache generated SQL statements for fast reuse.  More generally, these
-areas are making use of the "compiled cache" feature of :class:`.Connection`
-which can be invoked using :meth:`.Connection.execution_options`.
-
-The following two points summarize what should be done if this warning
-is occurring:
-
-* Ensure the application **does not create an arbitrary number of
-  Engine objects**, that is, it does not call :func:`.create_engine` on
-  a per-operation basis.  An application should have only **one Engine per
-  database URL**.
-
-* If the application does not have an unbounded number of engines,
-  **report the warning to the SQLAlchemy developers**.   Guidelines on
-  mailing list support is at: http://www.sqlalchemy.org/support.html#mailinglist
-
-The cache works by creating a cache key that can uniquely identify the
-combination of a specific dialect and a specific Core SQL expression.
-A cache key that already exists in the cache will reuse the already-compiled
-SQL expression.  A cache key that doesn't exist will create a *new* entry
-in the dictionary.   When this dictionary reaches the configured threshhold,
-the LRU cache will trim the size of the cache back down by a certain percentage.
-
-It is important to understand that from the above, **a compiled cache that
-is reaching its size limit will perform badly.**   This is because not only
-are the SQL statements being freshly compiled into strings rather than using
-the cached version, but the LRU cache is also spending lots of time trimming
-its size back down.
-
-The primary reason the compiled caches can grow is due to the **antipattern of
-using a new Engine for every operation**.   Because the compiled cache
-must key on the :class:`.Dialect` associated with an :class:`.Engine`,
-calling :func:`.create_engine` many times in an application will establish
-new cache entries for every engine.   Because the cache is self-trimming,
-the application won't grow in size unbounded, however the application should
-be repaired to not rely on an unbounded number of :class:`.Engine`
-objects.
-
-Outside of this pattern, the default size limits set for these caches within
-the ORM should not generally require adjustment, and the LRU boundaries
-should never be reached.  If this warning is occurring and the application
-is not generating hundreds of engines, please report the issue to the
-SQLAlchemy developers on the mailing list; see the guidelines
-at http://www.sqlalchemy.org/support.html#mailinglist.
index 9b9457213358c3982588803820c92dcd9f54e9f9..1d172f71a45203afe9f842fa81e80ec81ba9a513 100644 (file)
@@ -2871,20 +2871,7 @@ class Mapper(InspectionAttr):
 
     @_memoized_configured_property
     def _compiled_cache(self):
-        return util.LRUCache(self._compiled_cache_size,
-                             size_alert=self._alert_lru_cache_limit)
-
-    def _alert_lru_cache_limit(self, lru_cache):
-        util.warn(
-            "Compiled statement cache for mapper %s is "
-            "reaching its size threshold of %d, based on _compiled_cache_size "
-            "of %d.  Please refer to "
-            "http://docs.sqlalchemy.org/en/latest/faq/performance.html"
-            "#faq_compiled_cache_threshold"
-            " for best practices." %
-            (self,
-             lru_cache.size_threshold,
-             self._compiled_cache_size))
+        return util.LRUCache(self._compiled_cache_size)
 
     @_memoized_configured_property
     def _sorted_tables(self):
index 11ebcee50bb50f3191859c3e7f7d4375613c2e77..a57b66045c1164d218f890d912643b49c54a939b 100644 (file)
@@ -643,18 +643,7 @@ class LazyLoader(AbstractRelationshipLoader, util.MemoizedSlots):
 
     @util.dependencies("sqlalchemy.ext.baked")
     def _memoized_attr__bakery(self, baked):
-        return baked.bakery(size=50, _size_alert=self._alert_lru_cache_limit)
-
-    def _alert_lru_cache_limit(self, lru_cache):
-        util.warn(
-            "Compiled statement cache for lazy loader on attribute %s is "
-            "reaching its size threshold of %d.  Consider setting "
-            "bake_queries=False for this relationship.  Please refer to "
-            "http://docs.sqlalchemy.org/en/latest/faq/performance.html"
-            "#faq_compiled_cache_threshold"
-            " for best practices." %
-            (self.parent_property,
-             lru_cache.size_threshold))
+        return baked.bakery(size=50)
 
     @util.dependencies(
         "sqlalchemy.orm.strategy_options")
@@ -1851,18 +1840,7 @@ class SelectInLoader(AbstractRelationshipLoader, util.MemoizedSlots):
 
     @util.dependencies("sqlalchemy.ext.baked")
     def _memoized_attr__bakery(self, baked):
-        return baked.bakery(size=50, _size_alert=self._alert_lru_cache_limit)
-
-    def _alert_lru_cache_limit(self, lru_cache):
-        util.warn(
-            "Compiled statement cache for selectin loader on attribute %s is "
-            "reaching its size threshold of %d.  Consider setting "
-            "bake_queries=False for this relationship.  Please refer to "
-            "http://docs.sqlalchemy.org/en/latest/faq/performance.html"
-            "#faq_compiled_cache_threshold"
-            " for best practices." %
-            (self.parent_property,
-             lru_cache.size_threshold))
+        return baked.bakery(size=50)
 
     def create_row_processor(
             self, context, path, loadopt, mapper,
index f39e174b065dc064d9fcf7bf8c3c5f9dc14e0a05..42d114f6faf2b8b58bc111d8b377d0abbb754b9e 100644 (file)
@@ -262,31 +262,6 @@ class MapperTest(_fixtures.FixtureTest, AssertsCompiledSQL):
         assert_raises(TypeError, Foo, x=5)
         assert_raises(TypeError, Bar, x=5)
 
-    def test_lru_cache_warning(self):
-        users = self.tables.users
-        User = self.classes.User
-        m = mapper(User, users)
-
-        for i in range(149):
-            m._compiled_cache["key_%s" % i] = "foo"
-
-        def go():
-            m._compiled_cache["key_150"] = "foo"
-            m._compiled_cache["key_151"] = "foo"
-
-        assert_raises_message(
-            sa.exc.SAWarning,
-            r"Compiled statement cache for mapper Mapper.User.users is "
-            "reaching its size threshold of 150, based on "
-            "_compiled_cache_size of 100. ",
-            go
-        )
-        m._compiled_cache.size_alert = None
-        for i in range(152, 200):
-            m._compiled_cache["key_%d" % i] = "foo"
-        assert len(m._compiled_cache) < 150
-
-
     def test_sort_states_comparisons(self):
         """test that _sort_states() doesn't compare
         insert_order to state.key, for set of mixed