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.94.2) (envelope-from ) id 1tVrbv-00CAqI-9Z for pgsql-performance@arkaria.postgresql.org; Thu, 09 Jan 2025 12:26:03 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.94.2) (envelope-from ) id 1tVrbu-000xQb-ME for pgsql-performance@arkaria.postgresql.org; Thu, 09 Jan 2025 12:26:02 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1tVrbu-000xQT-Aa for pgsql-performance@lists.postgresql.org; Thu, 09 Jan 2025 12:26:02 +0000 Received: from mail-pj1-x1036.google.com ([2607:f8b0:4864:20::1036]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.96) (envelope-from ) id 1tVrbr-000jMJ-0r for pgsql-performance@postgresql.org; Thu, 09 Jan 2025 12:26:01 +0000 Received: by mail-pj1-x1036.google.com with SMTP id 98e67ed59e1d1-2f43d17b0e3so1487162a91.0 for ; Thu, 09 Jan 2025 04:25:59 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1736425558; x=1737030358; darn=postgresql.org; h=to:subject:message-id:date:from:mime-version:from:to:cc:subject :date:message-id:reply-to; bh=aO6xymPs0uo0aifoFqIK5xAZkTPSInATefw2gY7cpBI=; b=GWL2qeusCbNDh06xwYgDgHd5cYYEsTM3UYPved7DNKOWnA6fvTcsLHxUuH6fRXdRRC xyp4eIRqPpcQtiJTsFvNCYplFvnng4vGEPlyQOjOfWanwATyxIz1zEwoMqs0FgVFXnvZ U7HKx1vMtjgVlHnTvpGCmYGWtTva5BrFCe5SwhG/mA+9DOFSBSvnj1OaYWzt0Tync/N3 g59xo5hE/qANabUflgxLkaylhVnIB6Dx57JWGQRnDivj0tfQOiWioRB/Fl8v8Sc12zUf kDo3HgPQkGdEJm0r4tL3XDpNKt91PAC8ciRuR+f9HEnpXjrRc7Q4p+Kq+xm88yOpafSu 2J5w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1736425558; x=1737030358; h=to:subject:message-id:date:from:mime-version:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=aO6xymPs0uo0aifoFqIK5xAZkTPSInATefw2gY7cpBI=; b=LgZfWLF2rMfmzAgEu4/dm8e7U3Hrq2oEQBgc8NaqRrmSr9c6oKi+gNgQKj7GF25Lb+ ozPIhAG/eNyvt8WV91DWxsF981+JMS+ShZIcUsTc6havINgdmjNMo2Fm0dzvbEOx/Tlp r0rAZG32sKSUEP2t0mme0tRaxd9OEt6GKR9ZCWudufvCfbTGkyCty020/eHDGuK4ykDq iAndzePA8XLARUAGx7q71mIzLHLHLnM8cKK5nlJ2qPZPiN2P+UXTA61UM++teeTm9BZ6 bIIrU0AsyYnkGoU17N0weyslWiSiTQFZjCfSnHbZO3+w1H9ToqHSgO1xyzbSurN5ZRiS RwWg== X-Gm-Message-State: AOJu0YwRAa5g/XmumeOKxNDByp06DIj2OsmY+XGsNttxoBhl8LMqQDbV w2r3gr+wOLO1Xnk1EVA5I+hT1/JHF37KR1UdE/QozziA/zztDygUDqTI4eyCcMfWB4yejkFly2f G3vFqx0BzIJeAJYNV5RpBzkBdmtwipo47ZLQ= X-Gm-Gg: ASbGnctZ4gbU3jYnEUPbNUOxfTWS1bhGVwJ2zAaagdRS5JNTCf8TawtxAGhxWNnFvZI 0mpECUIAQ0UwnXvl4pChWe00Mqy+rq8qxRTfT X-Google-Smtp-Source: AGHT+IG/hcQKllTTcPD8aOOL7gEDp+FMBMwTc8xzoBAaoHHMpltNLVP9ThYYsKMZr125wK/zv41BjPYB0eJ2coiAU8s= X-Received: by 2002:a17:90b:5201:b0:2ee:ad18:b309 with SMTP id 98e67ed59e1d1-2f548f172f9mr9304952a91.3.1736425557401; Thu, 09 Jan 2025 04:25:57 -0800 (PST) MIME-Version: 1.0 From: Feike Steenbergen Date: Thu, 9 Jan 2025 13:25:45 +0100 X-Gm-Features: AbW1kvbDylw1vhJIXY4wTxhQOfGNU0f3ghz5Kwms6nbds2fPszHV5k0ixmonY2w Message-ID: Subject: Unexpected Seq Scan's when using MERGE WHEN NOT MATCHED BY SOURCE To: pgsql-performance@postgresql.org Content-Type: multipart/mixed; boundary="00000000000087a373062b45148f" List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --00000000000087a373062b45148f Content-Type: multipart/alternative; boundary="00000000000087a372062b45148d" --00000000000087a372062b45148d Content-Type: text/plain; charset="UTF-8" I'm trying to change a few applications to fully use this, as PostgreSQL 17 added this support. The application does something like this: - fetch information from a source system and store it in a temp table - run a MERGE with a table (target) in this database, updating, inserting and deleting in a single statement - the target table holds information for multiple systems The temp table (source) doesn't contain the identifier for the system, as we can inject that at runtime. This is the shape of the statement: MERGE INTO merge_target AS t USING merge_source AS s ON (t.time = s.time AND t.device_id = $1) WHEN MATCHED THEN UPDATE set value = s.value WHEN NOT MATCHED THEN INSERT (device_id, time, value) VALUES ($1, time, value) WHEN NOT MATCHED BY SOURCE AND t.device_id = $1 THEN DELETE; If we run this however, there is always a Seq Scan against merge_target, whereas the filter of `AND t.device_id = $1` uses a (Bitmap) Index scan in other types of queries. Previously we would - in a CTE - do a delete *and then* the merge. Which performed much better as the DELETE would not do a Seq Scan. Attached a full reproducing test case. Some numbers: Previously, DELETE in CTE, then merge: Planning Time: 6.700 ms Execution Time: 7.473 ms Using the MERGE WHEN MATCHED ON SOURCE THEN DELETE: Planning Time: 0.994 ms Execution Time: 65.695 ms My questions are: - is the Seq Scan expected by others in this mailing list as well? - Is it required to do the Seq Scan? - is this something that could be optimized? Kind regards, Feike Steenbergen --00000000000087a372062b45148d Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
I'm trying to change a few applications to fully use t= his, as PostgreSQL 17 added this support.

The application does somet= hing like this:

- fetch information from a source system and store i= t in a temp table
- run a MERGE with a table (target) in this database,<= br>=C2=A0 updating, inserting and deleting in a single statement
- the t= arget table holds information for multiple systems

The temp table (s= ource) doesn't contain the identifier for the system, as
we can inje= ct that at runtime.

This is the shape of the statement:

=C2= =A0 =C2=A0 MERGE INTO
=C2=A0 =C2=A0 =C2=A0 =C2=A0 merge_target AS t
= =C2=A0 =C2=A0 USING
=C2=A0 =C2=A0 =C2=A0 =C2=A0 merge_source AS s ON (t.= time =3D s.time AND t.device_id =3D $1)
=C2=A0 =C2=A0 WHEN MATCHED THEN<= br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 UPDATE set
=C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 value =3D s.value
=C2=A0 =C2=A0 WHEN NOT MATCHED THEN
= =C2=A0 =C2=A0 =C2=A0 =C2=A0 INSERT (device_id, time, value) VALUES ($1, tim= e, value)
=C2=A0 =C2=A0 WHEN NOT MATCHED BY SOURCE
=C2=A0 =C2=A0 =C2= =A0 =C2=A0 AND t.device_id =3D $1
=C2=A0 =C2=A0 =C2=A0 =C2=A0 THEN DELET= E;

If we run this however, there is always a Seq Scan against merge_= target,
whereas the filter of `AND t.device_id =3D $1` uses a (Bitmap) I= ndex scan
in other types of queries.

Previously we would - in a C= TE - do a delete *and then* the merge.

Which performed much better a= s the DELETE would not do a Seq Scan.

Attached a full reproducing te= st case. Some numbers:

Previously, DELETE in CTE, then merge:
=C2= =A0 =C2=A0 Planning Time: 6.700 ms
=C2=A0 =C2=A0 Execution Time: 7.473 m= s

Using the MERGE WHEN MATCHED ON SOURCE THEN DELETE:
=C2=A0 =C2= =A0 Planning Time: 0.994 ms
=C2=A0 =C2=A0 Execution Time: 65.695 ms
<= br>My questions are:

- is the Seq Scan expected by others in this ma= iling list as well?
- Is it required to do the Seq Scan?
- is this so= mething that could be optimized?

Kind regards,

Feike Steenber= gen
--00000000000087a372062b45148d-- --00000000000087a373062b45148f Content-Type: application/octet-stream; name="merge_delete_source_seq_scan_reproduction.sql.s" Content-Disposition: attachment; filename="merge_delete_source_seq_scan_reproduction.sql.s" Content-Transfer-Encoding: base64 Content-ID: X-Attachment-Id: f_m5paw8m10 Q1JFQVRFIFRBQkxFIG1lcmdlX3NvdXJjZSAoCiAgICB0aW1lIHRpbWVzdGFtcHR6IG5vdCBudWxs LAogICAgdmFsdWUgZmxvYXQ4IG5vdCBudWxsCik7CgpDUkVBVEUgVEFCTEUgbWVyZ2VfdGFyZ2V0 ICgKICAgIGRldmljZV9pZCBpbnRlZ2VyIG5vdCBudWxsLAogICAgdGltZSB0aW1lc3RhbXB0eiBu b3QgbnVsbCwKICAgIHZhbHVlIGZsb2F0OCBub3QgbnVsbCwKICAgIHByaW1hcnkga2V5IChkZXZp Y2VfaWQsIHRpbWUpCik7CgpTRUxFQ1Qgc2V0c2VlZCgwLjEyMzQpOwpJTlNFUlQgSU5UTyBtZXJn ZV90YXJnZXQKU0VMRUNUCiAgICBkZXZpY2VfaWQsCiAgICAnMjAyNS0wMS0wOVQwMDowMDowMCsw MCc6OnRpbWVzdGFtcHR6IC0gcmFuZG9tKCkgKiBpbnRlcnZhbCAnMSB5ZWFyJywKICAgIHJhbmRv bSgpICogMTAwMDAKRlJPTQogICAgZ2VuZXJhdGVfc2VyaWVzKDEsMTAwMCkgQVMgZChkZXZpY2Vf aWQpCkNST1NTIEpPSU4KICAgIGdlbmVyYXRlX3NlcmllcygxLCAxMDApIEFTIF87CgpJTlNFUlQg SU5UTwogICAgbWVyZ2Vfc291cmNlClNFTEVDVAogICAgJzIwMjUtMDEtMDlUMDA6MDA6MDArMDAn Ojp0aW1lc3RhbXB0eiAtIHJhbmRvbSgpICogaW50ZXJ2YWwgJzEgeWVhcicsCiAgICByYW5kb20o KSAqIDEwMDAwCkZST00KICAgIGdlbmVyYXRlX3NlcmllcygxLDEwKTsKClZBQ1VVTSAoQU5BTFla RSkgbWVyZ2VfdGFyZ2V0OwpWQUNVVU0gKEFOQUxZWkUpIG1lcmdlX3NvdXJjZTsKClBSRVBBUkUg ZXhhbXBsZV9tZXJnZSBBUwpNRVJHRSBJTlRPCiAgICBtZXJnZV90YXJnZXQgQVMgdApVU0lORwog ICAgbWVyZ2Vfc291cmNlIEFTIHMgT04gKHQudGltZSA9IHMudGltZSBBTkQgdC5kZXZpY2VfaWQg PSAkMSkKV0hFTiBNQVRDSEVEIFRIRU4KICAgIFVQREFURSBzZXQKICAgICAgICB2YWx1ZSA9IHMu dmFsdWUKV0hFTiBOT1QgTUFUQ0hFRCBUSEVOCiAgICBJTlNFUlQgKGRldmljZV9pZCwgdGltZSwg dmFsdWUpIFZBTFVFUyAoJDEsIHRpbWUsIHZhbHVlKQpXSEVOIE5PVCBNQVRDSEVEIEJZIFNPVVJD RQogICAgQU5EIHQuZGV2aWNlX2lkID0gJDEKICAgIFRIRU4gREVMRVRFOwoKLS0gVGhpcyBwbGFu IHNlZW1zIHRvIHVzZSBhIFNlcSBTY2FuLCBhbmQgYXBwbGllcyB0aGUgZmlsdGVyCi0tIGR1cmlu ZyB0aGUgam9pbjoKCi8qCgpIYXNoIENvbmQ6ICh0LiJ0aW1lIiA9IHMuInRpbWUiKQpKb2luIEZp bHRlcjogKHQuZGV2aWNlX2lkID0gMTgpCi0+ICBTZXEgU2NhbiBvbiBtZXJnZV90YXJnZXQgdCAg KGNvc3Q9MC4wMC4uMTYzNy4wMCByb3dzPTEwMDAwMCB3aWR0aD0xOCkKCiovCkVYUExBSU4gRVhF Q1VURSBleGFtcGxlX21lcmdlKDE4KTsKCi0tIFdoZXJlYXMgSSB3b3VsZCBleHBlY3QgdGhlIHF1 ZXJ5IHRvIG5vdCB1c2UgYSBTZXEgU2NhbiBoZXJlLAotLSBidXQgYW4gaW5kZXggc2NhbiAvIGJp dG1hcCBpbmRleCBzY2FuLAotLSBzaW1pbGFyIHRvIHdoYXQgd291bGQgaGFwcGVuIGlmIHdlIHJ1 bgotLSB0aGlzIHF1ZXJ5OgpFWFBMQUlOIFNFTEVDVCAqIEZST00gbWVyZ2VfdGFyZ2V0IFdIRVJF IGRldmljZV9pZCA9IDE4OwoKUFJFUEFSRSBvbGRfZmFzdGVyX3BsYW4gQVMKV0lUSCBkZWxldGVk IEFTICgKICAgIERFTEVURSBGUk9NCiAgICAgICAgbWVyZ2VfdGFyZ2V0IHQKICAgIFdIRVJFCiAg ICAgICAgdC5kZXZpY2VfaWQgPSAkMQogICAgICAgIEFORCBOT1QgRVhJU1RTICgKICAgICAgICAg ICAgU0VMRUNUCiAgICAgICAgICAgIEZST00KICAgICAgICAgICAgICAgIG1lcmdlX3NvdXJjZSBz CiAgICAgICAgICAgIFdIRVJFCiAgICAgICAgICAgICAgICB0LnRpbWUgPSBzLnRpbWUKICAgICAg ICAgICAgKQopCk1FUkdFIElOVE8KICAgIG1lcmdlX3RhcmdldCBBUyB0ClVTSU5HCiAgICBtZXJn ZV9zb3VyY2UgQVMgcyBPTiAodC50aW1lID0gcy50aW1lIEFORCB0LmRldmljZV9pZCA9ICQxKQpX SEVOIE1BVENIRUQgVEhFTgogICAgVVBEQVRFIHNldAogICAgICAgIHZhbHVlID0gcy52YWx1ZQpX SEVOIE5PVCBNQVRDSEVEIFRIRU4KICAgIElOU0VSVCAoZGV2aWNlX2lkLCB0aW1lLCB2YWx1ZSkg VkFMVUVTICgkMSwgdGltZSwgdmFsdWUpOwoKRVhQTEFJTiAoQU5BTFlaRSwgQlVGRkVSUywgTUVN T1JZKSBFWEVDVVRFIG9sZF9mYXN0ZXJfcGxhbigxOSk7CkVYUExBSU4gKEFOQUxZWkUsIEJVRkZF UlMsIE1FTU9SWSkgRVhFQ1VURSBleGFtcGxlX21lcmdlKDE4KTsK --00000000000087a373062b45148f--