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 1vNZDD-006jBp-2e for pgsql-hackers@arkaria.postgresql.org; Mon, 24 Nov 2025 16:14:47 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1vNZDC-001jh1-13 for pgsql-hackers@arkaria.postgresql.org; Mon, 24 Nov 2025 16:14:46 +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 1vNZDB-001jgt-2x for pgsql-hackers@lists.postgresql.org; Mon, 24 Nov 2025 16:14:46 +0000 Received: from mail-ej1-x629.google.com ([2a00:1450:4864:20::629]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.96) (envelope-from ) id 1vNZD9-001EL6-0V for pgsql-hackers@lists.postgresql.org; Mon, 24 Nov 2025 16:14:45 +0000 Received: by mail-ej1-x629.google.com with SMTP id a640c23a62f3a-b736ffc531fso639580166b.1 for ; Mon, 24 Nov 2025 08:14:43 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1764000881; x=1764605681; darn=lists.postgresql.org; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=g8gNl70aPVp94aOfuN71Y+mctYZxoDcIpQuGnsSJT5g=; b=lPXI5UmwRCZ0/yagaLVfLPLbHURD6Kwyqo+k5WFsYAl4EQFjlE2HEZCgFrXIWRAm2D SY7RTgjEa1/wYS7WCfD17PW7qPiDxlJtOfB10WIxGqG0gYRngYw67/MKbqHD+L5DXvHU ywxX55RBPj/Q4gM4v/HCmKpS5GvluhmnLWGr4pwuZBsDNVkgWpI0SC23XDwe6FLExA0K nhMNO/3yQZZwiwx/iY60LpfkWw1e04XWMWXjQHOWSVuAICUBXraoYsVXVxzCXwjQdfaj jws0JSNmmkjZZyenmGlVxprEoYGw8l+6BNG9j37zZMKzfn8rFzvnYHXlHGC7gUvuAfHA 8psA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1764000881; x=1764605681; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=g8gNl70aPVp94aOfuN71Y+mctYZxoDcIpQuGnsSJT5g=; b=YK3my0z0QN9oJVAk9yTO2G3dUtyVvTAStmGygdnTy1jjay6v+5dpUxQ1o+XN8MIH0T 9xuLh2qyaSFBX3ed/W410fpJPwDbcozdocAAhS3xI8SNvDdHk5B+rPqrXbpQ9ljEBX2m te0AoVZUmfJd/7DGiCL+RzV17/ZiX8eeWqc8e8xEIXR2G4cHB6lnFvmVa55S2/qMyRMi 8VDtXb3T9bf3PcbB0XNglGS5Oz6UwOB31/DzAh8qSxoGONfss9uf+AY26JndxbEJKBsd 9jqt5pLbq6LSS7rd6dRaBlXc1xdqPbMqG0hBkqT91ogvgqw8RGZJhGZLFp5WTWFpTIqh HH4g== X-Forwarded-Encrypted: i=1; AJvYcCVu3dhQCsZIE6Nd8BLG7eL6Misd0ixC61kE62DtuK6wkQKtgX1Ysh5b06H8VYK4kErC5j0qZoz0HvWrNS5S@lists.postgresql.org X-Gm-Message-State: AOJu0YwN4ewBpWcUR2ZBC5U9i4EuU1IC9dzh/lODqLf6dGOk6vogrfFc ZH/6CVw3Y226Xc67fJKXKNhttv9sZXPw6vp77Gihw8O9aeg8MGM4O0HaBGthDJP5jmShjSBlwkS 8UMQKxGvKYLhRitbRcD8MqoLrjZa2uYE= X-Gm-Gg: ASbGncuQExW995Hrurcd47AkWdgh+WK00ok+wQzQhLa3HuJnQRkhE04dLl3aWGIsynf 4LsP+HcMqId6L8dRvXJUDW12GrftwFh5RLeDoCklywW4soVQU1jsaG0qRDK8fKvHVFt9wFaJSAV M+J6C8o8KE53O68EkYRDmrimhkx/AO4fqqdiyiXIK0PGfLVHg7U369k32sqcXtOI5pV8vorMjeG Xfjt72O4+SOpK8tAEV8wN4XVLYfZCe70zamvzk9qgKWCKiyoE/y9SGYDchUFjNdUJqY/q9pTL7X YOy+RThT/gTPTK4XnQW000JaiBI= X-Google-Smtp-Source: AGHT+IHy8xaATjE9/wjBOo+FT6gIdAjDpXB1t3XOoa9pt/fHv92tfT6vT42wVoMOfPta8L6b8qEb0X6kDlrUh4rv5wA= X-Received: by 2002:a17:907:7287:b0:b73:9fea:331c with SMTP id a640c23a62f3a-b767170aec0mr1389094966b.47.1764000880514; Mon, 24 Nov 2025 08:14:40 -0800 (PST) MIME-Version: 1.0 References: In-Reply-To: From: Robert Haas Date: Mon, 24 Nov 2025 11:14:27 -0500 X-Gm-Features: AWmQ_bnF_EEHJz1cT15rD6vt5cf4OVRaFPu6wEEA4eLSfMSSo4FxHwbCI_QOLsI Message-ID: Subject: Re: pg_plan_advice To: Dian Fay Cc: Matheus Alcantara , Jakub Wartak , PostgreSQL Hackers Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk On Sat, Nov 22, 2025 at 7:43=E2=80=AFPM Dian Fay wrote: > Thanks for working on this, Robert! Thanks for looking at it! I was hoping for a bit more in the way of responses by now, honestly. > Since the policies don't contain any execution boundaries, all the quals > should be going into a single bucket for planning if I understand the > process correctly. The bitmap heap scan should be a candidate given the > `tags &&` predicate (and indeed if I switch to a privileged role, the > advice matches successfully without any policies in the mix), but gdb > shows the walker bouncing out of pgpa_walker_contains_scan without any > candidate scans for the BITMAP_HEAP_SCAN strategy. I can understand why it seems that way, but when I try setting enable_seqscan=3Dfalse instead of using pg_plan_advice, I get exactly the same result. I think this is actually a great example both of why this is actually a very powerful tool and also why it has the potential to be really confusing. The power comes from the fact that you can find out whether the planner thinks that the thing you want to do is even possible. In this case, that's easy anyway because the example is simple enough, but sometimes you can't set enable_seqscan=3Dfalse or similar because it would change too many other things in the plan at that same time and you wouldn't be able to compare. In those situations, this figures to be useful. However, all this can do is tell you that the answer to the question "is this a possible plan shape?" is "no". It cannot tell you why, and you may easily find the result counterintuitive. And honestly, this is one of the things I'm worried about if we go forward with this, that we'll get a ton of people who think it doesn't work because it doesn't force the planner to do things which the planner rejects on non-cost considerations. We're going to need really good documentation to explain to people that if you use this to try to force a plan and you can't, that's not a bug, that's the planner telling you that that plan shape is not able to be considered for some reason. That won't keep people from complaining about things that aren't really bugs, but at least it will mean that there's a link we can give them to explain why the way they're thinking about it is incorrect. However, that will just beg the next question of WHY the planner doesn't think a certain plan can be considered, and honestly, I've found over the years that I often need to resort to the source code to answer those kinds of questions. People who are not good at reading C source code are not going to like that answer very much, but I still think it's better if they know THAT the planner thinks the plan shape is impossible even if we can't tell them WHY the planner thinks that the plan shape is impossible. We probably will want to document at least some of the common reasons why this happens, to cut down on getting the same questions over and over again. In this particular case, I think the problem is that the user-supplied qual item.tags @> ARRAY[id] is not leakproof and therefore must be tested after the security qual. There's no way to use a Bitmap Heap Scan without reversing the order of those tests. > I do want to avoid getting bikesheddy about the advice language so I'll > forbear from syntax discussion, but one design thought with lower-level > implications did occur to me as I was playing with this: it might be > useful in some situations to influence the planner _away_ from known > worse paths while leaving it room to decide on the best other option. I > think the work you did in path management should make this pretty > straightforward for join and scan strategies, since it looks like you've > basically made the enable_* gucs a runtime-configurable bitmask (which > seems like a perfectly reasonable approach to my "have done some source > diving but not an internals hacker" eyes), and could disable one as > easily as forcing one. I mostly agree. Saying not to use a sequential scan on a certain table, or not to use a particular index, or not to use a particular join method seem like things that would be potentially useful, and they would be straightforward generalizations of what the code already does. For me, that would principally be a way to understand better why the planner chose what it did. I often wonder what the planner's second choice would have been, but I don't just want the plan with the second-cheapest overall cost, because that will be something just trivially different. I want the cheapest plan that excludes some key element of the current plan, so I can see a meaningfully different alternative. That said, I don't see this being a general thing that would make sense across all of the tags that pg_plan_advice supports. For example, NO_JOIN_ORDER() sounds hard to implement and largely useless. The main reason I haven't done this is that I want to keep the focus on plan stability, or said differently, on things that can properly round-trip. You should be able to run a query with EXPLAIN (PLAN_ADVICE), then set pg_plan_advice.advice to the resulting string, rerun the query, and get the same plan with all of the advice successfully matching. Since EXPLAIN (PLAN_ADVICE) would never emit these proposed negative tags, we'd need to think a little bit harder about how that stuff should be tested. That's not necessarily a big deal or anything, but I didn't think it was an essential element of the initial scope, so I left it out. I'm happy to add it in at some point, or for someone else to do so, but not until this much is working well. --=20 Robert Haas EDB: http://www.enterprisedb.com