IlmHamroh
JavaScript Full-stack/27-qism. Ma'lumotlar bazasi chuqur: Postgres, ORM, Mongo, Redis28/65-dars16 daqiqa
Mundarija (30)

Prisma prodakshnda: query log, relationLoadStrategy, N+1, hovuz va o'rnatish hajmi

Qisqacha: Prisma'ni prodakshnda ishlatishdan oldin uch narsani ko'rinadigan qiling: SQL (log hodisasi — so'rov, parametrlar, ms), so'rovlar soni (N+1 — siklda so'rov; biz o'lchadik: 9 SQL o'rniga _count bilan 1) va ulanishlar (adapter hovuzi). relationLoadStrategy: "join" (preview relationJoins) relation'larni bitta LATERAL JOIN bilan oladi. Bir tick'dagi findUnique lar avtomatik bitta IN (…) so'roviga birlashadi. Kanon o'lchovi: Prisma bilan prod node_modules 330 MB, --omit=optional bilan 89 MB; 26-qismdagi pg varianti — 15 MB.

Bu darsda

  • Prisma yuborgan har SQL'ni, parametrlarini va davomiyligini log'ga chiqarasiz.
  • relationLoadStrategy ning ikki rejimini SQL darajasida solishtirasiz.
  • N+1 ni topasiz va tuzatasiz; findUnique batching'idan foydalanasiz.
  • Hovuzni adapter orqali sozlaysiz; serverless'dagi ulanish muammosini tushuntirasiz.
  • Prisma Studio, prisma db seed, Accelerate/Optimize nima ekanini bilasiz.
  • Prod o'rnatish hajmini 330 MB dan 89 MB ga tushirasiz.

Oldin bilishingiz kerak: Prisma Client extensions, N+1 muammosi, Connection pooling, PgBouncer va tashqi poolerlar, Sekin so'rovlarni topish.

1. Nega bu kerak?

Lokal kompyuterda hamma narsa tez: 48 ta vazifa, bitta foydalanuvchi. Prodakshnda esa 500 000 vazifa, yuzlab parallel so'rov va bir nechta server nusxasi. ORM qulayligi shu yerda ko'rinmas narxga aylanadi: bir qator kod o'nlab SQL yuboradi, har nusxa o'z hovuzini ochadi, Docker image yuzlab megabayt o'sadi.

N+1 muammosi darsida bu tuzoqni pg bilan ko'rgan edik. Prisma'da u yashirinroq: include va sikl ichidagi await bir xil ko'rinadi, lekin SQL soni butunlay boshqa.

O'xshatish: mashina sotib olganda faqat tezligiga emas, yoqilg'i sarfiga ham qaraysiz. Prisma — qulay mashina; bu dars uning "yoqilg'i hisoblagichi"ni o'rnatadi.

Chiqishlarni biz ishga tushirdik: PostgreSQL 17.6, holat 20 namunasi, Prisma 7.10.1 (relationJoins yoqilgan tajriba nusxasi), Node 24.21.0. Hajm va tezlik o'lchovlari — kanondan (PostgreSQL 18.6, katta bazasi, 500 000 vazifa).

2. Ko'rinadigan qilish: query log

2.1 log sozlamasi

ts
const db = new PrismaClient({
  adapter,
  log: [
    { emit: "event", level: "query" },
    { emit: "stdout", level: "warn" },
    { emit: "stdout", level: "error" },
  ],
});
db.$on("query", (e) => {
  logger.debug({ sql: e.query, params: e.params, ms: e.duration });
});

Daraja to'rtta: query, info, warn, error. emit: "stdout" — Prisma o'zi konsolga yozadi; emit: "event" — siz $on bilan ushlab, o'z logger'ingizga (25-qismdagi Pino) yuborasiz. $on("query") ning turi faqat log da query hodisasi e'lon qilinganda to'g'ri chiqadi.

Bitta findFirst hodisasi:

text
sql, params, ms | duration turi: number
SQL: SELECT "t0"."id" FROM "vazifalar" AS "t0" WHERE ("t0"."egasi_id" = $1 AND "t0"."bajarildi" = $2) LIMIT $3
params: ["3",false,"1"]

params — JSON satri, ichida haqiqiy qiymatlar. Prodakshnda bu ma'lumot oqishi: parol hash'i, email, token log'ga tushadi. Qoida — query darajasi dev'da yoqiladi; prodda faqat sekin so'rovlar (e.duration > 200) va parametrlarsiz.

Diqqat: SQL'dagi "t0" taxalluslariga qarang — oldingi darslarda "vazifalar"."id" edi. Bu nusxada relationJoins preview yoqilgani uchun Prisma oddiy so'rovlarni ham boshqacha yasadi. Preview imkoniyat faqat bitta joyga emas, hamma so'rovga ta'sir qilishi mumkin — yoqishdan oldin to'liq test.

2.2 Bazaning o'zi ham ko'radi

Prisma log'i "ilova nima yubordi"ni ko'rsatadi. "Baza qancha vaqt sarfladi" — pg_stat_statements (Sekin so'rovlarni topish). Prisma SQL'ni parametrli yuborgani uchun u yerda bir xil so'rovlar bitta qatorga yig'iladi — "qaysi so'rov eng ko'p vaqt yeydi" darhol ko'rinadi. Hovuzni o'zimiz yaratganimiz uchun application_name: "vazifalar-api" ham beriladi (Prisma Client CRUD, «Loyiha qadami») — pg_stat_activity da API ulanishlari ajralib turadi.

3. Relation'lar: alohida so'rovlar yoki JOIN

3.1 Sukut: query strategiyasi

Prisma: relations darsida ko'rgandik: include har relation uchun alohida SQL yuboradi. Prisma hujjatida bu relationLoadStrategy: "query". Kanon Prisma 7.10 da "join" ni sinab ko'rganda:

text
" Unknown argument `relationLoadStrategy`. Available options are marked with ?."

Ya'ni bu parametr faqat previewFeatures = ["relationJoins"] yoqilganda bor.

3.2 join strategiyasi

Biz tajriba nusxasida relationJoins ni yoqdik va bir xil so'rovni ikki rejimda yubordik — Sardor va uning 2 ta vazifasi:

ts
const tanlov = {
  where: { id: 3n },
  select: {
    ism: true,
    vazifalar: {
      take: 2,
      orderBy: { id: "asc" as const },
      select: { matn: true },
    },
  },
};
await db.foydalanuvchi.findUnique({
  ...tanlov, relationLoadStrategy: "query",
});
await db.foydalanuvchi.findUnique({
  ...tanlov, relationLoadStrategy: "join",
});

Chiqishda ikki narsaga qarang: har rejim nechta SQL yubordi va join qatorida LEFT JOIN LATERAL qayerda turibdi (uzun qatorlar telefonda yonga suriladi).

text
query: 2 ta SQL
  SQL: SELECT "foydalanuvchilar"."id", "foydalanuvchilar"."ism" FROM "foydalanuvchilar" WHERE (…) LIMIT $2 OFFSET $3
  SQL: SELECT "vazifalar"."id", "vazifalar"."matn", "vazifalar"."egasi_id" FROM "vazifalar" WHERE "vazifalar"."egasi_id" = $1 ORDER BY "vazifalar"."id" ASC LIMIT $2 OFFSET $3
join: 1 ta SQL
  SQL: SELECT "t0"."id", "t0"."ism", "Foydalanuvchi_vazifalar"."__prisma_data__" AS "vazifalar" FROM "foydalanuvchilar" AS "t0" LEFT JOIN LATERAL (SELECT COALESCE(JSONB_AGG("__prisma_data__"), '[]') AS "__prisma_data__" FROM (… JSONB_BUILD_OBJECT('matn', "t2"."matn") … ORDER BY "t3"."id" ASC LIMIT $1 …) AS "t4") AS "Foydalanuvchi_vazifalar" ON true WHERE ("t0"."id" = $2 AND 1=1) LIMIT $3
{"ism":"Sardor Tursunov","vazifalar":[{"matn":"Mashinani texnik ko'rikka olib borish #mashina"},{"matn":"Moy almashtirish #mashina"}]}

Nima bo'ldi? query rejimi ikki so'rov yubordi: avval foydalanuvchi, keyin uning vazifalari — ularni Prisma JavaScript'da birlashtirdi. join — bitta so'rov: LEFT JOIN LATERAL (Subquery va LATERAL) va natijani Postgres'ning o'zida JSON'ga yig'ish (JSONB_AGG). Oxirgi qatordagi natija ikkala rejimda bir xil.

flowchart LR
  subgraph Q["query (sukut)"]
    Q1["SELECT foydalanuvchi"] --> Q2["SELECT vazifalar IN (…)"]
    Q2 --> Q3["JS'da birlashtirish"]
  end
  subgraph J["join (relationJoins)"]
    J1["SELECT … LEFT JOIN LATERAL<br/>JSONB_AGG"] --> J2["tayyor JSON"]
  end

Diagrammaga qarang: chapda ikki tarmoq aylanishi (round trip) va JavaScript'da yig'ish, o'ngda bitta aylanish va Postgres'da yig'ish.

Qaysi biri tez? Bu holatga bog'liq: baza uzoqda bo'lsa (har aylanish 20–50 ms, masalan boshqa regiondagi managed baza), join sezilarli yutadi. Baza yonida bo'lsa va relation katta bo'lsa, JSON yig'ish narxi farqni yeyishi mumkin. Biz bu ikki rejim tezligini o'lchamadik — preview imkoniyatni loyihaga kiritmadik. Qaror — EXPLAIN va o'z o'lchovingiz bilan.

4. So'rovlar soni: N+1 va batching

4.1 N+1 siklda

Har foydalanuvchining vazifalar sonini sanash — ikki usul:

ts
// ❌ siklda so'rov
const egalar = await db.foydalanuvchi.findMany({
  select: { id: true },
});
for (const e of egalar) {
  await db.vazifa.count({ where: { egasiId: e.id } });
}
// ✅ bitta so'rov
await db.foydalanuvchi.findMany({
  select: { id: true, _count: { select: { vazifalar: true } } },
});
text
sikl (count har biriga): 9 ta SQL
_count bilan: 1 ta SQL

8 foydalanuvchi — 1 + 8 = 9 SQL. 1 000 foydalanuvchida — 1 001. Har biri 1 ms bo'lsa ham, tarmoq aylanishlari bilan sekundga yetadi. Bunday kodni log'dan topish oson: bir xil SQL shablon ketma-ket ko'p marta (2-mashq).

4.2 findUnique batching

Tick — event loop ning bitta aylanishi: sinxron kod va shu paytgacha yig'ilgan microtask'lar bajariladigan oraliq. Prisma'ning ichida kichik "dataloader" (so'rovlarni yig'ib, bittaga birlashtiruvchi) bor: bir tick'da kelgan bir xil shakldagi findUnique lar bitta so'rovga birlashadi.

ts
await Promise.all([1n, 2n, 3n, 4n, 5n, 6n, 7n, 8n].map((id) =>
  db.foydalanuvchi.findUnique({
    where: { id }, select: { ism: true },
  })));
await Promise.all([1n, 2n, 3n, 4n].map((id) =>
  db.foydalanuvchi.findFirst({
    where: { id }, select: { ism: true },
  })));
text
Promise.all findUnique x8: 1 ta SQL
  SQL: SELECT "t0"."id", "t0"."ism" FROM "foydalanuvchilar" AS "t0" WHERE "t0"."id" IN ($1,$2,$3,$4,$5,$6,$7,$8)
  params: ["1","2","3","4","5","6","7","8"]
Promise.all findFirst x4: 4 ta SQL

8 ta findUnique — bitta IN (…). findFirst — batching'siz, 4 ta SQL. Qadamma-qadam:

Qadam Kod Prisma SQL
1 Promise.all 8 ta findUnique ni boshlaydi so'rovlarni navbatga yig'adi hali yo'q
2 tick tugadi 8 ta id ni bitta IN ga birlashtiradi 1 ta
3 natija keldi har qatorni o'z chaqiruviga qaytaradi —
4 for … await siklida har chaqiruv alohida tick'da har biriga 1 ta
Bu GraphQL'da (har maydon alohida resolver) N+1'ni avtomatik yumshatadi. Lekin faqat Promise.all kabi parallel chaqiruvda: for … await siklida har so'rov alohida tick'da — batching yo'q.

Tekshirib ko'ring: Nega 8 ta findUnique bitta so'rov bo'ldi-yu, 4 ta findFirst bo'lmadi?

Javob

findUnique noyob kalit bo'yicha — har natija aniq bitta yozuvga mos keladi, Prisma IN natijasini qaysi chaqiruvga qaytarishni biladi. findFirst istalgan shart bilan, orderBy va boshqa argumentlar bilan bo'lishi mumkin — ularni xavfsiz birlashtirib bo'lmaydi.

4.3 Kerakli ustunlar

Azizning 13 vazifasi — hamma ustun va faqat id, matn:

text
hamma ustun: 4216 bayt JSON | select: 717 bayt JSON

6 baravar. API javobi, tarmoq va xotira — hammasi shunga mutanosib. select (yoki global omit) — prodakshn odati (Prisma Client CRUD).

5. Ulanishlar: hovuz, serverless, pooler

5.1 Hovuz adapter orqali

Prisma 7 da ulanishlar — pg.Pool ning ishi. new PrismaPg({ connectionString, max: 10 }) yoki tayyor pg.Pool (Prisma Client CRUD, «Loyiha qadami»). pg sukutlari (node-postgres hujjati, 2026-10-25): max 10, connectionTimeoutMillis 0 — ya'ni ulanish bo'shashini cheksiz kutadi. Shuning uchun kanon 5 000 ms beradi: hovuz to'lsa, so'rov osilib qolmasdan xato beradi (Connection pooling).

Hovuz hajmining ta'siri — 10 ta parallel pg_sleep(0.1):

text
10 x pg_sleep(0.1), max 2: 600 ms atrofida
10 x pg_sleep(0.1), max 10: 400 ms atrofida

max: 2 — so'rovlar navbatda: 5 ta "to'lqin" × 100 ms + ulanish ochish. max: 10 — hammasi bir vaqtda, lekin 10 ta yangi ulanishni ochish vaqti qo'shildi (birinchi ishga tushirishda). Bitta o'lchov, yuklangan mashina — faqat tendensiyani ko'rsatadi.

5.2 Serverless

Serverless (AWS Lambda, Vercel Functions) — har so'rov alohida "nusxa"da ishlashi mumkin, nusxalar soni yuzlab. Har nusxada hovuz max: 10 bo'lsa — 100 nusxa × 10 = 1 000 ulanish, Postgres esa sukut 100 tani ko'taradi (Postgres arxitekturasi). Yechimlar (Prisma hujjati, sinalmagan): nusxa boshiga max: 1, oldida tashqi pooler — PgBouncer transaction rejimi (PgBouncer va tashqi poolerlar) yoki provayder pooleri (Neon, Supabase), yoki HTTP orqali ulanadigan adapterlar (@prisma/adapter-neon kabi). Transaction pooler bilan sessiya darajasidagi narsalar (SET va prepared statement) ishlamasligi mumkin — 26-qismda ko'rgan cheklovlar. Managed va serverless Postgres — alohida dars.

5.3 Accelerate va Optimize

Prisma kompaniyasining bulut xizmatlari (prisma.io, 2026-10): Accelerate — global ulanish hovuzi va so'rov keshi. Optimize — so'rovlarni tahlil qilib tavsiya beradigan vosita edi; Prisma blogiga ko'ra u 2026-yil mart oyida yopildi (sunset) va o'rnini Prisma Postgres ichidagi Query Insights egalladi. Eski loyihada @prisma/extension-optimize va withOptimize() ni ko'rsangiz — bu o'sha yopilgan xizmat, uni olib tashlash mumkin. Bu xizmatlar hisob ochishni talab qiladi — kanon ham, biz ham sinamadik. Ular ixtiyoriy: shu darsdagi log, pg_stat_statements va o'z hovuzingiz bilan ko'p muammolar bepul hal bo'ladi.

6. Vositalar: Studio va seed

  • Prisma Studio — npx prisma studio brauzerda jadvallarni ko'rish va tahrirlash interfeysini ochadi (lokal). Dev'da qulay; prod bazaga ulamang — u to'g'ridan yozadi, auditsiz. Biz uni bu darsda ochmadik (GUI); hujjat bo'yicha.
  • prisma db seed — prisma.config.ts dagi migrations.seed buyrug'ini bajaradi. Deterministik, idempotent seed va production'da ishlamaslik himoyasi — Seeding va test ma'lumotlari (holat 39).

7. O'rnatish hajmi va ishga tushish

7.1 330 MB dan 89 MB gacha

Kanon prod o'rnatishni (npm ci --omit=dev) o'lchadi. Chiqishda node_modules hajmiga va "prisma CLI: bor" kabi qatorlarga qarang — prodda ular bo'lmasligi kerak edi:

text
=== 26 kanoni (pg, Prisma'siz)
added 97 packages in 5s
node_modules: 15M; @prisma: ; prisma CLI: yo'q; typescript: yo'q; react-dom: yo'q
=== 27 holat 20 (Prisma 7)
added 238 packages in 27s
node_modules: 330M; @prisma: 146M; prisma CLI: bor; typescript: bor; react-dom: bor
@prisma/client peerDependencies: {"prisma":"*","typescript":">=5.4.0"}
node_modules/prisma {"devOptional":true}
node_modules/typescript {"devOptional":true}
node_modules/react-dom {"peer":true,"devOptional":true}

--omit=dev bilan ham prisma CLI, TypeScript va hatto react-dom o'rnatildi! Sababi: @prisma/client ularni ixtiyoriy peer sifatida e'lon qilgan, package-lock.json da devOptional: true — npm ularni "dev yoki optional" deb biladi va --omit=dev bilan chiqarmaydi. --omit=peer ham yordam bermadi (322 MB). Yechim:

text
$ npm ci --omit=dev --omit=optional   (/tmp/kanon27/prod-sinov)
added 105 packages in 5s
node_modules: 89M; @prisma: 72M; prisma CLI: yo'q; typescript: yo'q; react-dom: yo'q

89 MB — shundan 72 MB @prisma/client ning o'zi (hamma provayderlar uchun runtime). Docker image o'lchami 33-qismda yana ko'riladi; hozir qoida: prod o'rnatish — npm ci --omit=dev --omit=optional, va undan keyin ilova haqiqatan ishga tushishini tekshiring (ba'zi paketlar ixtiyoriy bog'liqlikka tayanadi).

7.2 Modul yuklash vaqti

Kanon src/ishga-tushir.ts ni import qilish vaqtini o'lchadi (prod node_modules, Windows):

text
  import #1: 598 ms
  import #2: 620 ms
  import #3: 576 ms
  faqat pg import #1: 183 ms
  faqat pg import #2: 178 ms

Prisma bilan ~0.6 s, pg bilan ~0.18 s. Doimiy server uchun bu ahamiyatsiz — bir marta. Serverless'da esa har "sovuq start" ga qo'shiladi. (Kanon server ishga tushishi va o'chishini ham o'lchamoqchi bo'lgan, lekin Windows'da jarayon osilib qolgan — o'lchov ishonchsiz deb olib tashlangan.)

7.3 So'rov tezligi

Bir xil VazifaOmbori — PgOmbori va PrismaOmbori (kanon, katta, egasi 77, mediana 50):

Bir xil so'rov: pg va Prisma (ms, mediana)
  • ro'yxat 50 — pg3,65 ms
  • ro'yxat 50 — prisma4,43 ms
  • teg filtri — pg7,33 ms
  • teg filtri — prisma8,36 ms
  • matn saralash — pg5,42 ms
  • matn saralash — prisma12,07 ms

Manba: Kanon o'lchovi: PostgreSQL 18.6, 500 000 vazifa, egasi 77, mediana 50 (2026-10-25)

Oddiy so'rovlarda farq 1 ms atrofida. Eng katta farq — matn bo'yicha saralash (12.07 ms): u yerda Prisma ikki so'rov qiladi (id'lar + raw SQL, raw SQL darsi). Yozuvlarda: 200 ta yangila — pg 2 842 ms, prisma 4 051 ms (har yozuvga uch so'rov). Xulosa: Prisma tezlikni o'zi "yemaydi" — qo'shimcha so'rovlar yeydi. Ularni log'da ko'rib, kerak joyda raw SQL ga o'tish — prodakshn ishi.

8. Ko'p uchraydigan xatolar

Belgi Sabab Davosi
sahifa sekin, log'da bir xil SQL 100 marta N+1 siklda include/_count, IN, batching
too many clients serverless'da har nusxa o'z hovuzi max: 1 + pooler
so'rov osilib qoldi connectionTimeoutMillis 0 aniq timeout
log'da email/token query + params prodda prodda faqat sekin so'rovlar, parametrsiz
image 330 MB ixtiyoriy peer'lar (devOptional) --omit=dev --omit=optional
Unknown argument relationLoadStrategy preview yoqilmagan previewFeatures = ["relationJoins"]
Failed to deserialize column of type 'void' $queryRaw da pg_sleep SELECT 1 FROM pg_sleep(…)

9. Mashqlar

Mashqlar kurs/mashqlar/27/28-prisma-prod/ da. 2-mashq yechimi Node 24 da tekshirilgan (bazasiz).

1-mashq (oson): to'ldiring

  • Parametrlarni ham ko'rsatadigan log hodisasi — $on("")
  • Bitta tick'dagi qaysi metod chaqiruvlari bitta IN ga birlashadi —
  • Relation'larni bitta LATERAL JOIN bilan olish — relationLoadStrategy: ""
  • Prisma'li prod o'rnatishni 89 MB ga tushiradigan bayroq — --omit=
Yechim
  • query — e.query, e.params, e.duration.
  • findUnique — findFirst birlashmaydi.
  • join — relationJoins preview bilan.
  • optional — --omit=dev bilan birga.

2-mashq (o'rta): N+1 detektori

Query log'dan yig'ilgan SQL satrlari massivini oladigan n1Top(sorovlar, chegara) funksiyasini yozing. U bir xil shablondagi so'rovlarni sanasin (shablon — $1, $2 kabi parametr raqamlari va raqamli literallar ? bilan almashtirilgan matn) va chegara dan ko'p takrorlanganlarini { shablon, soni } ko'rinishida, kamayish tartibida qaytarsin.

Yechim
js
function shablon(sql) {
  return sql.replace(/\$\d+/g, "?").replace(/\b\d+\b/g, "?");
}

function n1Top(sorovlar, chegara) {
  const hisob = new Map();
  for (const s of sorovlar) {
    const k = shablon(s);
    hisob.set(k, (hisob.get(k) ?? 0) + 1);
  }
  return [...hisob]
    .filter(([, n]) => n > chegara)
    .map(([k, n]) => ({ shablon: k, soni: n }))
    .sort((a, b) => b.soni - a.soni);
}

const log = [
  'SELECT "id" FROM "foydalanuvchilar" OFFSET $1',
  ...Array.from({ length: 8 }, () =>
    'SELECT COUNT(*) FROM "vazifalar" ' +
    'WHERE "egasi_id" = $1 OFFSET $2'),
  'SELECT 1',
];
console.log(n1Top(log, 3));

Konsolda:

text
[
  {
    shablon: 'SELECT COUNT(*) FROM "vazifalar" WHERE "egasi_id" = ? OFFSET ?',
    soni: 8
  }
]

Bu — «N+1 siklda» bo'limidagi 9 ta SQL'ning modeli: 8 marta takrorlangan COUNT shabloni ushlandi. Haqiqiy ilovada n1Top ni har HTTP so'rov oxirida (log'ni AsyncLocalStorage bilan har so'rov uchun yig'ib) dev rejimida chaqirib, ogohlantirish chiqarish mumkin.

3-mashq (qiyin): include bilan N+1 ni tuzatish

Quyidagi kod har vazifa uchun egasining ismini alohida so'raydi. Uni bitta findMany + select bilan qayta yozing va log'da SQL sonini solishtiring (o'z bazangizda).

ts
const vazifalar = await db.vazifa.findMany({
  where: { egasiId: 1n }, select: { id: true, egasiId: true },
});
for (const v of vazifalar) {
  const e = await db.foydalanuvchi.findFirst({
    where: { id: v.egasiId }, select: { ism: true },
  });
  console.log(v.id, e?.ism);
}
Yechim
ts
const vazifalar = await db.vazifa.findMany({
  where: { egasiId: 1n },
  select: { id: true, egasi: { select: { ism: true } } },
});
for (const v of vazifalar) console.log(v.id, v.egasi.ism);

Biz ishga tushirdik: asl kod — 14 SQL (1 + 13, findFirst batching'siz). Yangisi — 2 SQL (query strategiyasida — vazifalar va IN (…) bilan egalar) yoki relationJoins bilan 1. findFirst o'rniga findUnique qo'yib ham sinadik: for … await siklida baribir 13 ta alohida SQL (har chaqiruv alohida tick'da), Promise.all bilan esa 1 ta. Eng to'g'risi — relation'ni so'rovning o'zida olish.

10. Loyiha qadami: kanon tajribasi, loyihaga kirmaydi

Bu darsda vazifalar-api kodi o'zgarmaydi. Kanon o'lchovlari va qarorlari:

  1. Hovuz — holat 20 da allaqachon prodakshn shaklida: o'z pg.Pool imiz (application_name, idleTimeoutMillis 30 s, connectionTimeoutMillis 5 s, statement_timeout, error → Pino) PrismaPg ga beriladi.
  2. Query log API'ga qo'shilmadi: API'da allaqachon Pino so'rov log'i (pino-http, 25-qism) bor; SQL darajasida — pg_stat_statements (Sekin so'rovlarni topish). Dev'da SQL'ni ko'rish uchun shu darsdagi $on("query") ni vaqtincha yoqish yetarli.
  3. relationJoins — preview; u oddiy so'rovlarning SQL'ini ham o'zgartirdi (taxalluslar). Ombor relation'larni deyarli ishlatmaydi (ro'yxat bitta jadvaldan) — foyda kam, xavf bor. Kiritilmadi.
  4. O'rnatish — prod uchun npm ci --omit=dev --omit=optional (89 MB). Docker image va deploy — 33-qismda.
  5. Accelerate — hisob kerak, sinalmagan; Optimize 2026-03 da yopilgan.

11. Real ishda

  • Prodakshndagi Prisma muammolarining katta qismi — N+1 va keraksiz ustunlar; ular kod review'da emas, log va APM (Sentry, Datadog) da topiladi.
  • Serverless'ga ko'chishda birinchi savol: "ulanishlar soni qancha bo'ladi?" — hovuz max, pooler, adapter.
  • Intervyuda: "Prisma ilovasi sekin — nimadan boshlaysiz?", "Serverless'da Postgres ulanishlari muammosi?", "include qanday SQL beradi?"

Xulosa

  • log: [{ emit: "event", level: "query" }] + $on — SQL, parametrlar, ms; prodda parametrlarni log'lamang.
  • include sukut — alohida so'rovlar; relationJoins preview bilan join — bitta LATERAL + JSONB_AGG.
  • N+1: siklda 9 SQL, _count bilan 1; bir tick'dagi findUnique lar bitta IN ga birlashadi, findFirst — yo'q.
  • Hovuz — adapter orqali, aniq timeout bilan; serverless'da max: 1 + pooler.
  • Prod o'rnatish: --omit=dev --omit=optional — 330 → 89 MB; Prisma importi ~0.6 s.

Keyingi dars: Drizzle ORM 1: sxema va so'rovlar — sxema TypeScript'da, so'rovlar SQL'ga yaqin, natija turi avtomatik.

Manbalar

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
Prisma prodakshnda: query log, relationLoadStrategy, N+1, hovuz va o'rnatish hajmi — IlmHamroh