Thread

  1. GROUP BY ROLLUP queries on views trigger full table scans (index usage not optimized)

    Haowu Ge <gehaowu@bitmoe.com> — 2025-11-17T08:02:21Z

    Hello everyone,
    Recently, after upgrading my database from PostgreSQL 16 to 18, I encountered an issue: when performing a GROUP BY ROLLUP on a view, the query planner resorts to a full table scan instead of using the index on the underlying table. This severely impacts performance.
    ----------
     :-(  The task lasted for 20 seconds, and in the end, it ran for 3.6 hours, Under the same environment and query instructions, pg16 before the upgrade did not have this issue
    Planning:
     Buffers: shared hit=1829 read=67
     I/O Timings: shared read=309.026
    Planning Time: 344.548 ms
    Execution Time: 12999763.259 ms
    ----------
    Below is a step-by-step reproduction of the issue:
    # 1. Create a base table 'materials' to store product information.
    CREATE TABLE materials (
     material_id VARCHAR PRIMARY KEY,
     description TEXT NOT NULL,
     unit_price NUMERIC(10, 2) NOT NULL
    );
    # 2. Create an explicit index on 'material_id'.
    CREATE INDEX idx_material_id ON materials(material_id);
    # 3. Create a simple view that mirrors the base table structure.
    CREATE VIEW materials_view AS
    SELECT material_id, description, unit_price FROM materials;
    # 4. Insert test data:
    INSERT INTO materials (material_id, description, unit_price)
    VALUES ('PI', 'Example Product', 99.99);
    INSERT INTO materials (material_id, description, unit_price)
    SELECT 
     'MAT' || generate_series(1,49999)::TEXT,
     'Description of product ' || generate_series(1,49999)::TEXT,
     (random() * 1000 + 1)::NUMERIC(10,2);
    # 5. Query the base table to compute the average unit price for material 'PI',using a simple GROUP BY (no rollup)
    EXPLAIN ANALYZE
    SELECT material_id, AVG(unit_price) as avg_price
    FROM materials
    WHERE material_id = 'PI'
    GROUP BY material_id;
    # 6. Query the base table to compute the average unit price for material 'PI',using a simple GROUP BY (rollup)
    EXPLAIN ANALYZE
    SELECT material_id, AVG(unit_price) as avg_price
    FROM materials
    WHERE material_id = 'PI'
    GROUP BY ROLLUP(material_id);
    # 7. Query the view table to compute the average unit price for material 'PI',using a simple GROUP BY (no rollup)
    EXPLAIN ANALYZE
    SELECT material_id, AVG(unit_price) as avg_price
    FROM materials_view
    WHERE material_id = 'PI'
    GROUP BY
    material_id;
    # 8. Query the view table to compute the average unit price for material 'PI',using a simple GROUP BY (rollup)
    EXPLAIN ANALYZE
    SELECT material_id, AVG(unit_price) as avg_price
    FROM materials_view
    WHERE material_id = 'PI'
    GROUP BY ROLLUP(material_id);
    Log, please refer to the attachment for more logs:
    GroupAggregate (cost=0.00..1097.39 rows=251 width=64) (actual time=3.983..3.985 rows=2.00 loops=1)
     Group Key: materials.material_id
     Group Key: ()
     Buffers: shared hit=468
     -> Seq Scan on materials (cost=0.00..1093.00 rows=250 width=48) (actual time=0.018..3.970 rows=1.00 loops=1)
     Filter: ((material_id)::text = 'PI'::text)
     Rows Removed by Filter: 49999
     Buffers: shared hit=468
    Planning Time: 0.117 ms
    Execution Time: 4.029 ms
    Thanks & Best Regards
    _________________________________________________________________________________ 
    Haowu Ge (BG5FRG) | Homepage: https://www.gehaowu.com <https://www.gehaowu.com > | PGP:7A06 1F6E DF09 D8A8