Class: PgCanary::Rules::HugeInList
- Inherits:
-
Base
- Object
- Base
- PgCanary::Rules::HugeInList
show all
- Defined in:
- lib/pg_canary/rules/definitions/huge_in_list.rb
Overview
IN (...) / = ANY(...) with a huge number of values: the statement
itself becomes expensive to parse/plan and usually signals a missing
JOIN. Counts literal list items and runtime array binds, which static
SQL linters cannot see.
Threshold: config.rules.huge_in_list.threshold (default 500).
Constant Summary
PgQuerySupport::COMPARISON_OPS
Class Method Summary
collapse
Instance Method Summary
collapse
Methods inherited from Base
all, #enabled?, rule_name
Class Method Details
.options ⇒ Object
15
16
17
|
# File 'lib/pg_canary/rules/definitions/huge_in_list.rb', line 15
def self.options
{ threshold: 500 }
end
|
Instance Method Details
#check(query) ⇒ Object
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
# File 'lib/pg_canary/rules/definitions/huge_in_list.rb', line 19
def check(query)
threshold = rule_config(query).threshold
detections = []
query.each_scope do |scope|
next unless scope.where_clause
walk_within_scope(scope.where_clause) do |node|
next unless node.is_a?(PgQuery::A_Expr)
count = value_count(query, node)
next unless count && count > threshold
table, column = resolve_lexpr(scope, node)
detections << detection(
query,
table: table,
columns: column,
message: "IN / ANY list with #{count} values (threshold: #{threshold}). Huge value lists " \
"are expensive to parse and plan, and usually mean a JOIN is missing.",
suggestion: "Rewrite as a JOIN against the source of the values (subquery or VALUES list) " \
"instead of materializing the ids in the query."
)
end
end
detections
end
|
#default_enabled ⇒ Object
11
12
13
|
# File 'lib/pg_canary/rules/definitions/huge_in_list.rb', line 11
def default_enabled
true
end
|