cockroachdb / cockroachdb/cockroach

opt: three-way join does not have home region when using enforce_home_region

Open
#99,591 0 comments 0 reactions 0 assignees View on GitHub
A-multiregion A-sql-optimizer C-bug O-qa T-sql-queries
Dominant language
Go
Stars
32.5k
Forks
4.1k
PR merge metrics
PR metrics pending

Description

When using the MovR dataset with `REGIONAL BY ROW` tables (as described [here](https://www.cockroachlabs.com/docs/dev/demo-low-latency-multi-region-deployment.html)) and `enforce_home_region`, a three-way join query fails with no home region even though an almost equivalent two-way join query succeeds. It seems like this three-way join query should be able to either (a) use a locality-optimized join or (b) derive the home region based on equalities.

Here's the repro, using `cockroach demo movr --global --nodes 9 --multitenant=false --insecure`:

First, convert the MovR dataset to multi-region using these steps: https://gist.github.com/michae2/2d8eaabf0bfd27725b1876e0ab797e8c

Then:

```sql
SET enforce_home_region = on;
SET enforce_home_region_follower_reads_enabled = on;

-- assuming the gateway locality is us-east1
SHOW LOCALITY;

-- use these results to fill in name and city below
SELECT * FROM users LIMIT 1;

-- this query succeeds
SELECT max(rides.start_time), rides.vehicle_city, rides.vehicle_id
FROM users
JOIN rides ON rides.rider_id = users.id
AND rides.city = users.city
WHERE users.name = 'Amber Santiago'
AND users.city = 'boston'
GROUP BY rides.vehicle_city, rides.vehicle_id
ORDER BY max(rides.start_time)
LIMIT 5;

-- when we add a join to vehicles, the query fails with no home region
SELECT max(rides.start_time), rides.vehicle_city, rides.vehicle_id
FROM users
JOIN rides ON rides.rider_id = users.id
AND rides.city = users.city
JOIN vehicles ON vehicles.id = rides.vehicle_id
AND vehicles.city = rides.vehicle_city
WHERE users.name = 'Amber Santiago'
AND users.city = 'boston'
GROUP BY rides.vehicle_city, rides.vehicle_id
ORDER BY max(rides.start_time)
LIMIT 5;
```

The two query plans:

```
root@127.0.0.1:26257/movr> EXPLAIN SELECT max(rides.start_time), rides.vehicle_city, rides.vehicle_id
-> FROM users
-> JOIN rides ON rides.rider_id = users.id
-> AND rides.city = users.city
-> WHERE users.name = 'Amber Santiago'
-> AND users.city = 'boston'
-> GROUP BY rides.vehicle_city, rides.vehicle_id
-> ORDER BY max(rides.start_time)
-> LIMIT 5;
info
-----------------------------------------------------------------------------------------------
distribution: full
vectorized: true

• top-k
│ estimated row count: 1
│ order: +max
│ k: 5

└── • group (hash)
│ estimated row count: 1
│ group by: vehicle_city, vehicle_id

└── • hash join
│ estimated row count: 1
│ equality: (rider_id, city) = (id, city)
│ right cols are key

├── • scan
│ estimated row count: 56 (11% of the table; stats collected 30 minutes ago)
│ table: rides@rides_pkey
│ spans: [/'us-east1'/'boston' - /'us-east1'/'boston']

└── • filter
│ estimated row count: 1
│ filter: name = 'Amber Santiago'

└── • scan
estimated row count: 6 (11% of the table; stats collected 28 minutes ago)
table: users@users_pkey
spans: [/'us-east1'/'boston' - /'us-east1'/'boston']
(30 rows)

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

root@127.0.0.1:26257/movr> EXPLAIN SELECT max(rides.start_time), rides.vehicle_city, rides.vehicle_id
-> FROM users
-> JOIN rides ON rides.rider_id = users.id
-> AND rides.city = users.city
-> JOIN vehicles ON vehicles.id = rides.vehicle_id
-> AND vehicles.city = rides.vehicle_city
-> WHERE users.name = 'Amber Santiago'
-> AND users.city = 'boston'
-> GROUP BY rides.vehicle_city, rides.vehicle_id
-> ORDER BY max(rides.start_time)
-> LIMIT 5;
info
-------------------------------------------------------------------------------------------------------
distribution: full
vectorized: true

• top-k
│ estimated row count: 0
│ order: +max
│ k: 5

└── • group (hash)
│ estimated row count: 0
│ group by: vehicle_city, vehicle_id

└── • lookup join
│ estimated row count: 0
│ table: vehicles@vehicles_pkey
│ equality: (region_eq, vehicle_city, vehicle_id) = (region,city,id)
│ equality cols are key

└── • render

└── • hash join
│ estimated row count: 1
│ equality: (rider_id, city) = (id, city)
│ right cols are key

├── • scan
│ estimated row count: 56 (11% of the table; stats collected 30 minutes ago)
│ table: rides@rides_pkey
│ spans: [/'us-east1'/'boston' - /'us-east1'/'boston']

└── • filter
│ estimated row count: 1
│ filter: name = 'Amber Santiago'

└── • scan
estimated row count: 6 (11% of the table; stats collected 28 minutes ago)
table: users@users_pkey
spans: [/'us-east1'/'boston' - /'us-east1'/'boston']
(38 rows)

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

Jira issue: CRDB-25959

Contributor guide

Open the contributing guide

Research direction

Start by reproducing the issue with `cockroach demo movr --global --nodes 9 --multitenant=false --insecure`, the listed session settings, and the two queries. Compare their `EXPLAIN` plans, focusing on the lookup join and home-region handling for REGIONAL BY ROW tables. Done means the three-way query succeeds under `enforce_home_region` using an appropriate locality optimization or derived home region.

Written by the indexing model from the issue text.

Assessment

Tech stack
go, sql
Domain
databases, distributed-systems
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.