Doctrine - How to print out the real sql, not just the prepared statement?
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
Introduction
In Doctrine, query logging usually shows SQL with placeholders plus a separate parameter array. That is correct for execution, but it can be hard to read when debugging complex filters. The practical workflow is to capture SQL, parameters, and types together, then build a debug-only interpolated representation for human inspection.
Why You See Placeholders Instead of Final SQL
Doctrine uses prepared statements for safety and performance. A query such as WHERE status = ? is compiled once, then parameter values are bound separately. Because binding happens at execution, the logger naturally prints placeholders.
With QueryBuilder, the three key pieces are:
- SQL text from
getSQL() - parameter values from
getParameters() - parameter types from each
Parameterobject
You need all three to understand what the database actually receives.
Capture SQL, Parameters, and Types
This service-style snippet logs the exact query parts for troubleshooting.
This is usually enough to resolve wrong filters, timezone issues, or type mismatches.
Build an Interpolated Debug String Safely
Sometimes you still want one string that looks like final SQL for logs. Do this only for debugging and never execute the interpolated string.
This representation is approximate, but very useful during diagnostics.
Use SQL Logger and Profilers
Doctrine DBAL supports SQL logging integrations, and frameworks such as Symfony can expose executed queries in a profiler panel. These tools show timing and bind values with minimal custom code.
If performance matters, pair SQL capture with EXPLAIN in your database shell. Seeing bound values and execution plans together often reveals missing indexes or poor filter order.
Practical Workflow in a Request Debug Session
A reliable request-level workflow is to assign a correlation identifier, log query parts with that identifier, and inspect only the failing request trace. This keeps logs readable when many requests run concurrently.
With this pattern, support engineers can reconstruct one failing query path quickly without enabling global verbose logging.
Common Pitfalls
A common pitfall is assuming interpolated debug SQL is byte-for-byte identical to driver execution. Database drivers apply quoting and type handling internally, so your debug string is only a diagnostic approximation.
Another issue is logging sensitive values such as emails, tokens, or personal data. Always redact or mask sensitive fields before writing logs.
Timezone conversion mistakes are also frequent with date parameters. Log normalized values in UTC when investigating date filters.
Finally, avoid enabling verbose SQL logging permanently in production. It can increase overhead and leak internal details.
Summary
- Doctrine shows placeholders by design because it uses prepared statements.
- For reliable debugging, log SQL text, parameter values, and parameter types together.
- Interpolated SQL strings are helpful for reading but should never be executed.
- Use profiler tooling for timing and query visibility.
- Redact sensitive values and keep heavy logging scoped to diagnostics.
Related reading
- Doctrine and composite unique keys
- Does 1 phase commit make sense in distributed systems?
- Does 2 phase locking need to keep the order of commands?
- Does a UNIQUE constraint automatically create an INDEX on the fields?
- Does a finally block run even if you throw a new Exception?
- Does a locked object stay locked if an exception occurs inside it?
- Does all the nodes in cassandra cluster know the partition key ranges for each other?
- Does anyone know of a asynchronous mysql lib for python?

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.