Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Query Detector Laravel Package

beyondcode/laravel-query-detector

Detect N+1 query issues in Laravel during development. Monitors database queries in real time and alerts you when repeated queries suggest missing eager loading, helping you optimize performance and reduce unnecessary database calls.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the package in development:

composer require beyondcode/laravel-query-detector --dev

First use case: Run your Laravel app in debug mode (default). The package will automatically:

  1. Detect N+1 queries in real-time
  2. Show an alert on the page (e.g., "N+1 Query Detected: posts relation on Author model")

Where to look first:

  • Check the config file after publishing (php artisan vendor:publish --provider="BeyondCode\QueryDetector\QueryDetectorServiceProvider")
  • Review the default threshold (1 query by default)
  • Test with a known N+1 pattern (e.g., @foreach($authors as $author) {{ $author->posts }} @endforeach)

Implementation Patterns

Core Workflow

  1. Detection Phase:

    • Wrap your app in debug mode (or enable via QUERY_DETECTOR_ENABLED=true).
    • The package hooks into Laravel’s query builder to track relation loads.
  2. Alerting Phase:

    • Choose an output method (e.g., Alert, Log, Debugbar) via config.
    • Example: Log output writes to laravel.log with details like:
      [2024-05-20 12:00:00] local.DEBUG: N+1 Query Detected: "posts" relation on "App\Models\Author" (threshold: 1, query: "select * from `posts` where `posts`.`author_id` = ?")
      
  3. Fixing Phase:

    • Replace @foreach($authors as $author) {{ $author->posts }} with:
      $authors = Author::with('posts')->get();
      
    • Use the except config to whitelist relations that should trigger N+1 (e.g., lazy-loaded relations).

Integration Tips

  • Debugbar Integration: Install barryvdh/laravel-debugbar and add \BeyondCode\QueryDetector\Outputs\Debugbar::class to the output array. N+1 queries appear in the "Messages" tab.

  • Clockwork Integration: Add \BeyondCode\QueryDetector\Outputs\Clockwork::class and install itsgoingd/clockwork. Queries show in the "Queries" tab with a warning icon.

  • JSON Output for APIs: Add \BeyondCode\QueryDetector\Outputs\Json::class to inject warnings into API responses:

    {
      "data": { ... },
      "meta": {
        "query_warnings": [
          {
            "relation": "posts",
            "model": "App\Models\Author",
            "query": "select * from `posts` where `posts`.`author_id` = ?",
            "count": 5
          }
        ]
      }
    }
    
  • Event Listeners: Listen for \BeyondCode\QueryDetector\Events\QueryDetected to trigger custom actions (e.g., Slack alerts):

    QueryDetected::dispatch($query, $relation, $model, $count);
    
  • Lumen Support: Manually register the provider in bootstrap/app.php:

    $app->register(\BeyondCode\QueryDetector\LumenQueryDetectorServiceProvider::class);
    

Advanced Patterns

  • Dynamic Thresholds: Override the threshold per environment:

    QUERY_DETECTOR_THRESHOLD=3  # Warn only if a relation is loaded >3 times
    
  • Whitelisting Complex Relations: Whitelist nested relations (e.g., posts.comments):

    'except' => [
        Author::class => [
            Post::class,
            'posts',
            'posts.comments',
        ],
    ],
    
  • CI/CD Enforcement: Use the Log output in CI to fail builds with N+1 queries:

    php artisan query:detect --fail-on-n1  # Hypothetical future CLI command
    

Gotchas and Tips

Pitfalls

  1. False Positives:

    • The detector may flag intentional lazy loading (e.g., optional($user->profile)). Whitelist these relations in except.
    • Fix: Add the relation to except:
      'except' => [
          User::class => [
              Profile::class,
              'profile',
          ],
      ],
      
  2. Debugbar Conflicts:

    • If using Fruitcake Debugbar, ensure the Debugbar output class is updated to resolve the facade at runtime (handled in v2.3.0+).
  3. Lumen Quirks:

    • Lumen requires manual config file copying and provider registration. Forgetting this will silently disable detection.
  4. JSON Output Overhead:

    • The Json output adds metadata to every API response. Disable it in production:
      'output' => [
          \BeyondCode\QueryDetector\Outputs\Log::class,  // Only in dev
      ],
      
  5. Backtrace Limitations:

    • The detector uses PHP’s backtrace to identify the calling code. If the stack is obfuscated (e.g., by a decorator or proxy), it may misreport the source.
  6. Threshold Misconfiguration:

    • Setting threshold=0 disables detection entirely. Use threshold=1 (default) to catch all N+1 queries.

Debugging Tips

  • Inspect Queries: Use telescope or laravel-debugbar to verify the actual queries being fired. Compare with the detector’s output to confirm false positives/negatives.

  • Console Output: Add \BeyondCode\QueryDetector\Outputs\Console::class to see detailed warnings in the browser console, including:

    • The relation name (e.g., posts)
    • The model class (e.g., App\Models\Author)
    • The query SQL
    • The calling file and line
  • Event Debugging: Listen to QueryDetected in AppServiceProvider to log raw event data:

    public function boot()
    {
        \BeyondCode\QueryDetector\Events\QueryDetected::listen(function ($event) {
            \Log::debug('Raw event:', $event->toArray());
        });
    }
    
  • Performance Impact: The detector adds ~1–5ms overhead per query. Disable it in production:

    APP_DEBUG=false
    QUERY_DETECTOR_ENABLED=false
    

Extension Points

  1. Custom Output Channels: Extend \BeyondCode\QueryDetector\Contracts\Output to create a new channel (e.g., Datadog, Sentry):

    class SentryOutput implements Output
    {
        public function handle(QueryDetected $event)
        {
            Sentry::captureMessage(
                sprintf('N+1 Query: %s on %s', $event->relation, $event->model),
                'warning'
            );
        }
    }
    
  2. Query Filtering: Override the shouldDetect method in the service provider to ignore specific queries (e.g., cache misses):

    QueryDetector::shouldDetect(function ($query) {
        return !str_contains($query->sql, 'cache:');
    });
    
  3. Relation Normalization: Customize how relations are matched by extending the RelationResolver:

    QueryDetector::extend(function ($detector) {
        $detector->relationResolver = new CustomRelationResolver();
    });
    
  4. Multi-Tenant Support: Filter queries by tenant ID to avoid cross-tenant N+1 noise:

    'except' => [
        Tenant::class => [
            User::class,
            'users',
        ],
    ],
    

Pro Tips

  • Pair with laravel-debugbar: Use both packages to correlate N+1 queries with execution time, memory usage, and SQL query plans.

  • Automate Fixes: Write a PHPStan rule or PSR-12 linter to detect missing with() clauses:

    // Hypothetical rule: "Relation `$user->posts` is accessed without eager loading."
    
  • Benchmark Before/After: Use laravel-debugbar to measure query count reduction:

    - Queries: 50 (before)
    + Queries: 5  (after adding `with('posts')`)
    
  • Educate the Team: Add a Slack bot or GitHub template to notify devs when they introduce N+1 queries:

    🚨 N+1 Query Detected in PR #123:
    Relation `orders` on `Customer` loaded 10 times.
    Fix: Add `->with('orders')` to the query.
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
codraw/entity-migrator
codraw/doctrine-extra
codraw/aws-tool-kit
codraw/validator
codraw/workflow
codraw/open-api
codraw/cron-job
codraw/process
codraw/log
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony