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.96) (envelope-from ) id 1woeVD-001BVF-1n for pgsql-hackers@arkaria.postgresql.org; Tue, 28 Jul 2026 09:53:35 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1woeVC-000Kga-1u for pgsql-hackers@arkaria.postgresql.org; Tue, 28 Jul 2026 09:53:34 +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.96) (envelope-from ) id 1woeUy-000HIc-1L for pgsql-hackers@lists.postgresql.org; Tue, 28 Jul 2026 09:53:20 +0000 Received: from mail-wr1-x42f.google.com ([2a00:1450:4864:20::42f]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1woeUw-00000000itW-37li for pgsql-hackers@lists.postgresql.org; Tue, 28 Jul 2026 09:53:19 +0000 Received: by mail-wr1-x42f.google.com with SMTP id ffacd0b85a97d-47f307dd9d5so164583f8f.0 for ; Tue, 28 Jul 2026 02:53:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785232396; x=1785837196; darn=lists.postgresql.org; h=content-transfer-encoding:content-type:in-reply-to:from :content-language:references:cc:to:subject:user-agent:mime-version :date:message-id:from:to:cc:subject:date:message-id:reply-to :content-type; bh=zNUY/cXIYdmatPvgWXlNoKB/VZTwMqvWXN3+uBwJeJ8=; b=iPIsUOoAth6PR5PbcMBqnjrJbOVtAk4i1JdgUuGe5EfU6DmQNtN0abB6VOz4Ixt3IN Pvp5ePcTFKhRXeLX9OhYuyXhqImzleJBHdT2z01D7455qR1hAfpuaxHFoFuR5jqDoul+ dyD4agUd4nKBowKGY/25mf/R+LN9AhoOTrKx5T8aq4BrZK06eFcesepDIGSFJlN0pmEW wC+JdsnH3pbP7o1DBogyR/VXyhk0r87uwY1yG6hrFvwYi6Kydag24LBxZrZdGqI+J0z1 0n1peEpetqzw+kMZwrKwvEuBuVcv63wHbWM8XdcwdcIHWjmaYXd2yoYa13DFPGxMxBMD sUUg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785232396; x=1785837196; h=content-transfer-encoding:content-type:in-reply-to:from :content-language:references:cc:to:subject:user-agent:mime-version :date:message-id:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=zNUY/cXIYdmatPvgWXlNoKB/VZTwMqvWXN3+uBwJeJ8=; b=XQhE11Yj7LAbtjmQy1bVpr89gxKdqW4JMkyGUHOLLKg1L+zCkPZ4d1HPRCawKM1485 PnWg3aZXCOn9U3RK10740Hrd/dyHuIYD5SXddVnq3rT1gnQumNbeyJ2h2CXpXkAGKiXf tfE9hugk760Xh5OWqHqvM2jt7rzfTHUQ4n8RnWF50DFTunIL6Z0BknRotElJkHHh0fNX M9PbBD7R/tRJVp4WLY3XBmu4Pr3OSg580ab25ftdPH4HFq/kPPmNGadDOAHdcpO4E6Ut oOVBi7pGBB6eyV7OFgsS9g41UZcE1G19C0FRHQhimigmnj+1Ric7PoR1qXeDGP9bzj1h oEkA== X-Gm-Message-State: AOJu0Yww/IWkBmuBxTifARYn8s7lYCE3PQwRLTxVPy/f+IjzumRHlZzS kxDxe6fHCHuYfQj34D1OpA9FFmdyiz3kxNJMHCcYPZTl94SVC/tRARdy X-Gm-Gg: AR+sD11psTDFbmTwBGKAh4qe3pe916Mm36VvU2z7zfNt6L9QsuWMNfJSSedAKnKO7rA ugpBb1BUCZtvTTUf9qK75kBJUkqsso2VvdJeezNrCpen5Y9gsCH71A0p4WFIYLP83OXYNWkQNsk ahnTo8Y1uE1xqRi7egfHzBsx/jyQ3GUYr2OIsm19TswbtDBRCMRz18vaQ61ZdNXTaa/VAkjonMp lKtzNluGP2QmQVPOJGlq4DMj2Y9N+sOw/cohe9jqLBqwck6q207jhnMiOqYXjtkp1FEnMwnmOX2 X6bjR60a6ebyT3AD9y0yoQm23t40k+ZFioR9rcvNKUiZEzUs5ONQQYcLWm5A+f/geh02I8IR2y7 SOJNBOJB9HmNjmbNALQ1F1vfQjl8kORkkmKyVnCmg+K3vkizURUkXjMRZ8p+r6TG9b0kgK8j+BX JHgw62UWwVOI4ltXdYMHCuEkvs+5svstxRwhtRAPeIKEDWxybuZl0wQ3K1tme9WIg8 X-Received: by 2002:a05:600c:3b10:b0:492:5113:9beb with SMTP id 5b1f17b1804b1-496c65d55afmr9527945e9.7.1785232395657; Tue, 28 Jul 2026 02:53:15 -0700 (PDT) Received: from [10.87.88.24] ([163.116.235.144]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-496c45cb67esm68305495e9.8.2026.07.28.02.53.14 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 28 Jul 2026 02:53:15 -0700 (PDT) Message-ID: <9804d83b-b371-48ed-874e-e506466e0db9@gmail.com> Date: Tue, 28 Jul 2026 11:53:14 +0200 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: pg_plan_advice: add NO_ scan and join method tags To: song yanli , "Jonathan Gonzalez V." Cc: "pgsql-hackers@lists.postgresql.org" , "robertmhaas@gmail.com" References: <123bbb65-ae76-4112-b33d-864aca745b7b@gmail.com> <87qzl5pxuz.fsf@gmail.com> <9ba4c7da-06ee-4a5a-9479-9b1076cfc675@gmail.com> Content-Language: en-US From: Florin Irion In-Reply-To: Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk Hi, On 28/07/2026 08:43, song yanli wrote: > > Regarding the semantics of NO_ tags: > NO_HASH_JOIN((a b)) means a hash join cannot be used when the join > product of a and b appears on the inner side. > > Consider the following scenario: > SET pg_plan_advice.advice = 'JOIN_ORDER(t4 ((t2 t3) t1)) > NO_HASH_JOIN((t1 t2))'; > > pgpa_join_method_permits_join() matches the set of inner relations > against the target. > The result is ITM_TARGETS_ARE_SUBSET and restrict_method=false. > When inner={a,b,c}, a and b are indeed together on the inner side as > part of a larger join product. > Per the intended semantics, the restriction from the NO_ tag should > take effect: a hash join would be used with an inner side containing > {a,b}. > > But the current implementation only enforces the constraint for > ITM_EQUAL and skips the ITM_TARGETS_ARE_SUBSET case. > I tested this using  JOIN_ORDER(t4 (t3 (t1 t2)))  with and without NO_HASH_JOIN((t1 t2)): - Where the inner side is exactly {t1,t2} (ITM_EQUAL), the tag fires:   Hash Join → Merge Join there. - Where the inner side is {t1,t2,t3} (ITM_TARGETS_ARE_SUBSET), the Hash Join   stays, and EXPLAIN (PLAN_ADVICE) reports the tag as /* matched */. Per the docs, HASH_JOIN((a b))/NO_HASH_JOIN((a b)) both refer to the join product of exactly a and b — not any join whose inner side happens to contain them plus other relations. pgpa_join_method_permits_join() is shared betwen the positive and negative tags precisely to keep "NO_ is the logical complement of the positive tag" true; enforcing the NO_ form more broadly tahn the positive form's own matching scope would break that symmetry. The code comment says it directly: for the TARGETS_ARE_SUBSET case, "HASH_JOIN((x y)) doesn't restrict how x and y can be joined" — the join event being controlled is specifically the one where {a,b} becomes someone else's inner side, not any join that merely contains them. On your exact example, JOIN_ORDER(t4 ((t2 t3) t1)) NO_HASH_JOIN((t1 t2)): this isn't a silent bypass. That specific order requires joining t1 to the already combined (t2 t3), which splits the {t1,t2} target across sides (t2 merges with outsider t3 before t1 and t2 join each other), so NO_HASH_JOIN's own join-order logic denies that pairing, right where JOIN_ORDER demands it. Both tags come back marked conflicting in the advice output, and the permit wins, so the plan still follows your requested order. > > I think this may be an issue. > If you think this should be changed I think it's a design change that should be discussed on a separate thread, what do you think? Cheers, Florin www.enterprisedb.com