Offset vs Cursor Pagination











up vote
2
down vote

favorite












I am trying to compare any performance gain(s) from moving a current offset-based pagination endpoint to a cursor based one.



I have the following ruby code:



@limit = 25
@max_pages = 200

def query
@q ||= MyDataBaseClass.where(status: "open").order(:id)
end

def offset_paginatiion
# count is currently an implementation for this appraoch
total = query.count
ctr = 0
page_size = 1
while page_size < @max_pages
query.limit(@limit).offset(ctr).load
ctr += @limit
page_size += 1
end
end

def keyset_pagination
current_page = query.limit(@limit)

page_size = 1
while true
break if page_size >= @max_pages
page_size += 1
last_id = current_page.last.id
current_page = query.where("id > ?", last_id).limit(@limit).load
end
end

require 'benchmark/ips'

Benchmark.ips do |x|
x.report("offset_pagination") { offset_paginatiion }
x.report("keyset_pagination") { keyset_pagination }
x.compare!
end


I've seeded the database with 1 million rows but you can see here I'm only trying to page up to 200 pages (or 5,000 results).



The two methods are returning the exact same data in the same order so they are functionally equivalent and after running the benchmark are performing nearly the same:



│Calculating -------------------------------------
│ offset_pagination 0.009 (± 0.0%) i/s - 1.000 in 110.100327s
│ keyset_pagination 0.009 (± 0.0%) i/s - 1.000 in 112.732942s

│Comparison:
│ offset_pagination: 0.0 i/s
│ keyset_pagination: 0.0 i/s - 1.02x slower


I was under the impression performance (from numerous articles) was a benefit to moving to cursor pagination but have yet to been able to reproduce - what am I doing worng?










share|improve this question




























    up vote
    2
    down vote

    favorite












    I am trying to compare any performance gain(s) from moving a current offset-based pagination endpoint to a cursor based one.



    I have the following ruby code:



    @limit = 25
    @max_pages = 200

    def query
    @q ||= MyDataBaseClass.where(status: "open").order(:id)
    end

    def offset_paginatiion
    # count is currently an implementation for this appraoch
    total = query.count
    ctr = 0
    page_size = 1
    while page_size < @max_pages
    query.limit(@limit).offset(ctr).load
    ctr += @limit
    page_size += 1
    end
    end

    def keyset_pagination
    current_page = query.limit(@limit)

    page_size = 1
    while true
    break if page_size >= @max_pages
    page_size += 1
    last_id = current_page.last.id
    current_page = query.where("id > ?", last_id).limit(@limit).load
    end
    end

    require 'benchmark/ips'

    Benchmark.ips do |x|
    x.report("offset_pagination") { offset_paginatiion }
    x.report("keyset_pagination") { keyset_pagination }
    x.compare!
    end


    I've seeded the database with 1 million rows but you can see here I'm only trying to page up to 200 pages (or 5,000 results).



    The two methods are returning the exact same data in the same order so they are functionally equivalent and after running the benchmark are performing nearly the same:



    │Calculating -------------------------------------
    │ offset_pagination 0.009 (± 0.0%) i/s - 1.000 in 110.100327s
    │ keyset_pagination 0.009 (± 0.0%) i/s - 1.000 in 112.732942s

    │Comparison:
    │ offset_pagination: 0.0 i/s
    │ keyset_pagination: 0.0 i/s - 1.02x slower


    I was under the impression performance (from numerous articles) was a benefit to moving to cursor pagination but have yet to been able to reproduce - what am I doing worng?










    share|improve this question


























      up vote
      2
      down vote

      favorite









      up vote
      2
      down vote

      favorite











      I am trying to compare any performance gain(s) from moving a current offset-based pagination endpoint to a cursor based one.



      I have the following ruby code:



      @limit = 25
      @max_pages = 200

      def query
      @q ||= MyDataBaseClass.where(status: "open").order(:id)
      end

      def offset_paginatiion
      # count is currently an implementation for this appraoch
      total = query.count
      ctr = 0
      page_size = 1
      while page_size < @max_pages
      query.limit(@limit).offset(ctr).load
      ctr += @limit
      page_size += 1
      end
      end

      def keyset_pagination
      current_page = query.limit(@limit)

      page_size = 1
      while true
      break if page_size >= @max_pages
      page_size += 1
      last_id = current_page.last.id
      current_page = query.where("id > ?", last_id).limit(@limit).load
      end
      end

      require 'benchmark/ips'

      Benchmark.ips do |x|
      x.report("offset_pagination") { offset_paginatiion }
      x.report("keyset_pagination") { keyset_pagination }
      x.compare!
      end


      I've seeded the database with 1 million rows but you can see here I'm only trying to page up to 200 pages (or 5,000 results).



      The two methods are returning the exact same data in the same order so they are functionally equivalent and after running the benchmark are performing nearly the same:



      │Calculating -------------------------------------
      │ offset_pagination 0.009 (± 0.0%) i/s - 1.000 in 110.100327s
      │ keyset_pagination 0.009 (± 0.0%) i/s - 1.000 in 112.732942s

      │Comparison:
      │ offset_pagination: 0.0 i/s
      │ keyset_pagination: 0.0 i/s - 1.02x slower


      I was under the impression performance (from numerous articles) was a benefit to moving to cursor pagination but have yet to been able to reproduce - what am I doing worng?










      share|improve this question















      I am trying to compare any performance gain(s) from moving a current offset-based pagination endpoint to a cursor based one.



      I have the following ruby code:



      @limit = 25
      @max_pages = 200

      def query
      @q ||= MyDataBaseClass.where(status: "open").order(:id)
      end

      def offset_paginatiion
      # count is currently an implementation for this appraoch
      total = query.count
      ctr = 0
      page_size = 1
      while page_size < @max_pages
      query.limit(@limit).offset(ctr).load
      ctr += @limit
      page_size += 1
      end
      end

      def keyset_pagination
      current_page = query.limit(@limit)

      page_size = 1
      while true
      break if page_size >= @max_pages
      page_size += 1
      last_id = current_page.last.id
      current_page = query.where("id > ?", last_id).limit(@limit).load
      end
      end

      require 'benchmark/ips'

      Benchmark.ips do |x|
      x.report("offset_pagination") { offset_paginatiion }
      x.report("keyset_pagination") { keyset_pagination }
      x.compare!
      end


      I've seeded the database with 1 million rows but you can see here I'm only trying to page up to 200 pages (or 5,000 results).



      The two methods are returning the exact same data in the same order so they are functionally equivalent and after running the benchmark are performing nearly the same:



      │Calculating -------------------------------------
      │ offset_pagination 0.009 (± 0.0%) i/s - 1.000 in 110.100327s
      │ keyset_pagination 0.009 (± 0.0%) i/s - 1.000 in 112.732942s

      │Comparison:
      │ offset_pagination: 0.0 i/s
      │ keyset_pagination: 0.0 i/s - 1.02x slower


      I was under the impression performance (from numerous articles) was a benefit to moving to cursor pagination but have yet to been able to reproduce - what am I doing worng?







      performance ruby api postgresql pagination






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 29 at 21:39

























      asked Nov 29 at 21:24









      Anthony

      279212




      279212






















          1 Answer
          1






          active

          oldest

          votes

















          up vote
          0
          down vote













          I'm not surprised at your results, bar a few minor details that any decent database will optimize away your implementations are the same. You are also basically just re-implementing the find_each method.



          Note, you might find a real difference if you used database cursors but that is a completely different thing.



          The real difference between the two is that cursor based pagination responds better when the underlying data changes. i.e. using offset based pagination you might have a record included twice or skipped if a record is inserted or deleted by another process.






          share|improve this answer























          • Looks like your answer got cut off at the end
            – 404
            Dec 1 at 13:14











          Your Answer





          StackExchange.ifUsing("editor", function () {
          return StackExchange.using("mathjaxEditing", function () {
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          });
          });
          }, "mathjax-editing");

          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "196"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f208720%2foffset-vs-cursor-pagination%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          up vote
          0
          down vote













          I'm not surprised at your results, bar a few minor details that any decent database will optimize away your implementations are the same. You are also basically just re-implementing the find_each method.



          Note, you might find a real difference if you used database cursors but that is a completely different thing.



          The real difference between the two is that cursor based pagination responds better when the underlying data changes. i.e. using offset based pagination you might have a record included twice or skipped if a record is inserted or deleted by another process.






          share|improve this answer























          • Looks like your answer got cut off at the end
            – 404
            Dec 1 at 13:14















          up vote
          0
          down vote













          I'm not surprised at your results, bar a few minor details that any decent database will optimize away your implementations are the same. You are also basically just re-implementing the find_each method.



          Note, you might find a real difference if you used database cursors but that is a completely different thing.



          The real difference between the two is that cursor based pagination responds better when the underlying data changes. i.e. using offset based pagination you might have a record included twice or skipped if a record is inserted or deleted by another process.






          share|improve this answer























          • Looks like your answer got cut off at the end
            – 404
            Dec 1 at 13:14













          up vote
          0
          down vote










          up vote
          0
          down vote









          I'm not surprised at your results, bar a few minor details that any decent database will optimize away your implementations are the same. You are also basically just re-implementing the find_each method.



          Note, you might find a real difference if you used database cursors but that is a completely different thing.



          The real difference between the two is that cursor based pagination responds better when the underlying data changes. i.e. using offset based pagination you might have a record included twice or skipped if a record is inserted or deleted by another process.






          share|improve this answer














          I'm not surprised at your results, bar a few minor details that any decent database will optimize away your implementations are the same. You are also basically just re-implementing the find_each method.



          Note, you might find a real difference if you used database cursors but that is a completely different thing.



          The real difference between the two is that cursor based pagination responds better when the underlying data changes. i.e. using offset based pagination you might have a record included twice or skipped if a record is inserted or deleted by another process.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Dec 2 at 7:59

























          answered Nov 30 at 9:12









          Marc Rohloff

          2,98736




          2,98736












          • Looks like your answer got cut off at the end
            – 404
            Dec 1 at 13:14


















          • Looks like your answer got cut off at the end
            – 404
            Dec 1 at 13:14
















          Looks like your answer got cut off at the end
          – 404
          Dec 1 at 13:14




          Looks like your answer got cut off at the end
          – 404
          Dec 1 at 13:14


















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Code Review Stack Exchange!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          Use MathJax to format equations. MathJax reference.


          To learn more, see our tips on writing great answers.





          Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


          Please pay close attention to the following guidance:


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f208720%2foffset-vs-cursor-pagination%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Terni

          A new problem with tex4ht and tikz

          Sun Ra