Chào anh em, mình vừa open-source thư viện đầu tay: SeekKit.EntityFramework 🎉
Context: mình từng debug một API endpoint mà page 1 response 5ms, nhưng
page 50.000 mất vài giây. Nguyên nhân là OFFSET/FETCH (Skip/Take trong EF
Core) — execution plan phải scan và discard toàn bộ row trước offset, nên
cost tăng tuyến tính theo độ sâu của page. Chưa kể với bảng đang có write
concurrent, row bị shift giữa các page → user thấy duplicate hoặc miss
record.
Giải pháp chuẩn là keyset pagination (seek method): thay vì OFFSET, dùng
predicate WHERE (CreatedAt, Id) < (@lastCreatedAt, @lastId) để index seek
thẳng tới vị trí cursor — cost O(page size), không phụ thuộc độ sâu. Vấn đề
là tự implement cho multi-column sort trộn ASC/DESC thì phải expand predicate
dạng OR lồng nhau khá xấu, nên mình viết hẳn thư viện:
Cursor token dạng opaque (Base64url), bidirectional (nextToken /
previousToken) — client không thấy raw keyset value, không cần biết
page number
Query strategy tối ưu theo từng RDBMS: PostgreSQL dùng row-value
comparison WHERE (a,b) > (@a,@b) (planner translate thẳng thành index
seek), SQL Server chưa support row-value nên dùng pattern UNION ALL +
TOP N, MySQL/Oracle/SQLite cũng có strategy riêng. Toàn bộ build bằng
expression tree → LINQ, không raw SQL, provider tự translate
Support mixed sort direction, có fallback strategy tự động khi primary
strategy không áp dụng được
Optional HMAC-SHA256 signing cho token — chống client tamper/forge cursor
Repo có sẵn example: minimal API + docker compose SQL Server + script seed
data lớn để anh em tự benchmark seek vs offset, cả 2 endpoint đều trả
elapsedMs để so trực tiếp
Đây là thư viện open-source đầu tiên của mình nên rất mong anh em review
giúp — API design, edge case còn sót, hoặc anh em đang giải bài toán
pagination trên bảng lớn theo hướng nào (materialized view? search engine?)
cũng share cho mình học hỏi với. Cảm ơn anh em! 🙏
Chào anh em, mình vừa open-source thư viện đầu tay: SeekKit.EntityFramework 🎉
Context: mình từng debug một API endpoint mà page 1 response 5ms, nhưng page 50.000 mất vài giây. Nguyên nhân là OFFSET/FETCH (Skip/Take trong EF Core) — execution plan phải scan và discard toàn bộ row trước offset, nên cost tăng tuyến tính theo độ sâu của page. Chưa kể với bảng đang có write concurrent, row bị shift giữa các page → user thấy duplicate hoặc miss record.
Giải pháp chuẩn là keyset pagination (seek method): thay vì OFFSET, dùng predicate WHERE (CreatedAt, Id) < (@lastCreatedAt, @lastId) để index seek thẳng tới vị trí cursor — cost O(page size), không phụ thuộc độ sâu. Vấn đề là tự implement cho multi-column sort trộn ASC/DESC thì phải expand predicate dạng OR lồng nhau khá xấu, nên mình viết hẳn thư viện:
Cài đặt: dotnet add package SeekKit.EntityFramework (MIT license)
Repo: https://github.com/lttruc1402/SeekKit.EntityFramework
Đây là thư viện open-source đầu tiên của mình nên rất mong anh em review giúp — API design, edge case còn sót, hoặc anh em đang giải bài toán pagination trên bảng lớn theo hướng nào (materialized view? search engine?) cũng share cho mình học hỏi với. Cảm ơn anh em! 🙏