Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vt629-002USQ-25 for pgsql-hackers@arkaria.postgresql.org; Thu, 19 Feb 2026 15:33:41 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1vt622-003yao-0t for pgsql-hackers@arkaria.postgresql.org; Thu, 19 Feb 2026 15:33:34 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vt621-003yaf-2n for pgsql-hackers@lists.postgresql.org; Thu, 19 Feb 2026 15:33:34 +0000 Received: from relay3-d.mail.gandi.net ([2001:4b98:dc4:8::223]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.98.2) (envelope-from ) id 1vt61x-000000009pF-3d8u for pgsql-hackers@lists.postgresql.org; Thu, 19 Feb 2026 15:33:33 +0000 Received: by mail.gandi.net (Postfix) with ESMTPSA id 9F95D20085; Thu, 19 Feb 2026 15:33:23 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=vondra.me; s=gm1; t=1771515204; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=sKGPlaZauhUgQ0/p/dFojBRAKV5q/sXIOYDhwLvbD7g=; b=DK3Cx3/K1Wcvfl30STyje0rmN0jN0ryIQ+mQDu14xIQHuW0QU4c/jzUnIhA+RgdPfd0riZ CBVw037494cGSYP0kS8NYmQuXqvbvHtPGs3+26VTEnfXOYsA8cfDTXDV2WeXytLpPvy+8n H4xe46ZQ4voDVy5wk/re3sLeq0BGSp+NwJYSRtMtzu3J8dKsCfMYVWivaEBsDoTK/Sb0x5 JJYKBuvazLE0wbAPkYnbBa17WU8P17c4LJlH5eEsUZkKc4IaGF+pFMjOjc/dmujce7VdOe BajwOS6oEirE8ri8IoowMD+QG3xHpZzxHZ/w4hQzgqXKYuo+rRJmIiJ4jkPfLA== Message-ID: Date: Thu, 19 Feb 2026 16:33:22 +0100 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: Hash aggregate collisions cause excessive spilling To: Ants Aasma , PostgreSQL Hackers References: Content-Language: en-US From: Tomas Vondra In-Reply-To: Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-GND-Sasl: tomas@vondra.me X-GND-Score: -100 X-GND-Cause: gggruggvucftvghtrhhoucdtuddrgeefgedrtddtgddvvdehledtucetufdoteggodetrfdotffvucfrrhhofhhilhgvmecuifetpfffkfdpucggtfgfnhhsuhgsshgtrhhisggvnecuuegrihhlohhuthemuceftddunecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenucfjughrpefkffggfgfuvfhfhfgjtgfgsehtkeertddtvdejnecuhfhrohhmpefvohhmrghsucggohhnughrrgcuoehtohhmrghssehvohhnughrrgdrmhgvqeenucggtffrrghtthgvrhhnpeekffdvudegteefieelffetkeelffeggffhuefffefhleekleethfefieeggfffkeenucfkphepkeeirdegledrvdeftddrvddtieenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepihhnvghtpeekiedrgeelrddvfedtrddvtdeipdhhvghloheplgdutddrudefjedrtddrvdgnpdhmrghilhhfrhhomhepthhomhgrshesvhhonhgurhgrrdhmvgdpqhhiugeplefhleehffdvtddtkeehpdhmohguvgepshhmthhpohhuthdpnhgspghrtghpthhtohepvddprhgtphhtthhopegrnhhtshdrrggrshhmrgestgihsggvrhhtvggtrdgrthdprhgtphhtthhopehpghhsqhhlqdhhrggtkhgvrhhssehlihhsthhsrdhpohhsthhgrhgvshhqlhdrohhrgh X-GND-State: clean List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk On 2/19/26 15:49, Ants Aasma wrote: > Investigating a customer complaint I ran into an issue with the hash > aggregate code. The problem was that a query that usually completes in > less than a minute sometimes gets stuck indefinitely (hours+). I > tracked it down to a hash aggregate node returning one tuple from a > batch and spilling the rest. > > The reason for the behavior is that aggstate->hash_metacxt was 100M, > which is larger than work_mem*hash_mem_multiplier of 64M. This makes > hash_agg_check_limits() always spill after the first tuple. I think > that ends up having a n² overhead, with n being almost 4M here. > Not great :-( > I don't have a simple reproducer yet, because the live problem was on > a parallel query where looking at the backend wrong caused the problem > to disappear. After some retries I was able to catch an instance of > growing past work_mem with gdb. After that growth the simplehash was > {size = 4194304, members = 409839, ..}, i.e. the table was only 20% > full before growing. So the cause seems to be a run of hash collisions > bigger than SH_GROW_MAX_MOVE (150). > > AFAICT there is nothing in simplehash that would stop it growing past > work_mem, and once it does the spilling logic in > agg_refill_hash_table() enters this degenerate state until the end of > the plan node. > > I think the correct fix would be to have a way to insert into > simplehash with a limit on size, which means that the insert might > fail. I haven't yet looked at how complicated this would be to > implement. > Wouldn't it be easier to just start ignoring SH_GROW_MAX_MOVE? That'd have a little bit of performance impact on that one key, but that seems acceptable. And easier to do than dealing with failing inserts. > I also haven't checked what is the cause for such a long run of > collisions. But I think it's related to it being a HashAggregate on > top of Gather on top of HashAggregate. > So it's a parallel aggregate? Partial + Finalize? I wonder if that might be "correlating" the data in a way that makes it more likely to hit SH_GROW_MAX_MOVE. But If that was the case, wouldn't we see this issue more often? regards -- Tomas Vondra