Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtp (Exim 4.84_2) (envelope-from ) id 1e2pli-0003m2-W1 for pgsql-performance@arkaria.postgresql.org; Fri, 13 Oct 2017 02:32:11 +0000 Received: from localhost ([127.0.0.1] helo=postgresql.org) by malur.postgresql.org with smtp (Exim 4.84_2) (envelope-from ) id 1e2pli-00038x-FS for pgsql-performance@arkaria.postgresql.org; Fri, 13 Oct 2017 02:32:10 +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_SHA384:256) (Exim 4.84_2) (envelope-from ) id 1e2plh-000380-Je for pgsql-performance@postgresql.org; Fri, 13 Oct 2017 02:32:09 +0000 Received: from mail-it0-x230.google.com ([2607:f8b0:4001:c0b::230]) by magus.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.84_2) (envelope-from ) id 1e2ple-0005BP-Gk for pgsql-performance@postgresql.org; Fri, 13 Oct 2017 02:32:09 +0000 Received: by mail-it0-x230.google.com with SMTP id y15so9613045ita.4 for ; Thu, 12 Oct 2017 19:32:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:sender:in-reply-to:references:from:date:message-id :subject:to:cc; bh=+v2JtGQrWSslF47qYqnsN7mkWAEyO1OBdixMiYB7KrU=; b=ET3FobsaCmC/QmYKU1C8KgCau6Ehv3jeylryDs6nQbfLUYrH9ExiJ0yRVOzLq0Ptqt XZCrTkVvgnTZe4JHF1eBex/Nk87mP4h5JS1W8oaGirZZoSF1Dhm/OD7pD3vN0cy54PQG b3wFsyqloIOa/1yER/3xPXoVYelPONTLtToC0CxfCN0sQqTs1ey9PxBocEhdXMz75/r8 LrtvQ+tXl55rrjS8r9xWjL1UI8Y4LerrGdDlp4F4ryBSNsjn620hRmzNKFKoaXyhB8Ks zk8CnzYiibBGMPIs2mkgrkoE1ADwWEeIqgbpRILeMJ1K/RS90wPEzrMwZs0HW/kE/oq6 OBzw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:sender:in-reply-to:references:from :date:message-id:subject:to:cc; bh=+v2JtGQrWSslF47qYqnsN7mkWAEyO1OBdixMiYB7KrU=; b=Rn4Le6OmgP3pYUzGBdxeF5CwvgpUw3vq0TEN4yZYRWFd4ZoJu51OamMg2uuhWXMQ/X H2hlGmFFwlgF2SMBe1vpyOPIos3XG5qY4B4eTQnRVACmUqMHt4sd9z0g6ONifyFNw/Or 6ZUukMBtaTlO5FFddKypBXaKlEcPBFcTq0zWrjwHtEEfSc0PbCovcfszpLUaiaOZ1Z3F 4l53ffcn29d10wRebZlkfX1WKIJI1ZEbb4gVuRlLb30kpeJoUocZfTRD2RQijmzQzdvF RS+sq5WXcbJbYsJZdvGBRG6djDAWUyyhmEetkJTxjXTadf/6qLIJ9Gs5nP3uKbzdvMU5 4dQw== X-Gm-Message-State: AMCzsaUuSDdspFQl5V7hJv6sPCJAQKPxbugrG5M6OT0lMakGvW9zLGyj CFQUv0isNI/wF30QTcuSvCOm8MQSH19xeCG77NM= X-Google-Smtp-Source: ABhQp+QfeTfOJwF5Q5n8SgWYDfwXZrQPUSiZx9v3s90bYvcIYj0JJEHh4rnWYRHQUWxbcsSgoqncUR8KganAM3j+vd4= X-Received: by 10.36.68.207 with SMTP id o198mr332461ita.74.1507861924588; Thu, 12 Oct 2017 19:32:04 -0700 (PDT) MIME-Version: 1.0 Received: by 10.107.188.197 with HTTP; Thu, 12 Oct 2017 19:32:03 -0700 (PDT) In-Reply-To: <32209.1507841455@sss.pgh.pa.us> References: <32209.1507841455@sss.pgh.pa.us> From: Ants Aasma Date: Fri, 13 Oct 2017 05:32:03 +0300 X-Google-Sender-Auth: Vpz7QuSlEwAQr29bXxo5nrHC2Ok Message-ID: Subject: Re: Rowcount estimation changes based on from clause order To: Tom Lane Cc: "pgsql-performance@postgresql.org" Content-Type: text/plain; charset="UTF-8" List-Archive: List-Help: List-ID: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: X-Mailing-List: pgsql-performance Precedence: bulk Sender: pgsql-performance-owner@postgresql.org On Thu, Oct 12, 2017 at 11:50 PM, Tom Lane wrote: > Ants Aasma writes: >> I stumbled upon a severe row count underestimation that confusingly >> went away when two inner joins in the from clause were reordered. > > Hm, looks more like an overestimate in this example, but anyway ... > >> Does anybody have any idea what is going on here? > > set_joinrel_size_estimates says > > * Since there is more than one way to make a joinrel for more than two > * base relations, the results we get here could depend on which component > * rel pair is provided. In theory we should get the same answers no matter > * which pair is provided; in practice, since the selectivity estimation > * routines don't handle all cases equally well, we might not. But there's > * not much to be done about it. > > In this example I think the core of the issue is actually not so much > bad selectivity estimates as rowcount roundoff error. > > If we first consider joining "small" with "big", we get an estimate of > 2000 rows (which is dead on for what would happen if we just joined > those). Then we estimate the final result size as the join of that to > "lookup". The selectivity number for that step is somewhat hogwash but > happens to yield a result that's not awful (8 rows). > > In the other case we first estimate the size of the join of "small" with > the "lookup" subquery, and we get a rounded-off estimate of one row, > whereas without the roundoff it would have been probably about 0.01. > When that's joined to "big", we are computing one row times 1 million rows > times a selectivity estimate that's about right for the "small.id = > big.small_id" clause; but because the roundoff already inflated the first > join's size so much, you end up with an inflated final result. > > This suggests that there might be some value in considering the > sub-relations from largest to smallest, so that roundoff error > in the earlier estimates is less likely to contaminate the final > answer. Not sure how expensive it would be to do that or what > sort of instability it might introduce into plan choices. > > Whether that's got anything directly to do with your original problem is > hard to say. Joins to subqueries, which we normally lack any stats for, > tend to produce pretty bogus selectivity numbers in themselves; so the > original problem might've been more of that nature. Thanks for pointing me in the correct direction. The original issue was that values from lookup joined to ref_id and the subset filter in the small table were almost perfectly correlated, which caused the underestimate. In the second case this was hidden by the intermediate clamping to 1, accidentally resulting in a more correct estimate. I actually think that it might be better to consider relations from smallest to largest. The reasoning being - a join cannot produce a fraction of a row, it will either produce 0 or 1, and we should probably plan for the case when it does return something. Going even further, and I haven't looked at how feasible this is, but I have run into several cases lately where cardinality underestimates clamping to 1 result in catastrophically bad plans. Like a stack of nested loops with unparameterized GroupAggregates and HashAggregates as inner sides bad. It seems to me that row estimates should clamp to something slightly larger than 1 unless it's provably going to be 1. Regards, Ants Aasma -- Sent via pgsql-performance mailing list (pgsql-performance@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-performance