<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://www.memcp.org/index.php?action=history&amp;feed=atom&amp;title=Group_Caches</id>
	<title>Group Caches - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://www.memcp.org/index.php?action=history&amp;feed=atom&amp;title=Group_Caches"/>
	<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Group_Caches&amp;action=history"/>
	<updated>2026-09-25T23:46:56Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.39.1</generator>
	<entry>
		<id>https://www.memcp.org/index.php?title=Group_Caches&amp;diff=424&amp;oldid=prev</id>
		<title>Carli at 17:37, 25 September 2026</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Group_Caches&amp;diff=424&amp;oldid=prev"/>
		<updated>2026-09-25T17:37:18Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 19:37, 25 September 2026&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l155&quot;&gt;Line 155:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 155:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;The snapshot correction path currently focuses on exact integer-valued sums within its numerical safety limits and a supported record identity. It is not a general incremental engine for every SQL aggregate or join. Arbitrary floating-point sums, distinct counts, and arbitrary combinations of moving dimensions are not automatically eligible. If safe reuse cannot be established, the query retains an ordinary execution plan.&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;The snapshot correction path currently focuses on exact integer-valued sums within its numerical safety limits and a supported record identity. It is not a general incremental engine for every SQL aggregate or join. Arbitrary floating-point sums, distinct counts, and arbitrary combinations of moving dimensions are not automatically eligible. If safe reuse cannot be established, the query retains an ordinary execution plan.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;== Technical Details ==&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&#039;&#039;&#039;Candidate selection.&#039;&#039;&#039; Before materializing a deferred cache, MemCP records the measured cost of direct execution in &amp;lt;code&gt;system_statistic.group_cache_candidates&amp;lt;/code&gt;. Each entry has a &amp;lt;code&gt;canonical_name&amp;lt;/code&gt; and an &amp;lt;code&gt;accumulated_ns&amp;lt;/code&gt; counter. Compatible queries contribute to the same counter. The planner/runtime compares that accumulated work with the estimated additional cost of caching, allowing useful candidates to become caches without building every possible cache on first use.&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&#039;&#039;&#039;Canonical names.&#039;&#039;&#039; Cache tables use names such as &amp;lt;code&gt;.grp:source:hash&amp;lt;/code&gt;; aggregate columns use &amp;lt;code&gt;agg_hash&amp;lt;/code&gt;. The table identity describes normalized sources, grouping dimensions, and filters, while the column identity describes the aggregate formula. SQL aliases and output labels do not define these identities. The unified cell layout additionally distinguishes the dimension types; individual keys, range bounds, and snapshot coordinates are stored as cell values rather than requiring a new table for each request.&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;Consequently, similarly structured queries can share a cache table, and matching aggregate formulas can share its calculated values—even when the queries use different aliases or request different parameter values. Several aggregates can also occupy separate columns of the same table. Reuse requires matching normalized semantics and valid source dependencies; merely looking similar is not sufficient.&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;For executable examples using generated data, see [https://github.com/launix-de/memcp/blob/perf/kpi-moving-snapshot-domains/tests/performance/domain-snapshot.yaml snapshot workloads] and [https://github.com/launix-de/memcp/blob/perf/kpi-moving-snapshot-domains/tests/planner/aggregates/group-range-cache.yaml combined dimension tests]. The unified implementation is described in [https://github.com/launix-de/memcp/pull/999 PR #999].&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;For executable examples using generated data, see [https://github.com/launix-de/memcp/blob/perf/kpi-moving-snapshot-domains/tests/performance/domain-snapshot.yaml snapshot workloads] and [https://github.com/launix-de/memcp/blob/perf/kpi-moving-snapshot-domains/tests/planner/aggregates/group-range-cache.yaml combined dimension tests]. The unified implementation is described in [https://github.com/launix-de/memcp/pull/999 PR #999].&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;

&lt;!-- diff cache key memcp_wiki-mediawiki-:diff::1.12:old-423:rev-424 --&gt;
&lt;/table&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Group_Caches&amp;diff=423&amp;oldid=prev</id>
		<title>Carli: /* How much faster can it be? */</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Group_Caches&amp;diff=423&amp;oldid=prev"/>
		<updated>2026-09-25T17:33:14Z</updated>

		<summary type="html">&lt;p&gt;&lt;span dir=&quot;auto&quot;&gt;&lt;span class=&quot;autocomment&quot;&gt;How much faster can it be?&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 19:33, 25 September 2026&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l138&quot;&gt;Line 138:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 138:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;|-&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;|-&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;| Repeated total for a large customer group || Replace another aggregation over thousands of orders with a stored-result lookup.&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;| Repeated total for a large customer group || Replace another aggregation over thousands of orders with a stored-result lookup.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;|-&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;| Interval covered by 100 cached subtotals || Combine 100 results instead of reading, for example, a million sales.&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;| Interval covered by 100 cached subtotals || Combine 100 results instead of reading, for example, a million sales.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;|-&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;| 100 affected accounts out of 100,000 || Re-evaluate roughly 1,000 times fewer account contributions, plus the work needed to find them.&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;| 100 affected accounts out of 100,000 || Re-evaluate roughly 1,000 times fewer account contributions, plus the work needed to find them.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;|-&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;| Series of nearby snapshot points || Replace repeated full evaluations with a build followed by corrections where possible.&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;| Series of nearby snapshot points || Replace repeated full evaluations with a build followed by corrections where possible.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;|}&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;|}&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;

&lt;!-- diff cache key memcp_wiki-mediawiki-:diff::1.12:old-422:rev-423 --&gt;
&lt;/table&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Group_Caches&amp;diff=422&amp;oldid=prev</id>
		<title>Carli at 17:31, 25 September 2026</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Group_Caches&amp;diff=422&amp;oldid=prev"/>
		<updated>2026-09-25T17:31:55Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;a href=&quot;https://www.memcp.org/index.php?title=Group_Caches&amp;amp;diff=422&amp;amp;oldid=420&quot;&gt;Show changes&lt;/a&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Group_Caches&amp;diff=420&amp;oldid=prev</id>
		<title>Carli: Created page with &quot;&lt;!-- Copyright (C) 2026 Carl-Philip Hänsch --&gt; = Group Cache Dimensions: Equality, Additive Ranges, and Snapshots =  Implementation reference: 25 September 2026, commit b22387664, [https://github.com/launix-de/memcp/pull/999 PR #999]. Examples describe query shapes; actual eligibility and plan selection depend on semantic proofs, estimated costs, and cache state.  A group cache retains reusable aggregate state across SQL requests. It is separate from the query-plan cach...&quot;</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Group_Caches&amp;diff=420&amp;oldid=prev"/>
		<updated>2026-09-25T10:39:33Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;&amp;lt;!-- Copyright (C) 2026 Carl-Philip Hänsch --&amp;gt; = Group Cache Dimensions: Equality, Additive Ranges, and Snapshots =  Implementation reference: 25 September 2026, commit b22387664, [https://github.com/launix-de/memcp/pull/999 PR #999]. Examples describe query shapes; actual eligibility and plan selection depend on semantic proofs, estimated costs, and cache state.  A group cache retains reusable aggregate state across SQL requests. It is separate from the query-plan cach...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&amp;lt;!-- Copyright (C) 2026 Carl-Philip Hänsch --&amp;gt;&lt;br /&gt;
= Group Cache Dimensions: Equality, Additive Ranges, and Snapshots =&lt;br /&gt;
&lt;br /&gt;
Implementation reference: 25 September 2026, commit b22387664, [https://github.com/launix-de/memcp/pull/999 PR #999]. Examples describe query shapes; actual eligibility and plan selection depend on semantic proofs, estimated costs, and cache state.&lt;br /&gt;
&lt;br /&gt;
A group cache retains reusable aggregate state across SQL requests. It is separate from the query-plan cache and from caching complete HTTP responses. Cache eviction or changes to source dependencies can require reconstruction.&lt;br /&gt;
&lt;br /&gt;
The three dimension modes describe &amp;#039;&amp;#039;&amp;#039;how aggregate results at different parameter values relate to each other&amp;#039;&amp;#039;&amp;#039;. They are not specific to time. Coordinates can represent numeric versions, positions, thresholds, or timestamps.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Dimension mode !! Meaning !! Reuse strategy !! Typical query shape&lt;br /&gt;
|-&lt;br /&gt;
| &amp;#039;&amp;#039;&amp;#039;Equality / point domain&amp;#039;&amp;#039;&amp;#039; || An exact key or key tuple || Look up the aggregate state for that key || Aggregate over an equality group&lt;br /&gt;
|-&lt;br /&gt;
| &amp;#039;&amp;#039;&amp;#039;Additive range domain&amp;#039;&amp;#039;&amp;#039; || An interval of an ordered source dimension || Combine states for disjoint input intervals || Aggregate over selected facts&lt;br /&gt;
|-&lt;br /&gt;
| &amp;#039;&amp;#039;&amp;#039;Snapshot domain&amp;#039;&amp;#039;&amp;#039; || A parameter point at which contributions were evaluated || Read an exact point, or correct an existing state for a new point || Aggregate over parameter-dependent selected states&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The new shape is called &amp;#039;&amp;#039;&amp;#039;snapshot aggregation over a parameter domain&amp;#039;&amp;#039;&amp;#039;, or more precisely, &amp;#039;&amp;#039;&amp;#039;a snapshot domain with incremental contribution correction&amp;#039;&amp;#039;&amp;#039;. &amp;#039;&amp;#039;As-of state aggregation&amp;#039;&amp;#039; is a useful name for the ordered-state-selection subclass, but the abstraction is not restricted to temporal queries.&lt;br /&gt;
&lt;br /&gt;
== 1. Equality domains: One aggregate per exact key ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT COUNT(*) FROM orders WHERE customer_id = :customer;&lt;br /&gt;
SELECT SUM(amount) FROM orders WHERE customer_id = :customer;&lt;br /&gt;
SELECT COUNT(*) FROM orders;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first two queries can reuse aggregate states indexed by customer ID. An aggregate without a correlated parameter, such as the final COUNT(*), is the limiting case with one group and an empty key tuple. Additional fixed filters belong to the computation and its cache identity.&lt;br /&gt;
&lt;br /&gt;
This is particularly useful for correlated aggregates: many outer rows may request the same group. Once its aggregate state is available, the group need not be aggregated again for each outer row. Several equality keys can form a partition, such as tenant and product class.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Work avoided:&amp;#039;&amp;#039;&amp;#039; Repeated processing of M records in a group becomes a lookup of existing aggregate state. Whether to prepare groups together or populate them on demand is a physical planning decision.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Potential speedup:&amp;#039;&amp;#039;&amp;#039; No isolated A/B measurement of this mode is claimed here. If an expensive group aggregate is requested 100 times, its work can conceptually drop from 100 aggregations to one build plus 100 lookups. The speedup of that part approaches at most 100×, while other query work limits the end-to-end gain. Against a cheap index probe or a tiny group, the benefit may be small.&lt;br /&gt;
&lt;br /&gt;
== 2. Additive range domains: Combine disjoint fact intervals ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT SUM(revenue)&lt;br /&gt;
FROM sales&lt;br /&gt;
WHERE coordinate &amp;gt;= :lo AND coordinate &amp;lt; :hi;&lt;br /&gt;
&lt;br /&gt;
SELECT SUM(revenue)&lt;br /&gt;
FROM sales&lt;br /&gt;
WHERE tenant_id = :tenant&lt;br /&gt;
  AND coordinate &amp;gt;= :lo AND coordinate &amp;lt; :hi;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Each fact has a contribution that does not depend on the requested interval within this computation. The bounds determine which facts participate. The second query combines an equality partition with a range dimension.&lt;br /&gt;
&lt;br /&gt;
For a sum over disjoint intervals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
R([a,c)) = R([a,b)) + R([b,c))&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A cache can reuse and combine matching partial states. Missing coverage and boundary fragments still require work. Overlapping cells must not be counted twice. Inclusive/exclusive boundaries and SQL NULL semantics must be preserved.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Suitable query families:&amp;#039;&amp;#039;&amp;#039; Interval sums, interval counts, cumulative fact aggregates, and repeated overlapping reporting windows. SUM and COUNT are straightforward examples. More generally, each aggregate needs a valid state-combination rule. Conceptually, an average requires a sum and a count, rather than an unweighted average of averages. DISTINCT needs its own state semantics.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Work avoided:&amp;#039;&amp;#039;&amp;#039; Instead of reading M facts, a query may process K cached partial states and B uncovered facts.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Potential speedup:&amp;#039;&amp;#039;&amp;#039; No isolated measured factor for this mode is claimed here. If those operations have comparable costs, M/(K+B) approximates the reduction in aggregation work. For example, replacing 1,000,000 facts with 100 cached cells plus 9,900 remaining facts means roughly 100× fewer processing units. This is an illustrative work estimate, not a measured latency speedup. Cold construction, fragmentation, and little overlap between requests can consume much of the benefit.&lt;br /&gt;
&lt;br /&gt;
== 3. Snapshot domains: Aggregate state at a parameter point ==&lt;br /&gt;
&lt;br /&gt;
=== Why an additive range is insufficient ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT SUM((&lt;br /&gt;
  SELECT h.quantity&lt;br /&gt;
  FROM entity_history h&lt;br /&gt;
  WHERE h.entity_id = e.id AND h.coordinate &amp;lt;= :x&lt;br /&gt;
  ORDER BY h.coordinate DESC&lt;br /&gt;
  LIMIT 1&lt;br /&gt;
))&lt;br /&gt;
FROM entity e;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example requires an unambiguous ordered selection, for example UNIQUE(entity_id, coordinate).&lt;br /&gt;
&lt;br /&gt;
It does &amp;#039;&amp;#039;&amp;#039;not&amp;#039;&amp;#039;&amp;#039; sum all history entries up to x. Each entity contributes only its selected state. If an entity changes from quantity 3 to quantity 5, the aggregate must increase by 2. Simply adding the new quantity 5 would be incorrect.&lt;br /&gt;
&lt;br /&gt;
A snapshot retains aggregate state at an anchor point x₀, together with logical keys and contribution values needed for correction. &amp;#039;&amp;#039;&amp;#039;The snapshot itself is a point.&amp;#039;&amp;#039;&amp;#039; The interval between x₀ and x helps identify possible changes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
C(k,x) = contribution of entity k at parameter point x&lt;br /&gt;
S(x)   = sum of all C(k,x)&lt;br /&gt;
A      = a complete superset of potentially changed keys&lt;br /&gt;
&lt;br /&gt;
S(x) = S(x₀) - sum(C(k,x₀), k in A) + sum(C(k,x), k in A)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A key is corrected once even if several dependency paths identify it. For every key outside A, its contribution must be proven unchanged. Original residual predicates are still evaluated for candidates: a candidate may turn out not to change anything.&lt;br /&gt;
&lt;br /&gt;
=== Query structures recognized by the current implementation ===&lt;br /&gt;
&lt;br /&gt;
Subject to the corresponding proof conditions, the implementation handles these building blocks:&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Ordered state selection per entity:&amp;#039;&amp;#039;&amp;#039; Select an unambiguous state using a moving bound. Several scalar values may depend on that selection.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Selected state plus threshold predicates:&amp;#039;&amp;#039;&amp;#039; A contribution also depends on a selected property being less than, greater than, or equal to a coordinate. Boundary crossings without a new history row must be included in the change cover.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Conditional SUM payloads:&amp;#039;&amp;#039;&amp;#039; CASE/IF chooses a contribution using provable conditions. Change coverage includes selection, predicate, and payload dependencies.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Fixed first/last properties:&amp;#039;&amp;#039;&amp;#039; A coordinate-independent first or last value can use the same property group cache in both full construction and correction.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Bounded EXISTS predicates:&amp;#039;&amp;#039;&amp;#039; Relevant child rows crossing a bound can identify affected contributions through projected parent keys.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Derived outer coordinates:&amp;#039;&amp;#039;&amp;#039; A pure outer expression such as x-5 can define a dimension. The selected states for x and x-5 must remain distinct.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Supported clamps and combinations:&amp;#039;&amp;#039;&amp;#039; Certain MIN/MAX clamps on selection bounds, including clamps involving selected properties, COALESCE, and Boolean combinations have complete change-cover proofs.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Repeated aggregate series:&amp;#039;&amp;#039;&amp;#039; Multiple parameter points of the same formula can use retained anchors, which later SQL requests can reuse as well.&lt;br /&gt;
&lt;br /&gt;
MIN/MAX in the clamp example means a &amp;#039;&amp;#039;&amp;#039;scalar bound expression&amp;#039;&amp;#039;&amp;#039;, not general support for retractable MIN/MAX aggregates.&lt;br /&gt;
&lt;br /&gt;
Applications include versioned inventory, quantities of qualifying contracts, valid configurations, and other aggregates of “the selected state at coordinate x”. Eligibility follows the relational formula, not the application&amp;#039;s business terminology.&lt;br /&gt;
&lt;br /&gt;
=== What happens on a subsequent request ===&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Same point, matching fixed inputs, unchanged dependencies:&amp;#039;&amp;#039;&amp;#039; Read the retained aggregate state.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;New point:&amp;#039;&amp;#039;&amp;#039; Choose a valid anchor, identify potential changes, retract the old contributions, and add the new ones.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;No relevant change between selection bounds:&amp;#039;&amp;#039;&amp;#039; Proven equivalence of ordered selection cuts can permit reuse even when the numeric bound changes. A changed parameter value alone need not imply a fresh cache build.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Many changes:&amp;#039;&amp;#039;&amp;#039; Full reconstruction may be cheaper and can produce a new anchor.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Source mutation or eviction:&amp;#039;&amp;#039;&amp;#039; Reuse must be re-established. Moving an input parameter is distinct from modifying the underlying data.&lt;br /&gt;
&lt;br /&gt;
For monotone interval covers, the current anchor selection compares affected-key work at the nearest valid anchor on each side. Numeric distance alone is not a work estimate. A farther anchor can require fewer corrections.&lt;br /&gt;
&lt;br /&gt;
=== Current implementation limits ===&lt;br /&gt;
&lt;br /&gt;
* The new retraction path currently targets &amp;#039;&amp;#039;&amp;#039;SUM contributions&amp;#039;&amp;#039;&amp;#039;. Runtime admission permits NULL and integral numeric values within a conservative exactness budget; the sum of absolute magnitudes must not exceed 2^52. Other values retain the ordinary SQL reducer. Arbitrary floating-point sums are not silently reordered.&lt;br /&gt;
* A count can mathematically be represented as a sum of 0/1 contributions. This does not imply that every COUNT spelling currently selects the snapshot path. Nor does the new path provide general support for COUNT DISTINCT, AVG, MIN/MAX, or arbitrary user-defined aggregates.&lt;br /&gt;
* The contribution proof currently requires a suitable single base driver with a single-column primary key. Arbitrarily multiplying joins and composite contribution identities are not generally covered.&lt;br /&gt;
* Each contribution proof chooses one moving axis; other inputs partition the cache. This is not yet general incremental correction across freely moving multidimensional surfaces.&lt;br /&gt;
* The current snapshot runtime restricts coordinates to suitable integral numeric values. The abstraction is broader than this implementation; support for arbitrary ordered types is not implied.&lt;br /&gt;
* Not every algebraically related formula has a proof. For example, a scaled inner selection coordinate is not automatically treated as an identity change domain.&lt;br /&gt;
* INSERT/UPDATE/DELETE, changes to classification tables, and table replacement must participate in dependency handling. An invalid snapshot may be discarded and rebuilt. Fully incremental maintenance for every source mutation is not implemented.&lt;br /&gt;
* Cost selection and memory budgets may favor direct execution even when a formula is eligible. Small or empty inputs should not pay for unnecessary preparation.&lt;br /&gt;
&lt;br /&gt;
=== Potential speedup ===&lt;br /&gt;
&lt;br /&gt;
Let N be the number of contributions in a full build and D the number of potentially changed contributions. A follow-up replaces much of the work on N contributions with change-cover/index work and evaluation of D contributions. With comparable per-contribution costs, N/D is a rough estimate for the reduction in that part of execution, not the complete HTTP latency.&lt;br /&gt;
&lt;br /&gt;
For example, 100,000 entities with 100 change candidates mean roughly 1,000× fewer contributions to re-evaluate. Expensive candidate discovery, remaining scans elsewhere in the query, planning, and response handling reduce the actual speedup.&lt;br /&gt;
&lt;br /&gt;
Across P requested points, a favorable snapshot plan replaces P full evaluations with one build and P-1 corrections. An exact repeat can be cheaper still. Initial construction remains real work.&lt;br /&gt;
&lt;br /&gt;
== Performance expectations and reproducible evaluation ==&lt;br /&gt;
&lt;br /&gt;
There is no universal speedup factor for a dimension mode. The estimates above describe reductions in work under stated assumptions. They are not measured end-to-end latency guarantees.&lt;br /&gt;
&lt;br /&gt;
A reproducible comparison should identify the exact source revisions, hardware, generated fixture, query parameters, and cache preparation. Measure one cold request plus a fixed number of follow-ups, include all requests in the total, and report phase timings separately. Moving-bound tests should cover both empty and nonempty change sets. Repeating an identical query tests exact-point reuse; it does not establish the cost of snapshot correction.&lt;br /&gt;
&lt;br /&gt;
The public test suite provides neutral examples that can be inspected and executed without access to application or customer data:&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;tests/performance/domain-snapshot.yaml&amp;#039;&amp;#039;: generated entities and versioned values; ordered state selection, selected-property boundaries, moving parameters, retained snapshots, anchor selection, and source-change correctness.&lt;br /&gt;
* &amp;#039;&amp;#039;tests/performance/group-range-cache.yaml&amp;#039;&amp;#039;: generated range-aggregation workloads with performance configuration.&lt;br /&gt;
* &amp;#039;&amp;#039;tests/planner/aggregates/group-range-cache.yaml&amp;#039;&amp;#039;: correctness and plan regressions for group/range reuse.&lt;br /&gt;
&lt;br /&gt;
Use each test&amp;#039;s declared setup and sampling configuration when reproducing it. Small correctness fixtures establish semantics, not production-scale speedups. A comparison intended to isolate one cache mode must control the other planner and runtime changes as well.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;This page does not publish latency factors from private application workloads. It makes no independently measured speedup claim for an individual dimension mode.&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
== Combining dimensions and choosing a plan ==&lt;br /&gt;
&lt;br /&gt;
One report can use all three modes: equality partitions for tenants or categories, additive ranges for fact revenue, and snapshot domains for state-dependent quantities. Different metrics need not use the same mode. For example, the current implementation can keep categories as fixed partitions without computing every category together in one contribution vector.&lt;br /&gt;
&lt;br /&gt;
Logical IR exposes parameter dependencies, unique selection, contribution identity, and a complete superset of potentially changed keys. Physical planning then decides whether direct execution or cache reuse is cheaper. The logical IR does not introduce physical scans or cache tables prematurely.&lt;br /&gt;
&lt;br /&gt;
EXPLAIN IR and EXPLAIN REORDER help inspect the structure. EXPLAIN PHYSICAL exposes decisions such as &amp;#039;&amp;#039;contribution_domain&amp;#039;&amp;#039;, with &amp;#039;&amp;#039;domain_snapshot&amp;#039;&amp;#039; and &amp;#039;&amp;#039;direct_aggregate&amp;#039;&amp;#039; alternatives. EXPLAIN shows the generated Scheme plan. Actual latency and records visited still require execution measurements.&lt;br /&gt;
&lt;br /&gt;
A snapshot cache is distinct from RecMap. RecMap accelerates physical row mappings within a query. Retained snapshots use logical keys and values; query-local physical row identities must not survive arbitrary shard rebuilds.&lt;br /&gt;
&lt;br /&gt;
== Implementation and test references ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/launix-de/memcp/pull/999 PR #999]: implementation changes.&lt;br /&gt;
* [https://github.com/launix-de/memcp/blob/b2238766400c2c5b20d155a328d0ed380a7414ff/INVARIANTS.md INVARIANTS.md]: planner and group-cache contracts.&lt;br /&gt;
* [https://github.com/launix-de/memcp/blob/b2238766400c2c5b20d155a328d0ed380a7414ff/lib/queryplan-optimize.scm queryplan-optimize.scm]: logical contribution and dependency proofs.&lt;br /&gt;
* [https://github.com/launix-de/memcp/blob/b2238766400c2c5b20d155a328d0ed380a7414ff/lib/queryplan-physical-expr.scm queryplan-physical-expr.scm]: physical selection, snapshot admission, and correction.&lt;br /&gt;
* [https://github.com/launix-de/memcp/blob/b2238766400c2c5b20d155a328d0ed380a7414ff/tests/performance/domain-snapshot.yaml domain-snapshot.yaml]: neutral correctness and performance cases.&lt;br /&gt;
* [https://github.com/launix-de/memcp/blob/b2238766400c2c5b20d155a328d0ed380a7414ff/tests/planner/aggregates/group-range-cache.yaml group-range-cache.yaml]: group/range regression cases.&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
</feed>