Tại sao bạn cần hỗ trợ công cụ để phân trang trên các phím?

Chào mọi người! Tôi là nhà phát triển phụ trợ viết microservice bằng Java + Spring. Tôi làm việc tại một trong những nhóm phát triển sản phẩm nội bộ tại Tinkoff.

Tại sao bạn cần hỗ trợ công cụ để phân trang trên các phím?

Trong nhóm của chúng tôi, câu hỏi về tối ưu hóa các truy vấn trong DBMS thường được đặt ra. Bạn luôn muốn nhanh hơn một chút, nhưng không phải lúc nào bạn cũng có thể thực hiện được bằng các chỉ mục được xây dựng chu đáo—bạn phải tìm một số giải pháp thay thế. Trong một lần lang thang trên web để tìm kiếm những cách tối ưu hóa hợp lý khi làm việc với cơ sở dữ liệu, tôi đã tìm thấy Blog vô cùng hữu ích của Marcus Wynand, tác giả của Giải thích về hiệu suất SQL. Đây là loại blog hiếm hoi mà bạn có thể đọc tất cả các bài viết liên tiếp.

Tôi muốn dịch một bài viết ngắn của Marcus cho bạn. Ở một mức độ nào đó, nó có thể được gọi là một tuyên ngôn nhằm thu hút sự chú ý đến vấn đề cũ nhưng vẫn có liên quan về hiệu suất của hoạt động bù theo tiêu chuẩn SQL.

Ở một số chỗ tôi sẽ bổ sung cho tác giả những lời giải thích và nhận xét. Tôi sẽ gọi tất cả những nơi như vậy là “khoảng”. để rõ ràng hơn

Một lời giới thiệu nhỏ

Tôi nghĩ nhiều người biết việc chọn trang thông qua offset gặp khó khăn và chậm chạp như thế nào. Bạn có biết rằng nó có thể được thay thế khá dễ dàng bằng một thiết kế hiệu quả hơn không?

Vì vậy, từ khóa offset yêu cầu cơ sở dữ liệu bỏ qua n bản ghi đầu tiên trong yêu cầu. Tuy nhiên, cơ sở dữ liệu vẫn cần đọc n bản ghi đầu tiên này từ đĩa, theo thứ tự nhất định (lưu ý: áp dụng sắp xếp nếu được chỉ định) và chỉ khi đó mới có thể trả về các bản ghi từ n+1 trở đi. Điều thú vị nhất là vấn đề không nằm ở việc triển khai cụ thể trong DBMS mà nằm ở định nghĩa ban đầu theo tiêu chuẩn:

…đầu tiên các hàng được sắp xếp theo và sau đó được giới hạn bằng cách loại bỏ số lượng hàng được chỉ định trong ngay từ đầu…
-SQL:2016, Phần 2, 4.15.3 Bảng dẫn xuất (lưu ý: hiện là tiêu chuẩn được sử dụng nhiều nhất)

Điểm mấu chốt ở đây là offset lấy một tham số duy nhất - số lượng bản ghi cần bỏ qua, chỉ vậy thôi. Theo định nghĩa này, DBMS chỉ có thể truy xuất tất cả các bản ghi và sau đó loại bỏ những bản ghi không cần thiết. Rõ ràng, định nghĩa về offset này buộc chúng ta phải làm thêm việc. Và nó thậm chí không quan trọng cho dù đó là SQL hay NoSQL.

Chỉ đau thêm một chút thôi

Các vấn đề với offset không dừng lại ở đó và đây là lý do. Nếu, giữa việc đọc hai trang dữ liệu từ đĩa, một thao tác khác chèn một bản ghi mới, điều gì sẽ xảy ra trong trường hợp này?

Tại sao bạn cần hỗ trợ công cụ để phân trang trên các phím?

Khi offset được sử dụng để bỏ qua các bản ghi từ các trang trước, trong trường hợp thêm một bản ghi mới giữa các lần đọc các trang khác nhau, rất có thể bạn sẽ nhận được các bản ghi trùng lặp (lưu ý: điều này có thể xảy ra khi chúng ta đọc từng trang bằng cách sử dụng cấu trúc order by, sau đó ở giữa đầu ra của chúng tôi, nó có thể nhận được một mục mới).

Hình vẽ mô tả rõ ràng tình trạng này. Cơ sở đọc 10 bản ghi đầu tiên, sau đó một bản ghi mới được chèn vào, bù tất cả các bản ghi đã đọc bằng 1. Sau đó, cơ sở lấy một trang mới từ 10 bản ghi tiếp theo và bắt đầu không phải từ trang thứ 11 như lẽ ra phải thế, mà từ trang Lần thứ 10, nhân bản bản ghi này. Có những điểm bất thường khác liên quan đến việc sử dụng biểu thức này, nhưng đây là trường hợp phổ biến nhất.

Như chúng tôi đã phát hiện ra, đây không phải là vấn đề của một DBMS cụ thể hoặc việc triển khai chúng. Vấn đề nằm ở việc xác định phân trang theo tiêu chuẩn SQL. Chúng tôi cho DBMS biết trang nào cần tìm nạp hoặc số lượng bản ghi cần bỏ qua. Đơn giản là cơ sở dữ liệu không thể tối ưu hóa yêu cầu như vậy vì có quá ít thông tin cho việc này.

Cũng cần làm rõ rằng đây không phải là vấn đề với một từ khóa cụ thể mà là do ngữ nghĩa của truy vấn. Có một số cú pháp giống hệt nhau về bản chất có vấn đề:

  • Từ khóa offset như đã đề cập trước đó.
  • Việc xây dựng giới hạn hai từ khóa [bù đắp] (mặc dù bản thân giới hạn không quá tệ).
  • Lọc theo giới hạn dưới, dựa trên cách đánh số hàng (ví dụ: row_number(), rownum, v.v.).

Tất cả những biểu thức này chỉ cho bạn biết cần bỏ qua bao nhiêu dòng mà không có thêm thông tin hoặc ngữ cảnh nào.

Ở phần sau của bài viết này, từ khóa offset được sử dụng làm bản tóm tắt của tất cả các tùy chọn này.

Cuộc sống không có BẮT BUỘC

Bây giờ hãy tưởng tượng thế giới của chúng ta sẽ ra sao nếu không có tất cả những vấn đề này. Hóa ra cuộc sống không có offset không quá khó khăn: với một lựa chọn, bạn chỉ có thể chọn những hàng mà chúng ta chưa thấy (lưu ý: tức là những hàng không có trên trang trước), sử dụng điều kiện ở đâu.

Trong trường hợp này, chúng ta bắt đầu từ thực tế là các phép chọn được thực thi trên một tập hợp có thứ tự (thứ tự cũ tốt). Vì chúng tôi có một tập hợp có thứ tự, chúng tôi có thể sử dụng bộ lọc khá đơn giản để chỉ lấy dữ liệu nằm sau bản ghi cuối cùng của trang trước:

    SELECT ...
    FROM ...
    WHERE ...
    AND id < ?last_seen_id
    ORDER BY id DESC
    FETCH FIRST 10 ROWS ONLY

Đó là toàn bộ nguyên tắc của phương pháp này. Tất nhiên, mọi thứ sẽ thú vị hơn khi sắp xếp theo nhiều cột, nhưng ý tưởng vẫn như cũ. Điều quan trọng cần lưu ý là thiết kế này có thể áp dụng cho nhiều NoSQL-các quyết định.

Cách tiếp cận này được gọi là phương pháp tìm kiếm hoặc phân trang keyset. Nó giải quyết vấn đề về kết quả nổi (lưu ý: tình huống ghi giữa các lần đọc trang được mô tả trước đó) và tất nhiên, điều mà tất cả chúng ta đều yêu thích, nó hoạt động nhanh hơn và ổn định hơn so với offset cổ điển. Tính ổn định nằm ở chỗ thời gian xử lý yêu cầu không tăng tỷ lệ thuận với số lượng bảng được yêu cầu (lưu ý: nếu bạn muốn tìm hiểu thêm về công việc của các cách tiếp cận phân trang khác nhau, bạn có thể xem qua phần trình bày của tác giả. Bạn cũng có thể tìm thấy điểm chuẩn so sánh cho các phương pháp khác nhau ở đó).

Một trong những slide nói về điều đótất nhiên, việc phân trang theo khóa đó không phải là toàn năng - nó có những hạn chế. Điều quan trọng nhất là cô ấy không có khả năng đọc các trang ngẫu nhiên (lưu ý: không nhất quán). Tuy nhiên, trong thời đại cuộn vô tận (lưu ý: ở mặt trước), đây không phải là vấn đề như vậy. Dù sao thì việc chỉ định số trang để nhấp chuột là một quyết định tồi trong thiết kế giao diện người dùng (lưu ý: ý kiến ​​của tác giả bài viết).

Còn các công cụ thì sao?

Phân trang trên các phím thường không phù hợp do thiếu công cụ hỗ trợ cho phương pháp này. Hầu hết các công cụ phát triển, bao gồm nhiều khung công tác khác nhau, không cho phép bạn chọn chính xác cách thực hiện phân trang.

Tình hình trở nên trầm trọng hơn do phương pháp được mô tả yêu cầu hỗ trợ từ đầu đến cuối trong các công nghệ được sử dụng - từ DBMS đến việc thực hiện yêu cầu AJAX trong trình duyệt với khả năng cuộn vô tận. Thay vì chỉ xác định số trang, giờ đây bạn phải chỉ định một bộ khóa cho tất cả các trang cùng một lúc.

Tuy nhiên, số lượng framework hỗ trợ phân trang theo phím đang dần tăng lên. Đây là những gì chúng tôi có vào lúc này:

(Lưu ý: một số liên kết đã bị xóa do tại thời điểm dịch, một số thư viện chưa được cập nhật kể từ năm 2017-2018. Nếu quan tâm, bạn có thể xem nguồn gốc.)

Chính lúc này, sự giúp đỡ của bạn là cần thiết. Nếu bạn phát triển hoặc hỗ trợ một khung sử dụng bất kỳ tính năng phân trang nào, thì tôi yêu cầu, tôi mong bạn, khẩn cầu bạn cung cấp hỗ trợ riêng cho việc phân trang trên các phím. Nếu bạn có thắc mắc hoặc cần trợ giúp, tôi sẽ sẵn lòng trợ giúp (форум, Twitter, Mâu liên hệ) (lưu ý: từ kinh nghiệm của tôi với Marcus, tôi có thể nói rằng anh ấy thực sự rất nhiệt tình trong việc truyền bá chủ đề này).

Nếu bạn sử dụng các giải pháp làm sẵn mà bạn cho rằng xứng đáng được hỗ trợ phân trang theo khóa, hãy tạo yêu cầu hoặc thậm chí đưa ra giải pháp làm sẵn, nếu có thể. Bạn cũng có thể liên kết đến bài viết này.

Kết luận

Lý do tại sao cách tiếp cận đơn giản và hữu ích như phân trang theo khóa không phổ biến không phải vì nó khó thực hiện về mặt kỹ thuật hoặc đòi hỏi nỗ lực lớn. Lý do chính là nhiều người đã quen với việc nhìn và làm việc với offset - cách tiếp cận này do chính tiêu chuẩn quy định.

Kết quả là, ít người nghĩ đến việc thay đổi cách tiếp cận phân trang và do đó, sự hỗ trợ công cụ từ các khung và thư viện đang phát triển kém. Do đó, nếu ý tưởng và mục tiêu về phân trang không có offset gần gũi với bạn, hãy giúp truyền bá nó!

Nguồn: https://use-the-index-luke.com/no-offset
Tác giả: Markus Winand

Nguồn: www.habr.com

Thêm một lời nhận xét