Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 2daeba6

Browse files
committed
Doc: show how to get the equivalent of LIMIT for UPDATE/DELETE.
Add examples showing use of a CTE and a self-join to perform partial UPDATEs and DELETEs. Corey Huinker, reviewed by Laurenz Albe Discussion: https://postgr.es/m/CADkLM=caNEQsUwPWnfi2jR4ix99E0EJM_3jtcE-YjnEQC7Rssw@mail.gmail.com
1 parent 1973d9f commit 2daeba6

File tree

2 files changed

+61
-3
lines changed

2 files changed

+61
-3
lines changed

doc/src/sgml/ref/delete.sgml

+22-2
Original file line numberDiff line numberDiff line change
@@ -260,12 +260,32 @@ DELETE FROM tasks WHERE status = 'DONE' RETURNING *;
260260
</programlisting>
261261
</para>
262262

263-
<para>
263+
<para>
264264
Delete the row of <structname>tasks</structname> on which the cursor
265265
<literal>c_tasks</literal> is currently positioned:
266266
<programlisting>
267267
DELETE FROM tasks WHERE CURRENT OF c_tasks;
268-
</programlisting></para>
268+
</programlisting>
269+
</para>
270+
271+
<para>
272+
While there is no <literal>LIMIT</literal> clause
273+
for <command>DELETE</command>, it is possible to get a similar effect
274+
using the same method described in <link linkend="update-limit">the
275+
documentation of <command>UPDATE</command></link>:
276+
<programlisting>
277+
WITH delete_batch AS (
278+
SELECT l.ctid FROM user_logs AS l
279+
WHERE l.status = 'archived'
280+
ORDER BY l.creation_date
281+
FOR UPDATE
282+
LIMIT 10000
283+
)
284+
DELETE FROM user_logs AS dl
285+
USING delete_batch AS del
286+
WHERE dl.ctid = del.ctid;
287+
</programlisting>
288+
</para>
269289
</refsect1>
270290

271291
<refsect1>

doc/src/sgml/ref/update.sgml

+39-1
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,45 @@ COMMIT;
441441
<literal>c_films</literal> is currently positioned:
442442
<programlisting>
443443
UPDATE films SET kind = 'Dramatic' WHERE CURRENT OF c_films;
444-
</programlisting></para>
444+
</programlisting>
445+
</para>
446+
447+
<para id="update-limit">
448+
Updates affecting many rows can have negative effects on system
449+
performance, such as table bloat, increased replica lag, and increased
450+
lock contention. In such situations it can make sense to perform the
451+
operation in smaller batches, possibly with a <command>VACUUM</command>
452+
operation on the table between batches. While there is
453+
no <literal>LIMIT</literal> clause for <command>UPDATE</command>, it is
454+
possible to get a similar effect through the use of
455+
a <link linkend="queries-with">Common Table Expression</link> and a
456+
self-join. With the standard <productname>PostgreSQL</productname>
457+
table access method, a self-join on the system
458+
column <link linkend="ddl-system-columns-ctid">ctid</link> is very
459+
efficient:
460+
<programlisting>
461+
WITH exceeded_max_retries AS (
462+
SELECT w.ctid FROM work_item AS w
463+
WHERE w.status = 'active' AND w.num_retries &gt; 10
464+
ORDER BY w.retry_timestamp
465+
FOR UPDATE
466+
LIMIT 5000
467+
)
468+
UPDATE work_item SET status = 'failed'
469+
FROM exceeded_max_retries AS emr
470+
WHERE work_item.ctid = emr.ctid;
471+
</programlisting>
472+
This command will need to be repeated until no rows remain to be updated.
473+
Use of an <literal>ORDER BY</literal> clause allows the command to
474+
prioritize which rows will be updated; it can also prevent deadlock
475+
with other update operations if they use the same ordering.
476+
If lock contention is a concern, then <literal>SKIP LOCKED</literal>
477+
can be added to the <acronym>CTE</acronym> to prevent multiple commands
478+
from updating the same row. However, then a
479+
final <command>UPDATE</command> without <literal>SKIP LOCKED</literal>
480+
or <literal>LIMIT</literal> will be needed to ensure that no matching
481+
rows were overlooked.
482+
</para>
445483
</refsect1>
446484

447485
<refsect1>

0 commit comments

Comments
 (0)