cockroachdb / cockroachdb/cockroach

sql: SELECT FOR UPDATE not able to be optimized away

Open
#114,282 4 comments 0 reactions 0 assignees View on GitHub
A-read-committed A-sql-optimizer C-bug O-support P-3 T-sql-queries
Dominant language
Go
Stars
32.5k
Forks
4.1k
PR merge metrics
PR metrics pending

Description

This exact combination of SELECT FOR UPDATE, EXISTS, and NULL parameter using a prepared statement is able to be optimized to a constant `false` in 22.2.16 but becomes a full table scan in 23.1.11:

```sql
CREATE TABLE a (a INT, INDEX (a));
PREPARE p AS SELECT EXISTS (SELECT NULL FROM a WHERE a = $1 FOR UPDATE);
EXPLAIN ANALYZE EXECUTE p (NULL);
```

Here's v22.2.16:

```
demo@127.0.0.1:26257/defaultdb> CREATE TABLE a (a INT, INDEX (a)); PREPARE p AS SELECT EXISTS (SELECT NULL FROM a WHERE a = $1 FOR UPDATE); EXPLAIN ANALYZE EXECUTE p (NULL);
CREATE TABLE

Time: 2ms total (execution 2ms / network 0ms)

PREPARE

Time: 5ms total (execution 4ms / network 0ms)

info
-----------------------------------
planning time: 406µs
execution time: 476µs
distribution: local
vectorized: true
maximum memory usage: 10 KiB
network usage: 0 B (0 messages)
regions: us-east1

• values
nodes: n1
regions: us-east1
actual row count: 1
size: 1 column, 1 row
(13 rows)

Time: 1ms total (execution 1ms / network 0ms)
```

Here's v23.1.11:

```
demo@127.0.0.1:26257/defaultdb> CREATE TABLE a (a INT, INDEX (a));
-> PREPARE p AS SELECT EXISTS (SELECT NULL FROM a WHERE a = $1 FOR UPDATE);
-> EXPLAIN ANALYZE EXECUTE p (NULL);
->
CREATE TABLE

Time: 2ms total (execution 2ms / network 0ms)

PREPARE

Time: 8ms total (execution 8ms / network 0ms)

info
--------------------------------------------------------------------
planning time: 124µs
execution time: 372µs
distribution: local
vectorized: true
cumulative time spent in KV: 101µs
maximum memory usage: 30 KiB
network usage: 0 B (0 messages)
regions: us-east1
sql cpu time: 39µs

• root

├── • values
│ nodes: n1
│ regions: us-east1
│ actual row count: 1
│ sql cpu time: 11µs
│ size: 1 column, 1 row

└── • subquery
│ id: @S1
│ original sql: (SELECT NULL FROM a WHERE a = $1 FOR UPDATE)
│ exec mode: one row

└── • render

└── • filter
│ nodes: n1
│ regions: us-east1
│ actual row count: 0
│ sql cpu time: 24µs
│ estimated row count: 0
│ filter: false

└── • scan
nodes: n1
regions: us-east1
actual row count: 0
KV time: 101µs
KV contention time: 0µs
KV rows read: 0
KV bytes read: 0 B
KV gRPC calls: 1
estimated max memory allocated: 20 KiB
sql cpu time: 4µs
missing stats
table: a@a_pkey
spans: FULL SCAN
locking strength: for update
(49 rows)

Time: 1ms total (execution 1ms / network 0ms)
```

In v23.2.0-alpha.6 it's better if we use the new SELECT FOR UPDATE behavior (`optimizer_use_lock_op_for_serializable`):

```
demo@127.0.0.1:26257/system/defaultdb> SET optimizer_use_lock_op_for_serializable = true;
SET

Time: 0ms total (execution 0ms / network 0ms)

demo@127.0.0.1:26257/system/defaultdb> EXPLAIN ANALYZE EXECUTE p (NULL);
info
--------------------------------------------------------------------
planning time: 1ms
execution time: 201µs
distribution: local
vectorized: true
maximum memory usage: 10 KiB
network usage: 0 B (0 messages)
regions: us-east1
isolation level: serializable
priority: normal
quality of service: regular

• root

├── • values
│ nodes: n1
│ regions: us-east1
│ actual row count: 1
│ size: 1 column, 1 row

└── • subquery
│ id: @S1
│ original sql: (SELECT NULL FROM a WHERE a = $1 FOR UPDATE)
│ exec mode: one row

└── • render

└── • lookup join (semi)
│ nodes: n1
│ regions: us-east1
│ actual row count: 0
│ KV time: 0µs
│ KV contention time: 0µs
│ KV rows decoded: 0
│ KV bytes read: 0 B
│ KV gRPC calls: 0
│ estimated max memory allocated: 0 B
│ estimated row count: 0
│ table: a@a_pkey
│ equality: (rowid) = (rowid)
│ equality cols are key
│ locking strength: for update

└── • norows
nodes: n1
regions: us-east1
actual row count: 0
(46 rows)

Time: 2ms total (execution 2ms / network 0ms)
```

Jira issue: CRDB-33431

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.