Giới thiệu

Trong các dự án Fullstack sử dụng Prisma kết hợp MySQL, việc tối ưu truy vấn là yếu tố quyết định tốc độ phản hồi API. Bài viết này sẽ giới thiệu một số kỹ thuật thực tiễn giúp giảm thời gian thực thi query, đồng thời duy trì tính sạch sẽ của code TypeScript.

Hiểu vấn đề truy vấn chậm

Khi API trả về dữ liệu phức tạp, Prisma có thể tạo ra các câu lệnh JOIN hoặc SELECT * không cần thiết, dẫn tới lượng dữ liệu truyền qua mạng và thời gian xử lý tăng lên. Việc nhận diện các truy vấn “nặng” và tối ưu chúng sẽ mang lại lợi ích đáng kể.

Nguyên nhân phổ biến

  • Truy vấn toàn bộ cột thay vì chỉ lấy những trường cần thiết.
  • Không sử dụng pagination cho danh sách lớn.
  • Thực hiện nhiều query lặp lại trong vòng lặp (N+1 problem).
  • Thiếu chỉ mục (index) trên các cột được filter hoặc sort.

Kỹ thuật tối ưu Prisma

Dưới đây là một số cách tiếp cận thường dùng.

Sử dụng selectinclude một cách chọn lọc

Thay vì lấy toàn bộ đối tượng, hãy chỉ định các trường cần thiết bằng select. Khi cần dữ liệu quan hệ, dùng include nhưng vẫn giới hạn trường.

const order = await prisma.order.findUnique({
  where: { id: orderId },
  select: {
    id: true,
    total: true,
    createdAt: true,
    customer: {
      select: { id: true, name: true, email: true }
    },
    items: {
      select: { productId: true, quantity: true, price: true }
    }
  }
});

Áp dụng pagination và cursor

Đối với danh sách lớn, sử dụng skip/take hoặc cursor‑based pagination để tránh tải toàn bộ bản ghi.

const products = await prisma.product.findMany({
  take: 20,
  cursor: lastId ? { id: lastId } : undefined,
  orderBy: { id: 'asc' },
});

Batching và transaction

Khi cần thực hiện nhiều thao tác ghi liên tiếp, gom chúng lại trong một transaction để giảm số lần round‑trip tới database.

await prisma.$transaction(async (prisma) => {
  await prisma.inventory.update({
    where: { productId },
    data: { quantity: { decrement: soldQty } },
  });
  await prisma.order.create({
    data: { /* ... */ },
  });
});

Sử dụng raw query khi cần

Trong một số trường hợp đặc biệt, Prisma cho phép chạy câu lệnh SQL thuần để tận dụng các tính năng tối ưu của MySQL như FOR UPDATE hoặc các hàm tổng hợp.

const result = await prisma.$queryRaw`SELECT p.id, p.name, SUM(oi.quantity) AS sold
  FROM product p
  JOIN order_item oi ON oi.productId = p.id
  GROUP BY p.id
  ORDER BY sold DESC
  LIMIT 10;`;

Kiểm tra và đo lường hiệu năng

Sau khi áp dụng các tối ưu, cần đo thời gian thực thi để xác nhận cải thiện. Công cụ EXPLAIN của MySQL và các middleware log thời gian trong Prisma đều hữu ích.

# Kiểm tra plan của query
mysql -u root -p -e "EXPLAIN SELECT * FROM `order` WHERE created_at > '2024-01-01';"

Kết luận

Áp dụng các kỹ thuật trên sẽ giúp giảm đáng kể thời gian phản hồi API, tối ưu tài nguyên server và cải thiện trải nghiệm người dùng. Đối với những ai muốn học sâu hơn cách xây dựng một Dashboard Ecommerce hoàn chỉnh, Tham khảo khóa học "[Full Course] Ecommerce Dashboard Fullstack Clone" tại đây.