Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add repeated query #6815

Open
wants to merge 3 commits into
base: latest
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions optimize/optimize-repeated-query/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
DATABASE_URL=""
OPTIMIZE_API_KEY=""
5 changes: 5 additions & 0 deletions optimize/optimize-repeated-query/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules/
dist/
*.env
package-lock.json
prisma/migrations
183 changes: 183 additions & 0 deletions optimize/optimize-repeated-query/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
# Prisma Optimize Example: Applying the "Repeated query" Recommendation

This repository demonstrates how to use [Prisma Optimize](https://pris.ly/optimize) to improve query performance using the "Repeated query" recommendation.

## Prerequisites

To successfully run the project, you will need the following:

1. A **database connection string** supported by Prisma Optimize and Prisma Accelerate.
2. An Optimize API key, which you can obtain from your [Prisma Data Platform](https://pris.ly/pdp) account.
3. An Accelerate API key, which you can obtain from your [Prisma Data Platform](https://pris.ly/pdp) account.

## Getting started

### 1. Clone the repository

Clone the repository, navigate into it, and install the dependencies:

```bash
git clone [email protected]:prisma/prisma-examples.git --depth=1
cd prisma-examples/optimize/optimize-repeated-query
npm install
```

### 2. Configure environment variables

Create a `.env` file in the root of the project directory:

```bash
cp .env.example .env
```

Next, open the `.env` file and update the `DATABASE_URL` with your database connection string and the `OPTIMIZE_API_KEY` with your Optimize API key:

```env
# .env
DATABASE_URL="__YOUR_DATABASE_CONNECTION_STRING__"
# Replace __YOUR_DATABASE_CONNECTION_STRING__ with your actual connection string.
OPTIMIZE_API_KEY="your_secure_optimize_api_key"
```

- `DATABASE_URL`: The connection string to your database.
- `OPTIMIZE_API_KEY`: Reference the [Environment API Keys](https://www.prisma.io/docs/platform/about#environment) section in our documentation to learn how to obtain an API key for your project using Optimize.

### 3. Set up the project

Perform a database migration to prepare the project:

```bash
npx prisma migrate dev --name init
```

### 4. Open the Optimize dashboard

You can create [recordings](https://pris.ly/optimize-recordings) and view detailed insights into your queries, along with optimization [recommendations](https://pris.ly/optimize-recommendations), in the Optimize dashboard. To access the dashboard:

1. Log in to your [Prisma Data Platform](https://console.prisma.io/optimize) account. If you haven't already, complete the onboarding process for Optimize by clicking the **Get Started** button.
2. If Optimize hasn't been launched yet, click the **Launch Optimize** button.
3. If you want to use a different workspace, navigate to your desired [Workspace](https://www.prisma.io/docs/platform/about#workspace), click the **Optimize** tab on the left sidebar to open the Optimize dashboard. Then, if Optimize is not yet launched, click the **Launch Optimize** button.

### 5. Run the script

Let's run the [script with unoptimized Prisma queries](./script.ts):

1. In the Optimize dashboard, click the **Start new recording** button.
2. In the project terminal, run the project with:

```bash
npm run dev
```

3. After the script completes, you'll see a log saying "Done." Then, in the Optimize dashboard, click the **Stop recording** button.
4. Observe the queries with high latencies highlighted in red, and review the recommendations in the **Recommendations** tab. You should see the recommendation:
- **Repeated query**
> For more insights on this recommendation, click the **Ask AI** button and interact with the [AI Explainer](https://pris.ly/optimize-ai-chatbot) chatbot.
5. To create a reference for comparison with other recordings, rename the recording to _Unoptimized queries_ by clicking the green recording label chip in the top left corner and typing "Unoptimized queries".

![Rename recording](./images/edit-recording-name-chip.png)

### Add Prisma Accelerate to the project

To apply the recommendation, you need to add Prisma Accelerate to the project. To do that:

1. Use your database connection string and enable Prisma Accelerate in your [Prisma Data Platform account](https://pris.ly/pdp).
2. Install the required dependencies:
```bash
npm install @prisma/client@latest @prisma/extension-accelerate
```
3. Update [the database connection string to use the Accelerate connection string](https://www.prisma.io/docs/accelerate/getting-started#21-update-your-database-connection-string).
4. Regenerate `PrismaClient`:
```bash
npx prisma generate --no-engine
```
5. Extend `PrismaClient` by using the Accelerate client extension in [utils/db.ts](./utils/db.ts) folder:
```diff
import { PrismaClient } from '@prisma/client'
+ import { withAccelerate } from '@prisma/extension-accelerate'
import { withOptimize } from '@prisma/extension-optimize'

export const prisma = new PrismaClient().$extends(
withOptimize({
apiKey: process.env.OPTIMIZE_API_KEY!,
}),
)
+ .$extends(withAccelerate());
```

Afterward, continue with the next steps to complete the recommendation.

### Optimize example: Applying the "Repeated query" recommendation

Next, let’s follow the recommendation provided by Optimize to improve the performance of the queries:

1. To enhance the performance of [**Query 1**](./script.ts) through [**Query 5**](./script.ts) by addressing the "Repeated query" recommendation, add a [cache strategy](https://prisma.io/docs/accelerate/caching) to the queries:

```diff
// Query 1
await prisma.user.findFirst({
select: {
name: true,
},
+ cacheStrategy: {
+ ttl: 120
+ }
})

// Query 2
await prisma.user.findFirst({
select: {
name: true,
},
+ cacheStrategy: {
+ ttl: 120
+ }
})

// Query 3
await prisma.user.findFirst({
select: {
name: true,
},
+ cacheStrategy: {
+ ttl: 120
+ }
})

// Query 4
await prisma.user.findFirst({
select: {
name: true,
},
+ cacheStrategy: {
+ ttl: 120
+ }
})

// Query 5
await prisma.user.findFirst({
select: {
name: true,
},
+ cacheStrategy: {
+ ttl: 120
+ }
})
```
2. Click the **Start new recording** button to begin a new recording and check for any performance improvements.
3. In the project terminal, run the project with:
```bash
npm run dev
```
4. After the script completes, click the **Stop recording** button.
5. Rename the recording to _Optimized queries_ by clicking the recording chip in the top left corner and typing "Optimized queries."

You can now compare performance improvements by navigating to the "Optimized queries" and "Unoptimized queries" recording tabs and observing the query latency differences.

---

## Next steps

- Check out the [Optimize docs](https://pris.ly/d/optimize).
- Share your feedback on the [Prisma Discord](https://pris.ly/discord/).
- Create issues and ask questions on [GitHub](https://github.com/prisma/prisma/).
10 changes: 10 additions & 0 deletions optimize/optimize-repeated-query/environment.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
declare global {
namespace NodeJS {
interface ProcessEnv {
DATABASE_URL: string
OPTIMIZE_API_KEY: string | undefined
}
}
}

export {}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 21 additions & 0 deletions optimize/optimize-repeated-query/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "script",
"license": "MIT",
"scripts": {
"dev": "ts-node ./script.ts"
},
"dependencies": {
"@faker-js/faker": "9.0.3",
"@prisma/client": "5.20.0",
"@prisma/extension-optimize": "1.0.1",
"@types/node": "20.16.11"
},
"devDependencies": {
"prisma": "5.20.0",
"ts-node": "10.9.2",
"typescript": "5.6.3"
},
"prisma": {
"seed": "ts-node ./prisma/seed.ts"
}
}
26 changes: 26 additions & 0 deletions optimize/optimize-repeated-query/prisma/schema.prisma
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
generator client {
provider = "prisma-client-js"
previewFeatures = ["tracing"]
}

datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}

model User {
id Int @id @default(autoincrement())
email String @unique
name String?
posts Post[]
}

model Post {
id Int @id @default(autoincrement())
title String
content String?
published Boolean @default(false)
author User? @relation(fields: [authorId], references: [id])
authorId Int?
}

45 changes: 45 additions & 0 deletions optimize/optimize-repeated-query/prisma/seed.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { PrismaClient } from '@prisma/client'
import { faker } from '@faker-js/faker'

const prisma = new PrismaClient()
const TOTAL = 5000

const main = async () => {
await prisma.post.deleteMany({})
await prisma.user.deleteMany({})

for (let index = 0; index < TOTAL - 1; index++) {
await prisma.user.create({
data: {
email: `${Math.round(Math.random() * 1000)}${faker.internet.email()}`,
name: faker.internet.displayName(),
posts: {
create: {
title: faker.lorem.sentences(1),
content: faker.lorem.text(),
published: faker.datatype.boolean(),
},
},
},
})

console.log(`Inserted ${index + 1}/${TOTAL} item.`)
}

await prisma.user.create({
data: {
name: 'Nikolas Burk',
email: '[email protected]',
posts: {
create: {
title: 'The great gatsby',
content: 'The story had a nice ending.',
},
},
},
})

console.log(`Inserted ${5000}/${TOTAL} item.`)
}

main().then(() => console.log('🌿 Seeding completed.'))
57 changes: 57 additions & 0 deletions optimize/optimize-repeated-query/script.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { prisma } from './utils'

// A `main` function so that we can use async/await
async function main() {
// A simple query to create the database connection as the database connection usually takes a lot of time
await prisma.post.findFirst({
select: {
id: true,
},
})

// Query 1
await prisma.user.findFirst({
select: {
name: true,
},
})

// Query 2
await prisma.user.findFirst({
select: {
name: true,
},
})

// Query 3
await prisma.user.findFirst({
select: {
name: true,
},
})

// Query 4
await prisma.user.findFirst({
select: {
name: true,
},
})

// Query 5
await prisma.user.findFirst({
select: {
name: true,
},
})
}

main()
.then(async () => {
await prisma.$disconnect()
console.log('Done')
})
.catch(async (e) => {
console.error(e)
await prisma.$disconnect()
process.exit(1)
})
9 changes: 9 additions & 0 deletions optimize/optimize-repeated-query/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"compilerOptions": {
"sourceMap": true,
"outDir": "dist",
"strict": true,
"lib": ["esnext"],
"esModuleInterop": true
}
}
8 changes: 8 additions & 0 deletions optimize/optimize-repeated-query/utils/db.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { PrismaClient } from '@prisma/client'
import { withOptimize } from '@prisma/extension-optimize'

export const prisma = new PrismaClient().$extends(
withOptimize({
apiKey: process.env.OPTIMIZE_API_KEY!,
}),
)
1 change: 1 addition & 0 deletions optimize/optimize-repeated-query/utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './db'
2 changes: 2 additions & 0 deletions optimize/optimize-select-returning-all/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
DATABASE_URL=""
OPTIMIZE_API_KEY=""
5 changes: 5 additions & 0 deletions optimize/optimize-select-returning-all/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules/
dist/
*.env
package-lock.json
prisma/migrations
Loading