Download the PHP package karimalihussein/laravel-query-sentinel without Composer
On this page you can find all versions of the php package karimalihussein/laravel-query-sentinel. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download karimalihussein/laravel-query-sentinel
More information about karimalihussein/laravel-query-sentinel
Files in karimalihussein/laravel-query-sentinel
Package laravel-query-sentinel
Short Description A driver-agnostic, CI-ready, extensible Laravel package for analyzing database query performance
License MIT
Homepage https://github.com/karimalihussein/laravel-query-sentinel
Informations about the package laravel-query-sentinel
Laravel Query Sentinel
Enterprise-grade SQL performance diagnostics engine for Laravel. Runs EXPLAIN ANALYZE, scores queries across 5 weighted dimensions, detects 10 SQL anti-patterns, synthesizes index recommendations, estimates memory pressure under concurrency, tracks regressions over time, and simulates hypothetical indexes — all from a single diagnose() call or an interactive Artisan command.
Table of Contents
- Requirements
- Installation
- Quick Start
- Configuration
- Analysis Modes
- Mode 1: Raw SQL Analysis
- Mode 2: Query Builder / Eloquent Analysis
- Mode 3: Closure Profiling
- Mode 4: Class Method Profiling
- Mode 5: Full Deep Diagnostics
- Interactive Query Scanning
- Setting Up DiagnoseQuery
- Running the Scanner
- How It Works
- Writing Diagnosable Methods
- Automatic Profiling with Attributes
- Controller Profiling (Middleware)
- Service Class Profiling (Container Proxy)
- Sampling and Thresholds
- Fail on Critical
- Structured Logging
- Console Commands
- Deep Diagnostic Features
- 22-Step Analysis Pipeline
- Cardinality Drift Detection
- Anti-Pattern Detection
- Index Synthesis
- Confidence Scoring
- Concurrency Risk Analysis
- Memory Pressure Analysis
- Regression Baselines
- Hypothetical Index Simulation
- Workload Pattern Detection
- Plan Stability Analysis
- Report Reference
- Report Object (Single Query)
- DiagnosticReport Object (Full Diagnostics)
- ProfileReport Object (Multiple Queries)
- Grading System
- Scoring Components
- Metrics Extracted
- Built-in Rules
- Custom Rules
- Extension Points
- Architecture
- Testing
- License
Requirements
- PHP 8.2+
- Laravel 10, 11, or 12
- MySQL 8.0.18+ (for EXPLAIN ANALYZE) or PostgreSQL
Installation
Development only — Install as a dev dependency. It will not be present in production when you run
composer install --no-dev.
The service provider is auto-discovered. To publish the configuration:
Two facades are registered automatically:
QuerySentinel(primary)QueryDiagnostics(backward-compatible alias)
Quick Start
Configuration
After publishing, edit config/query-diagnostics.php:
Environment Variables
| Variable | Default | Description |
|---|---|---|
QUERY_SENTINEL_DRIVER |
mysql |
Database driver (mysql, pgsql) |
QUERY_SENTINEL_CONNECTION |
null |
Database connection name |
QUERY_SENTINEL_DIAGNOSTICS_ENABLED |
true |
Enable attribute-based profiling |
QUERY_SENTINEL_SAMPLE_RATE |
1.0 |
Global profiling sample rate (0.0-1.0) |
QUERY_SENTINEL_THRESHOLD_MS |
0 |
Global minimum cumulative time to log |
QUERY_SENTINEL_FAIL_ON_CRITICAL |
false |
Throw exception on critical findings |
Analysis Modes
Mode 1: Raw SQL Analysis
Analyze a raw SQL string. Validated for safety (only SELECT/WITH), sanitized, and run through EXPLAIN ANALYZE.
Safety: Only read-only SQL is accepted. Destructive statements throw UnsafeQueryException.
Mode 2: Query Builder / Eloquent Analysis
Analyze a Builder instance without executing it. SQL and bindings are extracted via toSql() / getBindings().
Mode 3: Closure Profiling
Profile all database queries inside a closure. Captures via DB::listen(), wraps in transaction (rolled back), and analyzes each SELECT.
Safety: Transaction is always rolled back. No writes persist.
Mode 4: Class Method Profiling
Profile a class method resolved from the Laravel container.
Mode 5: Full Deep Diagnostics
Run the full 22-step diagnostic pipeline with all deep analyzers.
Interactive Query Scanning
The query:scan command discovers methods annotated with #[DiagnoseQuery], presents an interactive list, and runs full EXPLAIN ANALYZE diagnostics on the selected query builder.
Setting Up DiagnoseQuery
Add the #[DiagnoseQuery] attribute to methods that return a Query Builder:
Running the Scanner
Example interactive session:
How It Works
- Scan — Finder locates PHP files containing
DiagnoseQueryin configured paths (app/,Modules/) - Reflect — PHP Reflection discovers annotated methods and extracts metadata
- Select — Developer picks a method from the interactive list
- Resolve — Class is resolved from the Laravel container (DI works normally)
- Execute — Method is called inside
DB::beginTransaction()to get the Builder - Rollback — Transaction is immediately rolled back (no side effects)
- Extract — SQL and bindings are extracted from the Builder via
toSql()/getBindings() - Diagnose — Full
Engine::diagnose()pipeline runs EXPLAIN ANALYZE + all deep analyzers - Report — Full diagnostic report is rendered to the console
Writing Diagnosable Methods
The annotated method must:
- Return an
Eloquent\BuilderorQuery\Builderinstance - Not execute the query (no
->get(),->paginate(),->first()) - Have no required parameters (all params must be optional or have defaults)
If your production method takes parameters, create a dedicated diagnosis method:
Configure which directories to scan:
Automatic Profiling with Attributes
The #[QueryDiagnose] attribute enables zero-code-change runtime profiling. Place it on any controller or service method to automatically capture, analyze, and log query performance during normal execution.
Two different attributes for two different purposes:
#[DiagnoseQuery]— Interactive CLI scanning (returns a Builder, used withquery:scan)#[QueryDiagnose]— Runtime profiling (captures queries during execution, logs results)
Controller Profiling (Middleware)
Register the middleware:
Apply to routes:
Add the attribute:
Methods without the attribute pass through with zero overhead.
Service Class Profiling (Container Proxy)
Register service classes in config:
Add attributes to methods:
When the service is resolved from the container, it is wrapped in a MethodInterceptor proxy that intercepts attributed methods and forwards everything else directly.
Sampling and Thresholds
Sampling controls how often profiling activates:
Effective rate: min(methodRate, globalRate).
Thresholds filter logging noise:
Effective threshold: max(methodThreshold, globalDefault).
| Attribute Param | Config Key | Combination Logic |
|---|---|---|
sampleRate |
diagnostics.global_sample_rate |
min(method, global) — most restrictive wins |
thresholdMs |
diagnostics.default_threshold_ms |
max(method, global) — highest bar wins |
Fail on Critical
Throw PerformanceViolationException on critical performance issues:
Triggers when: worst grade is D/F, any query > 500ms, full table scan, or N+1 detected.
Structured Logging
Profiled invocations are logged as structured JSON:
Log levels: error (D/F), warning (C or N+1), info (A/B).
Console Commands
query:diagnose — Analyze Raw SQL
query:scan — Interactive Builder Diagnosis
Console Report Output
CI Integration
Deep Diagnostic Features
When using Engine::diagnose() or query:diagnose / query:scan, the full 22-step pipeline runs automatically.
22-Step Analysis Pipeline
| Step | Phase | What It Does |
|---|---|---|
| 1 | Base | EXPLAIN ANALYZE + parse metrics + score + rules |
| 2 | Environment | Collect MySQL config (buffer pool, InnoDB, cache warmth) |
| 3 | Execution Profile | Nested loop depth, B-tree depths, physical reads, complexity |
| 4 | Index Cardinality | Per-table index statistics and selectivity |
| 5 | Cardinality Drift | Estimated vs actual rows divergence |
| 6 | Join Analysis | Join strategy, fan-outs, join order |
| 7 | Anti-Patterns | 10 SQL anti-patterns (SELECT *, leading wildcard, etc.) |
| 8 | Index Synthesis | ERS-ordered composite index recommendations |
| 9 | Memory Pressure | Sort/join/temp buffers, concurrency-adjusted footprint |
| 10 | Concurrency Risk | Lock scope, deadlock risk, contention scoring |
| 11 | Plan Stability | Plan flip risk, volatility score, optimizer hints |
| 12 | Regression Safety | Implicit type conversions, collation mismatches |
| 13 | Confidence Score | 8-factor trustworthiness rating |
| 14 | Regression Baselines | Score/time/rows changes vs historical baseline |
| 15 | Hypothetical Indexes | Before/after EXPLAIN simulation (local/testing) |
| 16 | Workload Patterns | Repeated exports, API bursts, large transfers |
| 17 | Complexity | Scan + sort complexity classification |
| 18 | Explain Why | Human-readable insight (index choice, filesort reason, etc.) |
| 19 | Root-cause suppression | Remove misleading generic findings |
| 20 | Finding deduplication | Merge overlapping recommendations |
| 21 | Confidence gating | Downgrade severity when confidence is low |
| 22 | Consistency validation | Log-only internal coherence check |
Cardinality Drift Detection
Compares optimizer row estimates against actual rows from EXPLAIN ANALYZE. Large deviations indicate stale statistics.
Config: cardinality_drift.warning_threshold (default 0.5), cardinality_drift.critical_threshold (default 0.9).
Anti-Pattern Detection
Static SQL analysis for 10 common performance anti-patterns:
| Pattern | Severity | Why It Matters |
|---|---|---|
SELECT * |
Warning | Prevents covering index optimization |
| Functions on indexed columns | Warning | Breaks index usage (e.g., WHERE YEAR(created_at) = 2026) |
| Excessive OR chains | Warning | Inefficient range scans (threshold: 3+) |
| Correlated subqueries | Warning | Executes once per outer row |
NOT IN with subquery |
Warning | NULL handling issues, anti-join problems |
| Leading wildcard LIKE | Warning | Forces full table scan (LIKE '%term') |
| Missing LIMIT on large result | Optimization | Unbounded memory consumption |
ORDER BY RAND() |
Warning | O(n log n) full sort |
| Redundant DISTINCT | Optimization | Unnecessary with PRIMARY/UNIQUE key |
| Implicit type conversion | Warning | Prevents index usage |
Config: anti_patterns.or_chain_threshold (default 3), anti_patterns.missing_limit_row_threshold (default 10000).
Index Synthesis
Recommends optimal composite indexes using the ERS principle (Equality, Range, Sort, Select columns):
Config: index_synthesis.max_recommendations (default 3), index_synthesis.max_columns_per_index (default 5).
Confidence Scoring
Attaches a trustworthiness score (0-1.0) to the analysis based on 8 weighted factors:
| Factor | Weight | Measures |
|---|---|---|
| Estimation accuracy | 25% | 1.0 minus composite drift score |
| Sample size | 20% | Actual rows (1.0 at 1000+ rows) |
| EXPLAIN ANALYZE available | 15% | 1.0 if supported, 0.3 otherwise |
| Cache warmth | 10% | 1.0 if buffer pool > 50% utilized |
| Statistics freshness | 10% | Ratio of non-stale tables |
| Plan stability | 10% | 1.0 if stable, 0.5 if flip risk |
| Query complexity | 5% | 0.7 if > 3 joins |
| Driver capabilities | 5% | Full support = 1.0 |
Labels: high (90%+), moderate (70-89%), low (50-69%), unreliable (<50%).
When confidence is low, findings are automatically downgraded (Critical to Warning at <70%, Critical/Warning down one level at <50%).
Concurrency Risk Analysis
Evaluates lock contention, deadlock potential, and isolation impact:
Memory Pressure Analysis
Estimates query memory footprint under concurrency:
Network pressure levels: LOW (<50MB), MODERATE (50-100MB), HIGH (100-200MB), CRITICAL (>200MB).
Regression Baselines
Tracks query performance over time. Each diagnose() call saves a snapshot. Subsequent runs compare against the baseline to detect regressions.
Smart regression detection:
- Normalizes for data growth (if rows grew >20%, checks per-row cost instead)
- Ignores sub-millisecond timing jitter (noise floor: 3ms)
- Detects plan changes (access type downgrades like
reftoALL)
Config: regression.score_warning_threshold (default 10%), regression.time_warning_threshold (default 50%).
Hypothetical Index Simulation
Creates temporary indexes, runs EXPLAIN, compares before/after, then drops them. Only runs in local/testing environments.
Improvement levels: significant (access type improved), moderate (>50% row reduction), marginal (>10%), none.
Workload Pattern Detection
Tracks query execution patterns over time to detect systemic issues:
| Pattern | Severity | Triggers When |
|---|---|---|
REPEATED_FULL_EXPORT |
Critical | 100K+ row query executed 10+ times with 3+ full exports |
HIGH_FREQUENCY_LARGE_TRANSFER |
Warning | >50MB network transfer, 10+ executions |
API_MISUSE_BURST |
Warning | 5+ executions within 60 seconds |
Config: workload.frequency_threshold (default 10), workload.export_row_threshold (default 100K).
Plan Stability Analysis
Detects optimizer plan flip risk from estimation deviations:
Report Reference
Report Object (Single Query)
Returned by analyzeSql() and analyzeBuilder():
DiagnosticReport Object (Full Diagnostics)
Returned by diagnose():
ProfileReport Object (Multiple Queries)
Returned by profile() and profileClass():
Grading System
| Grade | Score Range | Meaning |
|---|---|---|
| A+ | 98 - 100 | Perfect — optimal execution plan |
| A | 90 - 97 | Excellent — well-optimized query |
| B | 75 - 89 | Good — minor optimization opportunities |
| C | 50 - 74 | Fair — notable performance issues |
| D | 25 - 49 | Poor — significant performance problems |
| F | 0 - 24 | Critical — severe performance issues |
Score modifiers:
- Context override promotes to A (95+) when: LIMIT-optimized + covering index + no filesort + <10ms
- Dataset dampening applies log10 formula for large unbounded result sets
- Confidence gating caps grade when analysis confidence is low
Scoring Components
| Component | Default Weight | What It Measures |
|---|---|---|
execution_time |
30% | Query execution speed (3-regime model) |
scan_efficiency |
25% | Ratio of rows returned vs rows examined |
index_quality |
20% | Index usage, covering index, access type |
join_efficiency |
15% | Join type quality and nested loop depth |
scalability |
10% | Complexity class projection at scale |
Metrics Extracted
| Metric | Type | Description |
|---|---|---|
execution_time_ms |
float | EXPLAIN ANALYZE execution time |
rows_examined |
int | Total rows read from storage |
rows_returned |
int | Rows returned to client |
selectivity_ratio |
float | rows_examined / rows_returned |
complexity |
string | O(1), O(log n), O(n), O(n log n), O(n²) |
has_table_scan |
bool | Full table scan detected |
has_filesort |
bool | External sort operation |
has_temp_table |
bool | Temporary table created |
has_disk_temp |
bool | Temp table spilled to disk |
has_weedout |
bool | Semi-join weedout optimization |
has_index_merge |
bool | Index merge optimization |
has_covering_index |
bool | Query served entirely from index |
has_early_termination |
bool | LIMIT-optimized early stop |
is_index_backed |
bool | Uses any index |
is_intentional_scan |
bool | Full dataset retrieval (no WHERE, no LIMIT) |
indexes_used |
string[] | Index names used |
tables_accessed |
string[] | Table names accessed |
Built-in Rules
| Rule | Severity | Triggers When |
|---|---|---|
FullTableScanRule |
Critical | Full table scan on > 10,000 rows |
NoIndexRule |
Critical | No index used at all |
TempTableRule |
Critical/Warning | Temporary table created (critical if on disk) |
QuadraticComplexityRule |
Critical | O(n^2) complexity detected |
DeepNestedLoopRule |
Warning | Nested loop depth exceeds threshold (default 4) |
StaleStatsRule |
Warning | Table statistics appear outdated |
LimitIneffectiveRule |
Warning | LIMIT clause doesn't prevent full scan |
IndexMergeRule |
Info | Index merge optimization detected |
WeedoutRule |
Info | Semi-join weedout strategy detected |
Custom Rules
Extend BaseRule:
Register in config:
Extension Points
Custom Drivers
Implement DriverInterface for other databases:
Custom Scoring Engine
Implement ScoringEngineInterface:
Architecture
Design Principles
- Framework-agnostic core —
QueryAnalyzeroperates on SQL strings with no Laravel dependency - Lazy adapter loading — Adapters instantiated only when their Engine methods are called
- Safety first —
ExecutionGuardblocks destructive SQL;ProfilerAdapterwraps in transaction+rollback - Zero overhead — Non-attributed methods pass through with only a cached reflection lookup
- Confidence-aware — All findings are gated by analysis confidence; low confidence auto-downgrades severity
- Root-cause-aware — Generic index findings suppressed when the real issue is function wrapping or leading wildcard
Testing
License
MIT
All versions of laravel-query-sentinel with dependencies
illuminate/console Version ^10.0||^11.0||^12.0
illuminate/contracts Version ^10.0||^11.0||^12.0
illuminate/database Version ^10.0||^11.0||^12.0
illuminate/support Version ^10.0||^11.0||^12.0