# Profiling
TideORM exposes two different profiling tools:
- `GlobalProfiler` for lightweight application-wide query timing and slow-query counters.
- `Profiler` for manual profiling sessions where you want to build a detailed `ProfileReport` yourself.
Use `GlobalProfiler` when you want to observe real query execution with minimal setup. Use `Profiler` when you want to capture custom SQL strings, table names, row counts, and run `QueryAnalyzer` over a curated set of queries.
## Global Profiling
`GlobalProfiler` records aggregate timing data for real executed queries when it is enabled.
```rust
use tideorm::prelude::*;
use tideorm::profiling::GlobalProfiler;
GlobalProfiler::enable();
GlobalProfiler::reset();
GlobalProfiler::set_slow_threshold(200);
let users = User::query()
.where_eq("active", true)
.limit(25)
.get()
.await?;
let stats = GlobalProfiler::stats();
println!("{}", stats);
GlobalProfiler::disable();
```
When enabled, TideORM records query timings from the main execution paths:
- query-builder reads and counts routed through the database helpers
- raw SQL helpers such as `Database::raw`, `Database::execute`, and JSON/raw parameterized helpers
- direct CRUD methods generated by the `Model` derive such as `find`, `save`, `update`, `delete`, and `destroy`
- aggregate helpers such as `count_distinct`, `sum`, `avg`, `min`, and `max`
- full-text search execution paths
- internal executor paths used by batch and model helpers
`GlobalStats` exposes:
- `total_queries`
- `total_time()`
- `avg_query_time()`
- `slow_queries`
- `slow_percentage()`
## What Global Profiling Does Not Capture
`GlobalProfiler` is intentionally lightweight. It tracks counts and durations, but it does not retain SQL text or per-query metadata.
If you need a detailed report with SQL strings, operation types, slowest queries, table counts, or custom annotations, build that report manually with `Profiler` and `ProfiledQuery`.
## Manual Profile Reports
`Profiler` is a report builder. It does not automatically subscribe to all TideORM queries by itself.
```rust
use std::time::Duration;
use tideorm::profiling::{ProfiledQuery, Profiler};
let mut profiler = Profiler::start();
profiler.record("SELECT * FROM users WHERE active = true", Duration::from_millis(12));
profiler.record_full(
ProfiledQuery::new("SELECT * FROM posts WHERE user_id = 42", Duration::from_millis(37))
.with_table("posts")
.with_rows(8),
);
let report = profiler.stop();
println!("{}", report);
```
This is useful when you are instrumenting a benchmark, comparing alternative query shapes, or building a focused performance report in tests.
## Query Analysis
`QueryAnalyzer` can inspect SQL and return optimization suggestions.
```rust
use tideorm::profiling::QueryAnalyzer;
let suggestions = QueryAnalyzer::analyze("SELECT * FROM users WHERE email = 'john@example.com'");
for suggestion in suggestions {
println!("{}", suggestion);
}
```
Use this alongside `Profiler` when you want human-readable guidance about indexing, query shape, and complexity.
## Related Features
- Query logging is covered in [Queries](queries.md).
- Slow-query thresholds for logs and profiler statistics are separate settings.
- The global profiler is process-wide, so reset it between tests when you need deterministic assertions.