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 1tqhFF-008zWt-0B for pgsql-bugs@arkaria.postgresql.org; Fri, 07 Mar 2025 23:36:45 +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 1tqhFD-002QFC-NW for pgsql-bugs@arkaria.postgresql.org; Fri, 07 Mar 2025 23:36:43 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1tqhFD-002Q9u-Ef for pgsql-bugs@lists.postgresql.org; Fri, 07 Mar 2025 23:36:43 +0000 Received: from sss.pgh.pa.us ([68.162.161.243]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1tqhFB-001a2i-1m for pgsql-bugs@lists.postgresql.org; Fri, 07 Mar 2025 23:36:42 +0000 Received: from sss1.sss.pgh.pa.us (localhost [127.0.0.1]) by sss.pgh.pa.us (8.15.2/8.15.2) with ESMTP id 527Nadmc1144177; Fri, 7 Mar 2025 18:36:39 -0500 From: Tom Lane To: michael@joincandidhealth.com cc: pgsql-bugs@lists.postgresql.org Subject: Re: BUG #18834: Query planer is choosing the sub-optimal plan when limit is present In-reply-to: <18834-ec88fdda949458d0@postgresql.org> References: <18834-ec88fdda949458d0@postgresql.org> Comments: In-reply-to PG Bug reporting form message dated "Fri, 07 Mar 2025 16:09:38 +0000" MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-ID: <1144175.1741390599.1@sss.pgh.pa.us> Date: Fri, 07 Mar 2025 18:36:39 -0500 Message-ID: <1144176.1741390599@sss.pgh.pa.us> List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk PG Bug reporting form writes: > We observed **poor query performance** when using an **`ORDER BY`** clause > combined with **`LIMIT`**, which led us to investigate further. This is a well-known syndrome. The fundamental problem is the poor selectivity estimate: > -> Bitmap Index Scan on ix_fn_ledger_provenance > (cost=0.00..1228.15 rows=8020 width=0) (actual time=2.923..2.924 rows=1 > loops=1) > Index Cond: (provenance @> '{"locator": > "52ca2f03-8184-448f-9b9e-7a0ed99e6922"}'::jsonb) If the thing thinks there are 8020 matches for the @> condition when there's only one, it's really pure luck if you get an optimal plan. All its cost estimates will be off by a factor of more than 1000, and these decisions are by no means linear. They're particularly not linear in the presence of LIMIT, but query plans can go far astray even without that. So what you need to do about this is get a better selectivity estimate. You might be able to get somewhere with custom statistics (see CREATE STATISTICS), or just by cranking up the statistics target for the "provenance" column to the maximum. But I'm not sure how much that will help. Fundamentally, putting stuff into unstructured JSON storage and expecting to get efficient searches of it is an antipattern. A more reliable answer is to change your query. You could, for example, make an expression index on (provenance ->> 'locator') and then write WHERE (provenance ->> 'locator') = '52ca2f03-8184-448f-9b9e-7a0ed99e6922' That will provide both fast searches and reasonably trustworthy stats (once ANALYZE has seen the index). regards, tom lane