Class: QueryGuard::Suggest::IndexSuggester
- Inherits:
-
Object
- Object
- QueryGuard::Suggest::IndexSuggester
- Defined in:
- lib/query_guard/suggest/index_suggester.rb
Overview
Generates index suggestions for queries with missing index indicators. Conservative approach: only suggests when patterns match common cases. All suggestions include disclaimer that they're recommendations only.
Example:
suggester = IndexSuggester.new
suggestion = suggester.suggest_for_sequential_scan(
"SELECT * FROM users WHERE email = '[email protected]'",
table_name: "users"
)
# => {
# suggested_index_sql: "CREATE INDEX idx_users_email ON users (email);",
# explanation: "Index on email column for WHERE clause equality",
# confidence: :medium,
# columns: ["email"]
# }
Constant Summary collapse
- CONFIDENCE_LEVELS =
%i[high medium low].freeze
Instance Method Summary collapse
-
#build_recommendation_text(suggestion) ⇒ String
Build neutral recommendation text for a suggestion.
-
#initialize ⇒ IndexSuggester
constructor
A new instance of IndexSuggester.
-
#suggest_for_complex_filter(sql, table_name:) ⇒ Hash?
Generate index suggestion for multi-column filter For WHERE with multiple equality conditions, suggest composite.
-
#suggest_for_expensive_sort(sql, table_name:) ⇒ Hash?
Generate index suggestion for expensive sort.
-
#suggest_for_join(column_name, table_name:) ⇒ Hash
Generate index suggestion for JOIN condition Suggests index on join key in inner table.
-
#suggest_for_sequential_scan(sql, table_name:, filter_condition: nil) ⇒ Hash?
Generate index suggestion for sequential scan with filter.
Constructor Details
#initialize ⇒ IndexSuggester
Returns a new instance of IndexSuggester.
24 25 26 |
# File 'lib/query_guard/suggest/index_suggester.rb', line 24 def initialize @extractors = PatternExtractors.new end |
Instance Method Details
#build_recommendation_text(suggestion) ⇒ String
Build neutral recommendation text for a suggestion
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/query_guard/suggest/index_suggester.rb', line 97 def build_recommendation_text(suggestion) return nil unless suggestion text = suggestion[:explanation] text += " (confidence: #{suggestion[:confidence]})" text += "\n\nIMPORTANT: This is a recommendation based on query pattern analysis. " text += "Before creating the index:\n" text += " 1. Verify this index hasn't already been suggested elsewhere\n" text += " 2. Check index size impact and maintenance cost\n" text += " 3. Run EXPLAIN ANALYZE with and without the index\n" text += " 4. Consider selectivity of indexed columns\n" text += " 5. Test in development first\n\n" text += "Suggested SQL (REVIEW BEFORE RUNNING):\n#{suggestion[:suggested_index_sql]}" text end |
#suggest_for_complex_filter(sql, table_name:) ⇒ Hash?
Generate index suggestion for multi-column filter For WHERE with multiple equality conditions, suggest composite
69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/query_guard/suggest/index_suggester.rb', line 69 def suggest_for_complex_filter(sql, table_name:) return nil if sql.nil? || table_name.nil? where_cols = @extractors.extract_where_columns(sql) return nil if where_cols.length < 2 # Conservative: only suggest composite for 2-3 columns return nil if where_cols.length > 3 suggest_composite_index(table_name, where_cols, reason: "composite filter") end |
#suggest_for_expensive_sort(sql, table_name:) ⇒ Hash?
Generate index suggestion for expensive sort
52 53 54 55 56 57 58 59 60 61 |
# File 'lib/query_guard/suggest/index_suggester.rb', line 52 def suggest_for_expensive_sort(sql, table_name:) return nil if sql.nil? || table_name.nil? # Extract ORDER BY columns order_cols = @extractors.extract_order_by_columns(sql) return nil if order_cols.empty? # For sorts, index all ORDER BY columns in order suggest_composite_index(table_name, order_cols, reason: "sort") end |
#suggest_for_join(column_name, table_name:) ⇒ Hash
Generate index suggestion for JOIN condition Suggests index on join key in inner table
87 88 89 90 91 |
# File 'lib/query_guard/suggest/index_suggester.rb', line 87 def suggest_for_join(column_name, table_name:) return nil if column_name.nil? || table_name.nil? suggest_index(table_name, column_name, high_confidence: true, reason: "join condition") end |
#suggest_for_sequential_scan(sql, table_name:, filter_condition: nil) ⇒ Hash?
Generate index suggestion for sequential scan with filter
34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/query_guard/suggest/index_suggester.rb', line 34 def suggest_for_sequential_scan(sql, table_name:, filter_condition: nil) return nil if sql.nil? || table_name.nil? # Extract columns from WHERE clause where_cols = @extractors.extract_where_columns(sql) return nil if where_cols.empty? # Use first column as primary index candidate # This is conservative: most benefit comes from first filter primary_col = where_cols.first suggest_index(table_name, primary_col, high_confidence: true) end |