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 1q6wPl-0001l4-2r for pgsql-bugs@arkaria.postgresql.org; Wed, 07 Jun 2023 16:53:41 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1q6wPj-0001PZ-SL for pgsql-bugs@arkaria.postgresql.org; Wed, 07 Jun 2023 16:53:39 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1q6wPj-0001PQ-Jg for pgsql-bugs@lists.postgresql.org; Wed, 07 Jun 2023 16:53:39 +0000 Received: from mail-ej1-x62f.google.com ([2a00:1450:4864:20::62f]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.94.2) (envelope-from ) id 1q6wPh-000k8L-2f for pgsql-bugs@lists.postgresql.org; Wed, 07 Jun 2023 16:53:38 +0000 Received: by mail-ej1-x62f.google.com with SMTP id a640c23a62f3a-977c88c9021so751682566b.3 for ; Wed, 07 Jun 2023 09:53:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20221208; t=1686156815; x=1688748815; h=content-transfer-encoding:in-reply-to:from:cc:references:to :content-language:subject:user-agent:mime-version:date:message-id :from:to:cc:subject:date:message-id:reply-to; bh=6ntWrVMc0tB4s1FU7xJQe64fleCH+cQB40bNNAY48Qg=; b=NLwoMMa4oT5IhTsztX7V9ZTbgtFkrSOCxN9Cm0i0P54GpyIup6UuTWyQ3GTpCIZoAn k6De9A/C8Nl3GNDYsNjrZehMV/VkQoHt54KOmx7+DN1q2nXrOZm/NIfrCODoyhbIYdk8 HM9Hr12pWY+Pqq165C4dLmVUx+Od2XpNVXvgo8tRzCaUwYVNfU1Yh8cEvbOkXXqVQK8g By/BFVX+sogSA16Ttl+j+CNmSJD8HbpXAbSDVxZDF+cREUIWgdp5qN+IjtQsVg3kLqF8 hpOWIAs/1pi4i55b7iwhGSGg7crJ3Ro8bqOdq8nAX7m2dHmUwCKfQuxPQYyRzE6QzeL5 FqRA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1686156815; x=1688748815; h=content-transfer-encoding:in-reply-to:from:cc:references:to :content-language:subject:user-agent:mime-version:date:message-id :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=6ntWrVMc0tB4s1FU7xJQe64fleCH+cQB40bNNAY48Qg=; b=aB3pHk7ZnZeCMsxymEjHsxc/IpqJg1NA1Zwnm9Dy94jtlT0FeYXtWLY+mEOuRqPJUQ Km0DakH8gnDNDZmQkYq5ALfZfUgbUlWwZM/G6YaHdGUoycAnAOWwbyE2f1L/U2FvabjU y389ppyyZDYC1QuoK08Z2gyip9UrAh6uHItILoitXGLc3WDV3SdvZ5nPIWfdpgnOzuQT vBHT6J3IBi462cWaBOjiL4oVawPAw3VT7BdcNqXPieGCyCPOd8q64cv0/3+FO99Rtw1Y mo4xyEfLxy/AwStgX2xBmLPpLMCN8jLUOpz80X7BUm3mfTXqZfOhDvQ8Pb1DRKvJN1Be zcfw== X-Gm-Message-State: AC+VfDyfa7yGyDPBQVuI8wzj+KmMS3evIm8OPQr8Sc/r/2fENNl4g4GX C0L0ImX2RB3NyNpszSA9Iwx7fwcsG6w= X-Google-Smtp-Source: ACHHUZ4Nl2p6bqgZMonDbmPZeDw5dtuMhNR/IS5e5a4iO8nBBLvXK0NgHEyJq4gKdOB6+tvf4nKTPA== X-Received: by 2002:a17:907:7214:b0:973:e4c2:2bd0 with SMTP id dr20-20020a170907721400b00973e4c22bd0mr6477200ejc.8.1686156814413; Wed, 07 Jun 2023 09:53:34 -0700 (PDT) Received: from ?IPV6:2a02:8388:e002:8cf0:904:dd2c:61fe:518c? (2a02-8388-e002-8cf0-0904-dd2c-61fe-518c.cable.dynamic.v6.surfer.at. [2a02:8388:e002:8cf0:904:dd2c:61fe:518c]) by smtp.googlemail.com with ESMTPSA id dx1-20020a170906a84100b0096f7ae359a5sm7145843ejb.30.2023.06.07.09.53.33 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Wed, 07 Jun 2023 09:53:34 -0700 (PDT) Message-ID: <8ca5637b-32c4-cb17-2de6-10f9248c5857@gmail.com> Date: Wed, 7 Jun 2023 18:53:32 +0200 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.11.0 Subject: Re: BUG #17964: Missed query planner optimization Content-Language: de-AT To: David Rowley References: <17964-cdeb9e3f89c18393@postgresql.org> <94608857-707f-55ce-99a0-ac500aeb06f8@gmail.com> Cc: pgsql-bugs@lists.postgresql.org From: Mathias Kunter In-Reply-To: Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk Am 07.06.23 um 14:36 schrieb David Rowley: > On Wed, 7 Jun 2023 at 23:48, Mathias Kunter wrote: >> If I simply change the original query from this: >> >>> SELECT ... WHERE id IN (SELECT ...); >> >> into this: >> >>> SELECT ... WHERE id = ANY(ARRAY(SELECT ...)); >> >> then Postgres uses an index scan, and the query is orders of magnitude >> faster. > > What's going on here is that ... Thank you very much for the explanation, fully understood. > The main problem here is that in some cases the first of your queries > will be faster and in other cases the 2nd will be faster. It'll depend > on how many rows are in each table. So, really to find the fastest > plan, the planner would have to consider both options. Yes, considering both options is exactly what I'm suggesting. > The join search is going to be the slowest part of planning > when there are a few tables to join, so doing that twice could add > quite a bit of overhead to the planner. Yes, but I'd argue that we have to put that additional planning overhead into perspective. The planning time overhead will typically be in the order of milliseconds. Also, the additional planning time will not depend on the number of rows within the tables. In contrast to that, the execution time overhead can be in the order of minutes, since it will depend on the number of rows which are involved. After all, Postgres will unnecessarily execute a sequential scan, and the size of the scanned table might be gigabytes. > You might also then consider > how many times you'd need to perform the join search if there were, > say, 5 IN clauses. To exhaustively find the best plan we'd need to > try all possible combinations of converting each IN clause to a > semi-join vs leaving the qual alone. We don't necessarily have to use exhaustive search, a heuristic would already be a major improvement. For example, use the estimated number of rows returned by the subselect of each IN clause. If this number is below a certain threshold (which is yet to be defined), then rewrite the corresponding IN clause to ANY. As a final verification step, check the rewritten query against the original query, and only use the rewritten query if the estimated costs are lower. I think something like this should be possible to do with reasonable planner overhead. > I'm not all that sure you're likely to see us > making any improvements here. I'm very sorry to hear this. Please note that I stumbled upon this issue through a real-world use case. One of my queries was very slow. I looked at the query plan of the affected query, and I saw this: > Planning Time: 1.267 ms > Execution Time: 69566.632 ms > cost=3941783.88..3941783.92 Just by changing one IN clause to ANY, I now see this: > Planning Time: 1.103 ms > Execution Time: 0.232 ms > cost=1514.95..1515.62 The query time went from over a minute to about a millisecond! I couldn't believe it. Here, the overhead to find the better query plan would obviously have paid off hugely. > I suggest just rewriting the query in a > way that it executes more quickly for you. Yes, I'm happily doing that now. The problem is that most other Postgres users don't know that they might have to replace IN with ANY in order to massively speed up their queries. How should they know? This certainly comes unexpected, and this also isn't documented anywhere, as far as I can see. Thanks Mathias