This guide explains the complete lifecycle of a database query in Laravel—from the moment your code calls a query builder method to the point the result is returned—and shows you how to enable query logging to see exactly what SQL runs. You’ll learn how the query builder compiles SQL, how Eloquent adds its own layers, and how to track queries for debugging and performance tuning.
What You’ll Need
- A Laravel application (version 8 or newer recommended) with a database connection configured in
.env. - Basic familiarity with Laravel’s query builder and Eloquent models.
- Access to the command line to run
php artisan tinkeror use a route/controller for testing.
Step-by-Step
-
Start with the query builder or Eloquent call.
For example,DB::table('users')->where('active', 1)->get();orUser::where('active', 1)->get();. This initiates a new query on the connection. -
Understand the query builder’s role.
The query builder (classIlluminate\Database\Query\Builder) stores the query components—columns, where clauses, joins, orders, limits—in an internal array. No SQL is generated yet; it’s just an object holding instructions. -
Call a terminal method to execute.
Methods likeget(),first(),pluck(),insert(),update(), ordelete()trigger the execution. The builder passes itself to the connection’srun()method. -
Compile the SQL.
The connection calls the grammar class (e.g.,Illuminate\Database\Query\Grammars\MySqlGrammar) to convert the builder’s array into a SQL string. The grammar handles quoting, parameter placeholders, and dialect-specific syntax (likeLIMITvsTOP). -
Bind parameters.
Values fromwhere('active', 1)are extracted and stored as bindings. The SQL string contains placeholders (?), and the bindings array holds the actual values. This prevents SQL injection and allows the database to cache execution plans. -
Execute via PDO.
Laravel uses PDO to send the SQL and bindings to the database. The connection’srun()method callsPDOStatement::execute()and captures the result set or affected row count. -
Return results.
For SELECT queries, the result set is fetched and hydrated into objects (stdClass for query builder, Eloquent models for Eloquent). For INSERT, the last insert ID is returned; for UPDATE/DELETE, the affected row count is returned. -
Enable query logging.
To track queries, callDB::enableQueryLog()before your queries (or add it in a service provider). Then execute your queries. Afterward, retrieve the log withDB::getQueryLog(). It returns an array of entries, each withquery,bindings, andtime(in milliseconds). -
Use Eloquent’s lazy loading to see additional queries.
When you access a relationship like$user->posts, Laravel runs a separate query unless you eager load withwith('posts'). The query log will show these additional SELECT statements. -
Listen to query events for real-time tracking.
In yourAppServiceProvider, add a listener:DB::listen(function ($query) { ... });. The$queryobject hassql,bindings, andtime. This is useful for logging to a file or debugging bar. -
Clear the log when needed.
UseDB::flushQueryLog()to reset the log, especially if you’re profiling a specific section of code. -
Disable logging in production.
Query logging consumes memory and can slow down high-traffic apps. Keep it enabled only during development or debugging.
Common Mistakes
- Forgetting to enable the log before queries. If you call
getQueryLog()without enabling, you’ll get an empty array. - Assuming Eloquent runs one query per model call. Accessing relationships lazily triggers additional queries—this is the classic N+1 problem.
- Misreading the
timevalue. It’s in milliseconds, not seconds. A value of 2.5 means 2.5 milliseconds. - Using
DB::enableQueryLog()inside a loop. This resets the log each iteration; call it once before the loop. - Not clearing the log between test cases. In unit tests, queries accumulate; use
DB::flushQueryLog()insetUp().
Tips
- Use Laravel Debugbar or Clockwork in development to see queries in real time without manual logging.
- Eager load relationships with
with()to reduce query count and improve performance. - Use
DB::pretend()to run a query without actually executing it—useful for testing SQL generation. - Inspect the compiled SQL with
toSql()on a query builder instance to see the exact SQL before execution. - Use
explain()on a query to get the database’s execution plan, which helps identify missing indexes.
Troubleshooting
- Query log is empty. Ensure you called
DB::enableQueryLog()before any query. Also check that you’re using the same connection (default ismysql). If you use multiple connections, callDB::connection('other')->enableQueryLog(). - Queries are not appearing in the log. Some operations like
DB::statement()may not be logged by default. UseDB::listen()to capture all queries. - Bindings are empty or incorrect. This can happen when using raw expressions with
DB::raw()—those are not bound. Check your query for unbound raw values. - Performance is slow when logging is enabled. This is expected; the log stores every query in memory. Disable it in production and use a dedicated logging tool like Laravel Telescope or a database profiler.
- Eloquent relationship queries don’t show up. They do, but only if you access the relationship after enabling the log. If you eager load, the queries are executed as part of the main query, so they appear in the log as separate entries.
Frequently Asked Questions
How do I see the actual SQL with values instead of placeholders?
The query log stores the SQL with ? placeholders and a separate bindings array. To see the full SQL, you can manually replace placeholders with bindings, or use a tool like Laravel Debugbar that shows the interpolated query.
Does query logging affect performance?
Yes, it adds overhead because every query is stored in memory. In high-traffic production environments, it’s best to keep it disabled and rely on database-level logging or APM tools.
Can I log queries to a file instead of the array?
Yes, use DB::listen() and write the query details to a log file using Laravel’s Log facade or a custom logger.
Why does my Eloquent model run two queries for a simple find?
That’s unusual; find() runs one query. If you see two, check if you have model events, global scopes, or accessors that trigger additional queries. Also ensure you’re not accidentally accessing a relationship.
How do I count the number of queries in a request?
Use count(DB::getQueryLog()) after your code runs. For a more systematic approach, use middleware that captures the count and logs it.
Can I disable query logging for specific queries?
Not directly, but you can flush the log before a specific query and then compare the log size before and after to isolate that query’s entries.
Related
Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.
More cards in this drawer
- Campus Tech Innovation Hubs: What They Are
- Poco C51 Airtel Prepaid Locked Variant India?
- Jenkins vs GitHub Actions: Which CI/CD Fits Your Team?
- Turn Off Backup Encryption in iTunes?
- Shared VPS Hosting: Is It Better?
- Disk Defrag Pro: What It Does and Whether You Need It