Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions docs/environment-variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ OpenObserve is configured using the following environment variables.
| ZO_LOCAL_MODE | true | If local mode is set to true, OpenObserve becomes single node deployment.If it is set to false, it indicates cluster mode deployment which supports multiple nodes with different roles. For local mode one needs to configure SQLite DB, for cluster mode one needs to configure PostgreSQL (recommended) or MySQL. |
| ZO_LOCAL_MODE_STORAGE | disk | Applicable only for local mode. By default, local disk is used as storage. OpenObserve supports both disk and S3 in local mode. |
| ZO_NODE_ROLE | all | Node role assignment. Possible values are ingester, querier, router, compactor, alertmanager, and all. A single node can have multiple roles by specifying them as a comma-separated list. For example, compactor, alertmanager. |
| ZO_NODE_ROLE_GROUP | "" | Each query-processing node can be assigned to a specific group using ZO_NODE_ROLE_GROUP. <br>
**interactive**: Handles queries triggered directly by users through the UI. <br>
**background**: Handles automated or scheduled queries, such as alerts and reports. <br>
**empty string** (default): Handles all query types. <br>
In high-load environments, alerts or reports might run large, resource-intensive queries. By assigning dedicated groups, administrators can prevent such queries from blocking or slowing down real-time user searches. |
| ZO_NODE_HEARTBEAT_TTL | 30 | Time-to-live (TTL) for node heartbeats in seconds. |
| ZO_INSTANCE_NAME | - | In the cluster mode, each node has a instance name. Default is instance hostname. |
| ZO_CLUSTER_COORDINATOR | nats | Defines how nodes in the cluster discover each other. |
Expand Down Expand Up @@ -573,9 +578,9 @@ OpenObserve is configured using the following environment variables.
| Environment Variable | Default Value | Description |
| -------------------------------- | --------- | ------------------------------------------------------- |
| ZO_QUICK_MODE_ENABLED | false | Indicates if quick mode is enabled. |
| ZO_QUICK_MODE_NUM_FIELDS | 500 | The number of fields to consider for quick mode. |
| ZO_QUICK_MODE_STRATEGY | | Possible values are `first`, `last`, `both`. |
| ZO_QUICK_MODE_FORCE_ENABLED | true | |
| ZO_QUICK_MODE_FORCE_ENABLED | true | Enables automatic activation of Quick Mode from the backend. When set to true, OpenObserve applies Quick Mode automatically if the number of fields in a stream exceeds the limit defined by `ZO_QUICK_MODE_NUM_FIELDS`, even when the Quick Mode toggle in the UI is turned off.|
| ZO_QUICK_MODE_NUM_FIELDS | 500 | This defines the number of fields beyond which the quick mode will be force enabled. |

## Miscellaneous
| Environment Variable | Default Value | Description |
Expand Down
Binary file added docs/images/add-new-fields.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/cached-ratio-dashboard.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/dashboard-query-example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/delete-fields.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/images/example-1-query-recommendations.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/images/example-2-query-recommendations.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/field-name-data-type.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/images/select-query-recommendations.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/update-settings.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/images/use-query-recommendations.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
343 changes: 343 additions & 0 deletions docs/user-guide/dashboards/histogram-caching.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,343 @@
---
title: Histogram Caching in Dashboards
description: Learn how histogram caching in OpenObserve dashboards reuses results for overlapping time ranges, improves query performance.
---

## Overview
When dashboard panels run queries over relative time ranges such as `Past 15 minutes` or `Past 1 hour`, the queried data often overlaps between refreshes.
To avoid scanning the same data repeatedly, OpenObserve uses **histogram caching**.

### Why caching is needed
Most dashboard queries overlap in time when refreshed.
<br>

**For example**:

- First query: `07:00` to `07:15`
- Next query: `07:01` to `07:16`

The two ranges share 14 minutes of the same data.
Only the one new minute from `07:15` to `07:16` needs fresh scanning.
Histogram caching reuses data for that overlapping part to prevent redundant processing.

### How caching works
Histogram caching operates automatically for dashboard panels that visualize time-series data.
When a new query overlaps with the previous time window, OpenObserve:

- Fetches the cached portion of results for the shared range.
- Scans and appends only the new slice of time.
- Updates metadata such as start and end timestamps.

### Example query
```sql
SELECT histogram(_timestamp) AS x_axis_1,
count(k8s_node_name) AS y_axis_1
FROM "default"
GROUP BY x_axis_1
ORDER BY y_axis_1 DESC
```

In this query:

- `x_axis_1` represents time intervals on the X-axis, created by the `histogram()` function.
- `y_axis_1` represents the count of log entries for each interval.

When run repeatedly over relative time ranges, only the new data beyond the last cached timestamp is scanned, while older intervals are reused.
![dashboard-query-example](../../images/dashboard-query-example.png)

## Inspecting caching behavior
You can observe histogram caching in your browser’s developer tools by viewing the query metadata and response stream.

### View query response in the browser

Open the dashboard panel that already contains a runnable query.

1. Right-click anywhere on the page and select **Inspect**.
2. Select the **Network** tab.
3. Keep the **Network** tab open and click **Run query** in the OpenObserve dashboard.
4. Select the latest request.
5. Open the **Response** tab to see the event stream returned by the server.


### Key metadata fields
| Field name | Meaning | Typical observation |
| --------------------- | ---------------------------------------- | ------------------------------------------------- |
| `cached_ratio` | Percentage of results fetched from cache | `0` for cold query, `100` for full cache reuse |
| `order_by_metadata` | Field and direction used for sorting | `[["x_axis_1","asc"]]` or `[["y_axis_1","desc"]]` |
| `scan_records` | Number of records read from disk | Lower on cache hits |
| `took`, `took_detail` | Total query time and breakdown | Shorter when cache reuse occurs |
| `is_histogram_eligible` | Eligibility for histogram caching | True for time-based histogram queries |
| `search_response_hits` | Actual rows returned | Sorted consistently with order metadata |
| `progress` | Query progress percentage | Moves from `0` to `100` |


### Understanding cache ratios

`cached_ratio` indicates how much of a query’s output is reused.

- `0` > first run
- `100` > complete cache reuse
- Partial value (`40`–`70`) > partial reuse for extended ranges
- Slightly less than `100` > recent data freshly scanned for accuracy

![cached-ration-dashboard](../../images/cached-ratio-dashboard.png)

## Histogram caching scenarios

The following examples describe how histogram caching behaves across various query types and ordering patterns.
Each scenario includes the SQL query and what happens when executed in OpenObserve dashboards.

### Basic histogram with COUNT ORDER BY DESC

```sql
SELECT histogram(_timestamp) AS x_axis_1, count(_timestamp) AS y_axis_1
FROM "default"
GROUP BY x_axis_1
ORDER BY y_axis_1 DESC
```

**What happens**: Results are cached with data ordered by count descending. Later queries reuse the cached data while preserving order.

### Basic histogram with COUNT ORDER BY ASC
```sql
SELECT histogram(_timestamp) AS x_axis_1, count(_timestamp) AS y_axis_1
FROM "default"
GROUP BY x_axis_1
ORDER BY y_axis_1 ASC
```

**What happens**: Results are cached with data ordered by count ascending. A separate cache entry exists for ascending order.

### Histogram with SUM ORDER BY
```sql
SELECT histogram(_timestamp) AS time_bucket, SUM(bytes) AS total_bytes
FROM "default"
GROUP BY time_bucket
ORDER BY total_bytes DESC
```

**What happens**: Results are cached with records ordered by the sum of bytes. Cache preserves both ordering field and direction.

### Histogram with AVG ORDER BY
```sql
SELECT histogram(_timestamp) AS time_bucket, AVG(response_time) AS avg_response
FROM "default"
GROUP BY time_bucket
ORDER BY avg_response DESC
```

**What happens**: Results are cached with data ordered by average response time descending. Cached order metadata ensures correct sorting.

### Histogram with multiple aggregations, non-timestamp ORDER BY
```sql
SELECT histogram(_timestamp) AS time_bucket,
count(*) AS event_count,
SUM(bytes) AS total_bytes
FROM "default"
GROUP BY time_bucket
ORDER BY total_bytes DESC
```

**What happens**: Results are cached with records ordered by total bytes. Both aggregations are stored; ordering follows total_bytes.

### Histogram with MAX ORDER BY
```sql
SELECT histogram(_timestamp) AS time_bucket, MAX(value) AS max_val
FROM "default"
GROUP BY time_bucket
ORDER BY max_val DESC
```

**What happens**: Results are cached with data ordered by maximum value. Order metadata is preserved for consistent sorting.

### Multiple histogram columns with non-timestamp ORDER BY
```sql
SELECT histogram(_timestamp) AS time_bucket,
status_code,
count(*) AS request_count
FROM "default"
GROUP BY time_bucket, status_code
ORDER BY request_count DESC
```

**What happens**: Results are cached with grouping on both time_bucket and status_code. Cache preserves correct grouping and order.

### Standard histogram with timestamp ORDER BY (default ascending)
```sql
SELECT histogram(_timestamp) AS x_axis_1, count(_timestamp) AS y_axis_1
FROM "default"
GROUP BY x_axis_1
ORDER BY x_axis_1 ASC
```

**What happens**: Results are cached in chronological order. Fast first-and-last logic improves reuse.

### Standard histogram with timestamp ORDER BY DESC
```sql
SELECT histogram(_timestamp) AS x_axis_1, count(_timestamp) AS y_axis_1
FROM "default"
GROUP BY x_axis_1
ORDER BY x_axis_1 DESC
```

**What happens**: Results are cached in reverse chronological order. Cache reuse follows the same efficiency path.

### Histogram with no ORDER BY (default time order)
```sql
SELECT histogram(_timestamp) AS x_axis_1, count(_timestamp) AS y_axis_1
FROM "default"
GROUP BY x_axis_1
```

**What happens**: Results are cached in default ascending timestamp order. Overlapping time windows reuse cache data.

### Histogram with explicit _timestamp ORDER BY
```sql
SELECT histogram(_timestamp) AS time_bucket, count(*) AS cnt
FROM "default"
GROUP BY time_bucket
ORDER BY _timestamp DESC
```

**What happens**: Results are cached using timestamp ordering identical to the default histogram order.

### Non-histogram aggregate query
```sql
SELECT count(*) AS total_count, SUM(bytes) AS total_bytes
FROM "default"
WHERE _timestamp BETWEEN '2025-10-01' AND '2025-10-06'
```

**What happens**: Cached using standard mechanisms, not histogram caching.

### Raw log query (no aggregation)
```sql
SELECT * FROM "default"
WHERE _timestamp BETWEEN '2025-10-01' AND '2025-10-06'
ORDER BY _timestamp DESC
LIMIT 1000
```

**What happens**: Cached normally through standard query caching, not histogram caching.

### Non-histogram with non-timestamp ORDER BY
```sql
SELECT method, count(*) AS cnt
FROM "default"
GROUP BY method
ORDER BY cnt DESC
```

**What happens**: Not eligible for histogram caching since no histogram function is used.

### Histogram with mixed ORDER BY (timestamp first, then count)
```sql
SELECT histogram(_timestamp) AS time_bucket, count(*) AS cnt
FROM "default"
GROUP BY time_bucket
ORDER BY time_bucket ASC, cnt DESC
```

**What happens**: Treated as timestamp-ordered. Cache reuse continues for overlapping windows.

### Histogram with empty result set
```sql
SELECT histogram(_timestamp) AS time_bucket, count(*) AS cnt
FROM "default"
WHERE log_level = 'NONEXISTENT'
GROUP BY time_bucket
ORDER BY cnt DESC
```

**What happens**: Cache handles empty results correctly and stores metadata for the query range.

### Very large time-range histogram
```sql
SELECT histogram(_timestamp) AS time_bucket, count(*) AS cnt
FROM "default"
WHERE _timestamp BETWEEN '2025-01-01' AND '2025-12-31'
GROUP BY time_bucket
ORDER BY cnt DESC
```
**What happens**: Cache stores complete range metadata for long durations. Later queries reuse relevant parts efficiently.

### Histogram with recent data (within cache delay)
```sql
SELECT histogram(_timestamp) AS time_bucket, count(*) AS cnt
FROM "default"
WHERE _timestamp >= now() - INTERVAL '10 minutes'
GROUP BY time_bucket
ORDER BY cnt DESC
```
**What happens**: Recent buckets within the cache-delay window are freshly scanned, older buckets are reused from cache.

### Histogram with multiple non-timestamp ORDER BY columns
```sql
SELECT histogram(_timestamp) AS time_bucket,
status_code,
count(*) AS cnt,
SUM(bytes) AS total_bytes
FROM "default"
GROUP BY time_bucket, status_code
ORDER BY cnt DESC, total_bytes DESC
```
**What happens**: Cache preserves ordering across both fields. Results are reused across refreshes with identical ordering.

### Large dataset histogram (test scan performance)
```sql
SELECT histogram(_timestamp) AS time_bucket, count(*) AS cnt
FROM "default"
WHERE _timestamp BETWEEN '2025-01-01' AND '2025-10-31'
GROUP BY time_bucket
ORDER BY cnt DESC
```
**What happens**: Cache efficiently handles large scans. On later runs, reused buckets prevent redundant disk scans.

### High-cardinality histogram (many buckets)
```sql
SELECT histogram(_timestamp, '1m') AS time_bucket, count(*) AS cnt
FROM "default"
WHERE _timestamp BETWEEN '2025-10-01' AND '2025-10-06'
GROUP BY time_bucket
ORDER BY cnt DESC
```
**What happens**: Minute-level histograms are cached after the first scan. Future runs reuse cached buckets, minimizing scan time.

### First query (cold cache)
```sql
SELECT histogram(_timestamp) AS x_axis_1, count(*) AS y_axis_1
FROM "default"
GROUP BY x_axis_1
ORDER BY y_axis_1 DESC
```

**What happens**: This initial query builds the cache. result_cache_ratio is 0 and cache files are created with correct timestamps.

### Second query (warm cache)
```sql
SELECT histogram(_timestamp) AS x_axis_1, count(*) AS y_axis_1
FROM "default"
GROUP BY x_axis_1
ORDER BY y_axis_1 DESC
```
**What happens**: Cache is reused. result_cache_ratio rises to 100. Only new data is scanned, improving performance.

### Query with overlapping time range
```sql
SELECT histogram(_timestamp) AS x_axis_1, count(*) AS y_axis_1
FROM "default"
WHERE _timestamp BETWEEN '2025-10-01' AND '2025-10-05'
GROUP BY x_axis_1
ORDER BY y_axis_1 DESC
```
**What happens**: Cache reuses overlapping results. Only the subset is returned with no duplicates.

### Query with extended time range
```sql
SELECT histogram(_timestamp) AS x_axis_1, count(*) AS y_axis_1
FROM "default"
WHERE _timestamp BETWEEN '2025-10-01' AND '2025-10-10'
GROUP BY x_axis_1
ORDER BY y_axis_1 DESC
```
**What happens**: Cache partially reuses existing data and merges new results for the extended range. Duplicates are avoided, and ordering is preserved.
8 changes: 5 additions & 3 deletions docs/user-guide/management/query-management.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ description: >-
---
This page explains what Query Management is and shows how to use it.

> This feature is available only in [high-availability (HA)](../../openobserve-enterprise-edition-installation-guide.md) deployments.
!!! info "Availability"
This feature is available in Enterprise Edition. Not available in Open Source and Cloud.

=== "Overview"
## What is Query Management?
Expand Down Expand Up @@ -37,7 +38,7 @@ This page explains what Query Management is and shows how to use it.
The **Running Queries** table displays the following fields:

- **Email**: The email ID of the user who initiated the queries.
- **Search Type**: The origin of the query (for example, dashboards, alerts, or others).
- **Search Type**: The origin of the query. For example, dashboards, alerts, or others.
- **Number of Queries**: Total active queries for that user.
- **Total Exec. Duration**: Combined time spent executing all active queries.
- **Total Query Range**: Total log duration the queries are scanning.
Expand All @@ -48,7 +49,8 @@ This page explains what Query Management is and shows how to use it.

- **Email:** The email of the user who triggered the query.
- **Organization ID:** The organization context.
- **Search Type:** The source of the query, such as dashboards, UI, or alerts.
- **Search Type:** The source of the query, such as dashboards, alerts, or others.
- **Query Source:** Displays the specific origin of the query. If the query originates from a **dashboard**, this field shows the dashboard name. If the query originates from an **alert**, it shows the alert name.
- **Execution Duration:** The total time the query has been running.
- **Query Range:** The time range being queried.
- **Query Type:** Whether the system classifies the query as Short or Long.
Expand Down
Loading