Question: Locks and schema changes
What is SELECT FOR UPDATE SKIP LOCKED for?
Answered in the first paragraph. Last updated .
Dealing work out of a table to several workers at once without any of them waiting. A plain row lock makes the second worker block until the first is finished, which turns a queue table into a single-file line. Adding the skip instruction makes it step over rows another session already holds and take the next free ones instead. That is the entire mechanism behind most job queues built on this database.
The guarantee you are trading away
A normal read gives you a consistent picture of the table. This one does not: the rows you get depend on which rows other sessions happened to be holding at that instant, so the same statement run twice by two workers returns two different sets by design. That is correct for claiming work and wrong for anything that reports on it.
Two consequences follow. Order is approximate, because a row locked by a stalled worker is passed over and picked up later, so a strict priority queue needs more than this. And the claim lasts until the claiming transaction ends, not until the work is done, so a worker that takes a row and then sits waiting on an external service is holding the claim for the whole call. That is the idle in transaction pattern arriving through a side door, and it is worse here because the held row is invisible to everyone else.
The sibling option refuses rather than skips: it raises an error the moment a wanted row is held. That is the right choice when you must have one specific row and would rather fail fast than wait.
Building on it without the usual mistakes
Always bound the claim. A statement without a row limit locks everything it can and the second worker finds nothing to skip to.
Keep the claiming transaction to the claim itself. Take the rows, mark them, commit, then do the work outside the transaction and record the result separately. This costs one extra write and removes the entire class of problems caused by long-held claims.
Watch for ordering when the worker touches more than one table. Two workers claiming rows in one order and updating a shared table in another is the classic recipe for a deadlock, and the skip option does nothing to prevent it because the collision is elsewhere.
If workers do end up waiting on each other anyway, the wait is visible as an ordinary blocking chain, and finding what is blocking a query applies unchanged. Lock contention and blocking trees has the rest.