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 1wglUw-006Nty-1Y for pgsql-docs@arkaria.postgresql.org; Mon, 06 Jul 2026 15:44:42 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wglUu-001Tsw-2m for pgsql-docs@arkaria.postgresql.org; Mon, 06 Jul 2026 15:44:40 +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 1wgGf6-00BYOv-2E for pgsql-docs@lists.postgresql.org; Sun, 05 Jul 2026 06:49:08 +0000 Received: from mahout.postgresql.org ([2001:4800:3e1:1::227]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.98.2) (envelope-from ) id 1wgGf3-00000001afW-42qd for pgsql-docs@lists.postgresql.org; Sun, 05 Jul 2026 06:49:07 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=postgresql.org; s=20171124; h=Message-ID:Date:Reply-To:Cc:From:To:Subject: Content-Transfer-Encoding:MIME-Version:Content-Type:Sender:Content-ID: Content-Description:In-Reply-To:References; bh=nm5YDH6EG8mZWX759Av2G/eXJkkO483vmeodYEcWhwQ=; b=ZaBwHfbcE+e0Me8AdAPe7qENQG pvAzLjEhFCsTFiO2HeoHsLKwbzRJizhYZ99FXpwuFwdSDFY3IgRN/2ef4xqNWfAFpEOXdr+3A+MJ7 +fTCnHv9quxPfgYoowzgIxutgrFlo4xcgOxMz9ImiVFRyBe/q99WhYf5KSLgBJIWtxj9AXyKpNFAT 3rS5lgmVBwgmXpR/tJql0TYC4Aff9jRZY0DzcCvRZd2SQxw2249j+k9ayBQ1AKJfTuNAOOEEgOFyy bDTXFuyuFsMKQ5VBir39apovF/uJa9oOOfHBD7MPLxdrUE0lb0Lxgrxq0dGrHfBSJYQALNg844Wax JGa957pw==; Received: from wrigleys.postgresql.org ([2a02:16a8:dc51::60]) by mahout.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wgGf2-00Ax2e-2d for pgsql-docs@lists.postgresql.org; Sun, 05 Jul 2026 06:49:05 +0000 Received: from localhost ([127.0.0.1] helo=wrigleys.postgresql.org) by wrigleys.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wgGf1-00CsOQ-09 for pgsql-docs@lists.postgresql.org; Sun, 05 Jul 2026 06:49:03 +0000 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Subject: Index Only Scans with functions To: pgsql-docs@lists.postgresql.org From: PG Doc comments form Cc: jb@jbitc.de Reply-To: jb@jbitc.de, pgsql-docs@lists.postgresql.org Date: Sun, 05 Jul 2026 06:48:39 +0000 Message-ID: <178323411931.108997.17879075456450926050@wrigleys.postgresql.org> X-Auto-Response-Suppress: All Auto-Submitted: auto-generated List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk The following documentation comment has been logged on the website: Page: https://www.postgresql.org/docs/18/indexes-index-only-scans.html Description: On the documentation I read: "However, PostgreSQL's planner is currently not very smart about such cases. It considers a query to be potentially executable by index-only scan only when all columns needed by the query are available from the index. In this example, x is not needed except in the context f(x), but the planner does not notice that and concludes that an index-only scan is not possible." I tried to reproduce the behavior, but it used the index (which is good): select version(); drop table if exists t; drop function if exists add_ten; create or replace function add_ten(a integer) returns integer language plpgsql immutable as $$ begin return a + 10; end; $$; create table t as select generate_series(1, 1000000) a; create index t_i1 on t (add_ten(a)); analyze t; explain analyze select add_ten(a) from t where add_ten(a) < 12; Output: version ---------------------------------------------------------------------------= ---------------------------------------------------------- PostgreSQL 18.4 (Ubuntu 18.4-1.pgdg24.04+1) on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0, 64-bit (1 row) DROP TABLE DROP FUNCTION CREATE FUNCTION SELECT 1000000 CREATE INDEX ANALYZE QUERY PLAN ---------------------------------------------------------------------------= -------------------------------- Index Scan using t_i1 on t (cost=3D0.42..8.69 rows=3D1 width=3D4) (actual time=3D0.034..0.035 rows=3D1.00 loops=3D1) Index Cond: (add_ten(a) < 12) Index Searches: 1 Buffers: shared hit=3D4 Planning: Buffers: shared hit=3D8 read=3D5 Planning Time: 0.154 ms Execution Time: 0.051 ms (8 rows) mydb=3D# I also tried some older versions on dbfiddle.uk without success. What did I do wrong? Jochen