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 1vSqO7-006jZm-1i for pgsql-hackers@arkaria.postgresql.org; Tue, 09 Dec 2025 05:35:51 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1vSqO6-0035YW-0V for pgsql-hackers@arkaria.postgresql.org; Tue, 09 Dec 2025 05:35:50 +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 1vSqO5-0035YO-27 for pgsql-hackers@lists.postgresql.org; Tue, 09 Dec 2025 05:35:50 +0000 Received: from bee.birch.relay.mailchannels.net ([23.83.209.14]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vSqO3-003sNa-07 for pgsql-hackers@lists.postgresql.org; Tue, 09 Dec 2025 05:35:49 +0000 X-Sender-Id: dreamhost|x-authsender|nico@cryptonector.com Received: from relay.mailchannels.net (localhost [127.0.0.1]) by relay.mailchannels.net (Postfix) with ESMTP id 42D6880192D; Tue, 09 Dec 2025 05:35:46 +0000 (UTC) Received: from pdx1-sub0-mail-a207.dreamhost.com (trex-green-5.trex.outbound.svc.cluster.local [100.99.13.166]) (Authenticated sender: dreamhost) by relay.mailchannels.net (Postfix) with ESMTPA id D225E801F03; Tue, 09 Dec 2025 05:35:45 +0000 (UTC) ARC-Seal: i=1; a=rsa-sha256; d=mailchannels.net; s=arc-2022; cv=none; t=1765258545; b=4amFOXQZquoF39Wl9HNnYfcjCksIi/OqaAKfNPZmwuNDlsjsSmb4naihBCGePdh3ox5S42 7dQT6LVFOtJHoJ2vCZBNUIOWCKpp+0Snc34Rj1V2wHp+sSuaPdmrortPh2URy+vjAE49Bg +lWRxMdA15ACsZj7YijESOvKKSrH5IWDHYOIjVUTxLtLv97W51MdZ6l3SS1CObK7edjd/G 4eJ2rQ0+P4U5ixNwtLPaZB6gVI1n0pqlWoG06AiYCeFg0hNC1DKDoBX8YaPvCzRAI8mbMR tH7bBxd24eSwOt1CCwRFjlv9DI+kbCDitPzpE5ivbErzW5efrWtthnNJ0UAmXA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=mailchannels.net; s=arc-2022; t=1765258545; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references:dkim-signature; bh=2H7P59fC4/rnxY0u4ITMGey48TbDTqiipCb55zpQSzw=; b=M3KfJkGB7shGrdtsS/OdcNhE7oUS7JMvuGrGfU20JcxpVqD90FOGVr8SjeuYUvnIbjoU2p eCV3gXMgJ0Zw0wtkSXX6Q4dlVqD4svFhK8vTGS9aRn4HagLhCqd4oLZwXQ3LJKZ5lwbfb8 btoMOZ3RFqbA5EpiIcb0tk9ucUaRSV+1CoJHtsbh0kspBWbRZFALWqu97eIcthQjPj+Y8Z ZlVN0Jr5xmtTNhbGPG2BRmgqAAo5UJONItKjzPlUAwfb2lZDPfvkXUIiA08ESSAyjZ2iL5 0HUfM4UXCQ8Z+c4vZqM+dyywrjOjWwhJQ31dLy72EftXfaubK37TSj0dYhuzng== ARC-Authentication-Results: i=1; rspamd-858948c46c-642mz; auth=pass smtp.auth=dreamhost smtp.mailfrom=nico@cryptonector.com X-Sender-Id: dreamhost|x-authsender|nico@cryptonector.com X-MC-Relay: Neutral X-MailChannels-SenderId: dreamhost|x-authsender|nico@cryptonector.com X-MailChannels-Auth-Id: dreamhost X-Spicy-Coil: 1c28662518965763_1765258546088_3292539030 X-MC-Loop-Signature: 1765258546087:2826508167 X-MC-Ingress-Time: 1765258546087 Received: from pdx1-sub0-mail-a207.dreamhost.com (pop.dreamhost.com [64.90.62.162]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384) by 100.99.13.166 (trex/7.1.3); Tue, 09 Dec 2025 05:35:46 +0000 Received: from ubby (unknown [75.81.95.64]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-256) server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: nico@cryptonector.com) by pdx1-sub0-mail-a207.dreamhost.com (Postfix) with ESMTPSA id 4dQSHj0QrSz16; Mon, 8 Dec 2025 21:35:44 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cryptonector.com; s=dreamhost; t=1765258545; bh=2H7P59fC4/rnxY0u4ITMGey48TbDTqiipCb55zpQSzw=; h=Date:From:To:Cc:Subject:Content-Type; b=gBIiZLUwjziTt2A2uW0w9aEDCX916j6+k/fwK1GpUb1YPcXy8rlWJCvTYBvb/Jll0 mYP7nAfj56H8l2cD9WGVEyKx8QYnKCNg2vs2uzG1YOPxG/pcfH3C+fXRx3K63HDkZ9 1BGRIdxDdPOeFNPZf1JeFi42+5UY+wAt4DZ6QBICEnD3o1wzckSCQ+6X7+8UB9Rx8o iNfWX05fnmh+/+8LKPCNwS9KOTDyCsp68zueQknrOc/r1SizZVlWtAeHem4eODudhU J/HWI66x074CnW6P5EsmqwUgRZ357o2pH21bIx1jK0vPJn3gNbBJuU6iKBq724T2gb 6T2Z8EyiYwUaA== Date: Mon, 8 Dec 2025 23:35:42 -0600 From: Nico Williams To: Kirk Wolak Cc: PostgreSQL Hackers , Adam Brusselback , Nikolay Samokhvalov , Andrey Borodin Subject: Re: [Patch] Add WHERE clause support to REFRESH MATERIALIZED VIEW Message-ID: References: MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk On Tue, Dec 09, 2025 at 12:08:58AM -0500, Kirk Wolak wrote: > Our understanding is that many people run into this exact issue. The > cache needs small frequent updates. > (After reading the code that handles MVs, we just created our own TABLE, > and maintain it with a scheduler to rebuild HOURLY, > and when we process the file, a Simple UPDATE is issued for the one column). > > While this "Works", the CONCEPT of this patch (untested by me, as of > yet), would have fixed this with far less effort, > and would be easier to maintain. > > After I review the code, I will add additional comments. > > I am curious what others think? (And FWIW, I believe that the larger the > MV, the MORE this feature is needed, > vs refreshing the ENTIRE view). What I do is I have my own materialized view infrastructure, written entirely in PlPgSQL, and I completely avoid PG's MV support. This alternative MV scheme creates an actual table for each MV, which means: - one can update the MV directly (and I do, via triggers) - one can have triggers on the MV (e.g., to record history) This is has been very handy for me. I also have a state table in which to keep track of whether an MV needs a refresh, and I have a function i can use to mark an MV as needing a refresh. Marking an MV as needing a refresh sends a NOTIFY, and then I have a daemon that will refresh views as needed (with some debouncing/coalescing of notifications). This way I can have MVs with very complex underlying queries for which some kinds of updates I can easily write fast triggers for and others where I can't (or where they would slow down transactions too much) I simply mark the MV as needing a refresh. Typical MV queries I have that this works very well for include transitive reachability closure computations (e.g., all the groups a thing is a member of, directly and indirectly, or vice versa -- recursive CTEs basically). Though I do now have triggers that can do a reasonably good job of synchronously and quickly updating MVs with such queries, it's just I didn't always. Refreshes are always 'concurrent'. This is my 80/20 solution to the "Incremental View Maintenance" (IVM) problem. A not very current version is here: https://github.com/twosigma/postgresql-contrib/blob/master/mat_views.sql If you like it I might be able to get a newer version out. The version above has a few minor issues: - it uses DELETE FROM instead of TRUNCATE for its' sort-of temp tables - using TRUNCATE ends up requiring some care to avoid occasional deadlocks with VACUUM that are due to using tables as types of the columns of the deltas tables - logging -- lots of logging in the newest version Another issue is that I rely on NATURAL FULL OUTER JOIN to avoid having to generate ON conditions, but that means that all columns of the underlying VIEW must not have NULLs. As I've not needed to support nullable columns in these MVs, I don't mind. Nico --