Upstash RedisキャッシュでPrisma ORMのパフォーマンスを向上させる方法
前回のブログ記事では、キャッシュのメリット、一般的なキャッシュ手法、そしてUpstash Redisを使ってSQLデータをキャッシュする方法を、さまざまなコードサンプルとともに解説しました。
Upstash RedisによるSQLクエリのキャッシュについて、その詳細とメリットを確認したところで、今回はさらに一歩進めて実際の実装を見ていきましょう。そのためにまず、広く使われているORMであるPrismaを取り上げ、Upstash Redisによるキャッシュがデータベースクエリに対してどのように機能するかを確認します。
この記事では、Upstash RedisとPrismaを統合し、キャッシュアサイド(cache-aside)方式を使ってクエリをキャッシュすることで、データベースへの負荷を軽減し、アプリケーションのパフォーマンスを向上させる方法を解説します。
Prismaとは?
Prismaのセットアップに入る前に、いくつかの用語とPrismaの役割について確認しておきましょう。
まず、Prismaはオブジェクトリレーショナルマッパー(ORM)ツールであり、アプリケーションとデータベースの間のインターフェースを提供します。
ORMとは、開発者が生のSQLクエリを書く代わりに、高レベルなオブジェクト指向のコードを使ってデータベースとやり取りできるようにするプログラミング技法です。簡単に言えば、リレーショナルデータベースとオブジェクト指向プログラミング言語をつなぐ架け橋となります。
ORMはデータベースのテーブルをプログラミング言語のクラスやモデルにマッピングします。テーブルの各行はクラスのインスタンスに対応します。これは基本的に、オブジェクト指向言語で書かれたアプリケーションで行うデータモデリングそのものです。ORMはこれを自動的に処理し、SQLクエリを書く代わりにメソッドを提供してくれます。開発者はオブジェクトやクラスのメソッドを呼び出すだけで、CRUD操作を実行できます。
例えば、usersテーブルを生SQLでクエリすると、次のようになります。
SELECT * FROM users WHERE id = 1;
一方、ORMを使うと同じクエリは次のように書けます。
const user = await user.findUnique({ where: { id: 1 } });
このように、ORMはデータベースとのやり取りに必要な処理を担い、取得したデータを実行中のプログラム内で扱いやすい形に変換してくれるため、開発者にとって大きな利便性をもたらします。
Prismaは、ソフトウェアアプリケーションで最も広く使われている、使いやすいORMのひとつです。
Prismaが優れたORMの選択肢である理由を示すポイントをいくつか紹介します。
型安全なクエリ: Prismaはデータベーススキーマに基づいてTypeScriptクライアントを自動生成するため、ランタイムではなく開発段階でエラーを検出できます。
シンプルなデータモデリング:
schema.prismaファイルでは宣言的な構文でデータベース構造を定義でき、Prismaが必要なSQLやAPIコールへと変換してくれます。後ほど、このファイルでモデルを記述してテーブルを生成する例も見ていきます。マルチデータベース対応: PostgreSQL、MySQL、SQLite、MongoDBなど、主要なデータベースに対応しています。対応データベースの一覧はPrisma公式ドキュメントで確認できます。
マイグレーション管理: 使いやすいマイグレーションシステムにより、データベーススキーマとコードベースを常に同期できます。
さらにPrismaは、CLIやStudio(WebベースのデータベースGUI)も提供しており、データベース管理をより簡単に行えるようになっています。
Prismaのセットアップ
それでは、Prismaのインストール方法と、アプリケーションでの動作を見ていきましょう。
この記事の主眼はPrismaクエリのキャッシュなので、ここではローカル環境でごくシンプルなSQLiteデータベースを使い、Prismaの操作をデモンストレーションします。
まず、アプリがSQLiteデータベースに接続してやり取りできるよう、sqlite3をインストールしておきます。前述のとおり、SQLiteのセットアップはあくまでPrismaの動作確認のためのものです。他のデータベースを使いたい場合は、Prisma公式ドキュメントで各データベースタイプとの統合方法を確認してください。
ターミナルでプロジェクトディレクトリに移動し、SQLiteをインストールします。
npm install sqlite3
次に、Prisma ORMを利用できるようにするため、Prisma CLIをインストールします。
npm install prisma --save-dev
続いてPrismaを初期化します。この初期化により、schema.prismaファイルを含むprismaディレクトリが作成されます。schema.prismaファイルは、データベース構造(モデル、フィールドなど)を定義する場所です。
npx prisma init
それでは、Prismaスキーマを定義していきます。エディタでprisma/schema.prismaファイルを開いてください。
このファイルは3つのブロックで構成されています。最初のブロックはジェネレーター(generator)で、Node.jsアプリケーションで使用するクライアントを生成するようPrismaを設定します。2つ目はデータソース(datasource)ブロックで、Prismaが接続するために必要なデータベース情報を記述します。最後のブロックにはデータベースモデルを定義します。ここでテーブルとそのフィールド(データ型や制約を含む)を定義できます。
以下に例を示します。
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
model user {
id Int @id @default(autoincrement())
name String
email String @unique
age Int?
}
ご覧のとおり、データベースの種類を指定した上でURLを設定しています。なお、プロジェクトにDATABASE_URL環境変数を設定することを忘れないでください。他のデータベースタイプに接続する場合は、Prisma公式ドキュメントを参照してください。今回のサンプルケースでは、file:./dev.dbを設定すれば十分です。
さらに、カラムとその型・制約を定義することでuserテーブルを定義しています。必要に応じて、さまざまなデータベース型を使ったより高度なモデルを作成することもできますが、このデモではこの基本的なセットアップで進めます。
スキーマとデータベースを同期して必要なテーブルを作成するには、マイグレーションコマンドを実行します。--nameフラグでマイグレーションに名前を付けると、スキーマ変更の追跡が容易になります。
npx prisma migrate dev --name init
これで、Prisma ORMを使ったSQLiteデータベースの準備が整いました。
Upstash Redisのセットアップ
このセクションは最短で完了します。何度も繰り返してきた手順ですが、この記事を最初から最後まで通した完全なガイドにするため、ここでも手順を簡単に確認しておきます。すでに済ませた手順がある方は、必要なステップまで読み飛ばしても構いません。
UpstashコンソールからRedisデータベースを作成します。
「Create database」ボタンをクリックし、表示されるモーダルの手順を完了させてRedisデータベースを作成しましょう。
データベースのリージョンを選択する際は、Upstash Redisデータベースのリードレプリカ(read replicas)を選択することを忘れないでください。グローバルRedisのメリットについては、前回のブログ記事で詳しく解説しています。

これでRedisデータベースの準備ができました。Upstash Redisのセットアップで残っているのは、アプリケーション内でのRedisクライアントの初期化だけです。そのためには、まずUpstash Redis SDKをインストールします。
npm install @upstash/redis
続いて、UpstashコンソールからRedisのエンドポイントとトークンを取得します。そして、Upstash Redisに接続するコード内でRedisクライアントを設定します。
Upstash RedisでPrismaクエリをキャッシュする
冒頭で述べたとおり、ここではキャッシュアサイド(cache-aside)戦略を使用します。具体的には、まずキャッシュを確認し、指定されたクエリが要求するデータが存在するかどうかをチェックします。存在する場合は、Upstash Redisからデータを取得して返します。存在しない場合は、前のセクションで生成したPrismaクライアントを使ってSQLデータベースにクエリを実行し、取得したデータでキャッシュを更新します。
import { Redis } from '@upstash/redis';
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
const redis = new Redis({
url: '<UPSTASH-REDIS-ENDPOINT>',
token: '<UPSTASH-REDIS-TOKEN>',
})
async function getUser(userId: string) {
const cacheKey = `user:${userId}`;
// キャッシュを確認
const cachedUser = await redis.get(cacheKey);
if (cachedUser) {
console.log("Cache hit");
return JSON.parse(cachedUser);
}
// データベースにクエリ
console.log("Cache miss");
const user = await prisma.user.findUnique({
where: { id: userId },
});
// キャッシュに保存
if (user) {
await redis.set(cacheKey, JSON.stringify(user), { ex: 3600 }); // 1時間キャッシュ
}
return user;
}
この例からわかるように、クエリ条件を定義するパラメータを渡したprisma.<テーブル名>.findUnique()メソッドを使えば、コード形式でSQLデータベースにクエリを実行できます。
一例として、findMany()関数を使えば、userテーブルの全ユーザーを次のように取得できます。
const user = await prisma.user.findMany();
まとめ
この記事では、Prismaクエリをキャッシュするために、PrismaとUpstash Redisを統合する方法を解説しました。
PrismaもUpstash Redisも非常にシンプルで使いやすいツールです。開発者フレンドリーなアーキテクチャに加えて、両者とも大きな効果を発揮します。Prismaは、データベース管理をコーディング形式で可能にするマッピング機能のおかげで、膨大な開発時間を節約できます。また、Upstash RedisでPrismaクエリをキャッシュすることで、データ取得のレイテンシを大幅に削減し、アプリケーションのメインとなるSQLデータベースへの負荷も軽減できます。
この記事が皆さんのお役に立てば幸いです!
-
AWS LambdaとサーバーレスRedisで構築するReact Nativeアプリ:リーダーボード機能の実装ガイド
この記事では、React Native、Serverless Framework、Upstashを組み合わせて、リーダーボード(ランキング)の閲覧・更新ができるモバイルアプリケーションを開発する方法を解説します。 モバイルアプリの開発にはReact Nativeを使用し、バックエンドはServerless Frameworkで構築します。バックエンドは、AWS Lambda上で動作するPython関数で構成されています。 1. Upstash Redisを活用する 一般的なリーダーボードアプリでは、ユーザー情報と各ユーザーのスコアを保存する必要があります。これらのデータはスコア順にソートされる
-
Upstash for RedisでDenoアプリのパフォーマンスを向上させる:応答時間を大幅に短縮するサーバーレスキャッシュの実装
本記事では、Upstash for RedisとJavaScriptのPerformance APIを活用して、Denoアプリのパフォーマンスを最大限に引き出す方法を解説します。Upstash for Redisは、サーバーサイドキャッシュに最適なサーバーレスデータベースです。筆者が開発していたWebアプリは、初期サーバー応答時間(Initial Server Response Time)のスコアが低く、Lighthouseでは500ミリ秒と報告されていました。そこへUpstashのキャッシュを導入したところ、この数値を150ミリ秒未満まで削減し、監査にも合格できるようになりました。実は難しか