cockroachdb / cockroachdb/cockroach
opt: three-way join does not have home region when using enforce_home_region
- 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
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