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 1qsQpL-00826t-7n for pgsql-performance@arkaria.postgresql.org; Mon, 16 Oct 2023 16:52:23 +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 1qsQpH-002j45-Uk for pgsql-performance@arkaria.postgresql.org; Mon, 16 Oct 2023 16:52:20 +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 1qsQpH-002j3x-HI for pgsql-performance@lists.postgresql.org; Mon, 16 Oct 2023 16:52:20 +0000 Received: from smtp-19.smtpout.orange.fr ([80.12.242.19] helo=smtp.smtpout.orange.fr) by makus.postgresql.org with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.94.2) (envelope-from ) id 1qsQpE-000mXn-0r for pgsql-performance@postgresql.org; Mon, 16 Oct 2023 16:52:19 +0000 Received: from [10.0.0.41] ([90.70.10.94]) by smtp.orange.fr with ESMTPA id sQp9qfpIH45odsQp9qezte; Mon, 16 Oct 2023 18:52:12 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=wanadoo.fr; s=t20230301; t=1697475132; bh=Mlru5gF28hlqO6KVTOLwQ51bBfffobfwXED827rzRdo=; h=Date:Subject:To:Cc:References:From:In-Reply-To; b=BlYtNsrUOpMelzZ+vz6w3gLYVsW9fqFQX/+Zpf//IbfAyNoXis7B+ML00OdTC0Nbi +cMBoUhxkkDzxwMFbn1P2z6N/h3IZd8JvQPuTsJwAI+gq+mjcx8fXBa/wWe+TYCR3D Vvu1snnWmCtSMPxBWo4u9WNjN7jVE4sBa7SSsPRCxK/ZO9kqEP51edIsSJTJTxNocQ Whu64/43PTgwsrtesdQpc18jArnbNY8G35nkw0MOQkmxDWFLJfmD+prsG8jV+cHNOy /8uC5w7mXCedUMqhABz7xVlegoScphfuyE7VsGti6meRh5VXHporYIuaPWRD7k5/b4 vRuGjis35FKiw== X-ME-Helo: [10.0.0.41] X-ME-Auth: cGhpbGlwcGUuYmVhdWRvaW4xN0BvcmFuZ2UuZnI= X-ME-Date: Mon, 16 Oct 2023 18:52:12 +0200 X-ME-IP: 90.70.10.94 Content-Type: multipart/alternative; boundary="------------qJc7vY78DYKnoUUcbWs3sC6w" Message-ID: <84cc7977-49ba-49b2-ab36-dea0ed14ebdc@free.fr> Date: Mon, 16 Oct 2023 18:52:11 +0200 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: Underestimated number of output rows with an aggregate function Content-Language: fr To: Tom Lane Cc: "pgsql-performance@postgresql.org" References: <2091880.1697387849@sss.pgh.pa.us> From: Philippe BEAUDOIN In-Reply-To: <2091880.1697387849@sss.pgh.pa.us> List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk This is a multi-part message in MIME format. --------------qJc7vY78DYKnoUUcbWs3sC6w Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit Le 15/10/2023 à 18:37, Tom Lane a écrit : > Philippe BEAUDOIN writes: >> During my analysis, I realized that the output rows estimate of the >> second CTE is really bad, leading to a bad plan for the next CTE. >> I reproduced the issue in a very small test case with a simplified >> query. Attached is a shell script and its output. > Yeah. If you try it you'll see that the estimates for the > "keys.c1 = tbl.c1" and "keys.seq = tbl.seq" clauses are spot-on > individually. The problem is that the planner assumes that they > are independent clauses, so it multiplies those selectivities together. > In reality, because seq is already unique, the condition on c1 adds > no additional selectivity. > > If seq is guaranteed unique in your real application, you could just > drop the condition on c1. Otherwise I'm not sure about a good > answer. In principle creating extended stats on c1 and seq should > help, but I think we don't yet apply those for join clauses. > > A partial answer could be to defeat application of the table's > statistics by writing > > JOIN keys ON (keys.c1 = tbl.c1+0 AND keys.seq = tbl.seq+0) > > For me this gives an output estimate of 3000 rows, which is still not > great but should at least prevent choice of an insane plan at the > next join level. However, it pessimizes the plan for this query > itself a little bit (about doubling the runtime). Thanks for the trick (and the quick answer). In the test case, it effectively brings a pretty good plan. Unfortunately, as these statements are generated and depend on the base table structure, the issue remains for some of them (but not all). So, for the moment at least, I keep the previous workaround (disabling nested loops). >> For the hash join node, the plan shows a "Inner Unique: true" property. >> I wonder if this is normal. > Sure. The output of the WITH is visibly unique on c1. OK, I see. > regards, tom lane --------------qJc7vY78DYKnoUUcbWs3sC6w Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: 8bit
Le 15/10/2023 à 18:37, Tom Lane a écrit :
Philippe BEAUDOIN <phb.emaj@free.fr> writes:
During my analysis, I realized that the output rows estimate of the 
second CTE is really bad, leading to a bad plan for the next CTE.
I reproduced the issue in a very small test case with a simplified 
query. Attached is a shell script and its output.
Yeah.  If you try it you'll see that the estimates for the
"keys.c1 = tbl.c1" and "keys.seq = tbl.seq" clauses are spot-on
individually.  The problem is that the planner assumes that they
are independent clauses, so it multiplies those selectivities together.
In reality, because seq is already unique, the condition on c1 adds
no additional selectivity.

If seq is guaranteed unique in your real application, you could just
drop the condition on c1.  Otherwise I'm not sure about a good
answer.  In principle creating extended stats on c1 and seq should
help, but I think we don't yet apply those for join clauses.

A partial answer could be to defeat application of the table's
statistics by writing

          JOIN keys ON (keys.c1 = tbl.c1+0 AND keys.seq = tbl.seq+0)

For me this gives an output estimate of 3000 rows, which is still not
great but should at least prevent choice of an insane plan at the
next join level.  However, it pessimizes the plan for this query
itself a little bit (about doubling the runtime).

Thanks for the trick (and the quick answer). In the test case, it effectively brings a pretty good plan.

Unfortunately, as these statements are generated and depend on the base table structure, the issue remains for some of them (but not all). So, for the moment at least, I keep the previous workaround (disabling nested loops).


      
For the hash join node, the plan shows a "Inner Unique: true" property. 
I wonder if this is normal.
Sure.  The output of the WITH is visibly unique on c1.
OK, I see.
			regards, tom lane


--------------qJc7vY78DYKnoUUcbWs3sC6w--