Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1lyhG2-0008Qv-2g for pgsql-performance@arkaria.postgresql.org; Wed, 30 Jun 2021 20:56:30 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1lyhG0-00040K-JF for pgsql-performance@arkaria.postgresql.org; Wed, 30 Jun 2021 20:56:28 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1lyhG0-00040C-9c for pgsql-performance@lists.postgresql.org; Wed, 30 Jun 2021 20:56:28 +0000 Received: from mail-qt1-x82f.google.com ([2607:f8b0:4864:20::82f]) by magus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.92) (envelope-from ) id 1lyhFt-0006nx-L4 for pgsql-performance@lists.postgresql.org; Wed, 30 Jun 2021 20:56:27 +0000 Received: by mail-qt1-x82f.google.com with SMTP id y9so2534855qtx.9 for ; Wed, 30 Jun 2021 13:56:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:subject:from:in-reply-to:date:cc :content-transfer-encoding:message-id:references:to; bh=oS/eCziNZoh0FfZ/IHR7Lu04/y5l4AFDhAc9+yFmgeM=; b=Wp7I+R8xHF25laQxGD+Bts9TVitARnN9forKm9eK/QoyOf3lGHf/JkO0hwZp/4TXCW 8fNVQx0eGPDUbOQaxIp1FDgmCZRYZPTp+YARuKIAdwmSUO6QzxWTgrdjSS9IYA+o602B Fze5Z1r30BhjWNHD7vzt64FuGoAr0nyFxj2/p3J4fhv58T1/ouIZQnmGxsI+v0WZLPUQ J6YESQMfjBgUNLHxfieP9nBR5DDN7osUGHpnUvNb9NNyZramzSXAIxQZ/Zwc8ELmagfD l85tOvsHH1RxRt41IK1WFLx++hVxYbXWKTTGew47OOhHa8zf3f9KbrWR3Wm1Hh9jDn+9 /g1A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:subject:from:in-reply-to:date:cc :content-transfer-encoding:message-id:references:to; bh=oS/eCziNZoh0FfZ/IHR7Lu04/y5l4AFDhAc9+yFmgeM=; b=d/HXXG/2pJg3SauXwoLyMLKJ/9W/oeuT8s5NJPaWu3+zyiVHQnslKi5UhuKUUN77jt gH7SI6uELaPVJj1GbOw38UzzpTwnolQ30XiMmsKubD2IcH8+yYnAyv677XByw7+Y4yCF WBsy1Szf/soRlxF/RTKT7PBd01eeKrbwaSUD2+PyIQdovU+RXa6JiOXz220r+cI71RBy glmGQL9BdpfJ5BJN9Y/JFxh5HKjRCBltAH9g0DLZ6HiZ63HbRe5JjyX1AHOm7sjmZXRc +sorwQY/8QTUXPAek0bePPB05Od8lLQPjBAzugs7DIzS1qHMt6/fNRJQcCtM1mxrmeNl ypRg== X-Gm-Message-State: AOAM531C2n6MEmaRh/78+TerAU6tsIK/uC+QcWGM2mMHdSxHQU++MGNw d6IFBea2i4X14MaWLjhI39E= X-Google-Smtp-Source: ABdhPJw6LhlZLm7N3BwWi1e9S8LLSXNjNBOkaH0fSbuVz0LB/wroe+kJj3hFAl4ohBmbdA37AMiCoQ== X-Received: by 2002:a05:622a:1046:: with SMTP id f6mr32781382qte.237.1625086579639; Wed, 30 Jun 2021 13:56:19 -0700 (PDT) Received: from smtpclient.apple ([190.21.42.239]) by smtp.gmail.com with ESMTPSA id i21sm14158429qkl.20.2021.06.30.13.56.17 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Wed, 30 Jun 2021 13:56:19 -0700 (PDT) Content-Type: text/plain; charset=us-ascii Mime-Version: 1.0 (Mac OS X Mail 14.0 \(3654.100.0.2.22\)) Subject: Re: Planning performance problem (67626.278ms) From: Manuel Weitzman In-Reply-To: <508897.1625005916@sss.pgh.pa.us> Date: Wed, 30 Jun 2021 16:56:14 -0400 Cc: Ranier Vilela , David Rowley , Jeremy Schneider , "pgsql-performance@lists.postgresql.org" , Andres Freund Content-Transfer-Encoding: quoted-printable Message-Id: References: <6d58f68e-ed1a-c48e-1440-691554f6e1e7@9livesdata.com> <20190408144210.GG10080@telsasoft.com> <20190408232644.r6xixkeulsmomwfj@alap3.anarazel.de> <3f5e5673-06aa-bf7c-cdb7-0e053c45ba26@amazon.com> <767433.1619015825@sss.pgh.pa.us> <1588548.1624234651@sss.pgh.pa.us> <39C2266C-3143-4A7A-BCAF-E0C8394F9D24@gmail.com> <500142.1624995808@sss.pgh.pa.us> <508897.1625005916@sss.pgh.pa.us> To: Tom Lane X-Mailer: Apple Mail (2.3654.100.0.2.22) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk > 1. create_join_clause doesn't trouble to look for commuted > equivalents, which perhaps is penny-wise and pound-foolish. > The cost of re-deriving selectivity estimates could be way > more than the cost of checking this. Agreed. > 2. Although these look like they ought to be equivalent to the > original clauses (modulo commutation, for some of them), they don't > look that way to create_join_clause, because it's also checking > for parent_ec equality. Per the comment, >=20 > * parent_ec is either equal to ec (if the clause is a = potentially-redundant > * join clause) or NULL (if not). We have to treat this as part of the > * match requirements --- it's possible that a clause comparing the = same two > * EMs is a join clause in one join path and a restriction clause in = another. >=20 > It might be worth digging into the git history to see why that > became a thing and then considering whether there's a way around it. > (I'm pretty sure that comment is mine, but I don't recall the details > anymore.) To me that sounds OK, I cannot prove that they're equivalent to the original clauses so I think it is fine to assume they're not (not an expert here, quite the opposite). > Anyway, it's certainly not the case that we're making new > RestrictInfos for every pair of rels. It looks that way in this > example because the join vars all belong to the same EC, but > that typically wouldn't be the case in more complex queries. Good to know, this wasn't clear to me. > So we could look into whether this code can be improved to share > RestrictInfos across more cases. Another thought is that even > if we need to keep original and derived clauses separate, maybe it'd > be all right to copy previously-determined cached selectivity values > from an original clause to an otherwise-identical derived clause > (cf. commute_restrictinfo()). I'm not sure though whether it's > reliably the case that we'd have filled in selectivities for the > original clauses before this code wants to clone them. To be honest, even if that sounds like a good idea to dig on, I think it wouldn't completely solve the problem with repeated calls to get_actual_variable_range(). The example query I gave is doing a lot of simple auto-joins which makes the thought process simpler, but I worry more about the more "common" case in which there is more than 2 distinct tables involved in the query For example, instead of having "b1, b2, ..., bn" as aliases of "b" in this query >> explain (analyze, buffers) >> select * from a >> join b b1 on (b1.a =3D a.a) >> join b b2 on (b2.a =3D a.a) >> where b1.a in (1,100,10000,1000000,1000001); it is also possible to reproduce the increasing cost in planning buffers for each new join on a distinct table being added: explain (analyze, buffers) select * from a join b on (b.a =3D a.a) join c on (c.a =3D a.a) -- ... (etc) where c.a in (1,100,10000,1000000,1000001); I can imagine that deconstruct_jointree() and generate_join_implied_equalities() would generate multiple RestrictInfos, in which many of them a constraint on a.a would be involved (each involving a different table). b.a =3D a.a c.a =3D a.a c.a =3D b.a a.a =3D b.a a.a =3D c.a ... (etc) (if we wanted, we could also add a different WHERE clause on each of the tables involved to make really sure all RestrictInfos are different). For each of these RestrictInfos there *could* be one cache miss on cached_scansel() that *could* force the planner to compute get_actual_variable_range() for the same variable (a.a) over and over, as mergejoinscansel() always computes the selectivity for the intervals that require actual extremal values. In practice this re-computing of the variable range seems to happen a lot. One way in which I see possible to share this kind of information (of extremal values) across RestrictInfos is to store the known variable ranges in PlannerInfo (or within a member of such struct), which seems to be around everywhere it would be needed. Best regards, Manuel