# Query statistics

Every `QueryResult` carries a `statistics` block taken from Athena's
`GetQueryExecution`. It is the cheapest way to see what a query cost, how long
it waited, and whether it was served from cache.

```typescript
const result = await athena.query<Row>(sql, { includeRuntimeStats: true });

result.statistics.totalExecutionTimeInMillis;   // 8128
result.statistics.resultReused;                 // true
result.statistics.runtime?.outputRows;          // 99
```

## The type

Included from `src/runtime/types.ts`:

```typescript
/**
 * What Athena reports about an execution. Every {@link QueryResult} carries
 * one. `dataScannedInBytes` is what drives the bill.
 */
export interface QueryStatistics {
  /** Engine execution time, in ms. */
  engineExecutionTimeInMillis: number;
  /** Wall time Athena took, in ms. */
  totalExecutionTimeInMillis: number;
  /** Time spent waiting in the queue, in ms. */
  queryQueueTimeInMillis: number;
  /** Planning and partition retrieval, in ms. */
  queryPlanningTimeInMillis: number;
  /** Preprocessing before the engine ran, in ms. */
  servicePreProcessingTimeInMillis: number;
  /** Result publication, in ms. */
  serviceProcessingTimeInMillis: number;
  /** Bytes scanned after partition pruning and projection. This is the cost. */
  dataScannedInBytes: number;
  /** Only present for capacity-reservation workgroups. */
  dpuCount?: number;
  /** True when Athena served the result from its result cache. */
  resultReused?: boolean;
  /** Populated only when `query()` is called with `{ includeRuntimeStats: true }`. */
  runtime?: QueryRuntimeRows;
}
```

| Field | Meaning |
| --- | --- |
| `engineExecutionTimeInMillis` | engine execution time |
| `totalExecutionTimeInMillis` | wall time Athena took |
| `queryQueueTimeInMillis` | time spent waiting in the queue |
| `queryPlanningTimeInMillis` | planning and partition retrieval |
| `servicePreProcessingTimeInMillis` | preprocessing before the engine ran |
| `serviceProcessingTimeInMillis` | result publication |
| `dataScannedInBytes` | what drives the bill |
| `dpuCount` | capacity-reservation workgroups only |
| `resultReused` | true when Athena served the result from its cache |
| `runtime` | input/output row and byte counts, opt-in |

## Runtime statistics are opt-in

`runtime` stays undefined unless you pass `{ includeRuntimeStats: true }`,
because populating it costs an extra `GetQueryRuntimeStatistics` API call.
Ask for it when you are measuring; leave it off in hot paths.
