Hai phương pháp triển khai phân trang phổ biến hiện nay, bạn đang dùng cách nào?

Hai phương pháp triển khai phân trang phổ biến hiện nay, bạn đang dùng cách nào?

Tin ngắn hàng ngày dành cho bạn
  • Cũng giống như 12 Days of OpenAI - một chuỗi sự kiện diễn ra trong 12 ngày liên tiếp của OpenAI, mỗi ngày họ sẽ giới thiệu một công cụ "đột phá", và cứ như thế.

    DeepSeek đã bắt "trend" ngay sau đó với chuỗi 202502 Open-Source Week diễn ra ngay trong tuần sau. Mỗi ngày họ sẽ công bố một công cụ mã nguồn mở, trái được hoàn toàn với tính "Open" của AI. Chúng ta hãy chờ xem họ mang đến những dự án thú vị nào nhé 🤓. Chắc sẽ hấp dẫn lắm đây vì ai cũng biết từ lúc ra mô hình R1, Deepseek đã chiếm trọn tin tức nổi bật trên toàn thế giới.

    » Xem thêm
  • Grok 3 beta vừa ra mắt và cho mọi người dùng thử miễn phí có giới hạn số lần trong ngày (tài khoản trả phí hình như được dùng nhiều hơn). Trong đó có 2 tính năng nổi bật là Think và DeepSearch.

    Think thì chắc ai cũng biết hoặc dùng ở một số mô hình suy luận như ở ChatGPT rồi. Còn DeepSearch thì mới hơn, gõ điều bạn muốn vào thì nó sẽ tự lên mạng tìm kiếm thông tin rồi tổng hợp lại kết quả mà nó tìm thấy được. Khá hay nhưng chắc để tham khảo hoặc muốn tổng hợp thông tin nhanh chóng thôi chứ vẫn nên tự mình tìm kiếm thông tin 😅

    » Xem thêm
  • Có 2 phần mềm tiện ích cho Mac mà mỗi khi dùng máy Mac Mini hoặc Macbook có cắm thêm màn hình rời, thêm bàn phím với chuột nữa là BetterDisplayMac Mouse Fix. Đi qua từng cái nhé!

    BetterDisplay giúp tinh chỉnh kích thước của màn hình rời để đạt độ phân giải HiDPI. Như bạn biết Mac khá kén màn hình và tuỳ chọn độ phân giải trong cài đặt mặc định rất ít ỏi, nên BetterDisplay cung cấp nhiều lựa chọn phù hợp hơn.

    Cái thứ hai là Mac Mouse Fix, nếu dùng chuột ngoài bạn sẽ thấy nó cuộn không giống với Trackpad của Macbook cho lắm. Điều kì diệu xảy ra khi cài phần mềm này vào. Nó thêm hiệu ứng "smooth" và giúp cuộn chuột y như cuộn bằng Trackpad luôn. Thật thần kỳ.

    » Xem thêm

Vấn đề

Phân trang là một trong những yêu cầu cơ bản đối với API lấy dữ liệu là danh sách. Phân trang nhằm giảm tải lượng dữ liệu cần truy vấn cũng như giảm tải lượng dữ liệu truyền về, vì việc lấy hết dữ liệu trong một danh sách rất dài là một điều lãng phí đối với hầu hết tính năng thông thường.

Bài viết ngày hôm nay tôi xin phép trình bày hai kĩ thuật phân trang phổ biến mà dễ dàng triển khai nhất. Mỗi loại có ưu nhược điểm thế nào và nên áp dụng trong trường hợp nào thì mời bạn đọc tiếp bài viết dưới đây nhé.

Phân trang bằng LIMIT & OFFSET

/articles?limit=10&offset=0

Chắc hẳn url trên khá quen thuộc với mọi người, đây là kĩ thuật phân trang dựa trên limitoffset. Nguyên tắc hoạt động của nó khá đơn giản: limit là giới hạn bản ghi còn offset là bắt đầu lấy dữ liệu sau offset hàng.

Ví dụ trên sẽ lấy 10 hàng bắt đầu từ hàng đầu tiên.

Thể hiện của kĩ thuật phân trang này là một tính năng trông giống như hình bên dưới.

Phân trang dựa trên limit offset

Các trang như 1,2,3... đến 30 được hiển thị, người dùng có thể dễ dàng bấm vào trang muốn xem để xem nội dung trong trang đó.

Về phần xử lý phía máy chủ, hầu hết việc lấy dữ liệu ra theo limitoffset là từ trong cơ sở dữ liệu. Hiện tại hầu như cơ sở dữ liệu nào cũng hỗ trợ cú pháp truy vấn limitoffset. Ví dụ như trong PostgreSQL:

SELECT * FROM articles LIMIT 10 OFFSET 0;

Với mỗi limitoffset người dùng gọi lên thay thế vào câu truy vấn bạn sẽ lấy được kết quả mong muốn.

Trong quá trình người dùng đang lấy dữ liệu liên tục, nếu như thời điểm đó có bản ghi được thêm vào hoặc bị xóa sẽ gây ra hiện tượng trùng lặp hoặc thiếu sót dữ liệu ở trang tiếp theo. Vì bản ghi được thêm sẽ đẩy dữ liệu tiếp theo xuống dưới, còn bản ghi bị xóa thì lại kéo dữ liệu lên.

Một điểm trừ nữa là khi số lượng bản ghi rất lớn, truy vấn theo offset có khả năng bị chậm. Nguyên nhân là do cách cơ sở dữ liệu xử lý offset. Hầu hết truy vấn theo offset phải duyệt qua tất cả các hàng cho đến đủ số lượng offset rồi mới bắt đầu lấy dữ liệu. Ví dụ bạn có offset = 1.000.000 thì nó phải duyệt qua 1 triệu hàng rồi bắt đầu lấy từ hàng 1.000.001.

Tóm lại, offsetlimit phù hợp trong trường hợp mong muốn triển khai nhanh, danh sách phân trang được hiển thị theo số thứ tự, khi đó người dùng nhanh chóng điều hướng đến trang họ muốn. Cần cân nhắc sử dụng kĩ thuật này trên tập dữ liệu lớn vì khi đó hiệu năng khả năng cao là bị ảnh hưởng.

Phân trang bằng Cursor

Bạn đã gặp kiểu phân trang này bao giờ chưa? Chỉ bao gồm hai nút Next và Previous như hình dưới đây.

Phân trang dựa trên cursor

Khả năng cao là đang áp dụng kĩ thuật phân trang bằng cursor. Điều đặc biệt của phương pháp này là không có danh sách số thứ tự trang như kĩ thuật limit, offset bên trên.

Một url phân trang bằng cursor có thể trông giống như thế này:

/articles?cursor=4n5pxq24kp

Nguyên tắc hoạt động của cursor khá đơn giản. Ở lượt truy vấn lấy danh sách lần đầu tiên trả về một cursor, sau đó bạn sử dụng cursor này để lấy dữ liệu trong trang tiếp theo. Cứ như thế cho đến khi cursor không trả về nữa tức là dữ liệu đã hết.

{
    "articles": [...],
    "next_cursor": "4n5pxq24kn",
    "prev_cursor": "4n5pxq24kp",
}

Dễ thấy đối với kĩ thuật này bạn không thể nhảy đến một trang xác định nào, vì "con trỏ" chỉ được trả về sau mỗi lần gọi. Thông thường cursor được mã hóa theo quy tắc mà chỉ máy chủ biết, khi truyền lên nó sẽ giải mã để lấy ra dữ liệu cần thiết bên trong.

Ở phía máy chủ, lệnh truy vấn không dùng LIMITOFFSET, thay vào đó là cách truy vấn "lớn hơn hoặc bằng" (>=) kết hợp với index dữ liệu.

Ví dụ, giả sử con trỏ 4n5pxq24kp được máy chủ mã hóa từ id = 10. Khi lấy trang tiếp theo câu lệnh truy vấn giống như là:

SELECT * FROM articles WHERE id > 10 LIMIT 10;

Dễ thấy, nếu đánh index trên trường id của bảng articles thì câu lệnh không cần phải duyệt qua 10 bản ghi đầu tiên để bỏ qua nữa mà nó lấy luôn dữ liệu đằng sau 10. Độ phức tạp lúc này là O(1).

Phương pháp này còn khắc phục được trường hợp dữ liệu được thêm hoặc xóa trong lúc đang phân trang. Đơn giản vì nó không dựa vào offset để lấy bản ghi tiếp theo mà nó dựa vào phép so sánh. Giả sử bản ghi thứ 10 bị xóa đi thì trang tiếp theo vẫn lấy được đủ 10 bản ghi kể từ bản ghi thứ 10 thay vì thứ 9 nếu áp dụng offset.

Rõ ràng cách tiếp cận này về mặt hiệu suất cao hơn hẳn so với limitoffset, tuy nhiên thời gian triển khai và độ phức tạp có thể cao hơn so với phương pháp thông thường. Người dùng không thể điều hướng đến một trang mong muốn và yêu cầu bạn phải có một trường dữ liệu có thể sắp xếp đã được đánh index.

Tổng kết

Trên đây, tôi vừa trình bày hai kĩ thuật phân trang phổ biến. limit, offset thì đơn giản dễ triển khai tuy nhiên gặp vấn đề về hiệu năng trên tập dữ liệu rất lớn. Cursor thì cho hiệu năng tốt nhưng lại có một vài hạn chế khi sử dụng cùng độ phức tạp cao hơn. Mỗi phương pháp đều thể hiện ra ưu nhược điểm, chúng ta không nhất thiết phải chọn cursor vì hiệu năng cao mà thay vào đó biết cách lựa chọn phương pháp cho phù hợp với bài toán mà bạn đang xử lý.

Cao cấp
Hello

Bí mật ngăn xếp của Blog

Là một lập trình viên, bạn có tò mò về bí mật công nghệ hay những khoản nợ kỹ thuật về trang blog này? Tất cả bí mật sẽ được bật mí ngay bài viết dưới đây. Còn chờ đợi gì nữa, hãy bấm vào ngay!

Là một lập trình viên, bạn có tò mò về bí mật công nghệ hay những khoản nợ kỹ thuật về trang blog này? Tất cả bí mật sẽ được bật mí ngay bài viết dưới đây. Còn chờ đợi gì nữa, hãy bấm vào ngay!

Xem tất cả

Đăng ký nhận thông báo bài viết mới

hoặc
* Bản tin tổng hợp được gửi mỗi 1-2 tuần, huỷ bất cứ lúc nào.

Bình luận (0)

Nội dung bình luận...