Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1j1B9w-0004kb-7d for pgsql-performance@arkaria.postgresql.org; Mon, 10 Feb 2020 15:39:40 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.89) (envelope-from ) id 1j1B9v-0007aH-22 for pgsql-performance@arkaria.postgresql.org; Mon, 10 Feb 2020 15:39:39 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1j1B9u-0007aA-Oy for pgsql-performance@lists.postgresql.org; Mon, 10 Feb 2020 15:39:38 +0000 Received: from sss.pgh.pa.us ([66.207.139.130]) by magus.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1j1B9s-00045L-2l for pgsql-performance@lists.postgresql.org; Mon, 10 Feb 2020 15:39:38 +0000 Received: from sss1.sss.pgh.pa.us (localhost [127.0.0.1]) by sss.pgh.pa.us (8.14.4/8.14.4) with ESMTP id 01AFdV54006876; Mon, 10 Feb 2020 10:39:31 -0500 From: Tom Lane To: Chris Borckholder cc: pgsql-performance@lists.postgresql.org Subject: Re: Bad selectivity estimate when using a sub query to determine WHERE condition In-reply-to: References: Comments: In-reply-to Chris Borckholder message dated "Mon, 10 Feb 2020 11:34:01 +0100" MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-ID: <6874.1581349171.1@sss.pgh.pa.us> Date: Mon, 10 Feb 2020 10:39:31 -0500 Message-ID: <6875.1581349171@sss.pgh.pa.us> List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk Chris Borckholder writes: > When using a sub select or CTE to get the latest roll up time, the query > planner fails to recognize that a most of the large table would be filtered > out by the condition and tries a sequential scan instead of an index scan. > When using the literal value for the WHERE condition, the plan correctly > uses an index scan, which is much faster. Yeah, a scalar sub-select is pretty much a black box to the planner. > EXPLAIN (ANALYZE, BUFFERS) WITH current_rollup AS ( > SELECT COALESCE(MAX(window_end), '-infinity') AS cutoff > FROM exchange.ledger_zerosum_rollup > ) > SELECT * > FROM exchange.ledger > WHERE created > (SELECT cutoff FROM current_rollup); Well, it's not that hard to get rid of that scalar sub-select: since you're already relying on current_rollup to produce exactly one row, you could write a plain join instead, something like WITH current_rollup AS ... SELECT l.* FROM exchange.ledger l, current_rollup c WHERE l.created > c.cutoff; Unfortunately I doubt that will improve matters much, since the planner also knows relatively little about MAX() and nothing about COALESCE, so it's not going to be able to estimate what comes out of the WITH. I think you're going to have to cheat a bit. The form of cheating that comes to mind is to wrap the sub-select in a function that's marked STABLE: create function current_rollup_cutoff() returns timestamp -- or whatever stable language sql as $$ SELECT COALESCE(MAX(window_end), '-infinity') AS cutoff FROM exchange.ledger_zerosum_rollup $$; SELECT * FROM exchange.ledger WHERE created > current_rollup_cutoff(); I have not actually tried this, but I think that since the function is marked stable, the planner would test-run it to get an estimated value, and then produce a plan similar to what you'd get with a literal constant. Of course, then it's going to run the function once more when the query is executed for-real, so this approach doubles the cost of getting the MAX(). That shouldn't be too awful if you have an index on window_end, though. If you like living dangerously, you could cheat a LOT and mark the function immutable so that its value gets substituted at plan time. But that will only work for interactive submission of the outer query --- if the plan gets cached and re-used, you'll have a stale cutoff value. Personally I wouldn't risk that. regards, tom lane