Module: QueryOwl::Detector

Defined in:
lib/query_owl/detector.rb

Constant Summary collapse

NORMALIZE_PATTERNS =

Matches numeric literals, single-quoted strings, and IN-list contents.

[
  [/'[^']*'/, "?"],
  [/\b\d+\b/, "?"],
  [/\s+/, " "]
].freeze

Class Method Summary collapse

Class Method Details

.detect_n_plus_one(queries) ⇒ Object



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/query_owl/detector.rb', line 11

def detect_n_plus_one(queries)
  threshold = QueryOwl.config.n_plus_one_threshold

  queries
    .reject { |q| q[:cached] }
    .group_by { |q| normalize(q[:sql]) }
    .filter_map do |normalized_sql, group|
      next if group.length < threshold

      {
        type: :n_plus_one,
        sql: normalized_sql,
        count: group.length,
        backtrace: group.first[:backtrace]
      }
    end
end

.detect_slow_queries(queries) ⇒ Object



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/query_owl/detector.rb', line 29

def detect_slow_queries(queries)
  threshold = QueryOwl.config.slow_query_threshold_ms

  queries.filter_map do |q|
    next if q[:cached]
    next if q[:duration_ms] < threshold

    {
      type: :slow_query,
      sql: normalize(q[:sql]),
      duration_ms: q[:duration_ms],
      backtrace: q[:backtrace]
    }
  end
end

.normalize(sql) ⇒ Object



45
46
47
48
49
# File 'lib/query_owl/detector.rb', line 45

def normalize(sql)
  NORMALIZE_PATTERNS
    .reduce(sql.to_s) { |s, (pattern, replacement)| s.gsub(pattern, replacement) }
    .strip
end