Class: UnnestedInFilters::Rewriter
- Inherits:
-
Object
- Object
- UnnestedInFilters::Rewriter
- Includes:
- Gitlab::Utils::StrongMemoize
- Defined in:
- lib/unnested_in_filters/rewriter.rb
Defined Under Namespace
Classes: ValueTable
Instance Method Summary collapse
-
#initialize(relation) ⇒ Rewriter
constructor
A new instance of Rewriter.
-
#rewrite ⇒ Object
Rewrites the given ActiveRecord::Relation object to utilize the DB indices efficiently.
- #rewrite? ⇒ Boolean
Constructor Details
#initialize(relation) ⇒ Rewriter
Returns a new instance of Rewriter.
72 73 74 |
# File 'lib/unnested_in_filters/rewriter.rb', line 72 def initialize(relation) @relation = relation end |
Instance Method Details
#rewrite ⇒ Object
Rewrites the given ActiveRecord::Relation object to utilize the DB indices efficiently.
Example usage;
relation = Vulnerabilities::Read.where(state: [1, 4])
relation = relation.order(severity: :desc, vulnerability_id: :desc)
rewriter = UnnestedInFilters::Rewriter.new(relation)
optimized_relation = rewriter.rewrite
In the above example. the ‘relation` object would produce the following SQL query;
SELECT
"vulnerability_reads".*
FROM
"vulnerability_reads"
WHERE
"vulnerability_reads"."state" IN (1, 4)
ORDER BY
"vulnerability_reads"."severity" DESC,
"vulnerability_reads"."vulnerability_id" DESC
LIMIT 20;
And the ‘optimized_relation` object would would produce the following query to utilize the index on (state, severity, vulnerability_id);
SELECT
"vulnerability_reads".*
FROM
unnest('{1, 4}'::smallint[]) AS "states" ("state"),
LATERAL (
SELECT
"vulnerability_reads".*
FROM
"vulnerability_reads"
WHERE
(vulnerability_reads."state" = "states"."state")
ORDER BY
"vulnerability_reads"."severity" DESC,
"vulnerability_reads"."vulnerability_id" DESC
LIMIT 20) AS vulnerability_reads
ORDER BY
"vulnerability_reads"."severity" DESC,
"vulnerability_reads"."vulnerability_id" DESC
LIMIT 20
If one of the columns being used for filtering or ordering is the primary key, then the query will be further optimized to use an index-only scan for initial filtering before selecting all columns using the primary key.
Using the prior query as an example, where ‘vulnerability_id` is the primary key, This will be rewritten to:
SELECT
"vulnerability_reads".*
FROM
"vulnerability_reads"
WHERE
"vulnerability_reads"."vulnerability_id"
IN (
SELECT
"vulnerability_reads"."vulnerability_id"
FROM
unnest('{1, 4}'::smallint[]) AS "states" ("state"),
LATERAL (
SELECT
"vulnerability_reads"."vulnerability_id"
FROM
"vulnerability_reads"
WHERE
(vulnerability_reads."state" = "states"."state")
ORDER BY
"vulnerability_reads"."severity" DESC,
"vulnerability_reads"."vulnerability_id" DESC
LIMIT 20
) AS vulnerability_reads
)
ORDER BY
"vulnerability_reads"."severity" DESC,
"vulnerability_reads"."vulnerability_id" DESC
LIMIT 20
158 159 160 161 162 163 164 |
# File 'lib/unnested_in_filters/rewriter.rb', line 158 def rewrite log_rewrite return filter_query unless primary_key_present? index_only_filter_query end |
#rewrite? ⇒ Boolean
166 167 168 169 170 |
# File 'lib/unnested_in_filters/rewriter.rb', line 166 def rewrite? strong_memoize(:rewrite) do in_filters.present? && has_index_coverage? end end |