@@ -441,7 +441,45 @@ COMMIT;
441
441
<literal>c_films</literal> is currently positioned:
442
442
<programlisting>
443
443
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 > 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>
445
483
</refsect1>
446
484
447
485
<refsect1>
0 commit comments