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 1vcEHr-003MFI-1f for pgsql-hackers@arkaria.postgresql.org; Sun, 04 Jan 2026 02:56:12 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1vcEHo-00ELJ0-2G for pgsql-hackers@arkaria.postgresql.org; Sun, 04 Jan 2026 02:56:09 +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 1vcEHo-00ELIr-0t for pgsql-hackers@lists.postgresql.org; Sun, 04 Jan 2026 02:56:09 +0000 Received: from mail-qk1-x730.google.com ([2607:f8b0:4864:20::730]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.96) (envelope-from ) id 1vcEHj-0044Ly-0t for pgsql-hackers@lists.postgresql.org; Sun, 04 Jan 2026 02:56:07 +0000 Received: by mail-qk1-x730.google.com with SMTP id af79cd13be357-8be184d2fe8so239138485a.1 for ; Sat, 03 Jan 2026 18:56:02 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1767495362; cv=none; d=google.com; s=arc-20240605; b=BpwHrI5qZtwd9v3c0/LYE+C6jlj5fhKOr3d4iMJhE7BZyZXo3BivR6xsi0IJ++cO8a di/qP/cdM4a2jhWXU2zYCGlEXU6TDHJEFmJD1LSNv9RrGDeTsLYjeGikr50S7aPiot2m HNPeV/m25FXVHEmGkrbK+QYrZIgcyLu9SVySFOmceLR9ehFDBRf0SH5qwzoUOEGyHoJR QJu8T0Cp2annIDa0hRl/9CIkLlVBhnxs5LBHDdsKpJmLNTZ+dSRv4GFGDRWOMs2VpwSz cFVXiigl8i7J1u5P72EtVUDAv6Eri2fx/aaOztn1mqMQxskSDA9x33qzfzSxwo+UP54j DnMA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=to:subject:message-id:date:from:in-reply-to:references:mime-version :dkim-signature; bh=8mitzfy7ZGYwapcOx0g/CzOy04FeDhOfrhbSowYZZUI=; fh=dxJXJbLzq9Nah1LUdsj4QTuQ3JoDScd0wp1YHY64NXM=; b=VfgJvDGSE6FX8ufRNfycRxPZojYVpJEf7diE5lwru7Rp3MNPtu7Lh86dZkOfflVGty mPS+HEkzOrhbddLfT4hLvrDp6JP4TDo9lmDr/pOelmXZT9+aQ5+K/wufk43yl9YBelcS zGHGj3F3XNFSzojgY48dkOIGK3HM2TJFpUs6CQKhBzctyabd4KUUGMxbSy1ZfM+kolDj tW2NYjwGsPT7mrMTyxfzakc7asjPKY1Z8bYh5v3YrZl/08MLtHHZYxv1MWQ3q9HZ+9VB ypVoY0ItpIrRm4/iIZFpPmT9Ujxvxm2dB+a0Knm5EEgbWH8qBlvTlJRMMJplzSF83hFT XFVg==; 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=1767495362; x=1768100162; darn=lists.postgresql.org; h=to:subject:message-id:date:from:in-reply-to:references:mime-version :from:to:cc:subject:date:message-id:reply-to; bh=8mitzfy7ZGYwapcOx0g/CzOy04FeDhOfrhbSowYZZUI=; b=TJzBXDHvV5YEv+tjLcWrhuVGcgTxhvv9avURpT7xOGbUkXCbDb3fWfrGMRyL0eaKxP uD1QSWIseoJEs9S9thy0NfXRSOlRs70KeB7GZfp7QsSUGEwDidpspBkN8eQKK64uk2eJ VW8E9S+iTO4vaWk3I4p1qpNf86k1P20jNZBgvsvk/Bfpn7xAfKgpMplc+Vg7X4s9v03y ru4bYzQUFego2/v4/z72YfrBR1ywTf3RFPDmqYAnXF9EbYykSGkzC5LFXcfoyzjthA9V aPGFJPjYCar8Mk5LDh59xbWTEKEkzkwENm4CUQy4l5qbnDaJUU1IOlhBrl+rQdev1jcA CTnw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1767495362; x=1768100162; h=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=8mitzfy7ZGYwapcOx0g/CzOy04FeDhOfrhbSowYZZUI=; b=YWGHXotqptsaGpFGatvCW7aFwA/Qu6gj/YWyXIyVJtTxDGO24hcZTwsxOglNrVaJVp EVAFmw0cF2sJEeoQhmKtpmcXk/Ggg/G8w7dr6ALq4JCexYXyzNrgy7byTcKuB4DJlcGc EwvVY2WFjf4QP3A0gVA0dGYI6wzDlkiOeXcATa17BqOHbhcykWL0kFRLm/6CrHgv8YYw bdxjYfhRjOs/W93/op5r3ecc83FVd7fo+2tYE19JJLoXnJvfE1LrsugYXOnU0UqnGG95 lbzMxxvkJhh3BJyBsurpBOw8S/MjzHObh4UN41GsC6+ZxzQQthT/ugcEsgObcurjKynO q7cA== X-Gm-Message-State: AOJu0Yzj0seFGrS491xE6g8HeRk59Cn5YKKc2vMoiNcyrVk+eTyL1+1C /Q8SgoARXPFRp3Djpv2SSThtxCP5ZtG72NpIg98h4RhDMiazOzzBRv9/XUvu0rCTlGG/kf9c/uQ pfv9eShE0I+owpUD4pW62/S0M8C/JPhdtFkmL X-Gm-Gg: AY/fxX7tw3uS3SlGPS6pA1WI+E1tlqCtn6npfOaWaslE5EuCOaeOVvX+wm4O2Y8wY9s zD9wisg5y/eLsTT77jzJI0xnyWwL0cXYGdNgNSARYUp2V6VW0G1wDVR3C5A6ab+uvATkHsVHTVh uRCKNC/m7MtwoMnPtGfTjexihDLvS8I8IGCVqTouaHSmJ4MyN4YtTQ5zX4IF+Z0p512oa/GJZCB YzSt1gVxBeO5xHRnLbEvS6XhcmDv5E69XBAkX3dCIg8oWHfrYtIMftgm6kudiYMbnXQA+M= X-Google-Smtp-Source: AGHT+IHBb5BtnaCLu+cP1THSctw/clnwvCHVaLvN/jbuaaM1gO0Kppl7kJsOZimDHvxhfvX1xM5T23zkMgHGmgo9e7s= X-Received: by 2002:a05:6214:c28:b0:888:6dc8:5f96 with SMTP id 6a1803df08f44-88d882b691cmr491201696d6.7.1767495361768; Sat, 03 Jan 2026 18:56:01 -0800 (PST) MIME-Version: 1.0 References: In-Reply-To: From: Adam Brusselback Date: Sat, 3 Jan 2026 21:55:46 -0500 X-Gm-Features: AQt7F2pq9NZ7tvuMtuZLyz_3_UyXOusoHERYX2BiLqtQ9j7nk14xEfZbD4bJaGo Message-ID: Subject: Re: [Patch] Add WHERE clause support to REFRESH MATERIALIZED VIEW To: PostgreSQL Hackers Content-Type: multipart/alternative; boundary="0000000000002e31220647871593" List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --0000000000002e31220647871593 Content-Type: text/plain; charset="UTF-8" Hi all, I've been running some more concurrency tests against this patch (specifically looking for race conditions), and I found a flaw in the implementation for the REFRESH ... WHERE ... mode (without CONCURRENTLY). I believe the issue is that the DELETE -> INSERT strategy leaves a consistency gap. Since we relied on ROW EXCLUSIVE locks to allow concurrent reads, the moment we delete the rows, we lose the physical lock on them. If a concurrent transaction inserts a colliding row during that gap, the materialized view ends up inconsistent with the base query (or hits a constraint violation). I initially was using SELECT ... FOR UPDATE to lock the rows before modification, but that lock is (now that I know) obviously lost when the row is deleted. My plan is to replace that row-locking strategy with transaction-level advisory locks inside the refresh logic: Before the DELETE, run a SELECT pg_advisory_xact_lock(mv_oid, hashtext(ROW(unique_keys)::text)) for the rows matching the WHERE clause. This effectively locks the "logical" ID of the row, preventing concurrent refreshes on the same ID even while the physical tuple is temporarily gone. Hash collisions should not have any correctness issues that I can think of. However, before I sink time into implementing that fix: Is there general interest in having REFRESH MATERIALIZED VIEW ... WHERE ... in core? If the community feels this feature is a footgun or conceptually wrong for Postgres, I'd rather know now before spending more time on this. If the feature concept is sound, does the advisory lock approach seem like the right way to handle the concurrency safety here? Thanks, Adam Brusselback --0000000000002e31220647871593 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Hi all,

I've been running some more concurrency= tests against this patch (specifically looking for race conditions), and I= found a flaw in the implementation for the=C2=A0 REFRESH ... WHERE ... mod= e (without CONCURRENTLY).

I believe the issue is that the DELETE -&g= t; INSERT strategy leaves a consistency gap. Since we relied on ROW EXCLUSI= VE locks to allow concurrent reads, the moment we delete the rows, we lose = the physical lock on them. If a concurrent transaction inserts a colliding = row during that gap, the materialized view ends up inconsistent with the ba= se query (or hits a constraint violation).

I initially was using SEL= ECT ... FOR UPDATE to lock the rows before modification, but that lock is (= now that I know) obviously lost when the row is deleted.

My plan is = to replace that row-locking strategy with transaction-level advisory locks = inside the refresh logic:

Before the DELETE, run a SELECT pg_advisor= y_xact_lock(mv_oid, hashtext(ROW(unique_keys)::text)) for the rows matching= the WHERE clause.

This effectively locks the "logical" ID= of the row, preventing concurrent refreshes on the same ID even while the = physical tuple is temporarily gone. Hash collisions should not have any cor= rectness issues that I can think of.

However, before I sink time int= o implementing that fix:

Is there general interest in having REFRESH= MATERIALIZED VIEW ... WHERE ... in core?
If the community feels this fe= ature is a footgun or conceptually wrong for Postgres, I'd rather know = now before spending more time on this.

If the feature concept is sou= nd, does the advisory lock approach seem like the right way to handle the c= oncurrency safety here?

Thanks,
Adam Brusselback
--0000000000002e31220647871593--