prisma-sql 1.76.2 → 1.78.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/generator.cjs +61 -4
- package/dist/generator.cjs.map +1 -1
- package/dist/generator.js +61 -4
- package/dist/generator.js.map +1 -1
- package/dist/index.cjs +38 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +38 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/readme.md +59 -76
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -534,82 +534,6 @@ const users = await prisma.user.findMany({
|
|
|
534
534
|
|
|
535
535
|
That helps both the planner and the reducer keep result shapes predictable.
|
|
536
536
|
|
|
537
|
-
#### 4) Avoid unbounded deep fan-out in a single query
|
|
538
|
-
|
|
539
|
-
This is the biggest real-world improvement lever.
|
|
540
|
-
|
|
541
|
-
Less ideal:
|
|
542
|
-
|
|
543
|
-
```ts
|
|
544
|
-
await prisma.organization.findMany({
|
|
545
|
-
include: {
|
|
546
|
-
users: {
|
|
547
|
-
include: {
|
|
548
|
-
posts: {
|
|
549
|
-
include: {
|
|
550
|
-
comments: true,
|
|
551
|
-
},
|
|
552
|
-
},
|
|
553
|
-
},
|
|
554
|
-
},
|
|
555
|
-
},
|
|
556
|
-
})
|
|
557
|
-
```
|
|
558
|
-
|
|
559
|
-
Usually better:
|
|
560
|
-
|
|
561
|
-
- page parents
|
|
562
|
-
- cap nested collections with `take`
|
|
563
|
-
- add nested `where`
|
|
564
|
-
- split unrelated heavy branches into `$batch`
|
|
565
|
-
|
|
566
|
-
Example:
|
|
567
|
-
|
|
568
|
-
```ts
|
|
569
|
-
const result = await prisma.$batch((batch) => ({
|
|
570
|
-
orgs: batch.organization.findMany({
|
|
571
|
-
take: 20,
|
|
572
|
-
orderBy: { id: 'asc' },
|
|
573
|
-
}),
|
|
574
|
-
recentUsers: batch.user.findMany({
|
|
575
|
-
take: 50,
|
|
576
|
-
orderBy: { createdAt: 'desc' },
|
|
577
|
-
}),
|
|
578
|
-
}))
|
|
579
|
-
```
|
|
580
|
-
|
|
581
|
-
#### 5) Use one-to-one uniqueness where it is actually one-to-one
|
|
582
|
-
|
|
583
|
-
If the database guarantees one child row, encode that in Prisma.
|
|
584
|
-
|
|
585
|
-
This can let the planner avoid unnecessarily defensive high-fanout strategies.
|
|
586
|
-
|
|
587
|
-
#### 6) Keep nested filters sargable
|
|
588
|
-
|
|
589
|
-
Prefer predicates that use indexed equality/range conditions.
|
|
590
|
-
|
|
591
|
-
Better:
|
|
592
|
-
|
|
593
|
-
```ts
|
|
594
|
-
{
|
|
595
|
-
include: {
|
|
596
|
-
comments: {
|
|
597
|
-
where: {
|
|
598
|
-
postId: 42,
|
|
599
|
-
createdAt: { gte: someDate },
|
|
600
|
-
},
|
|
601
|
-
orderBy: { createdAt: 'desc' },
|
|
602
|
-
},
|
|
603
|
-
},
|
|
604
|
-
}
|
|
605
|
-
```
|
|
606
|
-
|
|
607
|
-
Less planner-friendly:
|
|
608
|
-
|
|
609
|
-
- broad `contains` / `%term%` everywhere
|
|
610
|
-
- unindexed OR-heavy nested filters
|
|
611
|
-
- deep includes without limits
|
|
612
|
-
|
|
613
537
|
### What to configure
|
|
614
538
|
|
|
615
539
|
Use the cardinality planner wherever your generator/runtime exposes it.
|
|
@@ -657,6 +581,65 @@ What good results look like:
|
|
|
657
581
|
- high-fanout includes stop exploding row counts
|
|
658
582
|
- moving a heavy include into `$batch` or splitting it improves latency materially
|
|
659
583
|
|
|
584
|
+
## Deployment without database access at build time
|
|
585
|
+
|
|
586
|
+
The cardinality planner collects relation statistics and roundtrip cost measurements directly from the database during `prisma generate`. In CI/CD pipelines or containerized builds, the database is often unreachable.
|
|
587
|
+
|
|
588
|
+
### Skip planner during generation
|
|
589
|
+
|
|
590
|
+
Set `PRISMA_SQL_SKIP_PLANNER=true` to skip stats collection at generate time. The generator will emit default planner values instead.
|
|
591
|
+
|
|
592
|
+
```bash
|
|
593
|
+
PRISMA_SQL_SKIP_PLANNER=true npx prisma generate
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
### Collect stats before server start
|
|
597
|
+
|
|
598
|
+
Run `prisma-sql-collect-stats` as a pre-start step, after deployment, when the database is reachable.
|
|
599
|
+
|
|
600
|
+
```bash
|
|
601
|
+
prisma-sql-collect-stats \
|
|
602
|
+
--output dist/prisma/generated/sql/planner.generated.js \
|
|
603
|
+
--prisma-client dist/prisma/generated/client/index.js
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
| Flag | Default | Description |
|
|
607
|
+
| ----------------- | -------------------------------------------------- | -------------------------------------------------------------- |
|
|
608
|
+
| `--output` | `./dist/prisma/generated/sql/planner.generated.js` | Path to the generated planner module |
|
|
609
|
+
| `--prisma-client` | `@prisma/client` | Path to the compiled Prisma client (must expose `Prisma.dmmf`) |
|
|
610
|
+
|
|
611
|
+
The script reads `DATABASE_URL` from the environment (supports `.env` via `dotenv`). If the connection fails or times out, it exits silently without blocking startup.
|
|
612
|
+
|
|
613
|
+
### Example scripts
|
|
614
|
+
|
|
615
|
+
```json
|
|
616
|
+
{
|
|
617
|
+
"prisma:generate": "PRISMA_SQL_SKIP_PLANNER=true prisma generate",
|
|
618
|
+
"collect-planner-stats": "prisma-sql-collect-stats --output dist/prisma/generated/sql/planner.generated.js --prisma-client dist/prisma/generated/client/index.js",
|
|
619
|
+
"start:production": "yarn collect-planner-stats; node dist/src/index.js"
|
|
620
|
+
}
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
The semicolon (`;`) after `collect-planner-stats` ensures the server starts even if stats collection fails. Use `&&` instead if you want startup to abort on failure.
|
|
624
|
+
|
|
625
|
+
### What happens with default planner values
|
|
626
|
+
|
|
627
|
+
When stats are not collected, the planner uses conservative defaults:
|
|
628
|
+
|
|
629
|
+
- `roundtripRowEquivalent`: 73
|
|
630
|
+
- `jsonRowFactor`: 1.5
|
|
631
|
+
- `relationStats`: empty (all relations treated as unknown cardinality)
|
|
632
|
+
|
|
633
|
+
This means the planner cannot make informed decisions about join strategies. Queries still work correctly — the planner falls back to safe general-purpose strategies — but relation-heavy reads may not use the optimal execution plan.
|
|
634
|
+
|
|
635
|
+
### Timeout control
|
|
636
|
+
|
|
637
|
+
Stats collection has a default timeout of 15 seconds. Override with:
|
|
638
|
+
|
|
639
|
+
```bash
|
|
640
|
+
PRISMA_SQL_PLANNER_TIMEOUT_MS=5000 yarn collect-planner-stats
|
|
641
|
+
```
|
|
642
|
+
|
|
660
643
|
### Practical recommendations
|
|
661
644
|
|
|
662
645
|
For best results with the planner:
|