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 1vkdpl-000VGJ-01 for pgsql-hackers@arkaria.postgresql.org; Tue, 27 Jan 2026 07:49:57 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1vkdpj-00Cfd1-2z for pgsql-hackers@arkaria.postgresql.org; Tue, 27 Jan 2026 07:49:56 +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 1vkdpj-00Cfcs-1S for pgsql-hackers@lists.postgresql.org; Tue, 27 Jan 2026 07:49:55 +0000 Received: from mail-pj1-x1033.google.com ([2607:f8b0:4864:20::1033]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.96) (envelope-from ) id 1vkdpd-002WrA-3C for pgsql-hackers@lists.postgresql.org; Tue, 27 Jan 2026 07:49:54 +0000 Received: by mail-pj1-x1033.google.com with SMTP id 98e67ed59e1d1-34c868b197eso4646755a91.2 for ; Mon, 26 Jan 2026 23:49:50 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1769500190; cv=none; d=google.com; s=arc-20240605; b=RK+8/DKOBBfgOPfMIQOfYNrqs3zHJHyPb5iKXlReIajP9OFMMpygyXeUYkL9wu5qPj CeUBPvzPGkPcPMySp6o5xAHuCNCzgy+4xfC1vEVz8zGRqxVqebHg761tpMw3GQe3FUBl rVWwu+8uZSz1JMhHlKRpgDdX2WUMy+n5V4ox/IiCR1fHZViPX079ZGNQXCe58WGDfMVz HsQO9Eh/D2eovRUWpXRqAj0UNs4+NMx8bW1YxPsw4A0J2htCeTZit3hZhB12J0h4iOPX ormZ0v+xrdveFNzfOflziZI2IHLHXK47XV2JNXbpl6sqqK3pEl6Sf2XOvAOwRufGtUFA mL9A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:dkim-signature; bh=/xibp4eNfqL2/sJepIH9EMbvEXNJE0Ravgi/oTBW9xE=; fh=MxkeSEXGYpXPZt/JmGtCegQ+vAQ6C05MCL7g393yAio=; b=So14+n0BEmCCwuEpVnzzPVHw4VYQ/p8+8vTZOHwAqaIRh+m3WzhlQccKFDau0dWKls SB/UFupgHAGeelw9t1T9mn12FXYTsIp3MU5NE3jLqGXnsYS6RYMLgdFDra0mCb/KEK1k 4ZqIByQyQ+ADg/mKQ7yOfpmBTy2HQACROewiEAEdGGnVl2cU5A26vUoDYctVploRugBW tvF4ByvzJa6V70RUJClybkFRMOlLVnMig6NgcPlAe5QD+YCAE5b1RpPfB7tUreBKFa6O l+/1IYH339QY/sauwAPeqTxf7k+MkfPGuD2Qscy2HOwkxyJhyjCcerhg+IZQJsSRi+h2 wjkA==; darn=lists.postgresql.org ARC-Authentication-Results: i=1; mx.google.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1769500190; x=1770104990; 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=/xibp4eNfqL2/sJepIH9EMbvEXNJE0Ravgi/oTBW9xE=; b=nKQ98LgTgTsCKT7vKIzKgkWZqKIwjgG0m8Qg/VstiNRkHWR8sMJyBbcaCSAmVPEj7w 6kR1AWwpaxNpaSol+TH4kODjcSOsSs3Dntq1w+J6NmkpbBeUVGJbXh5Bl7BuUUDDLXzS 49IBjjqjhGgE71LV+9NZrR1bJvBiuArT/0yEtp1+BRSss3AIGG3aIiEc/uUb9poZJd4x SBRzZbmxtQfR5tCp+IWWRvxLujRqW0i+T1c68Rgka0F/eE6BzBPQazwjCupa7937/A0m HRIO70uXyhRp0NcVPKlw0zBVMHtXQaxWVyAxu9ijcrgtGmG+qH9DvL73TNjwAGtwKowe oWUg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1769500190; x=1770104990; 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=/xibp4eNfqL2/sJepIH9EMbvEXNJE0Ravgi/oTBW9xE=; b=u4am1v2QuCmLLyvbWvwDvJUscuxJW7G6BIcftI+PN1zJ5zKSDUbLFm9iVnYvKrHUs3 DqZbdF8wvn2nTZpoULq8UE7Uf9s89rhA87d8RGxs/AM5AzzrM9FmQbhk8fD9t4M4FhGp /cd6Y7e7X1fP+0oIW1S4X3wv6AFAhNe/6rA4LreZbb87PeSzOfkxt74LMI+iMcvYJDcH TVeUqxAxxmIW59MCUJWqMJiXES78Lt7qscmwyRRVZ5nysnvGjN4N799PIUXbHDTOkKFa /66QAFTWl0QhcO6ZADj9YEW3U9Go7XLuLwoXmRcqUiAB6IaHreKvEGp1ViNr7gG38Oli n9xA== X-Forwarded-Encrypted: i=1; AJvYcCXdu/+UFRB5triltZRPHSOwHn9QSFWweWVZgBN7C+DQs+3a2BFCfEr9bUy6NbO3VOjnfGJSBT4+uxD14GTX@lists.postgresql.org X-Gm-Message-State: AOJu0Yz5tMCxwiBXeCfbtWIlNMUx3nKVwNXLn/bWVBFI7jmAbYRJzZ23 YRAuki5ChkcH9xW2ih9/Rm4miQkIKiOOjV6XiJln1+oIgC62wEbJcNw1il0p8SkBWnk0L+dS+Un RzrHl03UmBUenQzIZC8V2Qwu3Z5/c6w4= X-Gm-Gg: AZuq6aKqHzdhUFkbJqFyr+5PTf+fdwmvOI71yQKyt7SFTR9frtwYEJ69TEPG1N6FW7P xiyASvdMR8iJLHy6qHc0f6FxVSFBm2guppYMq/+xUYl8/QMKjp4ojxtEfogWu/8bz7mfv7kqs/T iIPsCV48M4LyCbseybXPyNXzlJ+0i+qfz5L7YcKnonmxyxghsgTHCrs1H9Gdr91/ByNKchcDx8I QCrykH2M1ZzvIzeBE53ltUxPImubyziw33tQ7FcFL7rxflt4hnSSyveheVhW8N14RpIdJT35Fwg s9kbQFs= X-Received: by 2002:a17:90b:3a87:b0:353:3934:1449 with SMTP id 98e67ed59e1d1-353feceebbdmr1087783a91.12.1769500189673; Mon, 26 Jan 2026 23:49:49 -0800 (PST) MIME-Version: 1.0 References: In-Reply-To: From: Ajay Pal Date: Tue, 27 Jan 2026 13:19:38 +0530 X-Gm-Features: AZwV_Qif6NoZrPxsOuYPt04J2HElt7XjyH-qzVpOvOFtP3hjcXprqYDeDgoddRg Message-ID: Subject: Re: pg_plan_advice To: Robert Haas Cc: Jakub Wartak , Lukas Fittl , Jacob Champion , Dian Fay , Matheus Alcantara , 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 Hi, with v12 patch, found below observations, #1 Grouped Hash Join, This forces the join of dim1 and dim2 to happen first, and then places that resulting set on the inner side of a Hash Join against fact. but the planner partially matches the generated advice. CREATE TABLE fact (f_id int, d1_id int, d2_id int, d3_id int); CREATE TABLE dim1 (id int PRIMARY KEY, val text); CREATE TABLE dim2 (id int PRIMARY KEY, val text); CREATE TABLE dim3 (id int PRIMARY KEY, val text); INSERT INTO fact SELECT g, g%10, g%10, g%10 FROM generate_series(1, 10000) = g; INSERT INTO dim1 SELECT g, 'd1-'||g FROM generate_series(0, 9) g; INSERT INTO dim2 SELECT g, 'd2-'||g FROM generate_series(0, 9) g; INSERT INTO dim3 SELECT g, 'd3-'||g FROM generate_series(0, 9) g; ANALYZE fact, dim1, dim2, dim3; -- We want (dim1 JOIN dim2) to be the inner side of a Hash Join SET LOCAL pg_plan_advice.advice =3D 'HASH_JOIN((dim1 dim2))'; postgres=3D*# EXPLAIN (COSTS OFF, PLAN_ADVICE) SELECT * FROM fact JOIN dim1 ON fact.d1_id =3D dim1.id JOIN dim2 ON fact.d2_id =3D dim2.id; QUERY PLAN ----------------------------------------------------------- Nested Loop Disabled: true -> Nested Loop Disabled: true -> Seq Scan on fact -> Index Scan using dim1_pkey on dim1 Index Cond: (id =3D fact.d1_id) -> Index Scan using dim2_pkey on dim2 Index Cond: (id =3D fact.d2_id) Supplied Plan Advice: HASH_JOIN((dim1 dim2)) /* partially matched */ Generated Plan Advice: JOIN_ORDER(fact dim1 dim2) NESTED_LOOP_PLAIN(dim1 dim2) SEQ_SCAN(fact) INDEX_SCAN(dim1 public.dim1_pkey dim2 public.dim2_pkey) NO_GATHER(fact dim1 dim2) (17 rows) #2 Multiple Instances of Same Table in Subqueries, here target the second instance of dim1 inside the subquery 'sq'. both seq_scan and index_scan advices are not matching. SET LOCAL pg_plan_advice.advice =3D 'SEQ_SCAN(dim1#2@sq) INDEX_SCAN(dim1@sq dim1_pkey)'; postgres=3D*# EXPLAIN (COSTS OFF, PLAN_ADVICE) SELECT * FROM fact JOIN ( SELECT a.id FROM dim1 a JOIN dim1 b ON a.id =3D b.id OFFSET 0 ) sq ON fact.d1_id =3D sq.id; QUERY PLAN --------------------------------------------------- Hash Join Hash Cond: (fact.d1_id =3D b.id) -> Seq Scan on fact -> Hash -> Seq Scan on dim1 b Supplied Plan Advice: SEQ_SCAN(dim1#2@sq) /* not matched */ INDEX_SCAN(dim1@sq dim1_pkey) /* not matched */ Generated Plan Advice: JOIN_ORDER(fact sq) HASH_JOIN(sq) SEQ_SCAN(b@sq fact) NO_GATHER(fact b@sq) (13 rows) Thanks Ajay On Mon, Jan 26, 2026 at 9:38=E2=80=AFPM Robert Haas = wrote: > > Here is v12. > > The big change in this version is that I've added extensive SGML > documentation for v0005. If the README was a little too low-level for > you, this might work better. If you'd like to view it without > downloading the patch set, I've put it up here: > > https://robertmhaas.github.io/postgresql-static/html-pgpa-v12/pgplanadvic= e.html > > Aside from that: > > * Added a new GUC pg_plan_advice.always_store_advice_details. Without > that, you can't generate advice or see feedback on supplied advice > when using prepared queries, because we don't know at plan time that > it's right to incur the overhead of generating that stuff, and most of > the time it won't be. > * Revoked privileges on pg_clear_collected_shared_advice() as I had > already done on pg_get_collected_shared_advice(). > * Removed a bogus elog(ERROR) in pgpa_walker_would_advise() in favor > of returning 0. I think somebody, likely Jakub, pointed this out > earlier, but I didn't quite absorb what I was being told until I > rediscovered the problem. > * Added a bunch more tests. I think the test coverage is getting > pretty decent now, but it could still use some tests targeting more > complex scenarios and corner cases. If you are curious about the > coverage report, see here: > > https://robertmhaas.github.io/postgresql-static/coveragereport-pgpa-v12/c= ontrib/pg_plan_advice/index.html > > The low number for pgpa_scanner.l is basically bogus, but I don't know > of a way to make it not bogus. The low number for pgpa_ast.c is due to > a bunch of things related to bitmap scans not being right, which at > this point is, I think, the largest outstanding issue with the patch. > It's probably more interesting to look into ways of covering a few > more lines from pgpa_planner.c and pgpa_walker.c, which is where a lot > of the complexity in this code lives. Also, it would be nice to have > coverage of foreign scan cases, but I'm not quite sure what I need to > do to create tests for this module that also depend on postgres_fdw. > Any tips appreciated. > > -- > Robert Haas > EDB: http://www.enterprisedb.com