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?

Threads
  • Mistral.ai là một công ty AI có trụ sở tại Pháp, được biết đến với nhiều mô hình ngôn ngữ lớn Mistral. Mới đây họ vừa ra mắt thêm một số mô hình có kích thước siêu lớn, siêu mạnh... Nhưng tạm khoan nói đến vì Mistral Chat cũng vừa được ra mắt với nhiều tính năng hay ho tương tự như Chat GPT mà lại miễn phí 😇

    » Xem thêm
  • Qwen2.5-Coder-32B đang là tâm điểm của sự chú ý khi điểm số của nó đánh bại cả GPT-4o hay kể cả là Claude Sonet 3.5. Điều đáng chú ý là nó là mã nguồn mở. Điều đó đồng nghĩa với việc bạn hoàn toàn có thể kéo models về máy và chạy cục bộ dưới máy tính của mình. Nhưng...

    Để chạy được mô hình thì GPU máy tính phải đạt cấp độ quái vật. Cụ thể trong một bài đăng của người dùng thử nghiệm Qwen2.5-Coder-32B trên GTX 3090 thì tốc độ tối đa models cho ra nằm ở mức hơn 30 tokens/s.

    Hy vọng vài nữa sẽ có một bên như Groq hay SambaNova dựng lên để "kiểm thử" hiệu năng con chip của họ, và quan trọng hơn hết là cho anh em dùng "chùa" thì hay biết mấy 🫣

    Tham khảo: Qwen2.5-Coder-32B is an LLM that can code well that runs on my Mac

    » Xem thêm
  • Hai ngày cuối tuần mình ngồi lên bản cập nhật cho OpenNotas.

    Ai còn đang cần tìm một ứng dụng ghi chú đa nền tảng, đơn giản, tập trung vào bảo mật thì dùng thử OpenNotas xem thế nào ha! Tham gia cộng đồng tại đây nha https://t.me/opennotas 🤓

    » 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ý.

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.
Author

Xin chào, tôi tên là Hoài - một anh Dev kể chuyện bằng cách viết ✍️ và làm sản phẩm 🚀. Với nhiều năm kinh nghiệm lập trình, tôi đã đóng góp một phần công sức cho nhiều sản phẩm mang lại giá trị cho người dùng tại nơi đang làm việc, cũng như cho chính bản thân. Sở thích của tôi là đọc, viết, nghiên cứu... Tôi tạo ra trang Blog này với sứ mệnh mang đến những bài viết chất lượng cho độc giả của 2coffee.dev.Hãy theo dõi tôi qua các kênh LinkedIn, Facebook, Instagram, Telegram.

Bạn thấy bài viết này có ích?
Không

Bình luận (0)

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