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.94.2) (envelope-from ) id 1tvlX4-007quN-HN for pgsql-general@arkaria.postgresql.org; Fri, 21 Mar 2025 23:12:06 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.94.2) (envelope-from ) id 1tvlX1-000Sqk-O6 for pgsql-general@arkaria.postgresql.org; Fri, 21 Mar 2025 23:12:03 +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.94.2) (envelope-from ) id 1tvlX0-000SiH-M2 for pgsql-general@lists.postgresql.org; Fri, 21 Mar 2025 23:12:03 +0000 Received: from fhigh-b3-smtp.messagingengine.com ([202.12.124.154]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1tvlWx-000Or0-1i for pgsql-general@postgresql.org; Fri, 21 Mar 2025 23:12:02 +0000 Received: from phl-compute-07.internal (phl-compute-07.phl.internal [10.202.2.47]) by mailfhigh.stl.internal (Postfix) with ESMTP id 80E9425400F6; Fri, 21 Mar 2025 19:11:56 -0400 (EDT) Received: from phl-mailfrontend-02 ([10.202.2.163]) by phl-compute-07.internal (MEProxy); Fri, 21 Mar 2025 19:11:56 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=aklaver.com; h= cc:content-transfer-encoding:content-type:content-type:date:date :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to; s=fm3; t=1742598716; x=1742685116; bh=oIQiCYH30fXTsv4zh1cBzI17YYlOdKY0RinQ5AZ2QbY=; b= Yi+MKAkalX49PXNwaHFIB0wfAsTqa4isMmcjgfYwTDQkVjTig/dn+RBe9aMuX+dY Nq55lAMFdPSTYx2xbOp866evfAkZwAU4EByMF2ugcjekcgWKYDDR5a7prUyMaspq qV2DLjK4n6fLmFTZJ8hPtV0CTX5c/1VkzFvQyVZzZ1wgpG29/Kis3FfWjS9j+Jkf 7CTcfNuIy2egkaLx+QhawDravHLO6E84DYu0QxEbTr/1xWHWnyj8EqEMuxAeyVPO Kt7zTSY8S7OPuUwqmadCkskkMllbyjk1AjkpbhEb3vUjAqOyX8aWhn3Evr6PBLMc sV+rubfCApeukB62dBjKBg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:content-type :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm1; t=1742598716; x=1742685116; bh=o IQiCYH30fXTsv4zh1cBzI17YYlOdKY0RinQ5AZ2QbY=; b=lNT3SWNieUdzRgUeX 4oLAuGuGXty1nfood5TLJe8W+K0EcUxweV6e0MkBdV9wU01qSny/3/MX7NsqCvdx xqq0LBBrOanK+xEgJ4PfMJ0oUZ5mS7yaN9QHVJh9nawhZH/M2AmVPxLf+80rj3Xq q/1KMDFIUCjhoF3Vk2jQsp2KfErmLpGRslyd9CEpH9PZwcgjcJWNcQ86J8cQWblT 0btj/gPwuZSlMPBv3B4edZNupaqxDlpdWkP1UCnmE0QmeQaeZjAPGGaNajUVyWVt +sWzR2msJKtLdzf1cWbW/eRcLH9As2wRbmzt9vXMRlJIDfn2/6aNFbSWHsalMMxE zuKQw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefvddrtddtgdduhedvfeejucetufdoteggodetrf dotffvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdggtfgfnhhsuhgsshgtrhhisggv pdfurfetoffkrfgpnffqhgenuceurghilhhouhhtmecufedttdenucesvcftvggtihhpih gvnhhtshculddquddttddmnecujfgurhepkfffgggfuffvfhfhjggtgfesthekredttddv jeenucfhrhhomheptegurhhirghnucfmlhgrvhgvrhcuoegrughrihgrnhdrkhhlrghvvg hrsegrkhhlrghvvghrrdgtohhmqeenucggtffrrghtthgvrhhnpeffleegieefgfevudeh tdfhkeeutdffjeevgeffgeejvedthefgudeiteefheejheenucevlhhushhtvghrufhiii gvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpegrughrihgrnhdrkhhlrghvvghrsegr khhlrghvvghrrdgtohhmpdhnsggprhgtphhtthhopedvpdhmohguvgepshhmthhpohhuth dprhgtphhtthhopehpohhsthhgrhgvshhqlhegsehrvggrlhhithihvgigihhsthhsrdhn vghtpdhrtghpthhtohepphhgshhqlhdqghgvnhgvrhgrlhesphhoshhtghhrvghsqhhlrd horhhg X-ME-Proxy: Feedback-ID: i76984098:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Fri, 21 Mar 2025 19:11:55 -0400 (EDT) Message-ID: <02682db3-e3fa-4de5-af49-1f6dc4f8e5cf@aklaver.com> Date: Fri, 21 Mar 2025 16:11:55 -0700 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: Querying one partition in a function takes locks on all partitions To: Evgeny Morozov , PostgreSQL General References: <01020195b987abd3-a008b77d-8c63-4931-80a4-be36a351c8b2-000000@eu-west-1.amazonses.com> Content-Language: en-US From: Adrian Klaver In-Reply-To: <01020195b987abd3-a008b77d-8c63-4931-80a4-be36a351c8b2-000000@eu-west-1.amazonses.com> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk On 3/21/25 09:27, Evgeny Morozov wrote: > I have a list-partitioned table. When I query the base table but filter > by the partition column in a regular SQL query this takes a lock only on > the one partition being queried, as I expect. However, when the exact > same SQL query is run fom a DB function, with the partition ID passed in > as argument, it takes (shared) locks on ALL partitions - which blocks > any other process that wants an exclusive lock on another partition (and > vice-versa). > > Originally found on PG 15.12, but happens on 17.4 as well. Easily > reproducible: > > -- One-time setup > > create table entity > ( >     part_id integer not null > ) partition by list (part_id); > > create table entity_1 partition of entity for values in (1); > create table entity_2 partition of entity for values in (2); > > create function read_partition(which_part int) returns bigint as > 'select count(*) from entity where part_id = which_part;' > language sql stable; > > -- Then try this, keeping the connection open (so the transaction is > pending): > > begin; > select read_partition(1); -- This takes shared locks on entity_1 AND > entity_2 > > -- select count(*) from entity where part_id = 1; -- but this would only > take a shared lock only on entity_1 > > If another session tries something that takes an exclusive lock on > another partition, like > > alter table entity_2 add column new_column text; > > I would expect that to be able to run concurrently, but it blocks due to > the shared lock on entity_2. (The way I originally found the problem was > the opposite: once one client took an exclusive lock on a partition many > others were blocked from reading from ANY partition.) > > This seems like quite the "gotcha", especially when the query plan for > the function call (logged via autoexplain) shows it only accessing one > partition (entity_1). Is this expected behavior? If so, is it documented > somewhere? Hmm, seems to be a sql function issue: CREATE OR REPLACE FUNCTION public.read_partition(which_part integer) RETURNS bigint LANGUAGE plpgsql STABLE AS $$ DECLARE id_ct bigint; BEGIN select count(*) into id_ct from entity where part_id = $1; RETURN id_ct; END; $$; BEGIN; select read_partition(1); read_partition ---------------- 0 select relation::regclass, mode from pg_locks ; relation | mode ----------+----------------- pg_locks | AccessShareLock entity_1 | AccessShareLock entity | AccessShareLock | ExclusiveLock > > > -- Adrian Klaver adrian.klaver@aklaver.com