Class: Gitlab::Pagination::Offset::PaginationWithIndexOnlyScan

Inherits:
Object
  • Object
show all
Defined in:
lib/gitlab/pagination/offset/pagination_with_index_only_scan.rb

Overview

rubocop: disable CodeReuse/ActiveRecord – Generic code for pagination

This class can build optimized offset queries where we try to force the DB to use index-only-scan for skipping the OFFSET rows by selecting the columns in the ORDER BY clause explicitly. The selected rows will be fully loaded from the table using a LATERAL SELECT.

The class can be used with any ActiveRecord scope however, the optimization will be only applied when:

  • ‘ORDER BY` clause is present

  • The columns in an ‘ORDER BY` point to one distinct record -> the `ORDER BY` clause can be keyset paginated

Usage:

scope = Issue.where(project_id: 1).order(:id)

records = PaginationWithIndexOnlyScan.new(scope: scope, page: 5, per_page: 100).paginate_with_kaminari puts records.to_a puts records.total_count

Constant Summary collapse

CTE_NAME =
:index_only_scan_pagination_cte
SUBQUERY_NAME =
:index_only_scan_subquery

Instance Method Summary collapse

Constructor Details

#initialize(scope:, page:, per_page:) ⇒ PaginationWithIndexOnlyScan

Returns a new instance of PaginationWithIndexOnlyScan.



27
28
29
30
31
32
33
# File 'lib/gitlab/pagination/offset/pagination_with_index_only_scan.rb', line 27

def initialize(scope:, page:, per_page:)
  @scope = scope
  @page = page
  @per_page = per_page
  @model = scope.model
  @original_order_values = scope.order_values
end

Instance Method Details

#paginate_with_kaminariObject



35
36
37
38
39
40
41
42
43
44
# File 'lib/gitlab/pagination/offset/pagination_with_index_only_scan.rb', line 35

def paginate_with_kaminari
  original_kaminari_query = scope.page(page).per(per_page)

  # Check for keyset pagination support
  if keyset_aware_scope && (keyset_order_by_columns.size == original_order_by_columns.size)
    original_kaminari_query.extend(build_module_for_load)
  end

  original_kaminari_query
end