NAME model_indexes - Database index analysis and recommendation system SYNOPSIS Automatic detection of required database indexes from model relationships and query patterns DESCRIPTION The RSX index analysis system automatically discovers which database indexes are required by analyzing model relationships and query patterns in your codebase. It generates optimized index recommendations using covering index logic and produces reviewable migration files. Unlike manual index management where developers must remember to create indexes for every foreign key and query pattern, RSX automatically detects missing indexes by analyzing: 1. Model relationships - Foreign key columns from #[Relationship] methods 2. Query patterns - AST analysis of Model::where() chains in /rsx/ Key differences from manual approaches: - Manual: Developer creates indexes as they remember - RSX: Automatic detection from code analysis - Manual: No way to know if indexes are missing - RSX: Command reports all missing indexes - Manual: Risk of redundant indexes - RSX: Covering index logic optimizes recommendations Benefits: - Never forget to index foreign keys - Automatic detection of query patterns - Optimized recommendations via covering logic - Quota management prevents too many indexes - Source attribution shows why each index is needed COMMAND USAGE Basic Analysis: php artisan rsx:db:check_indexes Shows summary of missing indexes and recommendations. Generate Migration: php artisan rsx:db:check_indexes --generate-migration Creates migration file in database/migrations/ with DDL statements. Detailed Analysis: php artisan rsx:db:check_indexes --show-details Shows verbose output with file counts and analysis progress. Analyze Specific Table: php artisan rsx:db:check_indexes --table=users Limit analysis to single table. Skip Relationship Analysis: php artisan rsx:db:check_indexes --no-relationships Only analyze query patterns, ignore relationship indexes. Skip Query Pattern Analysis: php artisan rsx:db:check_indexes --no-queries Only analyze relationships, ignore query patterns. RELATIONSHIP INDEX DETECTION How It Works: The system scans all models extending Rsx_Model_Abstract and finds methods with #[Relationship] attribute. For each relationship, it determines which table needs an index on which foreign key column. Detected Relationships: - hasMany() / hasOne() - Index on related table's foreign key - belongsTo() - No index needed (we have the foreign key) - belongsToMany() - Indexes on both pivot table foreign keys - morphMany() / morphOne() - Index on related table's morph_id Priority: Relationship indexes have HIGHEST priority and are never cut due to quota limits. Foreign keys must always be indexed for performance. Example Detection: // In User_Model.php #[Relationship] public function posts() { return $this->hasMany(Post_Model::class); } // Detected requirement: posts table needs index on user_id column // Source attribution: rsx/models/user_model.php:45 QUERY PATTERN DETECTION How It Works: The system uses AST parsing to scan all PHP files in /rsx/ that define classes. It finds Model::where() method chains and extracts the column names in order. Detected Patterns: // Single where clause User_Model::where('status', 'active')->get(); // Detected: Index on (status) // Chained where clauses User_Model::where('status', 'active') ->where('created_at', '>', '2024-01-01') ->get(); // Detected: Index on (status, created_at) // Multiple columns preserve order Order_Model::where('user_id', $id) ->where('status', 'pending') ->where('created_at', '>', $date) ->get(); // Detected: Index on (user_id, status, created_at) Not Detected (Documented Limitations): - Variable column names: where($column, 'value') - Complex WHERE clauses: whereIn(), whereRaw(), whereExists() - Join conditions (handled separately via relationship analysis) - Runtime-determined queries - orderBy() clauses (result set ordering, not filtering) Priority: Query pattern indexes have MEDIUM priority and are subject to quota limits. Multi-column indexes are preferred over single-column. Column Order: The system preserves the exact order of columns from your where() chain because MySQL index order matters for left-prefix matching. COVERING INDEX OPTIMIZATION Left-Prefix Matching Rule: MySQL can use an index (a, b, c) to satisfy queries filtering on: - (a) alone - (a, b) together - (a, b, c) together But it CANNOT use the index for: - (b) alone - (c) alone - (b, c) together Optimization Strategy: The system uses covering index logic to reduce redundant indexes: Requirements: (status), (status, created_at), (status, role) Analysis: - (status, created_at) covers (status) via left-prefix - (status, role) covers (status) via left-prefix - Neither covers the other (different second columns) Result: Create both (status, created_at) and (status, role) Drop standalone (status) - it's covered Reordering for Coverage: If you need both (status) and (user_id, status), the system could theoretically create (status, user_id) to cover both. However, this would hurt performance for queries filtering on user_id alone. Current Implementation: Does not reorder. Preserves query patterns. INDEX QUOTA MANAGEMENT MySQL Limits: MySQL InnoDB has a hard limit of 64 indexes per table. RSX Quota: The system reserves 32 indexes per table for auto-generated indexes, leaving 32 for user-defined custom indexes. When Quota Exceeded: If recommendations exceed available quota, the system prioritizes: Priority Tier 1: Relationship indexes (never cut) Priority Tier 2: Multi-column query indexes (2+ columns) Priority Tier 3: Single-column query indexes (cut first) The command displays a warning showing which indexes were cut and suggests manual review for those that couldn't be auto-applied. Example Warning: ⚠️ WARNING: Table 'users' exceeds index quota Recommended indexes: 45 Available quota: 12 (64 max - 52 existing user indexes) The following 33 indexes cannot be auto-applied: - idx_auto_status (single-column, cut) - idx_auto_email (single-column, cut) ... Consider reviewing existing user-defined indexes for redundancy. MIGRATION GENERATION Generated Migration Format: php artisan rsx:db:check_indexes --generate-migration Creates: database/migrations/{timestamp}_auto_index_recommendations.php Migration Content: where('status', 'active') - Better than: where('status', 'active')->where('user_id', $id) Custom Indexes: For queries the system can't detect, create custom indexes: - Use standard naming: idx_users_status_created_at - Avoid idx_auto_ prefix (reserved for system) - Document why the index is needed Regular Audits: Run index analysis as part of deployment checklist. Missing indexes are easier to add before production. Migration Review: Always review generated migrations before applying. Verify recommendations make sense for your data patterns. SEE ALSO model - RSX model system with relationships model_normalization - Schema normalization command migrations - Database migration system coding_standards - Code quality and standards