drizzle-team / drizzle-team/drizzle-orm
[BUG]: Avoid unnecessary nesting in the query builder
- Dominant language
- TypeScript
- Stars
- 35.8k
- Forks
- 1.6k
- Avg merge
- 2d 7h
- Merged PRs (30d)
- 4
Description
### Report hasn't been filed before.
- [X] I have verified that the bug I'm about to report hasn't been filed before.
### What version of `drizzle-orm` are you using?
0.37.0
### What version of `drizzle-kit` are you using?
0.29.1
### Other packages
better-sqlite3@11.6.0
### Describe the Bug
tl:dr; Remove unnecessary nesting if the relation depth ends in 1.
---
This query:
```js
db.query.userTable.findFirst({
columns: { id: true },
where: eq(userTable.id, ''),
with: { profile: { columns: { userId: true } } }
});
relations(profileTable, ({ one }) => ({
user: one(userTable, {
fields: [profileTable.userId], // this is a primary-key, which can be used as an index
references: [userTable.id]
})
}));
```
generates this nested SQL:
```sql
select
"id",
(
select
json_array ("user_id") as "data"
from
(
select
*
from
"profile" "userTable_profile"
where
"userTable_profile"."user_id" = "userTable"."id"
limit
?
) "userTable_profile"
) as "profile"
from
"user" "userTable"
where
"userTable"."id" = ?
limit
?
-- 1,,1
```
which causes a full-table scan (index 4):
```
┌─────────┬────┬────────┬─────────┬───────────────────────────────────────────────────────────────────────────────┐
│ (index) │ id │ parent │ notused │ detail │
├─────────┼────┼────────┼─────────┼───────────────────────────────────────────────────────────────────────────────┤
│ 0 │ 5 │ 0 │ 39 │ 'SEARCH userTable USING COVERING INDEX sqlite_autoindex_user_1 (id=?)' │
│ 1 │ 13 │ 0 │ 0 │ 'CORRELATED SCALAR SUBQUERY 2' │
│ 2 │ 16 │ 13 │ 0 │ 'CO-ROUTINE userTable_profile' │
│ 3 │ 22 │ 16 │ 39 │ 'SEARCH userTable_profile USING INDEX sqlite_autoindex_profile_1 (user_id=?)' │
│ 4 │ 36 │ 13 │ 17 │ 'SCAN userTable_profile' │
└─────────┴────┴────────┴─────────┴───────────────────────────────────────────────────────────────────────────────┘
```
---
Removing the nesting:
```sql
SELECT
"id",
(
SELECT
json_array ("user_id") AS "data"
FROM
"profile" AS "userTable_profile"
WHERE
"userTable_profile"."user_id" = "userTable"."id"
LIMIT
1
) AS "profile"
FROM
"user" AS "userTable"
WHERE
"userTable"."id" = ?
LIMIT
1;
```
removes the full-table scan:
```
┌─────────┬────┬────────┬─────────┬────────────────────────────────────────────────────────────────────────────────────────┐
│ (index) │ id │ parent │ notused │ detail │
├─────────┼────┼────────┼─────────┼────────────────────────────────────────────────────────────────────────────────────────┤
│ 0 │ 3 │ 0 │ 39 │ 'SEARCH userTable USING COVERING INDEX sqlite_autoindex_user_1 (id=?)' │
│ 1 │ 9 │ 0 │ 0 │ 'CORRELATED SCALAR SUBQUERY 1' │
│ 2 │ 17 │ 9 │ 39 │ 'SEARCH userTable_profile USING COVERING INDEX sqlite_autoindex_profile_1 (user_id=?)' │
└─────────┴────┴────────┴─────────┴────────────────────────────────────────────────────────────────────────────────────────┘
```
Contributor guide
Assessment
This issue has not been assessed yet.