github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/docs/RFCS/20171024_select_for_update.md (about) 1 - Feature Name: Support `SELECT FOR UPDATE` 2 - Status: postponed 3 - Start Date: 2017-10-17 4 - Authors: Rebecca Taft 5 - RFC PR: [#19577](https://github.com/cockroachdb/cockroach/pull/19577) 6 - Cockroach Issue: [#6583](https://github.com/cockroachdb/cockroach/issues/6583) 7 8 # Summary 9 10 This RFC is postponed because it seems that, given CockroachDB's model of concurrency control, 11 it is not possible to implement the functionality that users would expect for `SELECT ... FOR UPDATE`. 12 None of the implementation alternatives we have examined would fully replicate the semantics that Postgres 13 provides, and there is a risk that customers would try to use the feature without fully 14 understanding the pitfalls. The details are described below in the [Drawbacks](#drawbacks) and 15 [Alternatives](#alternatives) sections. We may revisit this feature if there is sufficient demand from 16 customers, or if we can prove that there is a significant benefit to using `SELECT ... FOR UPDATE` 17 for certain applications. 18 19 Original Summary: Support the `SELECT ... FOR UPDATE` SQL syntax, which locks rows returned by the `SELECT` 20 statement. This pessimistic locking feature prevents concurrent transactions from updating 21 any of the locked rows until the locking transaction commits or aborts. This is useful for 22 enforcing consistency when running in `SNAPSHOT` mode, and may be useful for avoiding deadlocks 23 when running in `SERIALIZABLE` mode. Several potential customers have asked for this feature, 24 and it would also get us closer to feature parity with Postgres. The proposed implementation is 25 to set row-level "dummy" intents by transforming the `SELECT ... FOR UPDATE` query tree to 26 include an `updateNode`. 27 28 # Motivation 29 30 As described in [Issue #6583](https://github.com/cockroachdb/cockroach/issues/6583), 31 `SELECT ... FOR UPDATE` is not standard SQL, but many databases now support it, including 32 Postgres. Thus the primary motivation for this feature is compatibility with existing code. 33 Several third party products such as the [Quartz Scheduler](http://www.quartz-scheduler.org), 34 [OpenJPA](http://openjpa.apache.org) and [Liquibase](http://www.liquibase.org) 35 also rely on this feature, preventing some potential customers from switching to CockroachDB. 36 37 In some cases, `SELECT ... FOR UPDATE` is required to maintain correctness when running CockroachDB 38 in `SNAPSHOT` mode. In particular, `SELECT ... FOR UPDATE` can be used to prevent write skew anomalies. 39 Write skew anomalies occur when two concurrent transactions read an overlapping set of 40 rows but update disjoint sets of rows. Since the transactions each operate on private snapshots of 41 the database, neither one will see the updates from the other. 42 43 The [Wikipedia entry on Snapshot Isolation](https://en.wikipedia.org/wiki/Snapshot_isolation) has a 44 useful concrete example: 45 46 > ... imagine V1 and V2 are two balances held by a single person, Phil. The bank will allow either 47 V1 or V2 to run a deficit, provided the total held in both is never negative (i.e. V1 + V2 ≥ 0). 48 Both balances are currently $100. Phil initiates two transactions concurrently, T1 withdrawing $200 49 from V1, and T2 withdrawing $200 from V2. .... T1 and T2 operate on private snapshots of the database: 50 each deducts $200 from an account, and then verifies that the new total is zero, using the other account 51 value that held when the snapshot was taken. Since neither update conflicts, both commit successfully, 52 leaving V1 = V2 = -$100, and V1 + V2 = -$200. 53 54 It is possible to prevent this scenario from happening in `SNAPSHOT` mode by using `SELECT ... FOR UPDATE`. 55 For example, if each transaction calls something like: 56 `SELECT * FROM accounts WHERE acct_name = 'V1' OR acct_name = 'V2' FOR UPDATE` at the start of the transaction, 57 one of the transactions would be blocked until the "winning" transaction commits and releases the locks. 58 At that point, the "losing" transaction would be able to see the update from the winner, so it would not deduct 59 $200. Therefore, using `SELECT ... FOR UPDATE` lets users obtain some of the performance benefits of using `SNAPSHOT` 60 isolation instead of `SERIALIZABLE`, without paying the price of write skew anomalies. 61 62 `SELECT ... FOR UPDATE` is not needed for correctness when running in `SERIALIZABLE` mode, 63 but it may still be useful for controlling lock ordering and avoiding deadlocks. For example, 64 consider the following schedule: 65 66 ``` 67 T1: Starts transaction 68 T2: Starts transaction 69 T1: Updates row A 70 T2: Updates row B 71 T1: Wants to update row B (blocks) 72 T2: Wants to update row A (deadlock) 73 ``` 74 75 This sort of scenario can happen in any database that tries to maintain some level of correctness. 76 It is especially common in databases that use pessimistic two-phased locking (2PL) since transactions 77 must acquire shared locks for reads in addition to exclusive locks for writes. But deadlocks like the 78 one shown above also happen in databases that use MVCC like PostgreSQL and CockroachDB, since writes must 79 acquire locks on all rows that will be updated. Postgres, CockroachDB, and many other systems detect deadlocks by 80 identifying cycles in a "waits-for" graph, where nodes represent transactions, and directed edges represent 81 transactions waiting on each other to release locks (or write intents). In Postgres, if a cycle (deadlock) is detected, 82 transactions will be selectively aborted until the cycle(s) are removed. CockroachDB forces one of the transactions 83 in the cycle to be "pushed", which generally has the effect of aborting at least one transaction. CockroachDB 84 can perform this detection and push almost instantaneously after the conflict happens, so "deadlocks" in CockroachDB 85 are less disruptive than in Postgres, where deadlock detection can take up to a second. Some other systems 86 use a timeout mechanism, where transactions will abort after waiting a certain amount of time to acquire a lock. 87 In all cases, the deadlock causes delays and/or aborted transactions. 88 89 `SELECT ... FOR UPDATE` will help avoid deadlocks by allowing transactions to acquire all of their locks 90 (lay down intents in CockroachDB) up front. For example, the above schedule would change to the following: 91 92 ``` 93 T1: Starts transaction 94 T2: Starts transaction 95 T1: Locks rows A and B 96 T1: Updates row A 97 T2: Wants to lock rows A and B (blocks) 98 T1: Updates row B 99 T1: Commits 100 T2: Locks rows A and B 101 T2: Updates row B 102 T2: Updates row A 103 T2: Commits 104 ``` 105 106 Since both transactions attempted to lock rows A and B at the start of the transaction, the deadlock was prevented. 107 Acquiring all locks (or laying down write intents) up front allows the database to lock rows in a consistent order 108 (even if they are updated in a different order), thus preventing deadlocks. 109 110 Many implementations of this feature also include options to control whether or not to wait on locks. 111 `SELECT ... FOR UPDATE NOWAIT` is one option, which causes the query to return an error if it is 112 unable to immediately lock all target rows. This is useful for latency-critical situations, 113 and could also be useful for auto-retrying transactions in CockroachDB. `SELECT ... FOR UPDATE SKIP LOCKED` 114 is another option, which returns only the rows that could be locked immediately, and skips over the others. 115 This option returns an inconsistent view of the data, but may be useful for cases when multiple 116 workers are trying to process data in the same table as if it were a queue of tasks. 117 The default behavior of `SELECT ... FOR UPDATE` is for the transaction to block if some of the 118 target rows are already locked by another transaction. Note that it is not possible to use the 119 `NOWAIT` and `SKIP LOCKED` modifiers without `FOR { UPDATE | SHARE | ... }`. 120 121 The first implementation of `FOR UPDATE` in CockroachDB will not include `NOWAIT` or `SKIP LOCKED` options. 122 It seems that some users want these features, but many would be satisfied with `FOR UPDATE` alone. 123 As of this writing we are not aware of any commonly used third-party products that use these options. 124 125 # Guide-level explanation 126 127 The [Postgres Documentation](https://www.postgresql.org/docs/current/static/sql-select.html#sql-for-update-share) 128 describes this feature as it is supported by Postgres. As shown, the syntax of the locking clause has the form 129 130 ``` 131 FOR lock_strength [ OF table_name [, ...] ] [ NOWAIT | SKIP LOCKED ] 132 ``` 133 134 where `lock_strength` can be one of 135 136 ``` 137 UPDATE 138 NO KEY UPDATE 139 SHARE 140 KEY SHARE 141 ``` 142 143 For our initial implementation in CockroachDB, we will likely simplify this syntax to 144 145 ``` 146 FOR UPDATE 147 ``` 148 149 i.e., no variation in locking strength, no specified tables, and no options for avoiding 150 waiting on intents. Using `FOR UPDATE` will result in laying intents on the rows returned by the `SELECT` 151 query. Note that it only lays intents for rows that already exist; preventing inserts matching 152 the `SELECT` query is not desired. As described above, this feature alone is useful because it helps 153 maintain correctness when running CockroachDB in `SNAPSHOT` mode (avoiding write skew), and serves 154 as a tool for optimization (avoiding deadlocks) when running in `SERIALIZABLE` mode. 155 156 For example, consider the following transaction: 157 158 <a name="employees_transaction"></a> 159 ``` 160 BEGIN; 161 162 SELECT * FROM employees WHERE name = 'John Smith' FOR UPDATE; 163 164 ... 165 166 UPDATE employees SET salary = 50000 WHERE name = 'John Smith'; 167 168 COMMIT; 169 ``` 170 171 This code will lay intents on the rows of all employees named John Smith at the beginning of the transaction, 172 preventing other concurrent transactions from simultaneously updating those rows. 173 As a result, the `UPDATE employees ...` statement at the end of the transaction will not need 174 to lay any additional intents. Note that `FOR UPDATE` will have no effect if it is used in a 175 stand-alone query that is not part of any transaction. 176 177 One important difference between CockroachDB and Postgres relates to transaction priorities. In CockroachDB, 178 if there is a conflict and the second transaction has a higher priority, the first transaction will be 179 pushed out of the way -- even if it has laid down intents already. This would apply to transactions with 180 `SELECT ... FOR UPDATE`, just as it would for any other transaction. 181 182 # Reference-level explanation 183 184 This section provides more detail about how and why the CockroachDB implementation of 185 the locking clause will differ from Postgres. 186 187 With the current model of CockroachDB, it is not possible to support the locking strengths 188 `NO KEY UPDATE` or `KEY SHARE` because 189 these options require locking at a sub-row granularity. It is also not clear that CockroachDB can support 190 `SHARE`, because there is currently no such thing as a "read intent". `UPDATE` can be supported by 191 marking the affected rows with dummy write intents. 192 193 By default, if `FOR UPDATE` is used in Postgres without specifying tables 194 (without the `OF table_name [, ...]` clause), 195 Postgres will lock all rows returned by the `SELECT` query. The `OF table_name [, ...]` clause 196 enables locking only the rows in the specified tables. To lock different tables with different 197 strengths or different options, Postgres users can string multiple locking clauses together. 198 For example, 199 200 ``` 201 SELECT * from employees e, departments d, companies c 202 WHERE e.did = d.id AND d.cid = c.id 203 AND c.name = `Cockroach Labs` 204 FOR UPDATE OF employees SKIP LOCKED 205 FOR SHARE OF departments NOWAIT 206 ``` 207 locks rows in the `employees` table that satisfy the join condition with an exclusive lock, 208 and skips over rows that are already locked by another transaction. 209 It also locks rows in the `departments` table that satisfy the join condition with a shared lock, 210 and returns an error if it cannot lock all of the rows immediately. It does not lock 211 the `companies` table. 212 213 Implementing this flexibility in CockroachDB for use of different tables and different options 214 may be excessively complicated, and it's not clear that our customers actually need 215 it. To avoid spending too much time on this, as mentioned above, we will probably just implement the most 216 basic functionality in which clients use `FOR UPDATE` to lay intents on the rows returned by the query. 217 Initially we won't include the `SKIP LOCKED` or `NOWAIT` options, but it may be worth implementing 218 these at some point. 219 220 At the moment `FOR UPDATE` is disabled for use in views (there will not be an error, but it will 221 be ignored). This is similar to the way `ORDER BY` and `LIMIT` are handled in views. See comment from @a-robinson in 222 [data_source.go:getViewPlan()](https://github.com/cockroachdb/cockroach/blob/5a6b4312a972b74b0af5de53dfdfb204dc0fd6d7/pkg/sql/data_source.go#L680). 223 As described in the comment, the outer `Select` AST node is currently being stripped out of the view plan. 224 If `ORDER BY` and `LIMIT` are enabled later by including the entire `Select`, `FOR UPDATE` would come for free. 225 Postgres supports all of these options in views, since it supports any `SELECT` query, and re-runs 226 the query each time the view is used. CockroachDB should do the same. 227 228 With the (temporary) exception of views, `FOR UPDATE` should propagate throughout the query plan 229 as expected. If `FOR UPDATE` only occurs in a subquery, the rows locked are those returned by the subquery 230 to the outer query (unless the optimizer reduces the amount of data scanned in the subquery). For example, 231 `SELECT * FROM employees e, (SELECT * FROM departments FOR UPDATE) d WHERE e.did = d.id` 232 would only lock rows in the departments table. If the `FOR UPDATE` occurs on the outer `SELECT`, however, 233 all rows returned by the query will be locked. 234 235 If the number of intents exceeds `maxIntents` as defined in `txn_coord_sender.go` 236 (default 100,000), the transaction will be rejected. This is similar to the way updates work, 237 and will prevent users from using `SELECT FOR UPDATE` with queries that would result in a full table 238 scan. If we need to reduce this number later we can add a new setting just for `SELECT FOR UPDATE`. 239 240 One issue that is not discussed in detail in the Postgres documentation is the order in which 241 locks are acquired. Acquiring locks in a consistent order is an important tool to prevent deadlocks 242 from occuring. For the CockroachDB implementation of `FOR UPDATE`, we will not implement the feature 243 in DistSQL at this time (DistSQL does not currently support writes), so our implementation 244 will most likely produce a consistent ordering of write intents (we currently have no evidence 245 to the contrary). It is difficult to guarantee a particular ordering, however, since the implementation 246 of the local execution engine may change in the future to take advantage of parallel processing. Likewise, 247 if `FOR UPDATE` is supported later in DistSQL, ordering will be more difficult to guarantee. 248 249 ## Detailed design 250 251 There are a number of changes that will need to be implemented in the SQL layer in order to 252 support `FOR UPDATE`. 253 254 - Update the parser to support the syntax in `SELECT` statements. 255 - Add checks to ensure that `FOR UPDATE` cannot be used with `GROUP BY`, `HAVING`, `WINDOW`, `DISTINCT`, 256 `UNION`, `INTERSECT`, `EXCEPT`, or in contexts where returned rows cannot be clearly identified with 257 individual table rows; for example it cannot be used with aggregation. Postgres also disallows 258 `FOR UPDATE` with all of these query types. 259 - Possibly add additional checks for the first implementation to limit `SELECT FOR UPDATE` queries to 260 "simple" queries where the primary key must be used in the `WHERE` clause, and the predicate must be either `==` or `IN`. 261 - Modify the query tree so that the top level `renderNode` is transformed to an `updateNode` which sets each selected 262 column value to itself and returns the selected rows (e.g., `UPDATE table SET a = a RETURNING a`). If needed, 263 a `sortNode` and/or `limitNode` can be applied above the `updateNode` in the query tree. 264 265 Note that none of this design involves DistSQL. At the moment DistSQL does not support writes, 266 so it would not make sense to support `FOR UPDATE`. 267 268 ## <a name="drawbacks"></a>Drawbacks 269 270 We have decided to postpone this feature because it is not clear that the proposed solution 271 (or any of the alternatives discussed below) would meet customer needs. 272 273 Some potential customers (such as those using the Quartz Scheduler) use `SELECT FOR UPDATE` 274 as if it were an advisory lock; they never actually update the rows selected by the `SELECT FOR UPDATE` 275 statement, so the only purpose of the lock is to prevent other concurrent transactions from accessing some 276 shared resource during the transaction. Although the proposed solution of laying intents 277 will achieve this isolation, it will result in many aborted transactions. For example, consider a 278 transaction `T1` with a lower timestamp than another transaction `T2`. If `T1` tries to access rows 279 already marked with an intent by `T2`, `T1` will block until `T2` commits or aborts, and then `T1` will 280 abort with a retryable error. Most existing codebases using `SELECT FOR UPDATE` are probably not equipped 281 to handle these retryable errors because other databases would not cause transactions to abort in this scenario. 282 283 The key motivation described above for using `SELECT FOR UPDATE` in `SERIALIZABLE` mode is to control 284 lock ordering so as to minimize transaction aborts. Due to the way concurrency control works in 285 CockroachDB, however, `SELECT FOR UPDATE` is still likely to cause many aborts (as described in the previous 286 paragraph). Postgres also recommends against using this feature in `SERIALIZABLE` mode, since it is not necessary 287 for correctness, and can degrade performance by causing disk accesses to set locks. Additionally, although `FOR UPDATE` 288 can prevent deadlocks if used judiciously, it can also cause deadlocks if not every transaction 289 sets intents in the same order. Since `FOR UPDATE` results in transactions setting more intents 290 for a longer period of time, the chance of collision is higher. There may be some benefit to using `FOR UPDATE` 291 with high-contention workloads since it would cause conflicting transactions to fail earlier and do less work 292 before aborting, but we would need to run some tests to validate this (perhaps by running benchmarks 293 with high-contention workloads). If we do eventually implement this feature, we should probably discourage customers 294 from using `FOR UPDATE` in `SERIALIZABLE` mode unless they have good reasons to use it. 295 296 It's also not clear that this feature is worth implementing for use in `SNAPSHOT` mode. 297 As mentioned above, the primary motivation for this feature is compatibility with existing code. 298 Simply running in `SERIALIZABLE` mode is (probably) a better way of avoiding write skew than `SNAPSHOT` 299 +`FOR UPDATE`. 300 301 Given the above drawbacks, we have decided it is not worth the effort to implement `SELECT FOR UPDATE` at 302 this time. But if we do implement it in the future, one way to make sure customers avoid the pitfalls 303 is to create an "opt-in" setting for using this feature. By default, using `FOR UPDATE` would throw an 304 error and direct users to view the documentation. Only users who explicitly opt in by updating their cluster 305 or session settings would be able to use the feature. We could also add an option to either use the feature 306 with intents or as a no-op (see the [Isolation Upgrade](#no-op) alternative below). Adding options adds 307 complexity, however. 308 309 If we implement this feature, we should probably start with only `FOR UPDATE`, and not 310 include other features (e.g., `NOWAIT`, `SKIP LOCKED`, etc). It will be a lot of work to implement 311 all of the features supported by Postgres, and it is probably not worth our time since it's not clear 312 these features will actually get used. We can easily add them later if needed. 313 314 In the mean time, customers who really need explicit locking functionality can emulate the 315 feature by executing something like `UPDATE x SET y=y WHERE y=y`. Executing this command at 316 the start of a transaction would effectively set intents on all of the rows in table `x`. 317 318 ## <a name="alternatives"></a>Rationale and Alternatives 319 320 The proposed solution is to "lock" rows by writing dummy write intents on each row as part 321 of an update operation. However, there are a couple of alternative implementations worth 322 considering, specifically row-level intents set as part of a scan operation, 323 range-level intents, and isolation ugrade. 324 325 ### Row-level intents set during scan 326 327 Laying intents as part of an `UPDATE` operation could be expensive for simple `SELECT FOR UPDATE` 328 queries since it requires multiple requests to the KV layer. The first KV request performs the scan 329 operation, and subsequent requests update each row to lay an intent. For simple queries, a less 330 expensive approach would be to lay intents directly during the scan operation. 331 332 This approach has a few downsides, however. First, it would be more work to implement since 333 it would require updates to the KV API to include new messages (e.g., ScanForUpdate and ReverseScanForUpdate). 334 These new messages would require updates to the KV and storage layers to mimic processing of Scan and ReverseScan 335 and set dummy write intents on every row touched. 336 337 As described in [issue #6583](https://github.com/cockroachdb/cockroach/issues/6583), 338 > Implementing this would touch a lot of different parts of the code. No part is individually too 339 tricky, but there are a lot of them (`git grep -i reversescan` will give you an idea of the scope). 340 The bulk of the changes would consist of implementing new ScanForUpdate and ReverseScanForUpdate 341 calls in the KV API. These would work similarly to regular scans, but A) would be flagged as read/write 342 commands instead of read-only and B) after performing the scan, they'd use MVCCPut to write back the 343 values that were just read (that's not the most efficient way to do things, but I think it's the right 344 way to start since it will have the right semantics without complicating the backwards-compatibility 345 story). Then the SQL layer would use these instead of plan Scan/ReverseScan when `FOR UPDATE` has been 346 requested. 347 348 There was some discussion in the issue about whether we really needed new API calls, but 349 the consensus was that making it possible to write on `Scan` requests would make debugging a nightmare. 350 351 This approach would also require a change in the SQL layer to handle the case when a `SELECT FOR UPDATE` 352 query would only scan a secondary index and not touch the primary key (PK) index. In this case, 353 we would need to implicitly modify the query plan to add a join with the PK index so that intents 354 would always be laid on the PK index. This would ensure that the `SELECT FOR UPDATE` query would prevent 355 concurrent transactions from updating the corresponding rows, since updates must always lay 356 intents on the PK index. 357 358 Another downside is that in many cases this approach would set intents on more rows than returned by the 359 `SELECT`, since most predicates are not applied until after the scan is completed. This should not affect 360 correctness in terms of consistency or isolation, but could affect performance if there is high contention. 361 For example, if the first `SELECT` statement in the [employees transaction shown above](#employees_transaction) 362 were `SELECT * FROM employees WHERE name like '%Smith' FOR UPDATE;`, CockroachDB would set intents on 363 all of the rows in the `employees` table because it's not possible to determine from the predicate 364 which key spans are affected. This lack of precision would be an issue for any predicate that 365 does not directly translate to particular key spans. Furthermore, since this translation may not be obvious 366 to users, they could easily write queries that would result in full-table scans by accident. 367 368 In contrast, Postgres (generally) locks exactly the rows returned by the query, and no more. There are a few 369 examples given in the [documentation](https://www.postgresql.org/docs/current/static/sql-select.html#sql-for-update-share) 370 where that's not the case. For example, `SELECT ... LIMIT 5 OFFSET 5 FOR UPDATE` may 371 lock up to 10 rows even though only 5 rows are returned. 372 373 ### Range-level intents 374 375 One alternative to row-level intents is to set an intent on an entire Range if the `SELECT` statement 376 would return the majority of rows in the range. This is similar to the approach 377 suggested by the [Revert Command RFC](https://github.com/cockroachdb/cockroach/pull/16294). 378 379 The advantage of setting intents on entire ranges is that it would significantly improve the performance 380 for large scans compared to setting intents on individual rows. The downside is that 381 this feature is not yet implemented, so it would be significantly more effort than using 382 simple row-level intents. (It was actually deemed to be too complex and all-interfering in the 383 [Revert Command RFC](https://github.com/cockroachdb/cockroach/pull/16294), which is why that 384 RFC is now closed.) It's also not clear that customers would use `FOR UPDATE` with 385 large ranges, so this may be an unneeded performance optimization. Furthermore, 386 setting an intent on the entire range based on the predicate could result in "locking" rows that should 387 not be observable by the `SELECT`. For instance, if the transaction performing the 388 `SELECT FOR UPDATE` query over some range is at a lower timestamp than a later `INSERT` 389 within that range, the `FOR UPDATE` should not apply to the newly written row. 390 This issue is probably not any worse than the other problems with locking precision described above, 391 though. 392 393 One advantage of implementing range-level intents is that we could reuse this feature 394 for other applications such as point-in-time recovery. The details of the proposed implementation 395 as well as other possible applications are described in the [Revert Command RFC](https://github.com/cockroachdb/cockroach/pull/16294). 396 However, in the interest of getting something working sooner rather than later, 397 I believe row-level intents make more sense at this time. 398 399 ### <a name="no-op"></a>Isolation upgrade 400 401 Another alternative approach is to avoid setting any intents whatsoever. Instead, the `SELECT FOR UPDATE` 402 would be a no-op for `SERIALIZABLE` transactions, and the database would automatically upgrade the isolation 403 of a `SNAPSHOT` transaction to `SERIALIZABLE` when a `SELECT FOR UPDATE` is used. The advantage of this 404 approach is its simplicity: the work required to support this feature would be minimal. Additionally, 405 it would avoid the issues of lock precision and poor performance that exist in the other proposed solutions. 406 Furthermore, it would successfully prevent write skew in 407 `SNAPSHOT` transactions, which is a key reason many customers might want to use `SELECT FOR UPDATE` 408 in the first place. 409 410 The downside is that it may not be what our customers expect. It would not allow customers to control 411 lock ordering, which as described above is one feature of `SELECT FOR UPDATE` that savvy users can employ to 412 prevent deadlocks and other conflicts. Some users may also have reason to lock rows that they don't intend to 413 update, and they will have no way to do that with this solution. 414 415 ### Alternatives to FOR UPDATE 416 417 So far this RFC has assumed that we want to implement some form of the `FOR UPDATE` 418 SQL syntax. However, there are many other types of locks provided by Postgres, and 419 it's possible that one of these other options would be a better choice for our customers. 420 421 1. <b>Table Level Locks:</b> 422 Postgres provides eight different types of table level locks: `ACCESS SHARE, ROW SHARE,` 423 `ROW EXCLUSIVE, SHARE UPDATE EXCLUSIVE, SHARE, SHARE ROW EXCLUSIVE, EXCLUSIVE,` and `ACCESS EXCLUSIVE`. 424 These locks can be acquired explicity using the `LOCK` command, but they are also implicitly 425 acquired by different SQL statements. For example, a `SELECT` command (without `FOR UPDATE`) 426 implicitly acquires the `ACCESS SHARE` lock on every table it accesses. This prevents concurrent 427 calls to `DROP TABLE, TRUNCATE,` etc. on the same table, since those commands must acquire 428 an `ACCESS EXCLUSIVE` lock, wchich conflicts with `ACCESS SHARE`. See the 429 [PG docs](https://www.postgresql.org/docs/current/static/explicit-locking.html#locking-tables) 430 for the full list of conflicts. 431 2. <b>Row Level Locks:</b> 432 There are four different types of row level locks: `UPDATE, NO KEY UPDATE, SHARE, KEY SHARE`. 433 As described above, these can be acquired explicitly with the `SELECT ... FOR locking_strength` 434 command. This RFC has been focused on `SELECT ... FOR UPDATE`, but the other three options 435 are available in Postgres to allow more concurrent accesses. The `UPDATE` (or under certain 436 circumstances `NO KEY UPDATE`) locks are also acquired implicitly by `UPDATE` and `DELETE` commands. 437 See the [PG docs](https://www.postgresql.org/docs/current/static/explicit-locking.html#locking-rows) 438 for more details. 439 3. <b>Advisory Locks:</b> 440 Advisory locks are used to lock application-level resources, identified either by a single 64-bit key 441 value or two 32-bit key values. It is up to the application programmer to ensure that locks are 442 acquired and released at the correct points in time to ensure application-level resources are 443 properly protected. Postgres provides numerous options for advisory locks. They can be: 444 - Session-level (must be explicitly unlocked) or transaction-level (will be unlocked automatically at commit/abort) 445 - Shared or exclusive 446 - Blocking or non-blocking (e.g. `pg_try_advisory_lock` is non-blocking) 447 448 All of the different advisory lock functions are listed in the [PG docs](https://www.postgresql.org/docs/current/static/functions-admin.html#functions-advisory-locks) 449 450 There are valid arguments for using each of these different lock types in different applications. 451 However, I do not think that either table-level locks or advisory locks will be a good 452 substitue for our customers that require explicit row-level locks. 453 Table-level locks are not a good substitue for `FOR UPDATE` and the other row-level locks 454 because they are too coarse-grained and will cause unnecessary performance degradation. 455 Advisory locks place too much responsibility on the application developer(s) to ensure that the 456 appropriate lock is always acquired before accessing a given row. This doesn't mean we 457 shouldn't support advisory locks, but I don't think we should force developers to use them 458 in place of explicit row-level locks.