# GreptimeDB Documentation > GreptimeDB is an open-source observability database for metrics, logs, traces, and wide events. Drop-in replacement for Prometheus, Loki & Elasticsearch, or the single backend for OpenTelemetry. This file contains all documentation content in a single document following the llmstxt.org standard. ## GreptimeDB # Introduction **GreptimeDB** is an open-source observability database that handles metrics, logs, and traces in one engine. Use it as the single OpenTelemetry backend — replacing Prometheus, Loki, and Elasticsearch with one database built on object storage. Query with [SQL](/user-guide/query-data/sql.md) and [PromQL](/user-guide/query-data/promql.md), scale without pain, cut costs up to 50x. ## Why GreptimeDB **Replace three systems with one.** Most teams run Prometheus for metrics, Loki or ELK for logs, and Elasticsearch or Tempo for traces — three systems, three query languages, three sets of operational overhead. GreptimeDB unifies all three in a single engine with native OpenTelemetry support. **Cut costs up to 50x.** Object storage (S3, Azure Blob, GCS) as primary data store with compute-storage separation. Compute nodes scale independently. Written in Rust with columnar storage and advanced compression for maximum efficiency. **Drop-in compatible.** [PromQL](/user-guide/query-data/promql.md), [Prometheus remote write](/user-guide/ingest-data/for-observability/prometheus.md), [Jaeger](/user-guide/query-data/jaeger.md), [MySQL](/user-guide/protocols/mysql.md), [PostgreSQL](/user-guide/protocols/postgresql.md) protocols — migrate without rewriting queries. [SQL](/user-guide/query-data/sql.md) + [PromQL](/user-guide/query-data/promql.md) dual query capability means one database replaces your metrics store + data warehouse combo. Learn more in [Why GreptimeDB](/user-guide/concepts/why-greptimedb.md) and [Observability 2.0](/user-guide/concepts/observability-2.md). Before getting started, please read the following documents that include instructions for setting up, fundamental concepts, architectural designs, and tutorials: - [Getting Started][1]: Provides an introduction to GreptimeDB for those who are new to it, including installation and database operations. - [For AI Agents][8]: Use GreptimeDB with AI agents via the MCP Server, Skills, and machine-readable docs. - [User Guide][2]: For application developers to use GreptimeDB or build custom integration. - [Contributor Guide][3]: For contributors interested in learning more about the technical details and enhancing GreptimeDB. - [Roadmap][7]: The latest GreptimeDB roadmap. - [Release Notes][4]: Presents all historical version release notes. - [FAQ][5]: Provides answers to the most frequently asked questions. [1]: ./getting-started/overview.md [8]: ./faq-and-others/vibecoding.md [2]: ./user-guide/overview.md [3]: ./contributor-guide/overview.md [4]: /release-notes [5]: ./faq-and-others/faq.md [7]: https://greptime.com/blogs/2026-02-11-greptimedb-roadmap-2026 --- ## GreptimeDB Cluster The GreptimeDB cluster can run in cluster mode to scale horizontally. ## Deploy the GreptimeDB cluster in Kubernetes For production environments, we recommend deploying the GreptimeDB cluster in Kubernetes. Please refer to [Deploy on Kubernetes](/user-guide/deployments-administration/deploy-on-kubernetes/overview.md). ## Use Docker Compose :::tip NOTE Although Docker Compose is a convenient way to run the GreptimeDB cluster, it is only for development and testing purposes. For production environments or benchmarking, we recommend using Kubernetes. ::: ### Prerequisites Using Docker Compose is the easiest way to run the GreptimeDB cluster. Before starting, make sure you have already installed the Docker. ### Step1: Download the YAML file for Docker Compose ``` wget https://raw.githubusercontent.com/GreptimeTeam/greptimedb/v1.0.2/docker/docker-compose/cluster-with-etcd.yaml ``` ### Step2: Start the cluster ``` GREPTIMEDB_VERSION=v1.0.2 \ docker compose -f ./cluster-with-etcd.yaml up ``` If the cluster starts successfully, it will listen on 4000-4003. , you can access the cluster by referencing the [Quick Start](../quick-start.md). ### Clean up You can use the following command to stop the cluster: ``` docker compose -f ./cluster-with-etcd.yaml down ``` By default, the data will be stored in `./greptimedb-cluster-docker-compose`. You also can remove the data directory if you want to clean up the data. ## Next Steps Learn how to write data to GreptimeDB in [Quick Start](../quick-start.md). --- ## GreptimeDB Dashboard Visualization plays a crucial role in effectively utilizing time series data. To help users leverage the various features of GreptimeDB, Greptime offers a simple [dashboard](https://github.com/GreptimeTeam/dashboard). The Dashboard is embedded into GreptimeDB's binary since GreptimeDB v0.2.0. After starting [GreptimeDB Standalone](greptimedb-standalone.md) or [GreptimeDB Cluster](greptimedb-cluster.md), the dashboard can be accessed via the HTTP endpoint `http://localhost:4000/dashboard`. The dashboard supports multiple query languages, including [SQL queries](/user-guide/query-data/sql.md), and [PromQL queries](/user-guide/query-data/promql.md). We offer various chart types to choose from based on different scenarios. The charts become more informative when you have sufficient data. ![line](/dashboard-line.png) ![scatter](/dashboard-scatter.png) We are committed to the ongoing development and iteration of this open-source project, and we plan to expand the application of time series data in monitoring, analysis, and other relevant fields in the future. --- ## GreptimeDB Standalone We use the simplest configuration for you to get started. For a comprehensive list of configurations available in GreptimeDB, see the [configuration documentation](/user-guide/deployments-administration/configuration.md). ## Deploy the GreptimeDB standalone in Kubernetes For production environments, we recommend deploying the GreptimeDB standalone in Kubernetes. Please refer to [Deploy on Kubernetes](/user-guide/deployments-administration/deploy-on-kubernetes/overview.md). ## Binary ### Download from website You can try out GreptimeDB by downloading the latest stable build releases from the [Download page](https://greptime.com/download). ### Linux and macOS For Linux and macOS users, you can download the latest build of the `greptime` binary by using the following commands: ```shell curl -fsSL \ https://raw.githubusercontent.com/greptimeteam/greptimedb/main/scripts/install.sh | sh -s v1.0.2 ``` Once the download is completed, the binary file `greptime` will be stored in your current directory. You can run GreptimeDB in the standalone mode: ```shell ./greptime standalone start ``` ### Windows If you have WSL([Windows Subsystem for Linux](https://learn.microsoft.com/en-us/windows/wsl/about)) enabled, you can launch a latest Ubuntu and run GreptimeDB like above! Otherwise please download the GreptimeDB binary for Windows at our [official site](https://greptime.com/resources), and unzip the downloaded artifact. To run GreptimeDB in standalone mode, open a terminal (like Powershell) at the directory where the GreptimeDB binary locates, and execute: ```shell .\greptime standalone start ``` ## Docker Make sure the [Docker](https://www.docker.com/) is already installed. If not, you can follow the official [documents](https://www.docker.com/get-started/) to install Docker. ```shell docker run -p 127.0.0.1:4000-4003:4000-4003 \ -v "$(pwd)/greptimedb_data:/greptimedb_data" \ --name greptime --rm \ greptime/greptimedb:v1.0.2 standalone start \ --http-addr 0.0.0.0:4000 \ --rpc-bind-addr 0.0.0.0:4001 \ --mysql-addr 0.0.0.0:4002 \ --postgres-addr 0.0.0.0:4003 ``` :::tip NOTE To avoid accidentally exit the Docker container, you may want to run it in the "detached" mode: add the `-d` flag to the `docker run` command. ::: The data will be stored in the `greptimedb_data/` directory in your current directory. If you want to use another version of GreptimeDB's image, you can download it from our [GreptimeDB Dockerhub](https://hub.docker.com/r/greptime/greptimedb). In particular, we support GreptimeDB based on CentOS, and you can try image `greptime/greptimedb-centos`. :::tip NOTE If you are using a Docker version lower than [v23.0](https://docs.docker.com/engine/release-notes/23.0/), you may experience problems with insufficient permissions when trying to run the command above, due to a [bug](https://github.com/moby/moby/pull/42681) in the older version of Docker Engine. You can: 1. Set `--security-opt seccomp=unconfined`, for example: ```shell docker run --security-opt seccomp=unconfined -p 4000-4003:4000-4003 \ -v "$(pwd)/greptimedb_data:/greptimedb_data" \ --name greptime --rm \ greptime/greptimedb:v1.0.2 standalone start \ --http-addr 0.0.0.0:4000 \ --rpc-bind-addr 0.0.0.0:4001 \ --mysql-addr 0.0.0.0:4002 \ --postgres-addr 0.0.0.0:4003 ``` 2. Upgrade the Docker version to v23.0.0 or higher; ::: ## Binding address GreptimeDB binds to `127.0.0.1` by default. If you need to accept connections from other addresses, you can start with the following parameters. > :::danger Warning > If the computer running GreptimeDB is directly exposed to the internet, binding to `0.0.0.0` is dangerous and will expose the instance to everybody on the internet. ```shell ./greptime standalone start \ --http-addr 0.0.0.0:4000 \ --rpc-bind-addr 0.0.0.0:4001 \ --mysql-addr 0.0.0.0:4002 \ --postgres-addr 0.0.0.0:4003 ``` ```shell docker run -p 0.0.0.0:4000-4003:4000-4003 \ -v "$(pwd)/greptimedb_data:/greptimedb_data" \ --name greptime --rm \ greptime/greptimedb:v1.0.2 standalone start \ --http-addr 0.0.0.0:4000 \ --rpc-bind-addr 0.0.0.0:4001 \ --mysql-addr 0.0.0.0:4002 \ --postgres-addr 0.0.0.0:4003 ``` You can also refer to the [Configuration](/user-guide/deployments-administration/configuration.md) document to modify the bind address in the configuration file. ## Next Steps Learn how to write data to GreptimeDB in the [Quick Start](../quick-start.md). --- ## GreptimeDB Installation Overview # Installation Follow these instructions to install GreptimeDB: - [GreptimeDB Standalone](greptimedb-standalone.md) runs as a standalone system in a single process. - [GreptimeDB Cluster](greptimedb-cluster.md) runs as a distributed, clustered time series database. ## Check database health After starting GreptimeDB, you can check its status to ensure it is running. ```shell curl http://localhost:4000/health ``` If the GreptimeDB instance is running healthily, you will see the following response: ```json {} ``` ## Next steps - [Quick Start](/getting-started/quick-start.md): Ingest and query data in GreptimeDB using MySQL or PostgreSQL clients. --- ## GreptimeDB Getting Started Overview # Getting Started > **AGENT ONBOARDING:** Read https://docs.greptime.com/SKILL.md and follow the instructions to use GreptimeDB with your AI agent — deploy, configure, ingest, and query. Get started with GreptimeDB quickly by following these steps: - [Installation](./installation/overview.md): Learn how to install GreptimeDB as a standalone or cluster. - [Quick Start](./quick-start.md): Get started with GreptimeDB using your preferred protocols or languages. - [For AI Agents](../faq-and-others/vibecoding.md): Use GreptimeDB with AI agents via the MCP Server, Skills, and machine-readable docs. --- ## GreptimeDB Getting Started Quick Start # Quick Start Before proceeding, please ensure you have [installed GreptimeDB](./installation/overview.md). This guide uses SQL to walk you through GreptimeDB's core capabilities — from ingestion to cross-signal correlation across metrics, logs, and traces. SQL is also GreptimeDB's management interface for creating tables, setting TTL policies, and configuring indexes. :::tip Already running Prometheus, OpenTelemetry, Loki or ES? You can start ingesting data immediately using your existing tools — no schema creation needed (GreptimeDB [creates tables automatically](/user-guide/ingest-data/overview.md#automatic-schema-generation)): - [Prometheus Remote Write](/user-guide/ingest-data/for-observability/prometheus.md) - [OpenTelemetry (OTLP)](/user-guide/ingest-data/for-observability/opentelemetry.md) - [Loki Protocol](/user-guide/ingest-data/for-observability/loki.md) - [Elasticsearch](/user-guide/ingest-data/for-observability/elasticsearch/) Continue with this guide to see what you can do with the data once it's in. ::: **You'll learn (10–15 minutes):** - Connect to GreptimeDB and create metrics, logs, and traces tables - Query and aggregate data with SQL - Search logs by keyword with full-text index - Compute p95 latency in time windows using range queries - **Correlate metrics, logs, and traces in a single query** - Combine SQL and PromQL ## Connect to GreptimeDB GreptimeDB supports [multiple protocols](/user-guide/protocols/overview.md) for interacting with the database. In this guide, we use SQL for simplicity. If your GreptimeDB instance is running on `127.0.0.1` with the MySQL client default port `4002` or the PostgreSQL client default port `4003`, connect using: ```shell mysql -h 127.0.0.1 -P 4002 ``` Or ```shell psql -h 127.0.0.1 -p 4003 -d public ``` You can also use the built-in Dashboard at `http://127.0.0.1:4000/dashboard` to run all the SQL queries in this guide. By default, GreptimeDB does not have [authentication](/user-guide/deployments-administration/authentication/overview.md) enabled. You can connect without providing a username and password. ## Create tables We'll create three tables to simulate a real scenario: gRPC latency metrics, application logs, and request traces. Two application servers, `host1` and `host2`, are recording data. Starting from `2024-07-11 20:00:10`, `host1` begins experiencing issues. ### Metrics table ```sql -- Metrics: gRPC call latency in milliseconds CREATE TABLE grpc_latencies ( ts TIMESTAMP TIME INDEX, host STRING, method_name STRING, latency DOUBLE, PRIMARY KEY (host, method_name) ); ``` - `ts`: Timestamp when the metric was collected (the [time index](/user-guide/concepts/data-model.md)). - `host` and `method_name`: [Tag](/user-guide/concepts/data-model.md) columns identifying the time series. - `latency`: [Field](/user-guide/concepts/data-model.md) column containing the actual measurement. ### Logs table ```sql -- Logs: application error logs CREATE TABLE app_logs ( ts TIMESTAMP TIME INDEX, host STRING, api_path STRING, log_level STRING, log_msg STRING FULLTEXT INDEX WITH('case_sensitive' = 'false'), PRIMARY KEY (host, log_level) ) WITH ('append_mode'='true'); ``` - `log_msg` enables [full-text index](/user-guide/manage-data/data-index.md#fulltext-index) for keyword search. - [`append_mode`](/user-guide/deployments-administration/performance-tuning/design-table.md#when-to-use-append-only-tables) optimizes for log workloads (no deduplication overhead). ### Traces table ```sql -- Traces: request spans CREATE TABLE traces ( ts TIMESTAMP TIME INDEX, trace_id STRING SKIPPING INDEX, span_id STRING, parent_span_id STRING, service_name STRING, operation STRING, duration DOUBLE, status_code INT, PRIMARY KEY (service_name) ) WITH ('append_mode'='true'); ``` For high-cardinality `trace_id`s, we have enabled the [skip index](/user-guide/manage-data/data-index.md#skipping-index). :::tip We use SQL to ingest data below, so we create the tables manually. However, GreptimeDB is [schemaless](/user-guide/ingest-data/overview.md#automatic-schema-generation) — when using protocols like OpenTelemetry, Prometheus Remote Write, or InfluxDB Line Protocol, tables are created automatically. ::: ## Write data Let's insert sample data simulating the scenario. Before `20:00:10`, both hosts are normal. After `20:00:10`, `host1` starts experiencing latency spikes. ### Normal period (before 20:00:10) ```sql INSERT INTO grpc_latencies (ts, host, method_name, latency) VALUES ('2024-07-11 20:00:06', 'host1', 'GetUser', 103.0), ('2024-07-11 20:00:06', 'host2', 'GetUser', 113.0), ('2024-07-11 20:00:07', 'host1', 'GetUser', 103.5), ('2024-07-11 20:00:07', 'host2', 'GetUser', 107.0), ('2024-07-11 20:00:08', 'host1', 'GetUser', 104.0), ('2024-07-11 20:00:08', 'host2', 'GetUser', 96.0), ('2024-07-11 20:00:09', 'host1', 'GetUser', 104.5), ('2024-07-11 20:00:09', 'host2', 'GetUser', 114.0); ``` ### Anomalous period (after 20:00:10) `host1`'s latency becomes unstable with spikes up to several thousand milliseconds:
Click to expand INSERT statements ```sql INSERT INTO grpc_latencies (ts, host, method_name, latency) VALUES ('2024-07-11 20:00:10', 'host1', 'GetUser', 150.0), ('2024-07-11 20:00:10', 'host2', 'GetUser', 110.0), ('2024-07-11 20:00:11', 'host1', 'GetUser', 200.0), ('2024-07-11 20:00:11', 'host2', 'GetUser', 102.0), ('2024-07-11 20:00:12', 'host1', 'GetUser', 1000.0), ('2024-07-11 20:00:12', 'host2', 'GetUser', 108.0), ('2024-07-11 20:00:13', 'host1', 'GetUser', 80.0), ('2024-07-11 20:00:13', 'host2', 'GetUser', 111.0), ('2024-07-11 20:00:14', 'host1', 'GetUser', 4200.0), ('2024-07-11 20:00:14', 'host2', 'GetUser', 95.0), ('2024-07-11 20:00:15', 'host1', 'GetUser', 90.0), ('2024-07-11 20:00:15', 'host2', 'GetUser', 115.0), ('2024-07-11 20:00:16', 'host1', 'GetUser', 3000.0), ('2024-07-11 20:00:16', 'host2', 'GetUser', 95.0), ('2024-07-11 20:00:17', 'host1', 'GetUser', 320.0), ('2024-07-11 20:00:17', 'host2', 'GetUser', 115.0), ('2024-07-11 20:00:18', 'host1', 'GetUser', 3500.0), ('2024-07-11 20:00:18', 'host2', 'GetUser', 95.0), ('2024-07-11 20:00:19', 'host1', 'GetUser', 100.0), ('2024-07-11 20:00:19', 'host2', 'GetUser', 115.0), ('2024-07-11 20:00:20', 'host1', 'GetUser', 2500.0), ('2024-07-11 20:00:20', 'host2', 'GetUser', 95.0); ```
### Error logs during the anomaly ```sql INSERT INTO app_logs (ts, host, api_path, log_level, log_msg) VALUES ('2024-07-11 20:00:10', 'host1', '/api/v1/resource', 'ERROR', 'Connection timeout'), ('2024-07-11 20:00:10', 'host1', '/api/v1/billings', 'ERROR', 'Connection timeout'), ('2024-07-11 20:00:11', 'host1', '/api/v1/resource', 'ERROR', 'Database unavailable'), ('2024-07-11 20:00:11', 'host1', '/api/v1/billings', 'ERROR', 'Database unavailable'), ('2024-07-11 20:00:12', 'host1', '/api/v1/resource', 'ERROR', 'Service overload'), ('2024-07-11 20:00:12', 'host1', '/api/v1/billings', 'ERROR', 'Service overload'), ('2024-07-11 20:00:13', 'host1', '/api/v1/resource', 'ERROR', 'Connection reset'), ('2024-07-11 20:00:13', 'host1', '/api/v1/billings', 'ERROR', 'Connection reset'), ('2024-07-11 20:00:14', 'host1', '/api/v1/resource', 'ERROR', 'Timeout'), ('2024-07-11 20:00:14', 'host1', '/api/v1/billings', 'ERROR', 'Timeout'), ('2024-07-11 20:00:15', 'host1', '/api/v1/resource', 'ERROR', 'Disk full'), ('2024-07-11 20:00:15', 'host1', '/api/v1/billings', 'ERROR', 'Disk full'), ('2024-07-11 20:00:16', 'host1', '/api/v1/resource', 'ERROR', 'Network issue'), ('2024-07-11 20:00:16', 'host1', '/api/v1/billings', 'ERROR', 'Network issue'); ``` ### Trace spans during the anomaly ```sql INSERT INTO traces (ts, trace_id, span_id, parent_span_id, service_name, operation, duration, status_code) VALUES ('2024-07-11 20:00:12', 'abc123', 'span1', '', 'host1', 'POST /api/v1/resource', 1050.0, 2), ('2024-07-11 20:00:12', 'abc123', 'span2', 'span1', 'host1', 'GetUser', 1000.0, 2), ('2024-07-11 20:00:14', 'def456', 'span3', '', 'host1', 'POST /api/v1/billings', 4250.0, 2), ('2024-07-11 20:00:14', 'def456', 'span4', 'span3', 'host1', 'CreateBilling', 4200.0, 2), ('2024-07-11 20:00:16', 'ghi789', 'span5', '', 'host1', 'POST /api/v1/resource', 3100.0, 2), ('2024-07-11 20:00:16', 'ghi789', 'span6', 'span5', 'host1', 'GetUser', 3000.0, 2), ('2024-07-11 20:00:12', 'jkl012', 'span7', '', 'host2', 'POST /api/v1/resource', 115.0, 0), ('2024-07-11 20:00:12', 'jkl012', 'span8', 'span7', 'host2', 'GetUser', 108.0, 0); ``` ## Query data ### Filter by tags and time index Query the latency of `host1` after `2024-07-11 20:00:15`: ```sql SELECT * FROM grpc_latencies WHERE host = 'host1' AND ts > '2024-07-11 20:00:15'; ``` ```sql +---------------------+-------+-------------+---------+ | ts | host | method_name | latency | +---------------------+-------+-------------+---------+ | 2024-07-11 20:00:16 | host1 | GetUser | 3000 | | 2024-07-11 20:00:17 | host1 | GetUser | 320 | | 2024-07-11 20:00:18 | host1 | GetUser | 3500 | | 2024-07-11 20:00:19 | host1 | GetUser | 100 | | 2024-07-11 20:00:20 | host1 | GetUser | 2500 | +---------------------+-------+-------------+---------+ 5 rows in set (0.14 sec) ``` Calculate the 95th percentile latency grouped by host: ```sql SELECT host, approx_percentile_cont(0.95) WITHIN GROUP (ORDER BY latency) AS p95_latency FROM grpc_latencies WHERE ts >= '2024-07-11 20:00:10' GROUP BY host; ``` ```sql +-------+-------------------+ | host | p95_latency | +-------+-------------------+ | host1 | 4164.999999999999 | | host2 | 115 | +-------+-------------------+ 2 rows in set (0.11 sec) ``` ### Search logs by keyword The `@@` operator performs [full-text search](/user-guide/logs/fulltext-search.md) on indexed columns: ```sql SELECT * FROM app_logs WHERE lower(log_msg) @@ 'timeout' AND ts > '2024-07-11 20:00:00' ORDER BY ts; ``` ```sql +---------------------+-------+------------------+-----------+--------------------+ | ts | host | api_path | log_level | log_msg | +---------------------+-------+------------------+-----------+--------------------+ | 2024-07-11 20:00:10 | host1 | /api/v1/billings | ERROR | Connection timeout | | 2024-07-11 20:00:10 | host1 | /api/v1/resource | ERROR | Connection timeout | | 2024-07-11 20:00:14 | host1 | /api/v1/billings | ERROR | Timeout | | 2024-07-11 20:00:14 | host1 | /api/v1/resource | ERROR | Timeout | +---------------------+-------+------------------+-----------+--------------------+ ``` ### Range query Use [range queries](/reference/sql/range.md) to calculate the p95 latency in 5-second windows: ```sql SELECT ts, host, approx_percentile_cont(0.95) WITHIN GROUP (ORDER BY latency) RANGE '5s' AS p95_latency FROM grpc_latencies ALIGN '5s' FILL PREV ORDER BY host, ts; ``` ```sql +---------------------+-------+-------------+ | ts | host | p95_latency | +---------------------+-------+-------------+ | 2024-07-11 20:00:05 | host1 | 104.5 | | 2024-07-11 20:00:10 | host1 | 4200 | | 2024-07-11 20:00:15 | host1 | 3500 | | 2024-07-11 20:00:20 | host1 | 2500 | | 2024-07-11 20:00:05 | host2 | 114 | | 2024-07-11 20:00:10 | host2 | 111 | | 2024-07-11 20:00:15 | host2 | 115 | | 2024-07-11 20:00:20 | host2 | 95 | +---------------------+-------+-------------+ 8 rows in set (0.06 sec) ``` Range queries are powerful for time-window aggregation. Read the [manual](/reference/sql/range.md) to learn more. ### Correlate metrics, logs, and traces This is where a unified database shines. One query to correlate p95 latency, error counts, and slow trace spans — across all three signal types: ```sql WITH -- Metrics: per-host p95 latency in 5s windows metrics AS ( SELECT ts, host, approx_percentile_cont(0.95) WITHIN GROUP (ORDER BY latency) RANGE '5s' AS p95_latency FROM grpc_latencies ALIGN '5s' FILL PREV ), -- Logs: per-host ERROR count in 5s windows logs AS ( SELECT ts, host, count(log_msg) RANGE '5s' AS num_errors FROM app_logs WHERE log_level = 'ERROR' ALIGN '5s' ), -- Traces: per-host slow span count in 5s windows slow_traces AS ( SELECT date_bin(INTERVAL '5' seconds, ts) AS ts, service_name AS host, COUNT(*) AS slow_spans, MAX(duration) AS max_span_duration FROM traces WHERE duration > 500 GROUP BY date_bin(INTERVAL '5' seconds, ts), service_name ) SELECT m.ts, m.host, m.p95_latency, COALESCE(l.num_errors, 0) AS num_errors, COALESCE(t.slow_spans, 0) AS slow_spans, t.max_span_duration FROM metrics m LEFT JOIN logs l ON m.host = l.host AND m.ts = l.ts LEFT JOIN slow_traces t ON m.host = t.host AND m.ts = t.ts ORDER BY m.ts, m.host; ``` ```sql +---------------------+-------+-------------+------------+------------+-------------------+ | ts | host | p95_latency | num_errors | slow_spans | max_span_duration | +---------------------+-------+-------------+------------+------------+-------------------+ | 2024-07-11 20:00:05 | host1 | 104.5 | 0 | 0 | NULL | | 2024-07-11 20:00:05 | host2 | 114 | 0 | 0 | NULL | | 2024-07-11 20:00:10 | host1 | 4200 | 10 | 4 | 4250 | | 2024-07-11 20:00:10 | host2 | 111 | 0 | 0 | NULL | | 2024-07-11 20:00:15 | host1 | 3500 | 4 | 2 | 3100 | | 2024-07-11 20:00:15 | host2 | 115 | 0 | 0 | NULL | | 2024-07-11 20:00:20 | host1 | 2500 | 0 | 0 | NULL | | 2024-07-11 20:00:20 | host2 | 95 | 0 | 0 | NULL | +---------------------+-------+-------------+------------+------------+-------------------+ 8 rows in set (0.02 sec) ``` The picture is clear: **during the `20:00:10` – `20:00:15` window, `host1` experienced p95 latency spikes (up to 4200ms), 10 error logs, and 4 slow trace spans (max 4250ms). `host2` was unaffected**. In a traditional three-pillar stack, this correlation requires switching between Prometheus, Loki, and Jaeger. With GreptimeDB, it's one query. ### Query with PromQL GreptimeDB natively supports [PromQL](/user-guide/query-data/promql.md). In the Dashboard, switch to the PromQL tab and run: ```promql quantile_over_time(0.95, grpc_latencies{host!=""}[5s]) ``` You can also query via the Prometheus-compatible HTTP API: ```bash curl -X POST \ -H 'Authorization: Basic {{authorization if exists}}' \ --data-urlencode 'query=quantile_over_time(0.95, grpc_latencies{host!=""}[5s])' \ --data-urlencode 'start=2024-07-11 20:00:00Z' \ --data-urlencode 'end=2024-07-11 20:00:20Z' \ --data-urlencode 'step=15s' \ 'http://localhost:4000/v1/prometheus/api/v1/query_range' ```
Output ```json { "status": "success", "data": { "resultType": "matrix", "result": [ { "metric": { "__name__": "grpc_latencies", "host": "host1", "method_name": "GetUser" }, "values": [ [ 1720728015.0, "3560" ] ] }, { "metric": { "__name__": "grpc_latencies", "host": "host2", "method_name": "GetUser" }, "values": [ [ 1720728015.0, "114.2" ] ] } ] } } ```
### Mix SQL and PromQL Use [TQL](/reference/sql/tql.md) to embed PromQL inside SQL — combining the power of both: ```sql TQL EVAL ('2024-07-11 20:00:00Z', '2024-07-11 20:00:20Z', '15s') quantile_over_time(0.95, grpc_latencies{host!=""}[5s]); ``` ```sql +---------------------+---------------------------------------------------------+-------+-------------+ | ts | prom_quantile_over_time(ts_range,latency,Float64(0.95)) | host | method_name | +---------------------+---------------------------------------------------------+-------+-------------+ | 2024-07-11 20:00:15 | 3560 | host1 | GetUser | | 2024-07-11 20:00:15 | 114.2 | host2 | GetUser | +---------------------+---------------------------------------------------------+-------+-------------+ ``` You can even use PromQL as a CTE in a correlation query: ```sql WITH metrics AS ( TQL EVAL ('2024-07-11 20:00:00Z', '2024-07-11 20:00:20Z', '5s') quantile_over_time(0.95, grpc_latencies{host!=""}[5s]) ), logs AS ( SELECT ts, host, COUNT(log_msg) RANGE '5s' AS num_errors FROM app_logs WHERE log_level = 'ERROR' ALIGN '5s' ) SELECT m.*, COALESCE(l.num_errors, 0) AS num_errors FROM metrics AS m LEFT JOIN logs AS l ON m.host = l.host AND m.ts = l.ts ORDER BY m.ts, m.host; ``` ```sql +---------------------+---------------------------------------------------------+-------+-------------+------------+ | ts | prom_quantile_over_time(ts_range,latency,Float64(0.95)) | host | method_name | num_errors | +---------------------+---------------------------------------------------------+-------+-------------+------------+ | 2024-07-11 20:00:10 | 140.89999999999998 | host1 | GetUser | 10 | | 2024-07-11 20:00:10 | 113.8 | host2 | GetUser | 0 | | 2024-07-11 20:00:15 | 3560 | host1 | GetUser | 4 | | 2024-07-11 20:00:15 | 114.2 | host2 | GetUser | 0 | | 2024-07-11 20:00:20 | 3400 | host1 | GetUser | 0 | | 2024-07-11 20:00:20 | 115 | host2 | GetUser | 0 | +---------------------+---------------------------------------------------------+-------+-------------+------------+ ``` ## GreptimeDB Dashboard GreptimeDB offers a [Dashboard](./installation/greptimedb-dashboard.md) for data exploration and management. ### Explore data Access the Dashboard at `http://localhost:4000/dashboard`. Click the `+` button to add a query, write SQL, and click `Run All`. Click the `Chart` button in the result panel to visualize the data. ```sql SELECT * FROM grpc_latencies; ``` ![select gRPC latencies](/select-grpc-latencies.png) ### Ingest data by InfluxDB Line Protocol Click the `Ingest` icon in the Dashboard to write data in [InfluxDB Line Protocol](/user-guide/ingest-data/for-iot/influxdb-line-protocol.md) format. For example: ```txt grpc_metrics,host=host1,method_name=GetUser latency=100,code=0 1720728021000000000 grpc_metrics,host=host2,method_name=GetUser latency=110,code=1 1720728021000000000 ``` Click `Write` to ingest the data. The `grpc_metrics` table is created automatically if it doesn't exist — this is GreptimeDB's [schemaless](/user-guide/ingest-data/overview.md#automatic-schema-generation) capability in action. ## Next steps **Connect your existing stack:** - [Prometheus Remote Write](/user-guide/ingest-data/for-observability/prometheus.md) — point your Prometheus at GreptimeDB - [OpenTelemetry](/user-guide/ingest-data/for-observability/opentelemetry.md) — configure OTel Collector to send metrics, logs, and traces - [Jaeger](/user-guide/query-data/jaeger.md) — use GreptimeDB as Jaeger's storage backend - [Loki](/user-guide/ingest-data/for-observability/loki.md) — send logs using Loki protocol - [Elasticsearch](/user-guide/ingest-data/for-observability/elasticsearch/) — send logs, traces and events using Elasticsearch `_bulk` API - Find [all ingestion methods](/user-guide/ingest-data/overview/#recommended-data-ingestion-methods). **Visualize and monitor:** - [Grafana integration](/user-guide/integrations/grafana.md) — connect Grafana with SQL or PromQL datasource - [Official Dashboard](/getting-started/installation/greptimedb-dashboard.md) — the embedded dashboard at `http://localhost:4000/dashboard` **Go deeper:** - [Why GreptimeDB](/user-guide/concepts/why-greptimedb.md) — architecture, cost comparison, and how GreptimeDB compares - [Observability 2.0](/user-guide/concepts/observability-2.md) — wide events and the unified data model - [Demo scene](https://github.com/GreptimeTeam/demo-scene/) — more hands-on examples - [User Guide](/user-guide/overview.md) — complete reference --- ## Architecture GreptimeDB uses a compute-storage separation architecture where durable data persists in object storage and compute nodes scale independently. This model supports elastic scaling and lower operational cost compared to architectures that rely on local disks as primary storage. ## High-level Architecture ![GreptimeDB high-level architecture](/architecture-4.png) ## Components GreptimeDB has three core components in distributed mode, and one optional component for flow computation: - [**Metasrv**](/contributor-guide/metasrv/overview.md): Metadata and routing control plane. It manages catalogs/schemas/tables/regions, coordinates scheduling, and serves routing data to other nodes. - [**Frontend**](/contributor-guide/frontend/overview.md): Stateless access layer. It accepts client protocols, authenticates requests, plans/distributes queries, and routes writes/reads using metadata from Metasrv. - [**Datanode**](/contributor-guide/datanode/overview.md): Storage and execution layer. It stores table regions, handles reads/writes, persists WAL, and flushes data files to object storage. - [**Flownode (optional)**](/contributor-guide/flownode/overview.md): Streaming/continuous computation runtime for [Flow Computation](/user-guide/flow-computation/overview.md). It is used when flow workloads run as a separate service in distributed deployments. In standalone mode, you run one GreptimeDB process instead of managing these services separately. ## How it works ### Write path 1. A client sends write requests to Frontend via supported protocols. 2. Frontend resolves table and region routes from Metasrv metadata (with cache refresh when needed). 3. Frontend splits and forwards requests to target Datanodes. 4. Datanode writes data to memory and [WAL](/user-guide/deployments-administration/wal/overview.md), then eventually flushes immutable data files to [object storage](./storage-location.md). ### Query path 1. A client sends SQL, PromQL, log, or trace queries to Frontend. 2. Frontend creates a distributed plan and dispatches sub-queries to relevant Datanodes. 3. Datanodes execute sub-queries on regions and return partial results. 4. Frontend merges the results and returns the final response. ### Flow path (optional) When flow computation is enabled, Flownode runs continuous tasks that read source table changes and write computed results to sink tables. For details, see [Flow Computation](/user-guide/flow-computation/overview.md). For implementation details, see [Contributor Guide](/contributor-guide/overview.md). --- ## Data Model ## Model GreptimeDB uses the [time-series](https://en.wikipedia.org/wiki/Time_series) table to guide the organization, compression, and expiration management of data. The data model is mainly based on the table model in relational databases while considering the characteristics of metrics, logs, and traces data. All data in GreptimeDB is organized into tables with names. Each data item in a table consists of three semantic types of columns: `Tag`, `Timestamp`, and `Field`. - Table names are often the same as the indicator names, log source names, or metric names. - `Tag` columns uniquely identify the time-series. Rows with the same `Tag` values belong to the same time-series. Some TSDBs may also call them labels. - `Timestamp` is the root of a metrics, logs, and traces database. It represents the date and time when the data was generated. A table can only have one column with the `Timestamp` semantic type, which is also called the `time index`. - The other columns are `Field` columns. Fields contain the data indicators or log contents that are collected. These fields are generally numerical values or string values, but may also be other types of data, such as geographic locations or timestamps. A table clusters rows of the same time-series and sorts rows of the same time-series by `Timestamp`. The table can also deduplicate rows with the same `Tag` and `Timestamp` values, depending on the requirements of the application. GreptimeDB stores and processes data by time-series. Choosing the right schema is crucial for efficient data storage and retrieval; please refer to the [schema design guide](/user-guide/deployments-administration/performance-tuning/design-table.md) for more details. ### Metrics Suppose we have a table called `system_metrics` that monitors the resource usage of machines in data centers: ```sql CREATE TABLE IF NOT EXISTS system_metrics ( host STRING, idc STRING, cpu_util DOUBLE, memory_util DOUBLE, disk_util DOUBLE, ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY(host, idc), TIME INDEX(ts) ); ``` The data model for this table is as follows: ![time-series-table-model](/time-series-data-model.svg) This is very similar to the table model everyone is familiar with. The difference lies in the `TIME INDEX` constraint, which is used to specify the `ts` column as the time index column of this table. - The table name here is `system_metrics`. - The `PRIMARY KEY` constraint specifies the `Tag` columns of the table. The `host` column represents the hostname of the collected standalone machine. The `idc` column shows the data center where the machine is located. - The `Timestamp` column `ts` represents the time when the data is collected. - The `cpu_util`, `memory_util`, `disk_util`, and `load` columns in the `Field` columns represent the CPU utilization, memory utilization, disk utilization, and load of the machine, respectively. These columns contain the actual data. - The table sorts and deduplicates rows by `host`, `idc`, `ts`. So `select count(*) from system_metrics` will scan all rows. To learn how GreptimeDB maps Prometheus metrics to this model, see [the documentation](/user-guide/ingest-data/for-observability/prometheus/#data-model). ### Logs Another example is creating a table for logs like web server access logs: ```sql CREATE TABLE access_logs ( access_time TIMESTAMP TIME INDEX, remote_addr STRING, http_status STRING, http_method STRING, http_refer STRING, user_agent STRING, request STRING, ) with ('append_mode'='true'); ``` - The time index column is `access_time`. - There are no tags. - `http_status`, `http_method`, `remote_addr`, `http_refer`, `user_agent` and `request` are fields. - The table sorts rows by `access_time`. - The table is an [append-only table](/reference/sql/create.md#create-an-append-only-table) for storing logs that do not support deletion or deduplication. - Querying an append-only table is usually faster. For example, `select count(*) from access_logs` can use the statistics for result without considering deduplication. To learn how to indicate `Tag`, `Timestamp`, and `Field` columns, please refer to [table management](/user-guide/deployments-administration/manage-data/basic-table-operations.md#create-a-table) and [CREATE statement](/reference/sql/create.md). ### Traces GreptimeDB supports writing OpenTelemetry traces data directly via the OTLP/HTTP protocol, refer to the [OTLP traces data model](/user-guide/ingest-data/for-observability/opentelemetry.md#data-model-2) for detail. ## Design Considerations GreptimeDB is designed on top of the table model for the following reasons: - The table model has a broad group of users and it's easy to learn; we have simply introduced the concept of time index to metrics, logs, and traces. - Schema is metadata that describes data characteristics, and it's more convenient for users to manage and maintain. - Schema brings enormous benefits for optimizing storage and computing with its information like types, lengths, etc., on which we can conduct targeted optimizations. - When we have the table model, it's natural for us to introduce SQL and use it to process association analysis and aggregation queries between various tables, reducing the learning and usage costs for users. - GreptimeDB uses a multi-value model where a single row can contain multiple field columns, reducing transfer traffic and simplifying queries compared to single-value models that require splitting data into multiple records. Read the [blog](https://greptime.com/blogs/2024-05-09-prometheus) for detailed benefits. - In the Observability 2.0 paradigm, metrics, logs, and traces are seen as different projections of the same underlying "wide events." GreptimeDB's unified table model naturally supports this view — all signal types share the same Tag + Timestamp + Field schema, enabling cross-signal correlation in a single SQL query. Read more in [Observability 2.0](./observability-2.md). GreptimeDB uses SQL to manage table schema. Please refer to [table management](/user-guide/deployments-administration/manage-data/basic-table-operations.md) for more information. However, our definition of schema is not mandatory and leans towards a **schemaless** approach, similar to MongoDB. For more details, see [Automatic Schema Generation](/user-guide/ingest-data/overview.md#automatic-schema-generation). --- ## Common Questions ## How does GreptimeDB handle metrics, logs, and traces? GreptimeDB treats all observability data — metrics, logs, and traces — as timestamped events with context, stored in a unified columnar engine. You can query all three signal types with SQL, use PromQL for metrics, and run continuous aggregations with Flow. Please read the [log user guide](/user-guide/logs/overview.md) and [traces user guide](/user-guide/traces/overview.md). ## Does GreptimeDB support updates? Partially supported. See [update data](/user-guide/manage-data/overview.md#update-data) for more information. ## Does GreptimeDB support deletion? Yes, it does. Please refer to the [delete data](/user-guide/manage-data/overview.md#delete-data) for more information. ## Can I set TTL or retention policy for different tables or measurements? Of course. Please refer to the document [on managing data retention with TTL policies](/user-guide/manage-data/overview.md#manage-data-retention-with-ttl-policies). ## What are the compression rates of GreptimeDB? The answer is it depends. GreptimeDB uses the columnar storage layout, and compresses data by best-in-class algorithms. And it will select the most suitable compression algorithm based on the column data's statistics and distribution. GreptimeDB will provide rollups that can compress data more compactly but lose accuracy. Therefore, the data compression rate of GreptimeDB may be between 2 and several hundred times, depending on the characteristics of your data and whether you can accept accuracy loss. ## How does GreptimeDB address the high cardinality issue? GreptimeDB resolves high cardinality challenges through a multi-layered approach: **At the architecture level:** - **Sharding**: Data and indexes are distributed across region servers, preventing any single node from becoming a bottleneck. Read more about GreptimeDB's [architecture](./architecture.md). **At the storage level:** - **Flat format for extreme cardinality**: For workloads with millions of unique series (e.g., request IDs, trace IDs, user tokens as tags), GreptimeDB 1.0+ offers a redesigned storage layout. Traditional time-series databases allocate separate buffers per series, causing memory bloat and degraded performance at scale. Flat format introduces BulkMemtable and multi-series merge paths that eliminate per-series overhead, delivering **4x better write throughput and up to 10x faster queries** in high-cardinality scenarios. Learn more in [Scaling Time Series to Millions of Cardinalities](https://greptime.com/blogs/2025-12-22-flat-format). **At the indexing level:** - **Flexible Indexing**: GreptimeDB supports on-demand manual index creation. You can create various index types (inverted, full-text, skipping) for both tag and field columns as needed, rather than automatically indexing every column. This allows you to optimize query performance while minimizing index overhead. Learn more in the [index documentation](/user-guide/manage-data/data-index.md). **At the query level:** - **MPP (Massively Parallel Processing)**: The query engine uses vectorized execution and distributed parallel processing to handle high-cardinality queries efficiently across the cluster. **The result:** GreptimeDB does not hit the same cardinality ceiling as Prometheus, where high-cardinality labels can cause memory exhaustion and query timeouts. Systems can handle millions of series without architectural rewrites. ## Does GreptimeDB support continuous aggregate or downsampling? Since 0.8, GreptimeDB added a new function called `Flow`, which is used for continuous aggregation. Please read the [user guide](/user-guide/flow-computation/overview.md). ## Can I store data in object storage in the cloud? Yes, GreptimeDB's data access layer is based on [OpenDAL](https://github.com/apache/incubator-opendal), which supports most kinds of object storage services. The data can be stored in cost-effective cloud storage services such as AWS S3 or Azure Blob Storage, please refer to storage configuration guide [here](/user-guide/deployments-administration/configuration.md#storage-options). ## How is GreptimeDB's performance compared to other solutions? [GreptimeDB achieves 1 billion cold run #1 in JSONBench!](https://greptime.com/blogs/2025-03-18-jsonbench-greptimedb-performance) Please read the performance benchmark reports: * [GreptimeDB vs. InfluxDB](https://greptime.com/blogs/2024-08-07-performance-benchmark) * [GreptimeDB vs. TimescaleDB](https://greptime.com/blogs/2025-12-09-greptimedb-vs-timescaledb-benchmark) * [GreptimeDB vs. Grafana Mimir](https://greptime.com/blogs/2024-08-02-datanode-benchmark) * [GreptimeDB vs. ClickHouse vs. Elasticsearch](https://greptime.com/blogs/2025-03-10-log-benchmark-greptimedb) * [GreptimeDB vs. SQLite](https://greptime.com/blogs/2024-08-30-sqlite) ## Does GreptimeDB have disaster recovery solutions? Yes. Please refer to [disaster recovery](/user-guide/deployments-administration/disaster-recovery/overview.md). ## Does GreptimeDB have geospatial index? Yes. We offer [built-in functions](/reference/sql/functions/geo.md) for Geohash, H3 and S2 index. ## Any JSON support? See [JSON functions](/reference/sql/functions/overview.md#json-functions). ## More Questions? For more comprehensive answers to frequently asked questions about GreptimeDB, including deployment options, migration guides, performance comparisons, and best practices, please visit our [FAQ page](/faq-and-others/faq.md). --- ## Key Concepts To understand how GreptimeDB manages and serves its data, you need to know about these building blocks of GreptimeDB. ## Database Similar to *database* in relational databases, a database is the minimal unit of data container, within which data can be managed and computed. Users can use the database to achieve data isolation, creating a tenant-like effect. ## Time-Series Table GreptimeDB designed time-series table to be the basic unit of data storage. It is similar to a table in a traditional relational database, but requires a timestamp column(We call it **time index**). The table holds a set of data that shares a common schema, it's a collection of rows and columns: * Column: a vertical set of values in a table, GreptimeDB distinguishes columns into time index, tag and field. * Row: a horizontal set of values in a table. It can be created using SQL `CREATE TABLE`, or inferred from the input data structure using the auto-schema feature. In a distributed deployment, a table can be split into multiple partitions that sit on different datanodes. For more information about the data model of the time-series table, please refer to [Data Model](./data-model.md). ## Table Engine Table engines (also called storage engines) determine how data is stored, managed, and processed within the database. Each engine offers different features, performance characteristics, and trade-offs. GreptimeDB supports `mito` and `metric` engines etc., see [Table Engines](/reference/about-greptimedb-engines.md) for more information. ## Table Region Each partition of distributed table is called a region. A region may contain a sequence of continuous data, depending on the partition algorithm. Region information is managed by Metasrv. It's completely transparent to users who send write requests or queries. ## Data Types Data in GreptimeDB is strongly typed. Auto-schema feature provides some flexibility when creating a table. Once the table is created, data of the same column must share common data type. Find all the supported data types in [Data Types](/reference/sql/data-types.md). ## Index The `index` is a performance-tuning method that allows faster retrieval of records. GreptimeDB provides various kinds of [indexes](/user-guide/manage-data/data-index.md) to accelerate queries. ## View The `view` is a virtual table that is derived from the result set of a SQL query. It contains rows and columns just like a real table, but it doesn’t store any data itself. The data displayed in a view is retrieved dynamically from the underlying tables each time the view is queried. ## Flow A `flow` in GreptimeDB refers to a [continuous aggregation](/user-guide/flow-computation/overview.md) process that continuously updates and materializes aggregated data based on incoming data. --- ## Observability 2.0 Observability 2.0 represents an evolution from the foundational "three pillars" (metrics, logs, and traces) toward a unified data foundation based on high-cardinality, wide-event datasets. Instead of maintaining separate systems for each signal type, this approach emphasizes a single source of truth that enables retroactive analysis rather than pre-aggregation. Despite its contested naming, the core concept is clear: breaking down the silos between metrics, logs, and traces to provide a more comprehensive view of modern distributed systems. ## The Limits of Three Pillars For years, observability has relied on the three pillars of metrics, logs, and traces. While these pillars spawned countless successful tools (including [OpenTelemetry](/user-guide/ingest-data/for-observability/opentelemetry.md)), their limitations become evident as systems grow in complexity: 1. **Data silos**: Metrics, logs, and traces are stored separately, leading to uncorrelated datasets. Correlating a spike in error metrics with log patterns requires manual context-switching between systems. 2. **Granularity vs. cost**: Traditional metrics sacrifice detail through pre-aggregation. But retaining full granularity creates millions of time-series with redundant metadata across systems, driving costs up instead of down. 3. **Unstructured logs**: While logs inherently contain structured data, extracting meaning requires intensive parsing, indexing, and computational effort. These limitations become even more pronounced in modern scenarios like AI agents and microservices, where high-dimensional, semi-structured data is the norm rather than the exception. ## Wide Events: A Unified Data Model Observability 2.0 addresses these issues by adopting **wide events** as its foundational data structure. A wide event is a context-rich, high-dimensional, and high-cardinality record that captures complete application state in a single event. ### What is a Wide Event? Instead of precomputing metrics or structuring logs upfront, wide events preserve raw, high-fidelity event data as the single source of truth. For example, a single wide event for a POST request might include: - User information and subscription data - Database queries with parameters - Cache operations - HTTP headers - Total: 2KB+ of contextual data in one record ```json { "method": "POST", "path": "/articles", "service": "articles", "outcome": "ok", "status_code": 201, "duration": 268, "user": { "id": "fdc4ddd4-8b30-4ee9-83aa-abd2e59e9603", "subscription": { "plan": "free", "trial": true } }, "db": { "query": "INSERT INTO articles (...)", "parameters": { "$1": "f8d4d21c-..." } }, "cache": { "operation": "write", "key": "..." }, "headers": { "user-agent": "...", "cf-connecting-ip": "..." } } ``` ### Metrics, Logs, and Traces as Projections Wide events fundamentally change how we think about observability data. Metrics, logs, and traces are not separate data types—they are different projections of the same underlying events: - **Metrics**: `SELECT COUNT(*) GROUP BY status, date_bin(INTERVAL '1' minute, timestamp)` — aggregated projection - **Logs**: `SELECT message, timestamp WHERE message @@ 'error'` — text projection - **Traces**: `SELECT span_id, duration WHERE trace_id = '...'` — relational projection This allows teams to perform exploratory analysis retroactively, deriving any metric, log query, or trace view from the original dataset—without pre-aggregation or code changes. ## AI and the Need for Fine-Grained Observability AI agents introduce a new level of observability complexity due to their non-deterministic behavior. Unlike traditional applications with predictable code paths, agents make dynamic decisions—choosing tools, reasoning through multi-step plans, and adapting responses based on context. Debugging "why did the agent do X?" requires preserving complete execution state: the full prompt, reasoning chain, tool calls with parameters, memory state, and quality scores—all in a single queryable record. This is where wide events become essential. Traditional three-pillar approaches fail here: stuffing prompts into logs loses structure and makes analysis impossible, forcing tool calls into traces is too rigid for dynamic behavior, and pre-aggregating token metrics loses the critical context needed for debugging. AI agents produce high-cardinality (millions of unique sessions), high-dimensional (dozens of fields per execution), context-rich events—exactly what wide events are designed to handle. This isn't "observability for the AI age" as a marketing slogan; it's a direct technical consequence: non-deterministic systems require fine-grained, structured, retroactive analysis that only wide events can provide. ## Why GreptimeDB is Built for This GreptimeDB's [architecture](/user-guide/concepts/architecture.md) naturally aligns with the Observability 2.0 paradigm. Its columnar engine efficiently compresses wide events (achieving 50% storage reduction compared to Loki and ~90% compared to Elasticsearch in production), and [native object storage](/user-guide/concepts/storage-location.md) (S3, Azure Blob, GCS) keeps costs low as wide event volumes grow. Below are the capabilities that matter most for wide events. ### Unified Tag + Timestamp + Field Model All observability data—metrics, logs, traces—share the same [schema model](/user-guide/concepts/data-model.md) in GreptimeDB: - **Tags**: Entity identifiers (pod_name, service, region, trace_id, session_id) - **Timestamp**: Temporal tracking - **Fields**: Multi-dimensional values (message, duration, status_code, prompts, responses) This unified model enables cross-signal correlation in a single SQL query. ### SQL + PromQL for Cross-Signal Correlation Use one [SQL query](/user-guide/query-data/sql.md) to correlate metrics spikes, log patterns, and trace latency: ```sql SELECT date_bin(INTERVAL '1' minute, timestamp) AS minute, COUNT(CASE WHEN status >= 500 THEN 1 END) AS errors, AVG(duration) AS avg_latency FROM access_logs WHERE timestamp >= NOW() - INTERVAL '1' hour AND message @@ 'timeout' GROUP BY date_bin(INTERVAL '1' minute, timestamp); ``` No context-switching between systems—all signals in one database. GreptimeDB also supports [PromQL](/user-guide/query-data/promql.md) for metrics queries, maintaining compatibility with existing dashboards. ### Flow Engine for Real-Time Derivation GreptimeDB's [Flow Engine](/user-guide/flow-computation/overview.md) derives metrics from raw events in real-time without preprocessing pipelines: ```sql CREATE FLOW http_status_count SINK TO status_metrics AS SELECT status, COUNT(*) AS count, date_bin('1 minute'::INTERVAL, timestamp) AS time_window FROM access_logs GROUP BY status, time_window; ``` Metrics are computed continuously from raw wide events, enabling both pre-aggregated dashboards and ad-hoc exploratory queries on the same dataset. ## Wide Events in Production Wide events are proven in production at scale: - **Poizon (得物)**: One of the early production deployments of Wide Events. Flow Engine with multi-level continuous aggregation reduced P99 latency from seconds to milliseconds. [Read more →](https://greptime.com/blogs/2025-05-06-poizon-observability-greptimedb-monitoring-use-case) - **OceanBase Cloud**: One year after migrating from Loki, running 80+ GreptimeDB clusters with 300TB of multi-cloud logs and SQL audit data, with overall log storage cost down by more than 60%. [Read more →](https://greptime.com/blogs/2025-07-22-user-case-obcloud-log-management-greptimedb) - **Trace Storage**: Replaced [Elasticsearch](/user-guide/protocols/elasticsearch.md) as [Jaeger](/user-guide/query-data/jaeger.md) backend. 45x storage cost reduction, 3x faster cold queries, enabled full-volume tracing at 400B rows/day. [Read more →](https://greptime.com/blogs/2025-04-24-elasticsearch-greptimedb-comparison-performance) ## Getting Started Transitioning to Observability 2.0 doesn't require ripping out your entire stack. Start from any pillar—[logs](/user-guide/logs/overview.md), [metrics](/user-guide/ingest-data/for-observability/prometheus.md), or [traces](/user-guide/traces/overview.md)—and extend naturally. GreptimeDB supports [PromQL](/user-guide/query-data/promql.md), [Jaeger](/user-guide/query-data/jaeger.md), [OpenTelemetry](/user-guide/ingest-data/for-observability/opentelemetry.md), and [Grafana](/user-guide/integrations/grafana.md) out of the box, so existing dashboards and alerts keep working. See [Why GreptimeDB](./why-greptimedb.md) for detailed migration paths. ## Further Reading - [Observability 2.0 and the Database for It](https://greptime.com/blogs/2025-04-25-greptimedb-observability2-new-database) — Full vision and technical deep dive - [Unified Storage for Observability - GreptimeDB's Approach](https://greptime.com/blogs/2024-12-24-observability) — GreptimeDB's unified model philosophy - [Agent Observability: Can the Old Playbook Handle the New Game?](https://greptime.com/blogs/2025-12-11-agent-observability) — Why AI agents need wide events - [Scaling Observability at Poizon - Building a Cost-Effective and Real-Time Monitoring Architecture with GreptimeDB](https://greptime.com/blogs/2025-05-06-poizon-observability-greptimedb-monitoring-use-case) — First production-grade validation - [Beyond Loki! GreptimeDB Log Scenario Performance Report Released](https://greptime.com/blogs/2025-08-07-beyond-loki-greptimedb-log-scenario-performance-report) — Logs pillar migration - [Beyond ELK: Lightweight and Scalable Cloud-Native Log Monitoring](https://greptime.com/blogs/2025-04-24-elasticsearch-greptimedb-comparison-performance) — Traces pillar migration --- ## GreptimeDB Concepts Overview # Concepts GreptimeDB is an observability database that unifies metrics, logs, and traces in a single engine. This section covers the core concepts you need to understand how GreptimeDB works and why it's designed this way. **Start here:** - [Why GreptimeDB](./why-greptimedb.md) — The problem with three-pillar observability stacks, and how GreptimeDB solves it - [Data Model](./data-model.md) — How metrics, logs, and traces are represented as timestamped events with tags and fields - [Architecture](./architecture.md) — Compute-storage separation, stateless frontends, and how GreptimeDB scales **Deep dives:** - [Observability 2.0](./observability-2.md) — Wide events, unified data model, and the evolution beyond three pillars - [Storage Location](./storage-location.md) — Object storage, local disk, and multi-engine storage options - [Key Concepts](./key-concepts.md) — Tables, regions, time index, data types, views, and flows - [Common Questions](./features-that-you-concern.md) — FAQ on updates, deletions, TTL, compression, high cardinality, and more ## Further Reading - [Observability 2.0 and the Database for It](https://greptime.com/blogs/2025-04-25-greptimedb-observability2-new-database) — Our vision for the next generation of observability - [Unifying Logs and Metrics](https://greptime.com/blogs/2024-06-25-logs-and-metrics) - [GreptimeDB Storage Engine Design](https://greptime.com/blogs/2022-12-21-storage-engine-design) --- ## Storage Location GreptimeDB supports storing data in local file system, AWS S3 and compatible services (including minio, digitalocean space, Tencent Cloud Object Storage(COS), Baidu Object Storage(BOS) and so on), Azure Blob Storage and Aliyun OSS. ## Local File Structure The storage file structure of GreptimeDB includes of the following: ```cmd ├── metadata ├── raftlog ├── rewrite └── LOCK ├── data │   ├── greptime │   └── public ├── cache ├── logs ├── index_intermediate │   └── staging └── wal ├── raftlog ├── rewrite └── LOCK ``` - `metadata`: The internal metadata directory that keeps catalog, database and table info, procedure states, etc. In cluster mode, this directory does not exist, because all those states including region route info are saved in `Metasrv`. - `data`: The files in data directory store time series data and index files of GreptimeDB. To customize this path, please refer to [Storage option](/user-guide/deployments-administration/configuration.md#storage-options). The directory is organized in a two-level structure of catalog and schema. - `cache`: The directory for internal caching, such as object storage cache, etc. - `logs`: The log files contains all the logs of operations in GreptimeDB. - `wal`: The wal directory contains the write-ahead log files. - `index_intermediate`: the temporary intermediate data while indexing. ## Cloud storage The `data` directory in the file structure can be stored in cloud storage. Please refer to [Storage option](/user-guide/deployments-administration/configuration.md#storage-options) for more details. Please note that only storing the data directory in object storage is not sufficient to ensure data reliability and disaster recovery. The `wal` and `metadata` also need to be considered for disaster recovery. Please refer to the [disaster recovery documentation](/user-guide/deployments-administration/disaster-recovery/overview.md). ## Multiple storage engines Another powerful feature of GreptimeDB is that you can choose the storage engine for each table. For example, you can store some tables on the local disk, and some tables in Amazon S3 or Google Cloud Storage, see [create table](/reference/sql/create.md#create-table). --- ## Why GreptimeDB ## The Problem: Three Systems for Three Signals Most observability stacks today look like this: [Prometheus](/user-guide/ingest-data/for-observability/prometheus.md) (or Thanos/Mimir) for metrics, [Grafana Loki](/user-guide/ingest-data/for-observability/loki.md) (or ELK) for logs, and [Elasticsearch](/user-guide/protocols/elasticsearch.md) (or Tempo) for traces. Each system has its own query language, storage backend, scaling model, and operational overhead. This "three pillars" architecture made sense when these were separate concerns. But in practice, it means: - **3x operational complexity** — three systems to deploy, monitor, upgrade, and debug - **Data silos** — correlating a spike in error logs with a metrics anomaly requires manual context-switching between systems - **Cost escalation** — each system stores redundant metadata, and scaling each independently leads to over-provisioning GreptimeDB takes a different approach: one database engine for all three signal types, built on object storage with compute-storage separation. ## Unified Processing for Observability Data GreptimeDB unifies the processing of metrics, logs, and traces through: - A consistent [data model](./data-model.md) that treats all observability data as timestamped wide events with context - Native support for both [SQL](/user-guide/query-data/sql.md) and [PromQL](/user-guide/query-data/promql.md) queries - Built-in stream processing capabilities ([Flow](/user-guide/flow-computation/overview.md)) for real-time aggregation and analytics - Seamless correlation analysis across different types of observability data (read the [SQL example](/getting-started/quick-start.md#correlate-metrics-logs-and-traces) for detailed info) It replaces complex legacy data stacks with a high-performance single solution. This means you can replace the [Prometheus](/user-guide/ingest-data/for-observability/prometheus.md) + [Loki](/user-guide/ingest-data/for-observability/loki.md) + [Elasticsearch](/user-guide/protocols/elasticsearch.md) stack with a single database, and use SQL to correlate metrics spikes with log patterns and trace latency — in one query, without context-switching between systems. ## Cost-Effective with Object Storage GreptimeDB leverages [cloud object storage](/user-guide/concepts/storage-location.md) (like AWS S3 and Azure Blob Storage etc.) as its storage layer, dramatically reducing costs compared to traditional storage solutions. Its optimized columnar storage and advanced compression algorithms achieve up to 50x cost efficiency. Scale flexibly across cloud storage systems (e.g., S3, Azure Blob Storage) for simplified management, dramatic cost efficiency, and **no vendor lock-in**. In production deployments, teams have achieved: - **Logs**: 60%+ storage cost reduction in production at OceanBase Cloud (migrated from [Loki](/user-guide/ingest-data/for-observability/loki.md) — 80+ GreptimeDB clusters, 300TB of multi-cloud logs and SQL audit data) - **Traces**: 45x storage cost reduction, 3x faster queries (replaced [Elasticsearch](/user-guide/protocols/elasticsearch.md) as [Jaeger](/user-guide/query-data/jaeger.md) backend — one-week migration) - **Metrics**: Replaced Thanos with native compute-storage separation, significantly reducing operational complexity ## High Performance As for performance optimization, GreptimeDB utilizes different techniques such as LSM Tree, data sharding, and flexible WAL options (local disk or distributed services like Kafka), to handle large workloads of observability data ingestion. GreptimeDB is written in pure Rust for superior performance and reliability. The powerful and fast query engine is powered by vectorized execution and distributed parallel processing (thanks to [Apache DataFusion](https://datafusion.apache.org/)), and combined with [indexing capabilities](/user-guide/manage-data/data-index.md) such as inverted index, skipping index, and full-text index. GreptimeDB combines smart indexing and Massively Parallel Processing (MPP) to boost pruning and filtering. [GreptimeDB achieves 1 billion cold runs #1 in JSONBench!](https://greptime.com/blogs/2025-03-18-jsonbench-greptimedb-performance) Read more [benchmark reports](https://www.greptime.com/blogs/2024-09-09-report-summary). ## Elastic Scaling with Kubernetes Built from the ground up for [Kubernetes](/user-guide/deployments-administration/deploy-on-kubernetes/overview.md), GreptimeDB features a disaggregated storage and compute [architecture](/user-guide/concepts/architecture.md) that enables true elastic scaling: - Independent scaling of storage and compute resources - Unlimited horizontal scalability through Kubernetes - Resource isolation between different workloads (ingestion, querying, compaction) - Automatic failover and high availability Unlike Thanos or Mimir, which require multiple stateful components (ingesters with persistent disks, store-gateways, compactors) to achieve scalability, GreptimeDB's architecture separates compute from storage at the core — data persists in object storage, compute nodes scale independently, with local disk serving as buffer/cache. WAL can be configured flexibly (local or distributed via Kafka). Scaling up means adding nodes; scaling down loses no data. ![Storage/Compute Disaggregation, Compute/Compute separation](/storage-compute-disaggregation-compute-compute-separation.png) ## Flexible Architecture: From Edge to Cloud ![The architecture of GreptimeDB](/architecture-2.png) GreptimeDB's modularized [architecture](/user-guide/concepts/architecture.md) allows different components to operate independently or in unison as needed. Its flexible design supports a wide variety of deployment scenarios, from edge devices to cloud environments, while still using consistent APIs for operations. For example: - Frontend, datanode, and metasrv can be merged into a standalone binary - Components like WAL or indexing can be enabled or disabled per table This flexibility ensures that GreptimeDB meets deployment requirements for edge-to-cloud solutions, like the [Edge-Cloud Integrated Solution](https://greptime.com/product/carcloud). From embedded and standalone deployments to cloud-native clusters, GreptimeDB adapts to various environments easily. ## Easy to Integrate GreptimeDB supports [PromQL](/user-guide/query-data/promql.md), [Prometheus remote write](/user-guide/ingest-data/for-observability/prometheus.md), [OpenTelemetry](/user-guide/ingest-data/for-observability/opentelemetry.md), [Jaeger](/user-guide/query-data/jaeger.md), [Loki](/user-guide/ingest-data/for-observability/loki.md), [Elasticsearch](/user-guide/protocols/elasticsearch.md), [MySQL](/user-guide/protocols/mysql.md), and [PostgreSQL](/user-guide/protocols/postgresql.md) protocols — migrate from your existing stack without rewriting queries or pipelines. Query with [SQL](/user-guide/query-data/sql.md) or PromQL, visualize with [Grafana](/user-guide/integrations/grafana.md). The combination of SQL and PromQL means GreptimeDB can replace the classic "Prometheus + data warehouse" combo — use PromQL for real-time monitoring and alerting, SQL for deep analytics, joins, and aggregations, all in one system. GreptimeDB also supports a [multi-value model](/user-guide/concepts/data-model.md), where a single row can contain multiple field columns, reducing transfer traffic and simplifying queries compared to single-value models. Beyond querying, SQL is also GreptimeDB's management interface — [create tables](/user-guide/deployments-administration/manage-data/basic-table-operations.md), [manage schemas](/reference/sql/alter.md), set [TTL policies](/user-guide/manage-data/overview.md#manage-data-retention-with-ttl-policies), and configure [indexes](/user-guide/manage-data/data-index.md), all through standard SQL. No proprietary config files, no custom APIs, no YAML-driven control planes. This is a key operational difference from systems like Prometheus (configured via YAML + relabeling rules), Loki (LogQL + config files), or Elasticsearch (REST API + JSON mappings). Teams with SQL skills can manage GreptimeDB without learning new tooling. ## How GreptimeDB Compares The following comparison is based on general architectural characteristics and typical deployment scenarios: | | GreptimeDB | Prometheus / Thanos / Mimir | Grafana Loki | Elasticsearch | |---|---|---|---|---| | Data types | Metrics, logs, traces | Metrics only | Logs only | Logs, traces | | Query language | SQL + PromQL | PromQL | LogQL | Query DSL | | Storage | Native object storage (S3, etc.) | Local disk + object storage (Thanos/Mimir), ingester requires persistent disk | Object storage (chunks) | Local disk | | Scaling | Compute-storage separation, compute nodes scale independently | Federation / Thanos / Mimir — multi-component, ops heavy | Stateless + object storage | Shard-based, ops heavy | | Cost efficiency | Up to 50x lower storage | High at scale | Moderate | High (inverted index overhead) | | OpenTelemetry | Native (metrics + logs + traces) | Partial (metrics only) | Partial (logs only) | Via instrumentation | | Management | Standard SQL (DDL, TTL, indexes) | YAML config + relabeling rules | YAML config + LogQL | REST API + JSON mappings | For more details, explore: - [Observability 2.0](./observability-2.md) — Wide events, unified data model, and GreptimeDB's architecture for the next generation of observability - [Unified Storage for Observability - GreptimeDB's Approach](https://greptime.com/blogs/2024-12-24-observability) — GreptimeDB's approach to unified storage - [Beyond Loki: Lightweight and Scalable Cloud-Native Log Monitoring](https://greptime.com/blogs/2025-08-07-beyond-loki-greptimedb-log-scenario-performance-report) --- ## Authentication Authentication occurs when a user attempts to connect to the database. In GreptimeDB, users are authenticated by "user provider"s. There are various implementations of user providers in GreptimeDB: - [Static User Provider](./static.md): A simple built-in user provider implementation that finds users from a static file. - [LDAP User Provider](/enterprise/deployments-administration/authentication.md): **Enterprise feature.** A user provider implementation that authenticates users against an external LDAP server. --- ## Static User Provider GreptimeDB offers a simple built-in mechanism for authentication, allowing users to configure either a fixed account for convenient usage or an account file for multiple user accounts. By passing in a file, GreptimeDB loads all users listed within it. ## Standalone Mode GreptimeDB reads the user configuration from a file where each line defines a user with their password and optional permission mode. ### Basic Configuration The basic format uses `=` as a separator between username and password: ``` greptime_user=greptime_pwd alice=aaa bob=bbb ``` Users configured this way have full read-write access by default. ### Permission Modes You can optionally specify permission modes to control user access levels. The format is: ``` username:permission_mode=password ``` Available permission modes: - `rw` or `readwrite` - Full read and write access (default when not specified) - `ro` or `readonly` - Read-only access - `wo` or `writeonly` - Write-only access Example configuration with mixed permission modes: ``` admin=admin_pwd alice:readonly=aaa bob:writeonly=bbb viewer:ro=viewer_pwd editor:rw=editor_pwd ``` In this configuration: - `admin` has full read-write access (default) - `alice` has read-only access - `bob` has write-only access - `viewer` has read-only access - `editor` has explicitly set read-write access ### Starting the Server Start the server with the `--user-provider` parameter and set it to `static_user_provider:file:` (replace `` with the path to your user configuration file): ```shell ./greptime standalone start --user-provider=static_user_provider:file: ``` The users and their permissions will be loaded into GreptimeDB's memory. You can create connections to GreptimeDB using these user accounts with their respective access levels enforced. :::tip Note When using `static_user_provider:file`, the file’s contents are loaded at startup. Changes or additions to the file have no effect while the database is running. ::: ### Dynamic File Reloading If you need to update user credentials without restarting the server, you can use the `watch_file_user_provider` instead of `static_user_provider:file`. This provider monitors the credential file for changes and automatically reloads it: ```shell ./greptime standalone start --user-provider=watch_file_user_provider: ``` The watch file provider: - Uses the same file format as the static file provider - Automatically detects file modifications and reloads credentials - Allows adding, removing, or modifying users without server restart - If the file is temporarily unavailable or invalid, it keeps the last valid configuration This is particularly useful in production environments where you need to manage user access dynamically. ## Kubernetes Cluster You can configure the authentication users in the `values.yaml` file. For more details, please refer to the [Helm Chart Configuration](/user-guide/deployments-administration/deploy-on-kubernetes/common-helm-chart-configurations.md#authentication-configuration). --- ## Capacity Plan This guide provides general advice on the CPU, memory, and storage requirements for GreptimeDB. GreptimeDB is designed to be lightweight upon startup, which allows for the database to be initiated with minimal server resources. However, when configuring your server capacity for a production environment, there are several key considerations: - Data points processed per second - Query requests per second - Data volume - Data retention policy - Hardware costs To monitor the various metrics of GreptimeDB, please refer to [Monitoring](/user-guide/deployments-administration/monitoring/overview.md). ## CPU Generally, applications that handle many concurrent queries, process large amounts of data, or perform other compute-intensive operations will require more CPU cores. Here are some recommendations for CPU resource usage, but the actual number of CPUs you should use depends on your workload. Consider allocating 30% of your CPU resources for data ingestion, with the remaining 70% to querying and analytics. A recommended guideline for resource allocation is to maintain a CPU to memory ratio of 1:4 (for instance, 8 core to 32 GB). However, if your workload consists primarily of data ingestion with few queries, a ratio of 1:2 (8 core to 16 GB) can also be acceptable. ## Memory In general, the more memory you have, the faster your queries will run. For basic workloads, it's recommended to have at least 8 GB of memory, and 32 GB for more advanced ones. ## Storage GreptimeDB features an efficient data compaction mechanism that reduces the original data size to about 1/8 to 1/10 of its initial volume. This allows GreptimeDB to store large amounts of data in a significantly smaller space. Data can be stored either in a local file system or in cloud storage, such as AWS S3. FOr more information on storage options, please refer to the [storage configuration](/user-guide/deployments-administration/configuration.md#storage-options) documentation. Cloud storage is highly recommended for data storage due to its simplicity in managing storage. With cloud storage, only about 200GB of local storage space is needed for query-related caches and Write-Ahead Log (WAL). In order to manage the storage costs effectively, it is recommended setting a [retention policy](/user-guide/concepts/features-that-you-concern.md#can-i-set-ttl-or-retention-policy-for-different-tables-or-measurements). ## Example Consider a scenario where your database handles a query rate of about 200 simple queries per second (QPS) and an ingestion rate of approximately 300k data points per second, using cloud storage for data. Given the high ingestion and query rates, here's an example of how you might allocate resources: - CPU: 8 cores - Memory: 32 GB - Storage: 200 GB Such an allocation is designed to optimize performance, ensuring smooth data ingestion and query processing without system overload. However, remember these are just guidelines, and actual requirements may vary based on specific workload characteristics and performance expectations. --- ## GreptimeDB Deployment Configuration # Configuration GreptimeDB supports **layered configuration** with the following precedence order (where each item overrides the one below it): - Greptime command line options - Configuration file options - Environment variables - Default values You only need to set up the configurations you require. GreptimeDB will assign default values for any settings not configured. ## How to set up configurations ### Greptime command line options You can specify several configurations using command line arguments. For example, to start GreptimeDB in standalone mode with a configured HTTP address: ```shell greptime standalone start --http-addr 127.0.0.1:4000 ``` For all the options supported by the Greptime command line, refer to the [GreptimeDB Command Line Interface](/reference/command-lines/overview.md). ### Configuration file options You can specify configurations in a TOML file. For example, create a configuration file `standalone.example.toml` as shown below: ```toml [storage] type = "File" data_home = "greptimedb_data" ``` Then, specify the configuration file using the command line argument `-c [file_path]`. ```sh greptime [standalone | frontend | datanode | metasrv] start -c config/standalone.example.toml ``` For example, to start in standalone mode: ```bash greptime standalone start -c standalone.example.toml ``` #### Example files Below are example configuration files for each GreptimeDB component, including all available configurations. In actual scenarios, you only need to configure the required options and do not need to configure all options as in the sample file. - [standalone](https://github.com/GreptimeTeam/greptimedb/blob/v1.0.2/config/standalone.example.toml) - [frontend](https://github.com/GreptimeTeam/greptimedb/blob/v1.0.2/config/frontend.example.toml) - [datanode](https://github.com/GreptimeTeam/greptimedb/blob/v1.0.2/config/datanode.example.toml) - [flownode](https://github.com/GreptimeTeam/greptimedb/blob/v1.0.2/config/flownode.example.toml) - [metasrv](https://github.com/GreptimeTeam/greptimedb/blob/v1.0.2/config/metasrv.example.toml) ### Helm Configurations When deploying GreptimeDB on Kubernetes using Helm charts, you can configure certain settings directly in the Helm `values.yaml` file. Please refer to the [Helm configuration documentation](/user-guide/deployments-administration/deploy-on-kubernetes/common-helm-chart-configurations.md) for all Helm-supported configurations. For configurations that are available only in the [options](#options) section of this document, you can [inject complete TOML configuration files](/user-guide/deployments-administration/deploy-on-kubernetes/common-helm-chart-configurations.md#injecting-configuration-files) into your deployment. ### Environment variable Every item in the configuration file can be mapped to environment variables. For example, to set the `data_home` configuration item for the datanode using an environment variable: ```toml # ... [storage] data_home = "/data/greptimedb" # ... ``` Use the following shell command to set the environment variable in the following format: ``` export GREPTIMEDB_DATANODE__STORAGE__DATA_HOME=/data/greptimedb ``` #### Environment Variable Rules - Each environment variable should have the component prefix, for example: - `GREPTIMEDB_FRONTEND` - `GREPTIMEDB_METASRV` - `GREPTIMEDB_DATANODE` - `GREPTIMEDB_STANDALONE` - Use **double underscore `__`** separators. For example, the data structure `storage.data_home` is transformed to `STORAGE__DATA_HOME`. The environment variable also accepts lists that are separated by commas `,`, for example: ``` GREPTIMEDB_METASRV__META_CLIENT__METASRV_ADDRS=127.0.0.1:3001,127.0.0.1:3002,127.0.0.1:3003 ``` ## Options In this section, we will introduce some main configuration options. For all options, refer to the [Configuration Reference](https://github.com/GreptimeTeam/greptimedb/blob/v1.0.2/config/config.md) on Github. ### Write memory limiter options Memory limiter options control the total memory used by concurrent write requests across all protocols (HTTP, gRPC, and Arrow Flight). These options are valid in `frontend` and `standalone` subcommands. ```toml # Maximum total memory for all concurrent write request bodies and messages # Set to 0 to disable the limit (unlimited by default) max_in_flight_write_bytes = "1GB" # Policy when write bytes quota is exhausted # Options: "wait" (default, 10s timeout), "wait()" (e.g., "wait(30s)"), "fail" write_bytes_exhausted_policy = "wait" ``` | Option | Type | Default | Description | | ------------------------------- | ------ | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `max_in_flight_write_bytes` | String | `"0"` | Maximum total memory for all concurrent write request bodies and messages (HTTP, gRPC, Flight). Set to `"0"` to disable the limit (unlimited). Supports units: `B`, `KB`, `MB`, `GB`, etc. Example: `"1GB"` limits total concurrent writes to 1GB. | | `write_bytes_exhausted_policy` | String | `"wait"`| Policy when write bytes quota is exhausted. Options: `"wait"` (default, waits up to 10 seconds), `"wait()"` (custom timeout, e.g., `"wait(30s)"`), `"fail"` (immediately reject the request). | ### Protocol options Protocol options are valid in `frontend` and `standalone` subcommands, specifying protocol server addresses and other protocol-related options. :::tip NOTE The HTTP protocol configuration is available for all GreptimeDB components: `frontend`, `datanode`, `flownode`, and `metasrv`. ::: Below is an example configuration with default values. You can change the values or disable certain protocols in your configuration file. For example, to disable OpenTSDB protocol support, set the `enable` parameter to `false`. Note that HTTP and gRPC protocols cannot be disabled for the database to function correctly. ```toml [http] addr = "127.0.0.1:4000" timeout = "0s" body_limit = "64MB" [grpc] bind_addr = "127.0.0.1:4001" runtime_size = 8 [mysql] enable = true addr = "127.0.0.1:4002" runtime_size = 2 [mysql.tls] mode = "disable" cert_path = "" key_path = "" watch = false [postgres] enable = true addr = "127.0.0.1:4003" runtime_size = 2 [postgres.tls] mode = "disable" cert_path = "" key_path = "" watch = false [opentsdb] enable = true [influxdb] enable = true [prom_store] enable = true with_metric_engine = true ``` The following table describes the options in detail: | Option | Key | Type | Description | | ---------- | -------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | http | | | HTTP server options | | | addr | String | Server address, "127.0.0.1:4000" by default | | | timeout | String | HTTP request timeout. Set to 0 to disable timeout (default: "0s"). | | | body_limit | String | HTTP max body size, "64MB" by default | | | prom_validation_mode | String | Whether to check if strings are valid UTF-8 strings in Prometheus remote write requests. Available options: `strict`(reject any request with invalid UTF-8 strings), `lossy`(replace invalid characters with [UTF-8 REPLACEMENT CHARACTER U+FFFD, which looks like �](https://www.unicode.org/versions/Unicode16.0.0/core-spec/chapter-23/#G24272)), `unchecked`(do not validate strings). | | grpc | | | gRPC server options | | | bind_addr | String | The address to bind the gRPC server, "127.0.0.1:4001" by default | | | runtime_size | Integer | The number of server worker threads, 8 by default | | | max_connection_age | String | Maximum lifetime of a gRPC connection that the server keeps it. Refer to ["MAX_CONNECTION_AGE"](https://grpc.io/docs/guides/keepalive/) for details. Defaults to not set. Example: "1h" for 1 hour, "30m" for 30 minutes | | | flight_compression | String | Compression mode for frontend side Arrow IPC service. Available options: `none`: disable all compression, `transport`: only enable gRPC transport compression (zstd), `arrow_ipc`: only enable Arrow IPC compression (lz4), `all`: enable all compression. Default value is `none`. | | mysql | | | MySQL server options | | | enable | Boolean | Whether to enable MySQL protocol, true by default | | | addr | String | Server address, "127.0.0.1:4002" by default | | | runtime_size | Integer | The number of server worker threads, 2 by default | | influxdb | | | InfluxDB Protocol options | | | enable | Boolean | Whether to enable InfluxDB protocol in HTTP API, true by default | | opentsdb | | | OpenTSDB Protocol options | | | enable | Boolean | Whether to enable OpenTSDB protocol in HTTP API, true by default | | prom_store | | | Prometheus remote storage options | | | enable | Boolean | Whether to enable Prometheus Remote Write and read in HTTP API, true by default | | | with_metric_engine | Boolean | Whether to use the metric engine on Prometheus Remote Write, true by default | | postgres | | | PostgresSQL server options | | | enable | Boolean | Whether to enable PostgresSQL protocol, true by default | | | addr | String | Server address, "127.0.0.1:4003" by default | | | runtime_size | Integer | The number of server worker threads, 2 by default | For MySQL, Postgres and gRPC interface, TLS can be configured to enable transport layer security. | Option | Key | Type | Description | | ----------------------------------------- | ----------- | ------- | ------------------------------------------------------------- | | `mysql.tls`, `postgres.tls` or `grpc.tls` | | | TLS configuration for MySQL and Postgres | | | `mode` | String | TLS mode, options are `disable`, `prefer` and `require` | | | `cert_path` | String | File path for TLS certificate | | | `key_path` | String | File path for TLS private key | | | `watch` | Boolean | Watch file system changes and reload certificate and key file | ### Query options The `query` options are valid in standalone, datanode and frontend modes, which controls the query engine's behavior. The following table describes the options in detail: | Option | Key | Type | Description | | ----------- | ------- | ---- | ----------------------------------------------------------------------------------- | | parallelism | Integer | `0` | Parallelism of the query engine. Default to 0, which means the number of CPU cores. | A sample configuration: ```toml [query] parallelism = 0 ``` ### Storage options The `storage` options are valid in datanode and standalone mode, which specify the database data directory and other storage-related options. GreptimeDB supports storing data in local file system, AWS S3 and compatible services (including MinIO, digitalocean space, Tencent Cloud Object Storage(COS), Baidu Object Storage(BOS) and so on), Azure Blob Storage and Aliyun OSS. | Option | Key | Type | Description | | ------- | ------------------------- | ------- | -------------------------------------------------------------------------------- | | storage | | | Storage options | | | type | String | Storage type, supports "File", "S3" and "Oss" etc. | | File | | | Local file storage options, valid when type="File" | | | data_home | String | Database storage root directory, "./greptimedb_data" by default | | S3 | | | AWS S3 storage options, valid when type="S3" | | | name | String | The storage provider name, default is `S3` | | | bucket | String | The S3 bucket name | | | root | String | The root path in S3 bucket | | | endpoint | String | The API endpoint of S3 | | | region | String | The S3 region | | | access_key_id | String | The S3 access key id | | | secret_access_key | String | The S3 secret access key | | | enable_virtual_host_style | Boolean | Send API requests in virtual host style instead of path style. Default is false. | | Oss | | | Aliyun OSS storage options, valid when type="Oss" | | | name | String | The storage provider name, default is `Oss` | | | bucket | String | The OSS bucket name | | | root | String | The root path in OSS bucket | | | endpoint | String | The API endpoint of OSS | | | access_key_id | String | The OSS AccessKey ID | | | access_key_secret | String | The OSS AccessKey Secret | | Azblob | | | Azure Blob Storage options, valid when type="Azblob" | | | name | String | The storage provider name, default is `Azblob` | | | container | String | The container name | | | root | String | The root path in container | | | endpoint | String | The API endpoint of Azure Blob Storage | | | account_name | String | The account name of Azure Blob Storage | | | account_key | String | The access key | | | sas_token | String | The shared access signature | | Gsc | | | Google Cloud Storage options, valid when type="Gsc" | | | name | String | The storage provider name, default is `Gsc` | | | root | String | The root path in Gsc bucket | | | bucket | String | The Gsc bucket name | | | scope | String | The Gsc service scope | | | credential_path | String | The Gsc credentials path | | | endpoint | String | The API endpoint of Gsc | A file storage sample configuration: ```toml [storage] type = "File" data_home = "./greptimedb_data/" ``` A S3 storage sample configuration: ```toml [storage] type = "S3" bucket = "test_greptimedb" root = "/greptimedb" access_key_id = "" secret_access_key = "" ``` ### Storage http client `[storage.http_client]` sets the options for the http client that is used to send requests to the storage service. Only applied for storage types "S3", "Oss", "Azblob" and "Gcs". | Key | Type | Default | Description | | ------------------------ | ------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------- | | `pool_max_idle_per_host` | Integer | 1024 | The maximum idle connection per host allowed in the pool. | | `connect_timeout` | String | "30s" (30 seconds) | The timeout for only the connect phase of a http client. | | `timeout` | String | "30s" (30 seconds) | The total request timeout, applied from when the request starts connecting until the response body has finished. Also considered a total deadline. | | `pool_idle_timeout` | String | "90s" (90 seconds) | The timeout for idle sockets being kept-alive. | ### Storage engine provider `[[storage.providers]]` setups the table storage engine providers. Based on these providers, you can create a table with a specified storage, see [create table](/reference/sql/create.md#create-table): ```toml # Allows using multiple storages [[storage.providers]] name = "S3" type = "S3" bucket = "test_greptimedb" root = "/greptimedb" access_key_id = "" secret_access_key = "" [[storage.providers]] name = "Gcs" type = "Gcs" bucket = "test_greptimedb" root = "/greptimedb" credential_path = "" ``` All configured providers' names can be used as the `storage` option when creating tables. For storage from the same provider, if you want to use different S3 buckets as storage engines for different tables, you can set different `name` values and specify the `storage` option when creating the table. ### Object storage cache When using remote storage services like AWS S3, Alibaba Cloud OSS, or Azure Blob Storage, fetching data during queries can be time-consuming. To address this, GreptimeDB provides a write cache mechanism to speed up repeated data access. You can configure the cache size and behavior in the mito config if you don't want to use the default values. ```toml [[region_engine]] [region_engine.mito] write_cache_size = "10GiB" # Download files from object storage to fill the cache on write cache miss enable_refill_cache_on_read = true ``` By default, GreptimeDB automatically downloads files from object storage to fill the write cache when there's a cache miss during queries (`enable_refill_cache_on_read = true`). This improves subsequent query performance by keeping frequently accessed data in the write cache. You can disable this behavior by setting `enable_refill_cache_on_read = false` if you want to minimize network traffic or storage costs. Read [Performance Tuning Tips](/user-guide/deployments-administration/performance-tuning/performance-tuning-tips.md) for more detailed info. ### WAL options GreptimeDB supports three WAL storage options—Local WAL, Remote WAL, and Noop WAL. See the [WAL Overview](/user-guide/deployments-administration/wal/overview.md) for a comparison of the options. For detailed configurations, refer to the [Local WAL](/user-guide/deployments-administration/wal/local-wal.md), [Remote WAL](/user-guide/deployments-administration/wal/remote-wal/configuration.md), and [Noop WAL](/user-guide/deployments-administration/wal/noop-wal.md) documentation. ### Logging options `frontend`, `metasrv`, `datanode` and `standalone` can all configure log and tracing related parameters in the `[logging]` section: ```toml [logging] dir = "./greptimedb_data/logs" level = "info" enable_otlp_tracing = false otlp_endpoint = "localhost:4317" append_stdout = true [logging.tracing_sample_ratio] default_ratio = 1.0 ``` - `dir`: log output directory. - `level`: output log level, available log level are `info`, `debug`, `error`, `warn`, the default level is `info`. - `enable_otlp_tracing`: whether to turn on tracing, not turned on by default. - `otlp_endpoint`: Export the target endpoint of tracing using gRPC-based OTLP protocol, the default value is `localhost:4317`. - `append_stdout`: Whether to append logs to stdout. Defaults to `true`. - `tracing_sample_ratio`: This field can configure the sampling rate of tracing. How to use `tracing_sample_ratio`, please refer to [How to configure tracing sampling rate](/user-guide/deployments-administration/monitoring/tracing.md#guide-how-to-configure-tracing-sampling-rate). How to use distributed tracing, please reference [Tracing](/user-guide/deployments-administration/monitoring/tracing.md#tutorial-use-jaeger-to-trace-greptimedb) ### Region engine options The parameters corresponding to different storage engines can be configured for `datanode` and `standalone` in the `[region_engine]` section. Currently, options for `mito` and `metric` region engines are available. Frequently used options: ```toml [[region_engine]] [region_engine.mito] num_workers = 8 manifest_checkpoint_distance = 10 max_background_flushes = 4 max_background_compactions = 2 max_background_purges = 4 auto_flush_interval = "1h" global_write_buffer_size = "1GB" global_write_buffer_reject_size = "2GB" sst_meta_cache_size = "128MB" vector_cache_size = "512MB" page_cache_size = "512MB" write_cache_size = "5GB" write_cache_ttl = "8h" scan_memory_limit = "50%" scan_memory_on_exhausted = "fail" min_compaction_interval = "0m" default_flat_format = true sst_write_buffer_size = "8MB" max_concurrent_scan_files = 384 [region_engine.mito.index] aux_path = "" staging_size = "2GB" staging_ttl = "7d" metadata_cache_size = "64MiB" content_cache_size = "128MiB" content_cache_page_size = "64KiB" result_cache_size = "128MiB" [region_engine.mito.inverted_index] create_on_flush = "auto" create_on_compaction = "auto" apply_on_query = "auto" mem_threshold_on_create = "64M" intermediate_path = "" [region_engine.mito.memtable] type = "time_series" ``` The `mito` engine provides an experimental memtable which optimizes for write performance and memory efficiency under large amounts of time-series. Its read performance might not as fast as the default `time_series` memtable. ```toml [region_engine.mito.memtable] type = "partition_tree" index_max_keys_per_shard = 8192 data_freeze_threshold = 32768 fork_dictionary_bytes = "1GiB" ``` Available options: | Key | Type | Default | Descriptions | | ---------------------------------------- | ------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `num_workers` | Integer | `8` | Number of region workers. | | `manifest_checkpoint_distance` | Integer | `10` | Number of meta action updated to trigger a new checkpoint for the manifest. | | `compress_manifest` | Bool | `false` | Whether to compress manifest and checkpoint file by gzip. | | `max_background_flushes` | Integer | Auto | Max number of running background flush jobs (default: 1/2 of cpu cores). | | `max_background_compactions` | Integer | Auto | Max number of running background compaction jobs (default: 1/4 of cpu cores). | | `max_background_purges` | Integer | Auto | Max number of running background purge jobs (default: cpu cores). | | `auto_flush_interval` | String | `1h` | Interval to auto flush a region if it has not flushed yet. | | `global_write_buffer_size` | String | `1GB` | Global write buffer size for all regions. If not set, it's default to 1/8 of OS memory with a max limitation of 1GB. | | `global_write_buffer_reject_size` | String | `2GB` | Global write buffer size threshold to reject write requests. If not set, it's default to 2 times of `global_write_buffer_size` | | `sst_meta_cache_size` | String | `128MB` | Cache size for SST metadata. Setting it to 0 to disable the cache.If not set, it's default to 1/32 of OS memory with a max limitation of 128MB. | | `vector_cache_size` | String | `512MB` | Cache size for vectors and arrow arrays. Setting it to 0 to disable the cache.If not set, it's default to 1/16 of OS memory with a max limitation of 512MB. | | `page_cache_size` | String | `512MB` | Cache size for pages of SST row groups. Setting it to 0 to disable the cache.If not set, it's default to 1/8 of OS memory. | | `write_cache_size` | String | `5GiB` | Capacity for write cache. If your disk space is sufficient, it is recommended to set it larger. | | `write_cache_ttl` | String | `8h` | TTL for write cache. Defaults to 8 hours. | | `preload_index_cache` | Bool | `true` | Preload index (puffin) files into cache on region open (default: true).When enabled, index files are loaded into the write cache during region initialization,which can improve query performance at the cost of longer startup times. | | `index_cache_percent` | Integer | `20` | Percentage of write cache capacity allocated for index (puffin) files (default: 20).The remaining capacity is used for data (parquet) files.Must be between 0 and 100 (exclusive). For example, with a 5GiB write cache and 20% allocation,1GiB is reserved for index files and 4GiB for data files. | | `enable_refill_cache_on_read` | Bool | `true` | Enable refilling cache on read operations (default: true).When disabled, cache refilling on read won't happen. | | `manifest_cache_size` | String | `256MB` | Capacity for manifest cache (default: 256MB). | | `selector_result_cache_size` | String | `512MB` | Cache size for time series selector (e.g. `last_value()`). Setting it to 0 to disable the cache.If not set, it's default to 1/8 of OS memory. | | `sst_write_buffer_size` | String | `8MB` | Buffer size for SST writing. | | `max_concurrent_scan_files` | Integer | `384` | Maximum number of SST files to scan concurrently. | | `allow_stale_entries` | Bool | `false` | Whether to allow stale WAL entries during replay. | | `scan_memory_limit` | String | `50%` | Memory limit for table scans across all queries. Supports absolute size (e.g., "2GB") or percentage of system memory (e.g., "20%"). Setting it to 0 disables the limit. | | `scan_memory_on_exhausted` | String | `fail` | Behavior when scan memory is exhausted. Options: `fail` (fail fast), `wait` or `wait()` (wait for memory). | | `min_compaction_interval` | String | `0m` | Minimum time interval between two compactions. Set to "0m" (default) to allow compactions to run immediately without restriction. | | `default_flat_format` | Bool | `true` | Whether to enable flat format as the default SST format. | | `scan_parallelism` | Integer | `0` | (Deprecated, use `max_concurrent_scan_files` instead) Legacy option for scan parallelism. | | `index` | -- | -- | The options for index in Mito engine. | | `index.aux_path` | String | `""` | Auxiliary directory path for the index in the filesystem. This path is used to store intermediate files for creating the index and staging files for searching the index. It defaults to `{data_home}/index_intermediate`. The default name for this directory is `index_intermediate` for backward compatibility. This path contains two subdirectories: `__intm` for storing intermediate files used during index creation, and `staging` for storing staging files used during index searching. | | `index.staging_size` | String | `2GB` | The maximum capacity of the staging directory. | | `index.staging_ttl` | String | `7d` | TTL for staging directory. Defaults to 7 days. Setting to "0s" disables TTL. | | `index.metadata_cache_size` | String | `64MiB` | Cache size for index metadata. | | `index.content_cache_size` | String | `128MiB` | Cache size for index content. | | `index.content_cache_page_size` | String | `64KiB` | Page size for index content cache. | | `index.result_cache_size` | String | `128MiB` | Cache size for index query results. | | `inverted_index` | -- | -- | The options for inverted index in Mito engine. | | `inverted_index.create_on_flush` | String | `auto` | Whether to create the index on flush.- `auto`: automatically- `disable`: never | | `inverted_index.create_on_compaction` | String | `auto` | Whether to create the index on compaction.- `auto`: automatically- `disable`: never | | `inverted_index.apply_on_query` | String | `auto` | Whether to apply the index on query- `auto`: automatically- `disable`: never | | `inverted_index.mem_threshold_on_create` | String | `64M` | Memory threshold for performing an external sort during index creation.Setting to empty will disable external sorting, forcing all sorting operations to happen in memory. | | `inverted_index.intermediate_path` | String | `""` | File system path to store intermediate files for external sorting (default `{data_home}/index_intermediate`). | | `memtable.type` | String | `time_series` | Memtable type.- `time_series`: time-series memtable- `partition_tree`: partition tree memtable (experimental) | | `memtable.index_max_keys_per_shard` | Integer | `8192` | The max number of keys in one shard.Only available for `partition_tree` memtable. | | `memtable.data_freeze_threshold` | Integer | `32768` | The max rows of data inside the actively writing buffer in one shard.Only available for `partition_tree` memtable. | | `memtable.fork_dictionary_bytes` | String | `1GiB` | Max dictionary bytes.Only available for `partition_tree` memtable. | The `metric` engine is optimized for handling metrics data with a large number of small tables: ```toml [[region_engine]] [region_engine.metric] sparse_primary_key_encoding = true ``` Available options: | Key | Type | Default | Descriptions | | ----------------------------- | ------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `sparse_primary_key_encoding` | Boolean | `true` | Whether to use sparse primary key encoding. This optimization improves write and query performance by encoding only non-null primary key columns. | ### Specify meta client The `meta_client` options are valid in `datanode` and `frontend` mode, which specify the Metasrv client information. ```toml metasrv_addrs = ["127.0.0.1:3002"] timeout = "3s" connect_timeout = "1s" ddl_timeout = "10s" tcp_nodelay = true ``` The `meta_client` configures the Metasrv client, including: - `metasrv_addrs`: The Metasrv address list. - `timeout`: operation timeout, `3s` by default. - `connect_timeout`, connect server timeout, `1s` by default. - `ddl_timeout`, DDL execution timeout, `10s` by default. - `tcp_nodelay`, `TCP_NODELAY` option for accepted connections, true by default. ### Heartbeat configuration In distributed mode, heartbeat intervals are controlled by Metasrv using the `heartbeat_interval` option. ```toml heartbeat_interval = "3s" ``` | Key | Type | Default | Description | | -------------------- | ------ | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `heartbeat_interval` | String | `3s` | Metasrv base heartbeat interval. The frontend heartbeat interval is 6 times this value, and the datanode/flownode heartbeat interval is equal to this value. Heartbeat intervals are negotiated from Metasrv during handshake. | ### Default time zone configuration The `default_timezone` option is applicable in both `frontend` and `standalone` modes, with a default value of `UTC`. It specifies the default client timezone for interactions with GreptimeDB. If the time zone is [specified in the clients](/user-guide/timezone.md#specify-time-zone-in-clients), this option will be overridden for that client session. ```toml default_timezone = "UTC" ``` The `default_timezone` value can be any named time zone, such as `Europe/Berlin` or `Asia/Shanghai`. For information on how the client time zone affects data ingestion and querying, refer to the [Time Zone](/user-guide/timezone.md#impact-of-time-zone-on-sql-statements) guide. ### Metasrv-only configuration ```toml # The working home directory. data_home = "./greptimedb_data" # Store server address default to etcd store. # For postgres store, the format is: # "password=password dbname=postgres user=postgres host=localhost port=5432" # For mysql store, the format is: # "mysql://user:password@ip:port/dbname" # For etcd store, the format is: # "127.0.0.1:2379" store_addrs = ["127.0.0.1:2379"] # If it's not empty, the metasrv will store all data with this key prefix. store_key_prefix = "" # The datastore for meta server. # Available values: # - `etcd_store` (default value) # - `memory_store` # - `postgres_store` # - `mysql_store` backend = "etcd_store" # Table name in RDS to store metadata. Effect when using a RDS kvbackend. # **Only used when backend is RDS kvbacken.** meta_table_name = "greptime_metakv" # Advisory lock id in PostgreSQL for election. Effect when using PostgreSQL as kvbackend # Only used when backend is `postgres_store`. meta_election_lock_id = 1 # Datanode selector type. # - `round_robin` (default value) # - `lease_based` # - `load_based` # For details, please see "https://docs.greptime.com/developer-guide/metasrv/selector". selector = "round_robin" # Store data in memory, false by default. use_memory_store = false # Whether to enable region failover. # This feature is only available on GreptimeDB running on cluster mode with shared storage (e.g., s3) and one of: # - Remote WAL # - Local WAL with `allow_region_failover_on_local_wal = true` (may lead to data loss during failover) enable_region_failover = false ## The delay before starting region failure detection. ## This delay helps prevent Metasrv from triggering unnecessary region failovers before all Datanodes are fully started. ## Especially useful when the cluster is not deployed with GreptimeDB Operator and maintenance mode is not enabled. region_failure_detector_initialization_delay = "10m" # Whether to allow region failover on local WAL. # **This option is not recommended to be set to true, # because it may lead to data loss during failover.** allow_region_failover_on_local_wal = false ## Max allowed idle time before removing node info from metasrv memory. node_max_idle_time = "24hours" ## The backend client options. ## Currently, only applicable when using etcd as the metadata store. [backend_client] ## The keep alive timeout for backend client. keep_alive_timeout = "3s" ## The keep alive interval for backend client. keep_alive_interval = "10s" ## The connect timeout for backend client. connect_timeout = "3s" ## The gRPC server options. [grpc] bind_addr = "127.0.0.1:3002" server_addr = "127.0.0.1:3002" runtime_size = 8 ## The server side HTTP/2 keep-alive interval http2_keep_alive_interval = "10s" ## The server side HTTP/2 keep-alive timeout. http2_keep_alive_timeout = "3s" ## Procedure storage options. [procedure] ## Procedure max retry time. max_retry_times = 12 ## Initial retry delay of procedures, increases exponentially retry_delay = "500ms" ## Max running procedures. ## The maximum number of procedures that can be running at the same time. ## If the number of running procedures exceeds this limit, the procedure will be rejected. max_running_procedures = 128 # Failure detectors options. # GreptimeDB uses the Phi Accrual Failure Detector algorithm to detect datanode failures. [failure_detector] ## Maximum acceptable φ before the peer is treated as failed. ## Lower values react faster but yield more false positives. threshold = 8.0 ## The minimum standard deviation of the heartbeat intervals. ## So tiny variations don't make φ explode. Prevents hypersensitivity when heartbeat intervals barely vary. min_std_deviation = "100ms" ## The acceptable pause duration between heartbeats. ## Additional extra grace period to the learned mean interval before φ rises, absorbing temporary network hiccups or GC pauses. acceptable_heartbeat_pause = "10000ms" ## Datanode options. [datanode] ## Datanode client options. [datanode.client] ## Operation timeout. timeout = "10s" ## Connect server timeout. connect_timeout = "10s" ## `TCP_NODELAY` option for accepted connections. tcp_nodelay = true [wal] # Available wal providers: # - `raft_engine` (default): there're none raft-engine wal config since metasrv only involves in remote wal currently. # - `kafka`: metasrv **have to be** configured with kafka wal config when using kafka wal provider in datanode. provider = "raft_engine" # Kafka wal config. ## The broker endpoints of the Kafka cluster. broker_endpoints = ["127.0.0.1:9092"] ## Automatically create topics for WAL. ## Set to `true` to automatically create topics for WAL. ## Otherwise, use topics named `topic_name_prefix_[0..num_topics)` auto_create_topics = true ## Number of topics. num_topics = 64 ## Topic selector type. ## Available selector types: ## - `round_robin` (default) selector_type = "round_robin" ## A Kafka topic is constructed by concatenating `topic_name_prefix` and `topic_id`. topic_name_prefix = "greptimedb_wal_topic" ## Expected number of replicas of each partition. replication_factor = 1 ## Above which a topic creation operation will be cancelled. create_topic_timeout = "30s" ## The connect timeout for kafka client. ## **It's only used when the provider is `kafka`**. connect_timeout = "3s" ## The timeout for kafka client. ## **It's only used when the provider is `kafka`**. timeout = "3s" # The Kafka SASL configuration. # **It's only used when the provider is `kafka`**. # Available SASL mechanisms: # - `PLAIN` # - `SCRAM-SHA-256` # - `SCRAM-SHA-512` # [wal.sasl] # type = "SCRAM-SHA-512" # username = "user_kafka" # password = "secret" # The Kafka TLS configuration. # **It's only used when the provider is `kafka`**. # [wal.tls] # server_ca_cert_path = "/path/to/server_cert" # client_cert_path = "/path/to/client_cert" # client_key_path = "/path/to/key" ``` | Key | Type | Default | Descriptions | | --------------------------------------------- | ------- | ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `data_home` | String | `./greptimedb_data/metasrv/` | The working home directory. | | `bind_addr` | String | `127.0.0.1:3002` | The bind address of metasrv. | | `server_addr` | String | `127.0.0.1:3002` | The communication server address for frontend and datanode to connect to metasrv, "127.0.0.1:3002" by default for localhost. | | `store_addrs` | Array | `["127.0.0.1:2379"]` | Store server address. Configure the address based on your backend type, for example:- Use `"127.0.0.1:2379"` to connect to etcd- Use `"password=password dbname=postgres user=postgres host=localhost port=5432"` to connect to postgres- Use `"mysql://user:password@ip:port/dbname"` to connect to mysql | | `selector` | String | `lease_based` | Datanode selector type.- `lease_based` (default value).- `load_based`For details, see [Selector](/contributor-guide/metasrv/selector.md) | | `use_memory_store` | Bool | `false` | Store data in memory. | | `enable_region_failover` | Bool | `false` | Whether to enable region failover.This feature is only available on GreptimeDB running on cluster mode with shared storage (e.g., s3) and one of:- Remote WAL- Local WAL with `allow_region_failover_on_local_wal = true` (may lead to data loss during failover). | | `region_failure_detector_initialization_delay` | String | `10m` | The delay before starting region failure detection. This delay helps prevent Metasrv from triggering unnecessary region failovers before all Datanodes are fully started. Especially useful when the cluster is not deployed with GreptimeDB Operator and maintenance mode is not enabled. | | `allow_region_failover_on_local_wal` | Bool | `false` | Whether to allow region failover on local WAL.**This option is not recommended to be set to true, because it may lead to data loss during failover.** | | `node_max_idle_time` | String | `24hours` | Max allowed idle time before removing node info from metasrv memory. Nodes that haven't sent heartbeats for this duration will be considered inactive and removed. | | `backend_client` | -- | -- | The backend client options.Currently, only applicable when using etcd as the metadata store. | | `backend_client.keep_alive_timeout` | String | `3s` | The keep alive timeout for backend client. | | `backend_client.keep_alive_interval` | String | `10s` | The keep alive interval for backend client. | | `backend_client.connect_timeout` | String | `3s` | The connect timeout for backend client. | | `grpc` | -- | -- | The gRPC server options. | | `grpc.bind_addr` | String | `127.0.0.1:3002` | The address to bind the gRPC server. | | `grpc.server_addr` | String | `127.0.0.1:3002` | The communication server address for frontend and datanode to connect to metasrv. | | `grpc.runtime_size` | Integer | `8` | The number of server worker threads. | | `grpc.http2_keep_alive_interval` | String | `10s` | The server side HTTP/2 keep-alive interval. | | `grpc.http2_keep_alive_timeout` | String | `3s` | The server side HTTP/2 keep-alive timeout. | | `backend` | String | `etcd_store` | The datastore for metasrv.- `etcd_store` (default)- `memory_store` (In memory metadata storage - only used for testing.)- `postgres_store`- `mysql_store` | | `meta_table_name` | String | `greptime_metakv` | Table name in RDS to store metadata. Effect when using a RDS kvbackend.**Only used when backend is `postgres_store` or `mysql_store`.** | | `meta_schema_name` | String | -- | Optional PostgreSQL schema for metadata table and election table name qualification. When PostgreSQL public schema is not writable (e.g., PostgreSQL 15+ with restricted public), set this to a writable schema. GreptimeDB will use `meta_schema_name.meta_table_name`.**Only used when backend is `postgres_store`.** | | `auto_create_schema` | Bool | `true` | Automatically create PostgreSQL schema if it doesn't exist. When enabled, the system will execute `CREATE SCHEMA IF NOT EXISTS ` before creating metadata tables. This is useful in production environments where manual schema creation may be restricted. Note: The PostgreSQL user must have CREATE SCHEMA permission for this to work.**Only used when backend is `postgres_store`.** | | `meta_election_lock_id` | Integer | `1` | Advisory lock id in PostgreSQL for election. Effect when using PostgreSQL as kvbackend**Only used when backend is `postgres_store`.** | | `procedure` | -- | -- | Procedure storage options. | | `procedure.max_retry_times` | Integer | `12` | Procedure max retry time. | | `procedure.retry_delay` | String | `500ms` | Initial retry delay of procedures, increases exponentially | | `procedure.max_running_procedures` | Integer | `128` | The maximum number of procedures that can be running at the same time. If the number of running procedures exceeds this limit, the procedure will be rejected. | | `failure_detector` | -- | -- | -- | | `failure_detector.threshold` | Float | `8.0` | Maximum acceptable φ before the peer is treated as failed.Lower values react faster but yield more false positives. | | `failure_detector.min_std_deviation` | String | `100ms` | The minimum standard deviation of the heartbeat intervals.So tiny variations don't make φ explode. Prevents hypersensitivity when heartbeat intervals barely vary. | | `failure_detector.acceptable_heartbeat_pause` | String | `10000ms` | The acceptable pause duration between heartbeats.Additional extra grace period to the learned mean interval before φ rises, absorbing temporary network hiccups or GC pauses. | | `datanode` | -- | -- | Datanode options. | | `datanode.client` | -- | -- | Datanode client options. | | `datanode.client.timeout` | String | `10s` | Operation timeout. | | `datanode.client.connect_timeout` | String | `10s` | Connect server timeout. | | `datanode.client.tcp_nodelay` | Bool | `true` | `TCP_NODELAY` option for accepted connections. | | `wal` | -- | -- | -- | | `wal.provider` | String | `raft_engine` | -- | | `wal.broker_endpoints` | Array | -- | The broker endpoints of the Kafka cluster. | | `wal.auto_prune_interval` | String | `0s` | Interval of automatically WAL pruning.Set to `0s` to disable automatically WAL pruning which delete unused remote WAL entries periodically. | | `wal.trigger_flush_threshold` | Integer | `0` | The threshold to trigger a flush operation of a region in automatically WAL pruning.Metasrv will send a flush request to flush the region when:`trigger_flush_threshold` + `prunable_entry_id` < `max_prunable_entry_id`where:- `prunable_entry_id` is the maximum entry id that can be pruned of the region. Entries before `prunable_entry_id` are not used by this region.- `max_prunable_entry_id` is the maximum prunable entry id among all regions in the same topic. Entries before `max_prunable_entry_id` are not used by any region.Set to `0` to disable the flush operation. | | `wal.auto_prune_parallelism` | Integer | `10` | Concurrent task limit for automatically WAL pruning. Each task is responsible for WAL pruning for a kafka topic. | | `wal.num_topics` | Integer | `64` | Number of topics. | | `wal.selector_type` | String | `round_robin` | Topic selector type.Available selector types:- `round_robin` (default) | | `wal.topic_name_prefix` | String | `greptimedb_wal_topic` | A Kafka topic is constructed by concatenating `topic_name_prefix` and `topic_id`. | | `wal.replication_factor` | Integer | `1` | Expected number of replicas of each partition. | | `wal.create_topic_timeout` | String | `30s` | Above which a topic creation operation will be cancelled. | | `wal.connect_timeout` | String | `3s` | The connect timeout for kafka client.**It's only used when the provider is `kafka`**. | | `wal.timeout` | String | `3s` | The timeout for kafka client.**It's only used when the provider is `kafka`**. | | `wal.sasl` | String | -- | The Kafka SASL configuration. | | `wal.sasl.type` | String | -- | The SASL mechanisms, available values: `PLAIN`, `SCRAM-SHA-256`, `SCRAM-SHA-512`. | | `wal.sasl.username` | String | -- | The SASL username. | | `wal.sasl.password` | String | -- | The SASL password. | | `wal.tls` | String | -- | The Kafka TLS configuration. | | `wal.tls.server_ca_cert_path` | String | -- | The path of trusted server ca certs. | | `wal.tls.client_cert_path` | String | -- | The path of client cert (Used for enable mTLS). | | `wal.tls.client_key_path` | String | -- | The path of client key (Used for enable mTLS). | ### Datanode-only configuration ```toml node_id = 42 [grpc] bind_addr = "127.0.0.1:3001" server_addr = "127.0.0.1:3001" runtime_size = 8 ``` | Key | Type | Description | | ----------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | node_id | Integer | The datanode identifier, should be unique. | | grpc.bind_addr | String | The address to bind the gRPC server, `"127.0.0.1:3001"` by default. | | grpc.server_addr | String | The address advertised to the metasrv, and used for connections from outside the host. If left empty or unset, the server will automatically use the IP address of the first network interface on the host, with the same port number as the one specified in `grpc.bind_addr`. | | grpc.runtime_size | Integer | The number of gRPC server worker threads, 8 by default. | ### Frontend-only configuration ```toml [datanode] [datanode.client] connect_timeout = "1s" tcp_nodelay = true ``` | Key | Type | Default | Description | | --------------------------------- | ------ | ------- | ---------------------------------------------- | | `datanode` | -- | -- | Datanode options. | | `datanode.client` | -- | -- | Datanode client options. | | `datanode.client.connect_timeout` | String | `1s` | Connect server timeout. | | `datanode.client.tcp_nodelay` | Bool | `true` | `TCP_NODELAY` option for accepted connections. | --- ## Common Helm Chart Configurations For each Helm Chart, you can create a `values.yaml` file for configuration. When you need to apply configurations, you can use the `helm upgrade` command: ``` helm upgrade --install ${release-name} ${chart-name} --namespace ${namespace} -f values.yaml ``` ## GreptimeDB Cluster Chart For complete configuration options, please refer to [GreptimeDB Cluster Chart](https://github.com/GreptimeTeam/helm-charts/tree/main/charts/greptimedb-cluster/README.md). ### GreptimeDB Image Configuration The top-level variable `image` is used to configure the global GreptimeDB image for the cluster, as shown below: ```yaml image: # -- The image registry registry: docker.io # -- The image repository repository: greptime/greptimedb # -- The image tag tag: "v1.0.2" # -- The image pull secrets pullSecrets: [] ``` If you want to configure different images for each role in the cluster, you can use the `${role}.podTemplate.main.image` field (where `role` can be `meta`, `frontend`, `datanode` and `flownode`). This field will **override** the top-level `image` configuration, as shown below: ```yaml image: # -- The image registry registry: docker.io # -- The image repository repository: greptime/greptimedb # -- The image tag tag: "v1.0.2" # -- The image pull secrets pullSecrets: [] frontend: podTemplate: main: image: "greptime/greptimedb:latest" ``` In this case, the `frontend` image will be set to `greptime/greptimedb:latest`, while other components will use the top-level `image` configuration. ### Service Ports Configuration You can configure service ports using the following fields: - `httpServicePort`: Configures the HTTP service port, default `4000` - `grpcServicePort`: Configures the SQL service port, default `4001` - `mysqlServicePort`: Configures the MySQL service port, default `4002` - `postgresServicePort`: Configures the PostgreSQL service port, default `4003` ### Datanode Storage Configuration You can configure Datanode storage through the `datanode.storage` field, as shown below: ```yaml datanode: storage: # -- Storage class for datanode persistent volume storageClassName: null # -- Storage size for datanode persistent volume storageSize: 20Gi # -- Storage retain policy for datanode persistent volume storageRetainPolicy: Retain # -- The dataHome directory, default is "/data/greptimedb/" dataHome: "/data/greptimedb" ``` - `storageClassName`: Configures the StorageClass, defaults to Kubernetes current default StorageClass - `storageSize`: Configures the storage size, default `20Gi`. You can use common capacity units, such as `50Gi`, etc. - `storageRetainPolicy`: Configures the storage retention policy, default `Retain`. If set to `Delete`, the storage will be deleted when the cluster is deleted - `dataHome`: Configures the data directory, default `/data/greptimedb/` ### Resource Configuration The top-level variable `base.podTemplate.main.resources` is used to globally configure resources for each role, as shown below: ```yaml base: podTemplate: main: resources: requests: memory: "1Gi" cpu: "1" limits: memory: "2Gi" cpu: "2" ``` If you want to configure different resources for each role in the cluster, you can use the `${role}.podTemplate.main.resources` field (where `role` can be `meta`, `frontend`, `datanode`, `flownode`, etc.). This field will **override** the top-level `base.podTemplate.main.resources` configuration, as shown below: ```yaml base: podTemplate: main: resources: requests: memory: "1Gi" cpu: "1" limits: memory: "2Gi" cpu: "2" frontend: podTemplate: main: resources: requests: cpu: "2" memory: "4Gi" limits: cpu: "4" memory: "8Gi" ``` ### Role Replicas Configuration For different roles, the number of replicas can be configured through the `${role}.replicas` field, as shown below: ```yaml frontend: replicas: 3 datanode: replicas: 3 ``` You can achieve horizontal scaling by configuring the number of replicas. ### Environment Variable Configuration You can configure global environment variables through the `base.podTemplate.main.env` field, and configure different environment variables for each Role through the `${role}.podTemplate.main.env` field, as shown below: ```yaml base: podTemplate: main: env: - name: GLOBAL_ENV value: "global_value" frontend: podTemplate: main: env: - name: FRONTEND_ENV value: "frontend_value" ``` ### Injecting Configuration Files For different Role services, youcan inject custom TOML configuration files through the `${role}.configData` field, as shown below: ```yaml datanode: configData: | [[region_engine]] [region_engine.mito] # Number of region workers num_workers = 8 ``` You can learn about GreptimeDB configuration options through [config.md](https://github.com/GreptimeTeam/greptimedb/blob/main/config/config.md). In addition to using the `${role}.configData` field to inject configuration files, you can also specify corresponding files through `${role}.configFile`, as shown below: ```yaml frontend: configFile: "configs/frontend.toml" ``` In this case, ensure that the configuration file path matches the directory where the `helm upgrade` command is executed. :::note User-injected configuration files have lower priority by default than configuration items managed by GreptimeDB Operator. Some configuration items can only be configured through GreptimeDB Operator, and these items are exposed by default in `values.yaml`. The following default configurations are managed by GreptimeDB Operator: - Logging configuration; - Datanode's Node ID; ::: ### Authentication Configuration The Helm Chart does not enable User Provider mode authentication by default. You can enable User Provider mode authentication and configure user information through the `auth.enabled` field, as shown below: ```yaml auth: enabled: true users: - username: "admin" password: "admin" permission: "readwrite" - username: "grafana" password: "grafana_pwd" permission: "readonly" - username: "telegraf" password: "telegraf_pwd" permission: "writeonly" ``` GreptimeDB supports three permission modes: | Mode | Shorthand | Allowed Operations | Typical Use Cases | |------|-----------|-------------------|-------------------| | `readwrite` | `rw` | Read + Write | Administrators, development environments | | `readonly` | `ro` | Read only | Dashboards, reporting systems, read replicas | | `writeonly` | `wo` | Write only | Data collectors, IoT devices, log aggregators | :::note Users without an explicit permission mode default to `readwrite`, maintaining backward compatibility. ### Logging Configuration The top-level variable `logging` is used to configure global logging levels, as shown below: ```yaml # -- Global logging configuration logging: # -- The log level for greptimedb, only support "debug", "info", "warn", "debug" level: "info" # -- The log format for greptimedb, only support "json" and "text" format: "text" # -- The logs directory for greptimedb logsDir: "/data/greptimedb/logs" # -- Whether to log to stdout only onlyLogToStdout: false # -- indicates whether to persist the log with the datanode data storage. It **ONLY** works for the datanode component. persistentWithData: false # -- The log filters, use the syntax of `target[span\{field=value\}]=level` to filter the logs. filters: [] ``` Where: - `logging.level`: Configures the global log level, supports `debug`, `info`, `warn`, `error`. - `logging.format`: Configures the global log format, supports `json` and `text`. - `logging.logsDir`: Configures the global log directory, default `/data/greptimedb/logs`. - `logging.onlyLogToStdout`: Configures whether to output only to stdout, disabled by default. - `logging.persistentWithData`: Configures whether to persist logs with data storage, only applies to the `datanode` component, disabled by default. - `logging.filters`: Configures global log filters, supports the syntax `target[span\{field=value\}]=level`. For example, if you want to enable `debug` level logging for certain components: ```yaml logging: level: "info" format: "json" filters: - mito2=debug ``` Each role's logging configuration can be configured through the `${role}.logging` field, with fields consistent with the top-level `logging` and will **override** the top-level `logging` configuration, for example: ```yaml frontend: logging: level: "debug" ``` ### Enabling Flownode The Helm Chart does not enable Flownode by default. You can enable Flownode through the `flownode.enabled` field, as shown below: ```yaml flownode: enabled: true ``` Other fields of `flownode` are configured similarly to other Roles, for example: ```yaml flownode: enabled: true replicas: 1 podTemplate: main: resources: requests: memory: "1Gi" cpu: "1" limits: memory: "2Gi" cpu: "2" ``` ### Object Storage Configuration The `objectStorage` field is used to configure cloud object storage (such as AWS S3 and Azure Blob Storage, etc.) as the GreptimeDB storage layer. #### AWS S3 ```yaml objectStorage: credentials: # AWS access key ID accessKeyId: "" # AWS secret access key secretAccessKey: "" s3: # AWS S3 bucket name bucket: "" # AWS S3 region region: "" # The root path in bucket is 's3:////data/...' root: "" # The AWS S3 endpoint, see more detail: https://docs.aws.amazon.com/general/latest/gr/s3.html endpoint: "" ``` #### Using AWS EKS Pod Identity for S3 Instead of providing static access keys, you can use [AWS EKS Pod Identity](https://docs.aws.amazon.com/eks/latest/userguide/pod-identities.html) (IAM Roles for Service Accounts) to grant S3 access to GreptimeDB. This approach is more secure as it eliminates the need to manage long-lived credentials. First, configure the datanode service account with the IAM role annotation. Only the datanode reads from and writes to S3: ```yaml datanode: podTemplate: serviceAccount: create: true annotations: eks.amazonaws.com/role-arn: ${YOUR_IAM_ROLE_ARN} ``` Make sure the IAM role has permissions to read and write to the target S3 bucket: - `s3:PutObject` - `s3:ListBucket` - `s3:GetObject` - `s3:DeleteObject` Then, configure the object storage without credentials: ```yaml objectStorage: s3: bucket: "${YOUR_S3_BUCKET}" region: "${YOUR_S3_REGION}" root: "greptimedb" ``` :::note When using EKS Pod Identity, omit the `objectStorage.credentials` section entirely. The datanode pods will automatically obtain temporary credentials through the IAM role associated with the service account. ::: #### Google Cloud Storage ```yaml objectStorage: credentials: # GCP serviceAccountKey JSON-formatted base64 value serviceAccountKey: "" gcs: # Google Cloud Storage bucket name bucket: "" # Google Cloud OAuth 2.0 Scopes, example: "https://www.googleapis.com/auth/devstorage.read_write" scope: "" # The root path in bucket is 'gcs:////data/...' root: "" # Google Cloud Storage endpoint, example: "https://storage.googleapis.com" endpoint: "" ``` #### Azure Blob ```yaml objectStorage: credentials: # Azure account name accountName: "" # Azure account key accountKey: "" azblob: # Azure Blob container name container: "" # The root path in container is 'blob:////data/...' root: "" # Azure Blob endpoint, see: "https://learn.microsoft.com/en-us/azure/storage/blobs/storage-blob-query-endpoint-srp?tabs=dotnet#query-for-the-blob-storage-endpoint" endpoint: "" ``` #### AliCloud OSS ```yaml objectStorage: credentials: # AliCloud access key ID accessKeyId: "" # AliCloud access key secret accessKeySecret: "" oss: # AliCloud OSS bucket name bucket: "" # AliCloud OSS region region: "" # The root path in bucket is 'oss:////data/...' root: "" # The AliCloud OSS endpoint endpoint: "" ``` #### Volcengine TOS TOS ([Torch Object Storage](https://www.volcengine.com/docs/6349)) is a massive, secure, cost-effective, user-friendly, highly reliable, and highly available object storage service provided by [Volcengine](https://www.volcengine.com). ```yaml objectStorage: credentials: # Volcengine access key ID accessKeyId: "" # Volcengine secret access key secretAccessKey: "" s3: # Volcengine TOS bucket name bucket: "" # Volcengine TOS region region: "" # The root path in bucket is 'tos:////data/...' root: "" # The Volcengine TOS endpoint, see more detail: https://www.volcengine.com/docs/6349/107356 endpoint: "" # Enable virtual host style so that OpenDAL will send API requests in virtual host style instead of path style. enableVirtualHostStyle: true ``` ### Prometheus Monitor Configuration If you have [prometheus-operator](https://github.com/prometheus-operator/prometheus-operator) installed, you can create Prometheus PodMonitor to monitor GreptimeDB through the `prometheusMonitor.enabled` field as follows: ```yaml prometheusMonitor: # -- Create PodMonitor resource for scraping metrics using PrometheusOperator enabled: false # -- Interval at which metrics should be scraped interval: "30s" # -- Add labels to the PodMonitor labels: release: prometheus ``` ### Debug Pod Configuration The debug pod has various tools installed (such as mysql-client, psql-client, etc.). You can exec into the debug pod for debugging. Create it with the `debugPod.enabled` field as follows: ```yaml debugPod: # -- Enable debug pod enabled: false # -- The debug pod image image: registry: docker.io repository: greptime/greptime-tool tag: "20250606-04e3c7d" # -- The debug pod resource resources: requests: memory: 64Mi cpu: 50m limits: memory: 256Mi cpu: 200m ``` ### Configuring Metasrv Backend Storage #### Using MySQL and PostgreSQL as Backend Storage You can configure the backend storage for the metasrv through the `meta.backendStorage` field. Let's take MySQL as an example. ```yaml meta: backendStorage: mysql: # -- MySQL host host: "mysql.default.svc.cluster.local" # -- MySQL port port: 3306 # -- MySQL database database: "metasrv" # -- MySQL table table: "greptime_metakv" # -- MySQL credentials credentials: # -- MySQL credentials secret name secretName: "meta-mysql-credentials" # -- MySQL credentials existing secret name existingSecretName: "" # -- MySQL credentials username username: "root" # -- MySQL credentials password password: "test" ``` - `mysql.host`: The MySQL host. - `mysql.port`: The MySQL port. - `mysql.database`: The MySQL database. - `mysql.table`: The MySQL table. - `mysql.credentials.secretName`: The MySQL credentials secret name. - `mysql.credentials.existingSecretName`: The MySQL credentials existing secret name. If you want to use an existing secret, you should make sure the secret contains the following keys: `username` and `password`. - `mysql.credentials.username`: The MySQL credentials username. It will be ignored if `mysql.credentials.existingSecretName` is set. The `username` will be stored in the `username` key of the secret with `mysql.credentials.secretName`. - `mysql.credentials.password`: The MySQL credentials password. It will be ignored if `mysql.credentials.existingSecretName` is set. The `password` will be stored in the `password` key of the secret with `mysql.credentials.secretName`. Most of the fields of `meta.backendStorage.postgresql` are the same as the fields of `meta.backendStorage.mysql`. For example: ```yaml meta: backendStorage: postgresql: # -- PostgreSQL host host: "postgres.default.svc.cluster.local" # -- PostgreSQL port port: 5432 # -- PostgreSQL database database: "metasrv" # -- PostgreSQL table table: "greptime_metakv" # -- PostgreSQL Advisory lock id used for election, shouldn't be used in other clusters or applications. electionLockID: 1 # -- PostgreSQL credentials credentials: # -- PostgreSQL credentials secret name secretName: "meta-postgresql-credentials" # -- PostgreSQL credentials existing secret name existingSecretName: "" # -- PostgreSQL credentials username username: "root" # -- PostgreSQL credentials password password: "root" ``` - `postgresql.host`: The PostgreSQL host. - `postgresql.port`: The PostgreSQL port. - `postgresql.database`: The PostgreSQL database. - `postgresql.table`: The PostgreSQL table. - `postgresql.electionLockID`: The Advisory lock id in PostgreSQL for election. - `postgresql.credentials.secretName`: The PostgreSQL credentials secret name. - `postgresql.credentials.existingSecretName`: The PostgreSQL credentials existing secret name. If you want to use an existing secret, you should make sure the secret contains the following keys: `username` and `password`. - `postgresql.credentials.username`: The PostgreSQL credentials username. It will be ignored if `mysql.credentials.existingSecretName` is set. The `username` will be stored in the `username` key of the secret with `mysql.credentials.secretName`. - `postgresql.credentials.password`: The PostgreSQL credentials password. It will be ignored if `mysql.credentials.existingSecretName` is set. The `password` will be stored in the `password` key of the secret with `mysql.credentials.secretName`. #### Using etcd as Backend Storage :::tip NOTE The configuration structure has changed between chart versions: - In older version: `meta.etcdEndpoints` - In newer version: `meta.backendStorage.etcd.endpoints` Always refer to the latest [values.yaml](https://github.com/GreptimeTeam/helm-charts/blob/main/charts/greptimedb-cluster/values.yaml) in the Helm chart repository for the most up-to-date configuration structure. ::: The etcd backend storage can be configured through the `meta.backendStorage.etcd` field. ```yaml meta: backendStorage: etcd: # -- Etcd endpoints endpoints: ["etcd.etcd-cluster.svc.cluster.local:2379"] # -- Etcd store key prefix storeKeyPrefix: "" ``` - `etcd.endpoints`: The etcd endpoints. - `etcd.storeKeyPrefix`: The etcd store key prefix. All keys will be stored with this prefix. If you want to use one etcd cluster for multiple GreptimeDB clusters, you can configure different store key prefixes for each GreptimeDB cluster. It's only for testing and debugging purposes. ### Enable Region Failover You can enable Region Failover through the `meta.enableRegionFailover` field. Before enabling Region Failover, ensure your deployment meets the prerequisites outlined in the [Region Failover](/user-guide/deployments-administration/manage-data/region-failover.md) documentation. If your configuration does not meet the prerequisites, the **Operator will fail to deploy the cluster components**. ```yaml meta: enableRegionFailover: true ``` ### Enable GC Repartitioning depends on shared object storage and GC. You can enable GC on both metasrv and datanode with the following example: ```yaml meta: configData: | [gc] enable = true gc_cooldown_period = "5m" datanode: configData: | [[region_engine]] [region_engine.mito] [region_engine.mito.gc] enable = true lingering_time = "10m" unknown_file_lingering_time = "1h" ``` Make sure the datanode `lingering_time` is longer than the metasrv `gc_cooldown_period` to avoid deleting files that may still be in use. #### Enable Region Failover on Local WAL To enable Region Failover on local WAL, you need to set both `meta.enableRegionFailover: true` and add `allow_region_failover_on_local_wal = true` in the `meta.configData` field. :::warning WARNING Enabling Region Failover on local WAL may lead to data loss during failover. Ensure your operator version is greater than or equal to v0.2.2. ::: ```yaml meta: enableRegionFailover: true configData: | allow_region_failover_on_local_wal = true ``` ### Dedicated WAL Volume Configuring a dedicated WAL volume allows you to use a separate disk with a custom `StorageClass` for the WAL directory when deploying a GreptimeDB Datanode. ```yaml dedicatedWAL: enabled: true raftEngine: fs: storageClassName: io2 # Use aws ebs io2 storage class for WAL for better performance. name: wal storageSize: 20Gi mountPath: /wal ``` ### Enable Remote WAL To enable Remote WAL, both Metasrv and Datanode must be properly configured. Before proceeding, make sure to read the [Remote WAL Configuration](/user-guide/deployments-administration/wal/remote-wal/configuration.md) documentation for a complete overview of configuration options and important considerations. ```yaml remoteWal: enabled: true kafka: brokerEndpoints: ["kafka.kafka-cluster.svc:9092"] meta: configData: | [wal] provider = "kafka" replication_factor = 1 auto_prune_interval = "30m" datanode: configData: | [wal] provider = "kafka" overwrite_entry_start_id = true ``` --- ## Deploying a GreptimeDB Cluster with Frontend Groups In this guide, you will learn how to deploy a GreptimeDB cluster on Kubernetes with a frontend group consisting of multiple frontend instances. ## Prerequisites - [Docker](https://docs.docker.com/get-started/get-docker/) >= v23.0.0 - [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) >= v1.18.0 - [Helm](https://helm.sh/docs/intro/install/) >= v3.0.0 - [GreptimeDB Operator](https://github.com/GrepTimeTeam/greptimedb-operator) >= v0.3.0 - [ETCD](https://github.com/bitnami/charts/tree/main/bitnami/etcd) ## Upgrade operator Install the GreptimeDB Operator, setting the image version to be greater than or equal to `v0.3.0`. For detailed instructions on upgrading the operator, please refer to the [GreptimeDB Operator Management](/user-guide/deployments-administration/deploy-on-kubernetes/greptimedb-operator-management.md#upgrade) guide. ## Frontend Groups Configuration :::tip NOTE The configuration structure has changed between chart versions: - In older version: `meta.etcdEndpoints` - In newer version: `meta.backendStorage.etcd.endpoints` Always refer to the latest [values.yaml](https://github.com/GreptimeTeam/helm-charts/blob/main/charts/greptimedb-cluster/values.yaml) in the Helm chart repository for the most up-to-date configuration structure. ::: When configuring frontend groups, ensure that each group includes a `name` field. The following `values.yaml` example demonstrates how to define separate frontend groups for read and write operations: ```yaml frontend: enabled: false # Disable default frontend group frontendGroups: - name: read replicas: 1 config: | default_timezone = "UTC" [http] timeout = "60s" template: main: resources: limits: cpu: 2000m memory: 2048Mi - name: write replicas: 1 meta: replicas: 1 backendStorage: etcd: endpoints: - "etcd.etcd-cluster.svc.cluster.local:2379" datanode: replicas: 1 ``` You can use the following command to apply the configuration: ``` helm upgrade --install greptimedb greptime/greptimedb-cluster --namespace default -f values.yaml ``` ## Validity When setting the frontend groups, the name must be set. ```yaml frontendGroups: # - name: read #<=========The name must be set=============> - replicas: 1 ``` ## Verify the Installation Check the status of the pods: ```bash kubectl get pods -n default NAME READY STATUS RESTARTS AGE greptimedb-datanode-0 1/1 Running 0 32s greptimedb-flownode-0 1/1 Running 0 17s greptimedb-frontend-read-6d45bc9b89-hftqz 1/1 Running 0 23s greptimedb-frontend-write-557b6585c6-jq874 1/1 Running 0 23s greptimedb-meta-58cd4cff6c-zp7s9 1/1 Running 0 37s ``` To check the services: ```bash kubectl get service -n default NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE greptimedb-datanode ClusterIP None 4001/TCP,4000/TCP 102s greptimedb-flownode ClusterIP None 4001/TCP 2m5s greptimedb-frontend-read ClusterIP 10.96.174.200 4001/TCP,4000/TCP,4002/TCP,4003/TCP 42s greptimedb-frontend-write ClusterIP 10.96.223.1 4001/TCP,4000/TCP,4002/TCP,4003/TCP 42s greptimedb-meta ClusterIP 10.96.195.163 3002/TCP,4000/TCP 3m4s ``` ## Conclusion You have successfully deployed a GreptimeDB cluster with a frontend group consisting of read and write instances. You can now proceed to explore the functionality of your GreptimeDB cluster or integrate it with additional tools as needed. --- ## Deploying GreptimeDB Cluster with Remote WAL In this guide, you will learn how to deploy GreptimeDB with Remote WAL on Kubernetes. Before you start, it's recommended to read the [Deploy GreptimeDB Cluster](/user-guide/deployments-administration/deploy-on-kubernetes/deploy-greptimedb-cluster.md) guide first. ## Prerequisites - [Docker](https://docs.docker.com/get-started/get-docker/) >= v23.0.0 - [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) >= v1.18.0 - [Helm](https://helm.sh/docs/intro/install/) >= v3.0.0 ## Dependencies Before deploying a GreptimeDB cluster with Remote WAL, ensure that the metadata storage and Kafka cluster are properly set up or that existing instances are available. - Metadata storage: you can refer to [Manage Metadata Overview](/user-guide/deployments-administration/manage-metadata/overview.md) for more details. In this example, we use etcd as the metadata storage. - Kafka Cluster: you can refer to [Manage Kafka](/user-guide/deployments-administration/wal/remote-wal/manage-kafka.md) for more details. ## Remote WAL Configuration :::tip NOTE The configuration structure has changed between chart versions: - In older version: `meta.etcdEndpoints` - In newer version: `meta.backendStorage.etcd.endpoints` Always refer to the latest [values.yaml](https://github.com/GreptimeTeam/helm-charts/blob/main/charts/greptimedb-cluster/values.yaml) in the Helm chart repository for the most up-to-date configuration structure. ::: This example assumes you have a Kafka cluster running in the `kafka-cluster` namespace, and an etcd cluster running in the `etcd-cluster` namespace. The `values.yaml` file is as follows: ```yaml meta: backendStorage: etcd: endpoints: ["etcd.etcd-cluster.svc.cluster.local:2379"] configData: | [wal] provider = "kafka" replication_factor = 1 topic_name_prefix = "gtp_greptimedb_wal_topic" auto_prune_interval = "30m" datanode: configData: | [wal] provider = "kafka" overwrite_entry_start_id = true remoteWal: enabled: true kafka: brokerEndpoints: ["kafka.kafka-cluster.svc.cluster.local:9092"] ``` ## Deploy GreptimeDB Cluster You can deploy the GreptimeDB cluster with the following command: ```bash helm upgrade --install mycluster \ --values values.yaml \ greptime/greptimedb-cluster \ -n default ``` ## Best Practices - **Avoid switching WAL storage options in an existing cluster**. If you need to change the WAL storage backend (e.g., from local to remote), you must **tear down the entire cluster** and perform a clean redeployment. This includes deleting: - All PersistentVolumeClaims (PVCs) used by the GreptimeDB cluster. - The object storage directory used by the cluster. - The metadata storage associated with the cluster. - Use a **minimal viable setup (MVP) to verify the cluster is functioning correctly**. This includes basic operations such as creating tables and inserting data to ensure the database works as expected. ## Next Steps - Follow the [Deploy GreptimeDB Cluster](/user-guide/deployments-administration/deploy-on-kubernetes/deploy-greptimedb-cluster.md) guide to access your GreptimeDB cluster. - Follow the [Quick Start](/getting-started/quick-start.md) guide to create tables and insert data. - For more information about Remote WAL configuration, see [Remote WAL Configuration](/user-guide/deployments-administration/wal/remote-wal/configuration.md). --- ## Deploy GreptimeDB Cluster In this guide, you will learn how to deploy a GreptimeDB cluster on Kubernetes using the GreptimeDB Operator. :::note The following output may have minor differences depending on the versions of the Helm charts and environment. ::: ## Prerequisites - [Docker](https://docs.docker.com/get-started/get-docker/) >= v23.0.0 - [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) >= v1.18.0 - [Helm](https://helm.sh/docs/intro/install/) >= v3.0.0 - [kind](https://kind.sigs.k8s.io/docs/user/quick-start/) >= v0.20.0 ## Create a test Kubernetes cluster :::warning Using `kind` is not recommended for production environments or performance testing. For such use cases, we recommend using cloud-managed Kubernetes services such as [Amazon EKS](https://aws.amazon.com/eks/), [Google GKE](https://cloud.google.com/kubernetes-engine/), or [Azure AKS](https://azure.microsoft.com/en-us/services/kubernetes-service/), or deploying your own production-grade Kubernetes cluster. ::: There are many ways to create a Kubernetes cluster for testing purposes. In this guide, we will use [kind](https://kind.sigs.k8s.io/docs/user/quick-start/) to create a local Kubernetes cluster. You can skip this step if you want to use the existing Kubernetes cluster. Here is an example using `kind` v0.20.0: ```bash kind create cluster ```
Expected Output ```bash Creating cluster "kind" ... ✓ Ensuring node image (kindest/node:v1.27.3) 🖼 ✓ Preparing nodes 📦 ✓ Writing configuration 📜 ✓ Starting control-plane 🕹️ ✓ Installing CNI 🔌 ✓ Installing StorageClass 💾 Set kubectl context to "kind-kind" You can now use your cluster with: kubectl cluster-info --context kind-kind Thanks for using kind! 😊 ```
Check the status of the cluster: ```bash kubectl cluster-info ```
Expected Output ```bash Kubernetes control plane is running at https://127.0.0.1:60495 CoreDNS is running at https://127.0.0.1:60495/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'. ```
## Add the Greptime Helm repository We provide the [official Helm repository](https://github.com/GreptimeTeam/helm-charts) for the GreptimeDB Operator and GreptimeDB cluster. You can add the repository by running the following command: ```bash helm repo add greptime https://greptimeteam.github.io/helm-charts/ helm repo update ``` Check the charts in the Greptime Helm repository: ``` helm search repo greptime ```
Expected Output ```bash NAME CHART VERSION APP VERSION DESCRIPTION greptime/greptimedb-cluster 0.8.3 1.0.1 A Helm chart for deploying GreptimeDB cluster i... greptime/greptimedb-enterprise-dashboard 0.1.0 0.1.0 The Helm chart for deploying GreptimeDB Enterpr... greptime/greptimedb-infra-test 0.1.0 0.1.0 The Helm chart for deploying GreptimeDB infra t... greptime/greptimedb-operator 0.5.9 0.5.5 The greptimedb-operator Helm chart for Kubernetes. greptime/greptimedb-remote-compaction 0.1.1 0.1.0 Remote compaction components (scheduler, compac... greptime/greptimedb-standalone 0.4.2 1.0.1 A Helm chart for deploying standalone greptimedb ```
## Install and verify the GreptimeDB Operator It's ready to use Helm to install the GreptimeDB Operator on the Kubernetes cluster. ### Install the GreptimeDB Operator The [GreptimeDB Operator](https://github.com/GrepTimeTeam/greptimedb-operator) is a Kubernetes operator that manages the lifecycle of GreptimeDB cluster. Let's install the latest version of the GreptimeDB Operator in the `greptimedb-admin` namespace: ```bash helm install greptimedb-operator greptime/greptimedb-operator -n greptimedb-admin --create-namespace ```
Expected Output ```bash NAME: greptimedb-operator LAST DEPLOYED: Sun Apr 26 20:43:58 2026 NAMESPACE: greptimedb-admin STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: *********************************************************************** Welcome to use greptimedb-operator Chart version: 0.5.9 GreptimeDB Operator version: 0.5.5 *********************************************************************** Installed components: * greptimedb-operator The greptimedb-operator is starting, use `kubectl get deployment greptimedb-operator -n greptimedb-admin` to check its status. ```
:::note There is another way to install the GreptimeDB Operator by using `kubectl` and `bundle.yaml` from the latest release: ```bash kubectl apply -f \ https://github.com/GreptimeTeam/greptimedb-operator/releases/latest/download/bundle.yaml \ --server-side ``` This method is only suitable for quickly deploying GreptimeDB Operator in the test environments and is not recommended for production use. ::: ### Verify the GreptimeDB Operator installation Check the status of the GreptimeDB Operator: ```bash kubectl get pods -n greptimedb-admin -l app.kubernetes.io/instance=greptimedb-operator ```
Expected Output ```bash NAME READY STATUS RESTARTS AGE greptimedb-operator-68d684c6cf-qr4q4 1/1 Running 0 4m8s ```
You also can check the CRD installation: ```bash kubectl get crds | grep greptimedb ```
Expected Output ```bash greptimedbclusters.greptime.io 2026-04-26T12:43:58Z greptimedbstandalones.greptime.io 2026-04-26T12:43:58Z ```
The GreptimeDB Operator will use `greptimedbclusters.greptime.io` and `greptimedbstandalones.greptime.io` CRDs to manage GreptimeDB cluster and standalone resources. ## Install the etcd cluster The GreptimeDB cluster requires an etcd cluster for metadata storage. Let's install an etcd cluster using Bitnami's etcd Helm [chart](https://github.com/bitnami/charts/tree/main/bitnami/etcd). ```bash helm install etcd \ oci://registry-1.docker.io/bitnamicharts/etcd \ --version 12.0.8 \ --set replicaCount=3 \ --set auth.rbac.create=false \ --set auth.rbac.token.enabled=false \ --create-namespace \ --set global.security.allowInsecureImages=true \ --set image.registry=docker.io \ --set image.repository=greptime/etcd \ --set image.tag=3.6.1-debian-12-r3 \ -n etcd-cluster ```
Expected Output ```bash NAME: etcd LAST DEPLOYED: Sun Apr 26 20:49:03 2026 NAMESPACE: etcd-cluster STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: CHART NAME: etcd CHART VERSION: 12.0.8 APP VERSION: 3.6.1 ** Please be patient while the chart is being deployed ** etcd can be accessed via port 2379 on the following DNS name from within your cluster: etcd.etcd-cluster.svc.cluster.local To create a pod that you can use as a etcd client run the following command: kubectl run etcd-client --restart='Never' --image docker.io/greptime/etcd:3.6.1-debian-12-r3 --env ETCDCTL_ENDPOINTS="etcd.etcd-cluster.svc.cluster.local:2379" --namespace etcd-cluster --command -- sleep infinity Then, you can set/get a key using the commands below: kubectl exec --namespace etcd-cluster -it etcd-client -- bash etcdctl put /message Hello etcdctl get /message To connect to your etcd server from outside the cluster execute the following commands: kubectl port-forward --namespace etcd-cluster svc/etcd 2379:2379 & echo "etcd URL: http://127.0.0.1:2379" WARNING: There are "resources" sections in the chart not set. Using "resourcesPreset" is not recommended for production. For production installations, please set the following values according to your workload needs: - resources - preUpgradeJob.resources - disasterRecovery.cronjob.resources +info https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ Substituted images detected: - docker.io/greptime/etcd:3.6.1-debian-12-r3 ```
Wait for the etcd cluster to be ready: ```bash kubectl get pods -n etcd-cluster -l app.kubernetes.io/instance=etcd ```
Expected Output ```bash NAME READY STATUS RESTARTS AGE etcd-0 1/1 Running 0 2m8s etcd-1 1/1 Running 0 2m8s etcd-2 1/1 Running 0 2m8s ```
You can test the etcd cluster by running the following command: ```bash kubectl -n etcd-cluster \ exec etcd-0 -- etcdctl endpoint health \ --endpoints=http://etcd-0.etcd-headless.etcd-cluster.svc.cluster.local:2379,http://etcd-1.etcd-headless.etcd-cluster.svc.cluster.local:2379,http://etcd-2.etcd-headless.etcd-cluster.svc.cluster.local:2379 ```
Expected Output ```bash http://etcd-1.etcd-headless.etcd-cluster.svc.cluster.local:2379 is healthy: successfully committed proposal: took = 3.008575ms http://etcd-0.etcd-headless.etcd-cluster.svc.cluster.local:2379 is healthy: successfully committed proposal: took = 3.136576ms http://etcd-2.etcd-headless.etcd-cluster.svc.cluster.local:2379 is healthy: successfully committed proposal: took = 3.147702ms ```
## Setup `values.yaml` The `values.yaml` file contains parameters and configurations for GreptimeDB and is the key to defining the Helm chart. For example, a minimal GreptimeDB cluster configuration is as follows: ```yaml image: # Image registry: # Use `docker.io` for OSS GreptimeDB, # consult staff for Enterprise GreptimeDB registry: # Image repository: # Use `greptime/greptimedb` for OSS GreptimeDB, # consult staff for Enterprise GreptimeDB repository: # Image tag: # use database version for OSS GreptimeDB, for example, `v1.0.2` # consult staff for Enterprise GreptimeDB tag: pullSecrets: [] initializer: registry: docker.io repository: greptime/greptimedb-initializer tag: "v0.5.6" frontend: replicas: 1 meta: replicas: 1 backendStorage: etcd: endpoints: ["etcd.etcd-cluster.svc.cluster.local:2379"] datanode: replicas: 1 flownode: replicas: 1 ``` The configuration above for the GreptimeDB cluster is not recommended for production use. You should adjust the configuration according to your requirements. You can refer to the [configuration documentation](/user-guide/deployments-administration/deploy-on-kubernetes/common-helm-chart-configurations.md) for the complete `values.yaml` configuration options. ## Install the GreptimeDB cluster Now that the GreptimeDB Operator and etcd cluster are installed, and `values.yaml` is configured, you can deploy a minimal GreptimeDB cluster: ```bash helm upgrade --install mycluster \ greptime/greptimedb-cluster \ --values /path/to/values.yaml \ -n default ```
Expected Output ```bash Release "mycluster" does not exist. Installing it now. NAME: mycluster LAST DEPLOYED: Sun Apr 26 21:00:40 2026 NAMESPACE: default STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: *********************************************************************** Welcome to use greptimedb-cluster Chart version: 0.8.3 GreptimeDB Cluster version: 1.0.1 *********************************************************************** Installed components: * greptimedb-meta * greptimedb-datanode * greptimedb-frontend * greptimedb-flownode The greptimedb-cluster is starting, use `kubectl get pods -n default` to check its status. ```
When starting the cluster installation, we can check the status of the GreptimeDB cluster with the following command. If you use a different cluster name and namespace, you can replace `mycluster` and `default` with your configuration: ```bash kubectl -n default get greptimedbclusters.greptime.io mycluster ```
Expected Output ```bash NAME FRONTEND DATANODE META FLOWNODE PHASE VERSION AGE mycluster 1 1 1 1 Running v1.0.1 111s ```
The above command will show the status of the GreptimeDB cluster. When the `PHASE` is `Running`, it means the GreptimeDB cluster has been successfully started. You also can check the Pods status of the GreptimeDB cluster: ```bash kubectl -n default get pods ```
Expected Output ```bash NAME READY STATUS RESTARTS AGE mycluster-datanode-0 1/1 Running 0 2m51s mycluster-flownode-0 1/1 Running 0 2m26s mycluster-frontend-5894994974-w2cls 1/1 Running 0 2m32s mycluster-meta-58cd4cff6c-ddbxq 1/1 Running 0 2m58s ```
As you can see, we have created a minimal GreptimeDB cluster consisting of 1 frontend, 1 datanode, 1 flownode, and 1 metasrv by default. For information about the components of a complete GreptimeDB cluster, you can refer to [architecture](/user-guide/concepts/architecture.md). ## Explore the GreptimeDB cluster :::warning For production use, you should access the GreptimeDB cluster or Grafana inside the Kubernetes cluster or using the LoadBalancer type service. ::: ### Access the GreptimeDB cluster You can access the GreptimeDB cluster by using `kubectl port-forward` the frontend service: ```bash kubectl -n default port-forward svc/mycluster-frontend 4000:4000 4001:4001 4002:4002 4003:4003 ```
Expected Output ```bash Forwarding from 127.0.0.1:4000 -> 4000 Forwarding from [::1]:4000 -> 4000 Forwarding from 127.0.0.1:4001 -> 4001 Forwarding from [::1]:4001 -> 4001 Forwarding from 127.0.0.1:4002 -> 4002 Forwarding from [::1]:4002 -> 4002 Forwarding from 127.0.0.1:4003 -> 4003 Forwarding from [::1]:4003 -> 4003 ```
Please note that when you use a different cluster name and namespace, you can use the following command, and replace `${cluster}` and `${namespace}` with your configuration: ```bash kubectl -n ${namespace} port-forward svc/${cluster}-frontend 4000:4000 4001:4001 4002:4002 4003:4003 ``` :::warning If you want to expose the service to the public, you can use the `kubectl port-forward` command with the `--address` option: ```bash kubectl -n default port-forward --address 0.0.0.0 svc/mycluster-frontend 4000:4000 4001:4001 4002:4002 4003:4003 ``` Please make sure you have the proper security settings in place before exposing the service to the public. ::: Open the browser and navigate to `http://localhost:4000/dashboard` to access by the [GreptimeDB Dashboard](https://github.com/GrepTimeTeam/dashboard). If you want to use other tools like `mysql` or `psql` to connect to the GreptimeDB cluster, you can refer to the [Quick Start](/getting-started/quick-start.md). ## Cleanup :::danger The cleanup operation will remove the metadata and data of the GreptimeDB cluster. Please make sure you have backed up the data before proceeding. ::: ### Stop the port-forwarding Stop the port-forwarding for the GreptimeDB cluster: ```bash pkill -f kubectl port-forward ``` ### Uninstall the GreptimeDB cluster To uninstall the GreptimeDB cluster, you can use the following command: ```bash helm -n default uninstall mycluster ``` ### Delete the PVCs The PVCs wouldn't be deleted by default for safety reasons. If you want to delete the PV data, you can use the following command: ```bash kubectl -n default delete pvc -l app.greptime.io/component=mycluster-datanode ``` ### Cleanup the etcd cluster You can use the following command to clean up the etcd cluster: ```bash kubectl -n etcd-cluster exec etcd-0 -- etcdctl del "" --from-key=true ``` ### Destroy the Kubernetes cluster If you are using `kind` to create the Kubernetes cluster, you can use the following command to destroy the cluster: ```bash kind delete cluster ``` ## Next Steps If you want to deploy a GreptimeDB cluster with Remote WAL, you can refer to [Configure Remote WAL](/user-guide/deployments-administration/deploy-on-kubernetes/configure-remote-wal.md) for more details. --- ## Deploy GreptimeDB Infrastructure Tests In this guide, you will learn how to deploy GreptimeDB infrastructure testing tools on Kubernetes. ## Prerequisites - [Docker](https://docs.docker.com/get-started/get-docker/) >= v23.0.0 - [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) >= v1.18.0 - [Helm](https://helm.sh/docs/intro/install/) >= v3.0.0 - [kind](https://kind.sigs.k8s.io/docs/user/quick-start/) >= v0.20.0 ## Create a test Kubernetes cluster :::warning Using `kind` is not recommended for production environments or performance testing. For such use cases, we recommend using cloud-managed Kubernetes services such as [Amazon EKS](https://aws.amazon.com/eks/), [Google GKE](https://cloud.google.com/kubernetes-engine/), or [Azure AKS](https://azure.microsoft.com/en-us/services/kubernetes-service/), or deploying your own production-grade Kubernetes cluster. ::: There are many ways to create a Kubernetes cluster for testing purposes. In this guide, we will use [kind](https://kind.sigs.k8s.io/docs/user/quick-start/) to create a local Kubernetes cluster. You can skip this step if you want to use the existing Kubernetes cluster. Here is an example using `kind` v0.20.0: ```bash kind create cluster ```
Expected Output ```bash Creating cluster "kind" ... ✓ Ensuring node image (kindest/node:v1.27.3) 🖼 ✓ Preparing nodes 📦 ✓ Writing configuration 📜 ✓ Starting control-plane 🕹️ ✓ Installing CNI 🔌 ✓ Installing StorageClass 💾 Set kubectl context to "kind-kind" You can now use your cluster with: kubectl cluster-info --context kind-kind Thanks for using kind! 😊 ```
Check the status of the cluster: ```bash kubectl cluster-info ```
Expected Output ```bash Kubernetes control plane is running at https://127.0.0.1:60495 CoreDNS is running at https://127.0.0.1:60495/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'. ```
## Add the Greptime Helm repository We provide the [official Helm repository](https://github.com/GreptimeTeam/helm-charts) for the GreptimeDB Operator and GreptimeDB cluster. You can add the repository by running the following command: ```bash helm repo add greptime https://greptimeteam.github.io/helm-charts/ helm repo update ``` Check the charts in the Greptime Helm repository: ``` helm search repo greptime ```
Expected Output ```bash NAME CHART VERSION APP VERSION DESCRIPTION greptime/greptimedb-cluster 0.8.3 1.0.1 A Helm chart for deploying GreptimeDB cluster i... greptime/greptimedb-enterprise-dashboard 0.1.0 0.1.0 The Helm chart for deploying GreptimeDB Enterpr... greptime/greptimedb-infra-test 0.1.0 0.1.0 The Helm chart for deploying GreptimeDB infra t... greptime/greptimedb-operator 0.5.9 0.5.5 The greptimedb-operator Helm chart for Kubernetes. greptime/greptimedb-remote-compaction 0.1.1 0.1.0 Remote compaction components (scheduler, compac... greptime/greptimedb-standalone 0.4.2 1.0.1 A Helm chart for deploying standalone greptimedb ```
## Configuration Create a custom configuration file `infra-test-values.yaml`: ```yaml image: # -- The image registry registry: docker.io # -- The image repository repository: greptime/greptime-tool # -- The image tag tag: "20260521-c19a702" # -- The image pull secrets pullSecrets: [] # -- Configure to the tests case: disk: enabled: true storageClass: null size: 20Gi cpu: enabled: true rds: enabled: true host: "your-rds-host" port: 3306 database: "test" username: "your-rds-username" password: "your-rds-password" s3: enabled: true bucket: "bucket-name" region: "s3-region" accessKeyID: "your-access-key-id" secretAccessKey: "your-secret-access-key" kafka: enabled: true endpoint: "your-kafka-endpoint" ``` ## Installation Install with custom configuration: ```bash helm upgrade --install greptimedb-infra-test greptime/greptimedb-infra-test \ --values infra-test-values.yaml \ -n default ``` ## View Test Results The testing tool runs as a Kubernetes job, with results output in the pod logs: ```bash kubectl get pod -n default ```
Expected output ```bash NAMESPACE NAME READY STATUS RESTARTS AGE default greptimedb-infra-test-n7z74 0/1 Completed 0 10m ```
```bash kubectl logs greptimedb-infra-test-n7z74 -n default ```
Expected output ```bash ================== Starting testing... ================== ================== Disk tests ================== ================== Running full I/O test ================== seq-read: (g=0): rw=read, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=libaio, iodepth=64 seq-write: (g=0): rw=write, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=libaio, iodepth=64 rand-iops: (g=0): rw=randrw, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=libaio, iodepth=256 ... fio-3.28 Starting 6 processes seq-read: Laying out IO file (1 file / 1024MiB) seq-read: (groupid=0, jobs=6): err= 0: pid=14: Thu May 21 19:01:15 2026 read: IOPS=48.2k, BW=188MiB/s (198MB/s)(11.1GiB/60436msec) slat (nsec): min=625, max=615290k, avg=53392.68, stdev=2634423.19 clat (nsec): min=875, max=636646k, avg=7912987.95, stdev=30341131.85 lat (usec): min=52, max=636649, avg=7966.49, stdev=30463.52 clat percentiles (usec): | 1.00th=[ 223], 5.00th=[ 375], 10.00th=[ 562], 20.00th=[ 979], | 30.00th=[ 1303], 40.00th=[ 1680], 50.00th=[ 2311], 60.00th=[ 3490], | 70.00th=[ 4752], 80.00th=[ 6128], 90.00th=[ 13042], 95.00th=[ 23725], | 99.00th=[103285], 99.50th=[270533], 99.90th=[421528], 99.95th=[438305], | 99.99th=[488637] bw ( KiB/s): min= 9969, max=450583, per=99.87%, avg=192706.79, stdev=24021.38, samples=596 iops : min= 2490, max=112644, avg=48175.32, stdev=6005.33, samples=596 write: IOPS=34.0k, BW=133MiB/s (139MB/s)(8021MiB/60436msec); 0 zone resets slat (nsec): min=708, max=615509k, avg=77566.35, stdev=3387406.46 clat (usec): min=241, max=640859, avg=22321.94, stdev=54921.92 lat (usec): min=281, max=640862, avg=22399.63, stdev=55019.71 clat percentiles (msec): | 1.00th=[ 3], 5.00th=[ 5], 10.00th=[ 7], 20.00th=[ 8], | 30.00th=[ 9], 40.00th=[ 10], 50.00th=[ 11], 60.00th=[ 12], | 70.00th=[ 14], 80.00th=[ 16], 90.00th=[ 26], 95.00th=[ 54], | 99.00th=[ 359], 99.50th=[ 414], 99.90th=[ 485], 99.95th=[ 502], | 99.99th=[ 634] bw ( KiB/s): min=15032, max=284142, per=99.98%, avg=135879.94, stdev=12430.31, samples=596 iops : min= 3757, max=71033, avg=33968.77, stdev=3107.56, samples=596 lat (nsec) : 1000=0.01% lat (usec) : 20=0.01%, 50=0.01%, 100=0.01%, 250=0.95%, 500=3.99% lat (usec) : 750=3.41%, 1000=3.77% lat (msec) : 2=15.07%, 4=11.77%, 10=31.21%, 20=20.84%, 50=5.71% lat (msec) : 100=1.14%, 250=0.99%, 500=1.12%, 750=0.02% cpu : usr=1.88%, sys=8.37%, ctx=786665, majf=0, minf=263 IO depths : 1=0.1%, 2=0.1%, 4=0.1%, 8=0.1%, 16=0.1%, 32=0.1%, >=64=100.0% submit : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0% complete : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.1%, >=64=0.1% issued rwts: total=2915521,2053386,0,0 short=0,0,0,0 dropped=0,0,0,0 latency : target=0, window=0, percentile=100.00%, depth=256 Run status group 0 (all jobs): READ: bw=188MiB/s (198MB/s), 188MiB/s-188MiB/s (198MB/s-198MB/s), io=11.1GiB (11.9GB), run=60436-60436msec WRITE: bw=133MiB/s (139MB/s), 133MiB/s-133MiB/s (139MB/s-139MB/s), io=8021MiB (8411MB), run=60436-60436msec Disk stats (read/write): vda: ios=2915375/2054793, merge=4/1130, ticks=8259465/6477837, in_queue=14772291, util=82.28% ================== Running mixed read/write test ================== fiotest: (g=0): rw=rw, bs=(R) 64.0KiB-64.0KiB, (W) 64.0KiB-64.0KiB, (T) 64.0KiB-64.0KiB, ioengine=libaio, iodepth=16 ... fio-3.28 Starting 8 processes fiotest: Laying out IO file (1 file / 1024MiB) fiotest: (groupid=0, jobs=8): err= 0: pid=22: Thu May 21 19:02:19 2026 read: IOPS=42.5k, BW=2657MiB/s (2786MB/s)(4092MiB/1540msec) slat (nsec): min=1541, max=3755.0k, avg=6912.45, stdev=28881.60 clat (usec): min=30, max=52156, avg=1045.12, stdev=2441.43 lat (usec): min=45, max=52191, avg=1052.13, stdev=2441.68 clat percentiles (usec): | 1.00th=[ 118], 5.00th=[ 188], 10.00th=[ 265], 20.00th=[ 392], | 30.00th=[ 506], 40.00th=[ 635], 50.00th=[ 783], 60.00th=[ 922], | 70.00th=[ 1074], 80.00th=[ 1254], 90.00th=[ 1680], 95.00th=[ 2311], | 99.00th=[ 3949], 99.50th=[ 4948], 99.90th=[47973], 99.95th=[49546], | 99.99th=[50070] bw ( MiB/s): min= 2578, max= 2871, per=100.00%, avg=2697.33, stdev=16.88, samples=24 iops : min=41246, max=45946, avg=43154.67, stdev=270.28, samples=24 write: IOPS=42.6k, BW=2662MiB/s (2792MB/s)(4100MiB/1540msec); 0 zone resets slat (usec): min=2, max=3271, avg= 8.33, stdev=25.30 clat (usec): min=95, max=52303, avg=1920.68, stdev=2554.97 lat (usec): min=138, max=52312, avg=1929.12, stdev=2555.52 clat percentiles (usec): | 1.00th=[ 310], 5.00th=[ 498], 10.00th=[ 693], 20.00th=[ 988], | 30.00th=[ 1254], 40.00th=[ 1516], 50.00th=[ 1762], 60.00th=[ 1975], | 70.00th=[ 2212], 80.00th=[ 2474], 90.00th=[ 2835], 95.00th=[ 3294], | 99.00th=[ 4817], 99.50th=[ 5800], 99.90th=[50594], 99.95th=[50594], | 99.99th=[50594] bw ( MiB/s): min= 2560, max= 2861, per=100.00%, avg=2701.42, stdev=15.97, samples=24 iops : min=40960, max=45780, avg=43219.67, stdev=255.59, samples=24 lat (usec) : 50=0.01%, 100=0.26%, 250=4.39%, 500=12.56%, 750=12.72% lat (usec) : 1000=12.92% lat (msec) : 2=34.10%, 4=21.45%, 10=1.28%, 20=0.01%, 50=0.23% lat (msec) : 100=0.06% cpu : usr=2.91%, sys=9.45%, ctx=35300, majf=0, minf=295 IO depths : 1=0.1%, 2=0.1%, 4=0.1%, 8=0.1%, 16=99.9%, 32=0.0%, >=64=0.0% submit : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0% complete : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.1%, 32=0.0%, 64=0.0%, >=64=0.0% issued rwts: total=65475,65597,0,0 short=0,0,0,0 dropped=0,0,0,0 latency : target=0, window=0, percentile=100.00%, depth=16 Run status group 0 (all jobs): READ: bw=2657MiB/s (2786MB/s), 2657MiB/s-2657MiB/s (2786MB/s-2786MB/s), io=4092MiB (4291MB), run=1540-1540msec WRITE: bw=2662MiB/s (2792MB/s), 2662MiB/s-2662MiB/s (2792MB/s-2792MB/s), io=4100MiB (4299MB), run=1540-1540msec Disk stats (read/write): vda: ios=58387/58501, merge=35/82, ticks=56442/57649, in_queue=114196, util=49.76% ================== CPU tests ================== Architecture: aarch64 CPU op-mode(s): 64-bit Byte Order: Little Endian CPU(s): 6 On-line CPU(s) list: 0-5 Vendor ID: Apple Model: 0 Thread(s) per core: 1 Core(s) per cluster: 6 Socket(s): - Cluster(s): 1 Stepping: 0x0 BogoMIPS: 48.00 Flags: fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 asimddp sha512 asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp flagm2 frint Vulnerability Gather data sampling: Not affected Vulnerability Itlb multihit: Not affected Vulnerability L1tf: Not affected Vulnerability Mds: Not affected Vulnerability Meltdown: Not affected Vulnerability Mmio stale data: Not affected Vulnerability Reg file data sampling: Not affected Vulnerability Retbleed: Not affected Vulnerability Spec rstack overflow: Not affected Vulnerability Spec store bypass: Vulnerable Vulnerability Spectre v1: Mitigation; __user pointer sanitization Vulnerability Spectre v2: Not affected Vulnerability Srbds: Not affected Vulnerability Tsx async abort: Not affected ================== PostgreSQL Tests ================== ================== Running connection test ================== ✓ Connection successful PostgreSQL version: 17.5 ================== Running latency test ================== Query 1: 62.14ms Query 2: 32.75ms Query 3: 26.37ms Query 4: 27.06ms Query 5: 27.67ms ================== Running write performance test ================== DROP TABLE CREATE TABLE Testing single row INSERT performance (1000 rows)... Inserted 1000 rows in 50.45ms Average: .05ms per insert Testing bulk INSERT performance (10000 rows)... k Bulk inserted 10000 rows in 292.07ms Throughput: 34238 rows/sec ================== Running read performance test ================== Total rows: 10001 Count query took: 29.80ms SELECT with condition (id < 1000): 30.32ms Aggregate query (GROUP BY): 32.23ms ================== Running concurrent connection test ================== Spawned 20 concurrent connections (all completed) ================== Running database info query ================== Database size: 8531091 bytes Active connections: 6 PostgreSQL uptime: 2026-05-21 17:37:54.672924+00 ================== Running cleanup ================== DROP TABLE ================== PostgreSQL tests completed ================== ================== Generating 10MB test file... ================== 1+0 records in 1+0 records out 10485760 bytes (10 MB, 10 MiB) copied, 0.0255081 s, 411 MB/s ================== Running S3 transfer test... ================== ================== Upload s3 testfile... ================== 100.00% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 10.49 MB / 10.49 MB (491.69 kB/s) 22s (1/1) Script started on 2026-05-21 19:02:22+00:00 [] 100.00% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 10.49 MB / 10.49 MB (491.69 kB/s) 22s (1/1) Script done on 2026-05-21 19:02:44+00:00 [COMMAND_EXIT_CODE="0"] ================== Upload time: 22 seconds ================== ================== Download s3 testfile... ================== 100.00% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 10.49 MB / 10.49 MB (7.48 MB/s) 1.6s (1/1) Script started on 2026-05-21 19:02:44+00:00 [] 100.00% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 10.49 MB / 10.49 MB (7.48 MB/s) 1.6s (1/1) Script done on 2026-05-21 19:02:45+00:00 [COMMAND_EXIT_CODE="0"] ================== Download time: 1 seconds ================== ================== Verifying file integrity... ================== ================== S3 test passed ================== File size: 10485760 bytes MD5 checksum: 29022c552b0f81a9c89f6ff676a5c102 ================== Kafka test ================== ================== Creating Kafka Topic ================== ================== Starting Consumer ================== ================== Producing Messages ================== Produce time: 1 seconds ================== Consumed Messages ================== Successfully consumed 23 messages ================== All tests completed! ================== ```
--- ## Deploy GreptimeDB Standalone In this guide, you will learn how to deploy a GreptimeDB standalone on Kubernetes. :::note The following output may have minor differences depending on the versions of the Helm charts and environment. ::: ## Prerequisites - [Docker](https://docs.docker.com/get-started/get-docker/) >= v23.0.0 - [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) >= v1.18.0 - [Helm](https://helm.sh/docs/intro/install/) >= v3.0.0 - [kind](https://kind.sigs.k8s.io/docs/user/quick-start/) >= v0.20.0 ## Create a test Kubernetes cluster :::warning Using `kind` is not recommended for production environments or performance testing. For such use cases, we recommend using cloud-managed Kubernetes services such as [Amazon EKS](https://aws.amazon.com/eks/), [Google GKE](https://cloud.google.com/kubernetes-engine/), or [Azure AKS](https://azure.microsoft.com/en-us/services/kubernetes-service/), or deploying your own production-grade Kubernetes cluster. ::: There are many ways to create a Kubernetes cluster for testing purposes. In this guide, we will use [kind](https://kind.sigs.k8s.io/docs/user/quick-start/) to create a local Kubernetes cluster. You can skip this step if you want to use the existing Kubernetes cluster. Here is an example using `kind` v0.20.0: ```bash kind create cluster ```
Expected Output ```bash Creating cluster "kind" ... ✓ Ensuring node image (kindest/node:v1.27.3) 🖼 ✓ Preparing nodes 📦 ✓ Writing configuration 📜 ✓ Starting control-plane 🕹️ ✓ Installing CNI 🔌 ✓ Installing StorageClass 💾 Set kubectl context to "kind-kind" You can now use your cluster with: kubectl cluster-info --context kind-kind Thanks for using kind! 😊 ```
Check the status of the cluster: ```bash kubectl cluster-info ```
Expected Output ```bash Kubernetes control plane is running at https://127.0.0.1:60495 CoreDNS is running at https://127.0.0.1:60495/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'. ```
## Add the Greptime Helm repository We provide the [official Helm repository](https://github.com/GreptimeTeam/helm-charts) for the GreptimeDB Operator and GreptimeDB cluster. You can add the repository by running the following command: ```bash helm repo add greptime https://greptimeteam.github.io/helm-charts/ helm repo update ``` Check the charts in the Greptime Helm repository: ``` helm search repo greptime ```
Expected Output ```bash NAME CHART VERSION APP VERSION DESCRIPTION greptime/greptimedb-cluster 0.8.3 1.0.1 A Helm chart for deploying GreptimeDB cluster i... greptime/greptimedb-enterprise-dashboard 0.1.0 0.1.0 The Helm chart for deploying GreptimeDB Enterpr... greptime/greptimedb-infra-test 0.1.0 0.1.0 The Helm chart for deploying GreptimeDB infra t... greptime/greptimedb-operator 0.5.9 0.5.5 The greptimedb-operator Helm chart for Kubernetes. greptime/greptimedb-remote-compaction 0.1.1 0.1.0 Remote compaction components (scheduler, compac... greptime/greptimedb-standalone 0.4.2 1.0.1 A Helm chart for deploying standalone greptimedb ```
## Install the GreptimeDB Standalone ### Basic Installation For a quick start with default configuration: ```bash helm upgrade --install greptimedb-standalone greptime/greptimedb-standalone -n default ```
Expected Output ```bash Release "greptimedb-standalone" does not exist. Installing it now. NAME: greptimedb-standalone LAST DEPLOYED: Sun Apr 26 20:30:51 2026 NAMESPACE: default STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: *********************************************************************** Welcome to use greptimedb-standalone Chart version: 0.4.2 GreptimeDB Standalone version: 1.0.1 *********************************************************************** Installed components: * greptimedb-standalone The greptimedb-standalone is starting, use `kubectl get statefulset greptimedb-standalone -n default` to check its status. ```
```bash kubectl get pod -n default ```
Expected Output ```bash NAME READY STATUS RESTARTS AGE greptimedb-standalone-0 1/1 Running 0 40s ```
### Customized Installation For production or customized deployments, create a `values.yaml` file: ```yaml resources: requests: cpu: "2" memory: "4Gi" limits: cpu: "4" memory: "8Gi" ``` For more configuration options, please refer to the [documentation](https://github.com/GreptimeTeam/helm-charts/tree/main/charts/greptimedb-standalone). Then install with custom values: ```bash helm upgrade --install greptimedb-standalone greptime/greptimedb-standalone \ --values values.yaml \ --namespace default ```
Expected Output ```bash Release "greptimedb-standalone" has been upgraded. Happy Helming! NAME: greptimedb-standalone LAST DEPLOYED: Sun Apr 26 20:35:11 2026 NAMESPACE: default STATUS: deployed REVISION: 2 TEST SUITE: None NOTES: *********************************************************************** Welcome to use greptimedb-standalone Chart version: 0.4.2 GreptimeDB Standalone version: 1.0.1 *********************************************************************** Installed components: * greptimedb-standalone The greptimedb-standalone is starting, use `kubectl get statefulset greptimedb-standalone -n default` to check its status. ```
```bash kubectl get pod -n default ```
Expected Output ```bash NAME READY STATUS RESTARTS AGE greptimedb-standalone-0 1/1 Running 0 3s ```
## Access GreptimeDB After installation, you can access GreptimeDB through: ### MySQL Protocol ```bash kubectl port-forward svc/greptimedb-standalone 4002:4002 -n default > connections.out & ``` ```bash mysql -h 127.0.0.1 -P 4002 ```
Expected Output ```bash Welcome to the MariaDB monitor. Commands end with ; or \g. Your MySQL connection id is 8 Server version: 8.4.2 Greptime Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. MySQL [(none)]> ```
### PostgreSQL Protocol ```bash kubectl port-forward svc/greptimedb-standalone 4003:4003 -n default > connections.out & ``` ```bash psql -h 127.0.0.1 -p 4003 -d public ```
Expected Output ```bash psql (16.2, server 16.3-GreptimeDB-1.0.1) Type "help" for help. public=> ```
### HTTP API ```bash kubectl port-forward svc/greptimedb-standalone 4000:4000 -n default > connections.out & ``` ```bash curl -X POST \ -d 'sql=show databases' \ http://localhost:4000/v1/sql | jq . ```
Expected Output ```json { "output": [ { "records": { "schema": { "column_schemas": [ { "name": "Database", "data_type": "String" } ] }, "rows": [ [ "greptime_private" ], [ "information_schema" ], [ "public" ] ], "total_rows": 3 } } ], "execution_time_ms": 2 } ```
## Uninstallation To remove GreptimeDB standalone: ```bash helm uninstall greptimedb-standalone -n default ``` ```bash kubectl delete pvc -l app.kubernetes.io/instance=greptimedb-standalone -n default ``` --- ## Deploying Kafka Cluster In this guide, you will learn how to deploy a Kafka cluster on Kubernetes using a Helm Chart. ## Prerequisites - Kubernetes >= v1.18.0 - [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) >= v1.18.0 - [Helm](https://helm.sh/docs/intro/install/) >= v3.0.0 ## Configuration Management Before installation, you need to create a configuration file for the Kafka cluster. Please adjust the following `kafka-values.yaml` reference configuration according to your Kubernetes environment: ```yaml image: registry: docker.io repository: greptime/kafka tag: 3.9.0-debian-12-r1 listeners: client: containerPort: 9092 protocol: PLAINTEXT name: CLIENT controller: protocol: PLAINTEXT heapOpts: "-Xmx512m -Xms512m -XX:MetaspaceSize=96m -XX:+UseG1GC -XX:MaxGCPauseMillis=20 -XX:InitiatingHeapOccupancyPercent=35 -XX:G1HeapRegionSize=16M -XX:MinMetaspaceFreeRatio=50 -XX:MaxMetaspaceFreeRatio=80 -XX:+ExplicitGCInvokesConcurrent" controller: replicaCount: 3 resources: limits: cpu: '1' memory: 1Gi requests: cpu: 500m memory: 512Mi persistence: enabled: true storageClass: "" size: 50Gi broker: replicaCount: 3 resources: limits: cpu: '1' memory: 1Gi requests: cpu: 500m memory: 512Mi persistence: enabled: true storageClass: "" size: 50Gi extraConfig: | num.network.threads=3 num.io.threads=8 min.insync.replicas=1 socket.send.buffer.bytes=102400 socket.receive.buffer.bytes=102400 socket.request.max.bytes=104857600 num.recovery.threads.per.data.dir=1 offsets.topic.replication.factor=1 transaction.state.log.replication.factor=1 transaction.state.log.min.isr=1 allow.everyone.if.no.acl.found=true auto.create.topics.enable=true default.replication.factor=1 max.partition.fetch.bytes=1048576 max.request.size=1048576 message.max.bytes=20000000 log.dirs=/bitnami/kafka/data log.flush.interval.messages=10000 log.flush.interval.ms=1000 log.retention.hours=4 log.roll.hours=3 log.retention.bytes=250000000 log.segment.bytes=1073741824 ``` ## Installing Kafka Cluster Install the Kafka cluster in the kafka namespace: ```bash helm upgrade --install kafka \ --create-namespace \ oci://registry-1.docker.io/bitnamicharts/kafka \ --version 31.0.0 \ -n kafka --values kafka-values.yaml ```
Expected Output ```bash Release "kafka" does not exist. Installing it now. Pulled: greptime-registry.cn-hangzhou.cr.aliyuncs.com/charts/kafka:31.0.0 Digest: sha256:85b135981fd5d951ceef8b51cdcbc6917ebface50d0eb3367eb7ddc4a5db482b NAME: kafka LAST DEPLOYED: Tue May 12 00:57:32 2026 NAMESPACE: kafka STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: CHART NAME: kafka CHART VERSION: 31.0.0 APP VERSION: 3.9.0 ** Please be patient while the chart is being deployed ** Kafka can be accessed by consumers via port 9092 on the following DNS name from within your cluster: kafka.kafka.svc.cluster.local Each Kafka broker can be accessed by producers via port 9092 on the following DNS name(s) from within your cluster: kafka-controller-0.kafka-controller-headless.kafka.svc.cluster.local:9092 kafka-broker-0.kafka-broker-headless.kafka.svc.cluster.local:9092 To create a pod that you can use as a Kafka client run the following commands: kubectl run kafka-client --restart='Never' --image greptime-registry.cn-hangzhou.cr.aliyuncs.com/greptime/kafka:3.9.0-debian-12-r1 --namespace kafka --command -- sleep infinity kubectl exec --tty -i kafka-client --namespace kafka -- bash PRODUCER: kafka-console-producer.sh \ --bootstrap-server kafka.kafka.svc.cluster.local:9092 \ --topic test CONSUMER: kafka-console-consumer.sh \ --bootstrap-server kafka.kafka.svc.cluster.local:9092 \ --topic test \ --from-beginning Substituted images detected: - greptime-registry.cn-hangzhou.cr.aliyuncs.com/greptime/kafka:3.9.0-debian-12-r1 ```
## Verifying Kafka Cluster Installation Check the status of Kafka components (Broker and Controller): ```bash kubectl get pod -n kafka ```
Expected Output ```bash NAME READY STATUS RESTARTS AGE kafka-broker-0 1/1 Running 0 8m3s kafka-broker-1 1/1 Running 0 8m2s kafka-broker-2 1/1 Running 0 8m1s kafka-controller-0 1/1 Running 0 8m3s kafka-controller-1 1/1 Running 0 8m2s kafka-controller-0 1/1 Running 0 8m1s ```
# Configuring Kafka Endpoints After the Kafka cluster is deployed, GreptimeDB can enable Remote WAL by configuring Kafka endpoints. For more information, refer to [this documentation](/user-guide/deployments-administration/deploy-on-kubernetes/configure-remote-wal.md). ```yaml remoteWal: enabled: true kafka: brokerEndpoints: - "kafka-broker-0.kafka-broker-headless.kafka.svc.cluster.local:9092" - "kafka-broker-1.kafka-broker-headless.kafka.svc.cluster.local:9092" - "kafka-broker-2.kafka-broker-headless.kafka.svc.cluster.local:9092" ``` # Monitoring - Install Prometheus Operator (eg: [kube-prometheus-stack](https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack))。 - Install the servicemonitor CRD。 To monitor the Kafka cluster, you need to have a monitoring system (such as Prometheus and Grafana) deployed in advance. Then add the following content to `kafka-values.yaml` and re-run the command to update the Kafka configuration: ```yaml metrics: jmx: enabled: true image: registry: greptime-registry.cn-hangzhou.cr.aliyuncs.com repository: greptime/jmx-exporter tag: 1.0.1-debian-12-r9 serviceMonitor: enabled: true namespace: "kafka" interval: "10s" labels: release: kube-prometheus-stack ``` ## Grafana dashboard Use [Kubernetes Kafka](https://grafana.com/grafana/dashboards/12483-kubernetes-kafka/) (ID: 12483) to monitor Kafka metrics. 1. Log in to your Grafana. 2. Navigate to Dashboards -> New -> Import. 3. Enter Dashboard ID: 12483, select a data source and load the dashboard. ![Kubernetes Kafka](/kubernetes-kafka-monitoring-dashboard.png) # Uninstalling Kafka Cluster Use the following command to uninstall the Kafka cluster: ```bash helm -n kafka uninstall kafka ``` ## Deleting PVCs Deleting PVCs will remove persistent data from the Kafka cluster. Please ensure you have backed up your data before proceeding. ```bash kubectl -n kafka delete pvc -l app.kubernetes.io/instance=kafka ``` --- ## Deploying MinIO Cluster In this guide, you will learn how to deploy a MinIO cluster on Kubernetes using a Helm Chart. ## Prerequisites - Kubernetes >= v1.18.0 - [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) >= v1.18.0 - [Helm](https://helm.sh/docs/intro/install/) >= v3.0.0 ## Configuration Management Before installation, you need to create a `minio-values.yaml` configuration file. Please adjust the following configuration according to your Kubernetes environment: ```yaml global: security: allowInsecureImages: true image: registry: docker.io repository: greptime/minio tag: 2025.4.22-debian-12-r1 auth: rootUser: greptimedbadmin rootPassword: "greptimedbadmin" resources: requests: cpu: 500m memory: 500Mi limits: cpu: '2' memory: 2Gi extraEnvVars: - name: MINIO_REGION value: "ap-southeast-1" statefulset: replicaCount: 4 mode: distributed persistence: storageClass: null size: 100Gi ``` ## Installing MinIO Cluster Install the MinIO cluster in the minio namespace: ```bash helm upgrade \ --install minio oci://registry-1.docker.io/bitnamicharts/minio \ --create-namespace \ --version 16.0.10 \ -n minio --values minio-values.yaml ```
Expected Output ```bash Release "minio" does not exist. Installing it now. Pulled: greptime-registry.cn-hangzhou.cr.aliyuncs.com/charts/minio:16.0.10 Digest: sha256:96e220fd7cf1596879a243453b39c96a95d34f0005fdd452da3d094a7b386eb4 NAME: minio LAST DEPLOYED: Tue May 12 17:21:30 2026 NAMESPACE: minio STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: CHART NAME: minio CHART VERSION: 16.0.10 APP VERSION: 2025.4.22 Did you know there are enterprise versions of the Bitnami catalog? For enhanced secure software supply chain features, unlimited pulls from Docker, LTS support, or application customization, see Bitnami Premium or Tanzu Application Catalog. See https://www.arrow.com/globalecs/na/vendors/bitnami for more information. ** Please be patient while the chart is being deployed ** MinIO® can be accessed via port on the following DNS name from within your cluster: minio.minio.svc.cluster.local To get your credentials run: export ROOT_USER=$(kubectl get secret --namespace minio minio -o jsonpath="{.data.root-user}" | base64 -d) export ROOT_PASSWORD=$(kubectl get secret --namespace minio minio -o jsonpath="{.data.root-password}" | base64 -d) To connect to your MinIO® server using a client: - Run a MinIO® Client pod and append the desired command (e.g. 'admin info'): kubectl run --namespace minio minio-client \ --rm --tty -i --restart='Never' \ --env MINIO_SERVER_ROOT_USER=$ROOT_USER \ --env MINIO_SERVER_ROOT_PASSWORD=$ROOT_PASSWORD \ --env MINIO_SERVER_HOST=minio \ --image docker.io/bitnami/minio-client:2025.4.16-debian-12-r1 -- admin info minio To access the MinIO® web UI: - Get the MinIO® URL: echo "MinIO® web URL: http://127.0.0.1:9001/minio" kubectl port-forward --namespace minio svc/minio 9001:9001 Substituted images detected: - greptime-registry.cn-hangzhou.cr.aliyuncs.com/greptime/minio:2025.4.22-debian-12-r1 ```
## Verifying MinIO Cluster Installation Check the status of MinIO Pods: ```bash kubectl get pod -n minio ```
Expected Output ```bash NAME READY STATUS RESTARTS AGE minio-0 1/1 Running 0 30s minio-1 1/1 Running 0 30s minio-2 1/1 Running 0 30s minio-3 1/1 Running 0 30s ```
# Creating Bucket and Access Key ## Accessing MinIO Console 1. First, expose the MinIO console service. You can use the kubectl port-forward command: ```bash kubectl port-forward -n minio svc/minio 9001:9001 ``` 2. Open your browser: http://localhost:9001/login 3. Log in using the credentials set in the configuration file: - username: `greptimedbadmin` - password: `greptimedbadmin` ![MinIO login](/minio-login-page.png) ## Creating a Bucket After logging into the MinIO console, follow these steps to create a Bucket: 1. Click "Buckets" in the left sidebar 2. Click the "Create Bucket" button 3. Enter a Bucket name, for example:`greptimedb-bucket` 4. Click "Create Bucket" to confirm creation ![MinIO create bucket step 1](/minio-create-bucket-1.png) ![MinIO create bucket step 2](/minio-create-bucket-2.png) ## Generating Access Key 1. Click "Access Keys" in the left sidebar 2. Click the "Create Access Key" button 3. Optional: Set permission policies 4. Click "Create" to generate the Access Key and Secret Key ![MinIO create access key step 1](/minio-create-access-key-1.png) ![MinIO create access key step 2](/minio-create-access-key-2.png) :::warning ⚠️ Important: Please save the following information securely. You will need it when deploying GreptimeDB. - Bucket name:greptimedb-bucket - Region:ap-southeast-1 - MinIO Endpoint:`http://minio.minio:9000` - Access Key:The Access Key - Secret Key:The Secret Key ::: # Configuring GreptimeDB to Use MinIO When deploying a GreptimeDB cluster, you can use MinIO as backend storage with the following configuration: ```yaml objectStorage: credentials: accessKeyId: "" secretAccessKey: "" s3: bucket: "greptimedb-bucket" region: "ap-southeast-1" root: "greptimedb-data" endpoint: "http://minio.minio:9000" ``` # Monitoring - Install Prometheus Operator (e.g: [kube-prometheus-stack](https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack))。 - Install podmonitor CRD。 To monitor the MinIO cluster, you need to have a monitoring system (such as Prometheus and Grafana) deployed in advance. Then add the following content to `minio-values.yaml` and re-run the command to update the MinIO configuration: ```yaml metrics: enabled: true serviceMonitor: enabled: true namespace: minio labels: release: kube-prometheus-stack interval: 30s ``` ## Grafana dashboard Use the [MinIO Dashboard](https://grafana.com/grafana/dashboards/13502-minio-dashboard/) (ID: 13502) to monitor MinIO metrics. 1. Log in to your Grafana. 2. Navigate to Dashboards -> New -> Import. 3. Enter Dashboard ID: 13502, select a data source, and load the dashboard. ![MinIO Dashboard](/kubernetes-minio-monitoring-dashboard.png) # Uninstalling MinIO Cluster Use the following command to uninstall the MinIO cluster: ```bash helm -n minio uninstall minio ``` ## Deleting PVCs Deleting PVCs will remove persistent data from the MinIO cluster. Please ensure you have backed up your data before proceeding. ```bash kubectl -n minio delete pvc -l app.kubernetes.io/instance=minio ``` --- ## GreptimeDB Operator Management The GreptimeDB Operator manages the [GreptimeDB](https://github.com/GrepTimeTeam/greptimedb) resources on [Kubernetes](https://kubernetes.io/) using the [Operator pattern](https://kubernetes.io/docs/concepts/extend-kubernetes/operator/). It is like an autopilot that automates the deployment, provisioning, and orchestration of the GreptimeDB cluster and standalone. The GreptimeDB Operator includes, but is not limited to, the following features: - **Automated Provisioning**: Automates the deployment of the GreptimeDB cluster and standalone on Kubernetes by providing CRD `GreptimeDBCluster` and `GreptimeDBStandalone`. - **Multi-Cloud Support**: Users can deploy the GreptimeDB on any Kubernetes cluster, including on-premises and cloud environments(like AWS, GCP, Aliyun, etc.). - **Scaling**: Scale the GreptimeDB cluster as easily as changing the `replicas` field in the `GreptimeDBCluster` CR. - **Monitoring Bootstrap**: Bootstrap the GreptimeDB monitoring stack for the GreptimeDB cluster by providing the `monitoring` field in the `GreptimeDBCluster` CR. This document will show you how to install, upgrade, configure, and uninstall the GreptimeDB Operator on Kubernetes. :::note The following output may have minor differences depending on the versions of the Helm charts and environment. ::: ## Prerequisites - Kubernetes >= v1.18.0 - [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) >= v1.18.0 - [Helm](https://helm.sh/docs/intro/install/) >= v3.0.0 ## Production Deployment For production deployments, it's recommended to use Helm to install the GreptimeDB Operator. ### Installation You can refer [Install and verify the GreptimeDB Operator](/user-guide/deployments-administration/deploy-on-kubernetes/deploy-greptimedb-cluster.md#install-and-verify-the-greptimedb-operator) for detailed instructions. :::note If you are using [Argo CD](https://argo-cd.readthedocs.io/en/stable/) to deploy applications, please make sure that the `Application` has set the [`ServerSideApply=true`](https://argo-cd.readthedocs.io/en/latest/user-guide/sync-options/#server-side-apply) to enable the server-side apply (other GitOps tools may have similar settings). ::: ### Upgrade We always publish the latest version of the GreptimeDB Operator as a Helm chart in our official Helm repository. When the new version of the GreptimeDB Operator is released, you can upgrade the GreptimeDB Operator by running the following commands. #### Update the Helm repository ```bash helm repo update greptime ```
Expected Output ```bash Hang tight while we grab the latest from your chart repositories... ...Successfully got an update from the "greptime" chart repository Update Complete. ⎈Happy Helming!⎈ ```
You can use the following command to search the latest version of the GreptimeDB Operator: ```bash helm search repo greptime/greptimedb-operator ```
Expected Output ```bash NAME CHART VERSION APP VERSION DESCRIPTION greptime/greptimedb-operator 0.5.9 0.5.5 The greptimedb-operator Helm chart for Kubernetes. ```
You also can use the following command to list all the available versions: ```bash helm search repo greptime/greptimedb-operator --versions ``` #### Upgrade the GreptimeDB Operator You can upgrade to the latest released version of the GreptimeDB Operator by running the following command: ```bash helm -n greptimedb-admin upgrade --install greptimedb-operator greptime/greptimedb-operator ```
Expected Output ```bash NAME: greptimedb-operator LAST DEPLOYED: Sun Apr 26 20:43:58 2026 NAMESPACE: greptimedb-admin STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: *********************************************************************** Welcome to use greptimedb-operator Chart version: 0.5.9 GreptimeDB Operator version: 0.5.5 *********************************************************************** Installed components: * greptimedb-operator The greptimedb-operator is starting, use `kubectl get deployment greptimedb-operator -n greptimedb-admin` to check its status. ```
If you want to upgrade to a specific version, you can use the following command: ```bash helm -n greptimedb-admin upgrade --install greptimedb-operator greptime/greptimedb-operator --version ``` After the upgrade is complete, you can use the following command to verify the installation: ```bash helm list -n greptimedb-admin ```
Expected Output ```bash NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION greptimedb-operator greptimedb-admin 1 2026-04-26 20:43:58.003167 +0800 CST deployed greptimedb-operator-0.5.9 0.5.5 ```
### CRDs There are two kinds of CRD that are installed with the GreptimeDB Operator: `GreptimeDBCluster` and `GreptimeDBStandalone`. You can use the following command to verify the installation: ```bash kubectl get crd | grep greptime ```
Expected Output ```bash greptimedbclusters.greptime.io 2026-04-26T12:43:58Z greptimedbstandalones.greptime.io 2026-04-26T12:43:58Z ```
By default, the GreptimeDB Operator chart will manage the installation and upgrade of the CRDs and the users don't need to manage them manually. If you want to know the specific definitions of these two types of CRD, you can refer to the GreptimeDB Operator [API documentation](https://github.com/GreptimeTeam/greptimedb-operator/blob/main/docs/api-references/docs.md). ### Configuration The GreptimeDB Operator chart provides a set of configuration options that allow you to customize the installation, you can refer to the [GreptimeDB Operator Helm Chart](https://github.com/GreptimeTeam/helm-charts/blob/main/charts/greptimedb-operator/README.md##values) for more details. You can create a `values.yaml` to configure the GreptimeDB Operator chart (the complete configuration of `values.yaml` can be found in the [chart](https://github.com/GreptimeTeam/helm-charts/blob/main/charts/greptimedb-operator/values.yaml)), for example: ```yaml image: # -- The image registry registry: docker.io # -- The image repository repository: greptime/greptimedb-operator # -- The image pull policy for the controller imagePullPolicy: IfNotPresent # -- The image tag tag: "v0.5.6" # -- The image pull secrets pullSecrets: [] replicas: 1 resources: limits: cpu: 500m memory: 512Mi requests: cpu: 250m memory: 256Mi ``` You also can use one command to install or upgrade the GreptimeDB Operator with the custom configuration: ```bash helm -n greptimedb-admin upgrade --install greptimedb-operator greptime/greptimedb-operator -f values.yaml ``` ### Uninstallation You can use the `helm` command to uninstall the GreptimeDB Operator: ```bash helm -n greptimedb-admin uninstall greptimedb-operator ``` We don't delete the CRDs by default when you uninstall the GreptimeDB Operator. :::danger If you really want to delete the CRDs, you can use the following command: ```bash kubectl delete crd greptimedbclusters.greptime.io greptimedbstandalones.greptime.io ``` The related resources will be removed after you delete the CRDs. ::: --- ## Deploy GreptimeDB on Kubernetes GreptimeDB is designed for cloud-native environments and supports Kubernetes deployment from day one. You can deploy GreptimeDB on any cloud service provider, including AWS, Alibaba Cloud, or Google Cloud. ## Deploy GreptimeDB Standalone For development, testing, or small-scale production use cases, you can [deploy a standalone GreptimeDB instance](deploy-greptimedb-standalone.md) on Kubernetes. This provides a simple way to get started with GreptimeDB without the complexity of managing a full cluster. ## Deploy GreptimeDB Cluster For production environments requiring high availability and scalability, you can [deploy a GreptimeDB cluster](deploy-greptimedb-cluster.md) using the GreptimeDB Operator on Kubernetes. This enables you to set up a distributed GreptimeDB cluster that scales horizontally and efficiently handles large volumes of data. ## Configurations You can apply custom configurations to GreptimeDB by creating a `values.yaml` file when deploying either GreptimeDB clusters or standalone instances. For a complete list of available configuration options, see [Common Helm Chart Configurations](./common-helm-chart-configurations.md). ## Manage GreptimeDB Operator The GreptimeDB Operator manages GreptimeDB deployments on Kubernetes, automating the setup, provisioning, and management of GreptimeDB cluster instances. This enables quick deployment and scaling of GreptimeDB in any Kubernetes environment, whether on-premises or in the cloud. Learn how to [manage the GreptimeDB Operator](./greptimedb-operator-management.md), including installation and upgrades. ## Advanced Deployments After familiarizing yourself with [the architecture and components of GreptimeDB](/user-guide/concepts/architecture.md), you can explore advanced deployment scenarios: - [Deploy GreptimeDB Infrastructure test](deploy-greptimedb-infra-test.md): Prerequisite infrastructure testing for installing GreptimeDB. - [Deploy MinIO cluster](deploy-minio.md):Learn how to deploy, configure, and monitor a MinIO cluster. - [Deploy Kafka cluster](deploy-kafka.md):Learn how to deploy, configure, and monitor a Kafka cluster. - [Deploy GreptimeDB Cluster with Remote WAL](configure-remote-wal.md): Configure Kafka as a remote write-ahead log (WAL) for your GreptimeDB cluster to persistently record every data modification and ensure no loss of memory-cached data. - [Use MySQL/PostgreSQL as Metadata Store](/user-guide/deployments-administration/deploy-on-kubernetes/common-helm-chart-configurations.md#configuring-metasrv-backend-storage): Integrate MySQL/PostgreSQL databases to provide robust metadata storage capabilities for enhanced reliability and performance. - [Deploy Multi-Frontend GreptimeDB Cluster](configure-frontend-groups.md): Set up a GreptimeDB cluster on Kubernetes with a frontend group consisting of multiple frontend instances for improved load distribution and availability. --- ## Data Export & Import This guide describes how to use GreptimeDB's Export and Import tools for database data backup and restoration operations. For detailed command-line options and advanced configurations, please refer to [Data Export & Import](/reference/command-lines/utilities/data.md). ## Overview ## Export Operations ### Full Databases Backup Export all databases backup. This operation exports each database into a single directory, including all tables and their data. ```bash # Export all databases backup greptime cli data export \ --addr localhost:4000 \ --output-dir /tmp/backup/greptimedb ``` The output directory structure is as follows: ``` / └── greptime/ └── / ├── create_database.sql ├── create_tables.sql ├── copy_from.sql └── ``` #### Export to S3 Export all databases backup to S3: ```bash greptime cli data export \ --addr localhost:4000 \ --s3 \ --s3-bucket \ --s3-access-key-id \ --s3-secret-access-key \ --s3-region \ --s3-root \ --s3-endpoint ``` ### Export with Basic Authentication If the GreptimeDB instance has authentication enabled, pass the credentials with `--auth-basic`: ```bash greptime cli data export \ --addr localhost:4000 \ --output-dir /tmp/backup/greptimedb \ --auth-basic : ``` ### Schema-Only Operations Export only schemas without data. This operation exports `CREATE TABLE` statements into SQL files, allowing you to backup table structures without the actual data. ```bash # Export only schemas greptime cli data export \ --addr localhost:4000 \ --output-dir /tmp/backup/schemas \ --target schema ``` ### Time-Range Based Backup ```bash # Export data within specific time range greptime cli data export --addr localhost:4000 \ --output-dir /tmp/backup/timerange \ --start-time "2024-01-01 00:00:00" \ --end-time "2024-01-31 23:59:59" ``` ### Specific Database Backup ```bash # To export a specific database greptime cli data export \ --addr localhost:4000 \ --output-dir /tmp/backup/greptimedb \ --database '{my_database_name}' ``` ## Import Operations ### Full Databases Backup Import all databases backup. ```bash # Import all databases greptime cli data import \ --addr localhost:4000 \ --input-dir /tmp/backup/greptimedb ``` ### Import with Basic Authentication If the GreptimeDB instance has authentication enabled, pass the credentials with `--auth-basic`: ```bash greptime cli data import \ --addr localhost:4000 \ --input-dir /tmp/backup/greptimedb \ --auth-basic : ``` ### Schema-Only Operations Import only schemas without data. This operation imports `CREATE TABLE` statements from SQL files, allowing you to restore table structures without the actual data. ```bash # Import only schemas greptime cli data import \ --addr localhost:4000 \ --input-dir /tmp/backup/schemas \ --target schema ``` ### Specific Database Backup ```bash # The same applies to import tool greptime cli data import \ --addr localhost:4000 \ --input-dir /tmp/backup/greptimedb \ --database '{my_database_name}' ``` ## Best Practices 1. **Parallelism Configuration** - Adjust `--export-jobs`/`--import-jobs` based on available system resources - Start with a lower value and increase gradually - Monitor system performance during operations 2. **Backup Strategy** - Incremental data backups using time ranges - Periodic backups for disaster recovery 3. **Error Handling** - Use `--max-retry` for handling transient failures - Keep logs for troubleshooting ## Performance Tips 1. **Export Performance** - Use time ranges for large datasets - Adjust parallel jobs based on CPU/Memory - Consider network bandwidth limitations 2. **Import Performance** - Monitor database resources ## Troubleshooting 1. **Connection Errors** - Verify server address and port - Check network connectivity - Ensure authentication credentials are correct 2. **Permission Issues** - Verify read/write permissions on output/input directories 3. **Resource Constraints** - Reduce parallel jobs - Ensure sufficient disk space - Monitor system resources during operations --- ## Metadata Export & Import This guide describes how to use GreptimeDB's metadata export and import tools for metadata backup and restoration operations. For detailed command-line options and advanced configurations, please refer to [Metadata Export & Import](/reference/command-lines/utilities/metadata.md). ## Overview ## Export Operations ### Export to S3 Cloud Storage Export metadata from PostgreSQL to S3 for cloud-based backup storage: ```bash greptime cli meta snapshot save \ --store-addrs 'password=password dbname=postgres user=postgres host=localhost port=5432' \ --backend postgres-store \ --s3 \ --s3-bucket your-bucket-name \ --s3-region ap-southeast-1 \ --s3-access-key-id \ --s3-secret-access-key ``` **Output**: Creates `metadata_snapshot.metadata.fb` file in the specified S3 bucket. ### Export to Local Directory #### From PostgreSQL Backend Export metadata from PostgreSQL to local directory: ```bash greptime cli meta snapshot save \ --store-addrs 'password=password dbname=postgres user=postgres host=localhost port=5432' \ --backend postgres-store ``` #### From MySQL Backend Export metadata from MySQL to local directory: ```bash greptime cli meta snapshot save \ --store-addrs 'mysql://user:password@127.0.0.1:3306/database' \ --backend mysql-store ``` #### From etcd Backend Export metadata from etcd to local directory: ```bash greptime cli meta snapshot save \ --store-addrs 127.0.0.1:2379 \ --backend etcd-store ``` **Output**: Creates `metadata_snapshot.metadata.fb` file in the current working directory. #### From RaftEngine Backend :::note RaftEngine locks the metadata directory while the standalone instance is running. Stop the standalone instance before exporting. ::: Export metadata from RaftEngine to local directory: ```bash greptime cli meta snapshot save \ --store-addrs "raftengine:///path/to/metadata" \ --backend raft-engine-store ``` **Output**: Creates `metadata_snapshot.metadata.fb` file in the current working directory. ## Import Operations :::warning **Important**: Before importing metadata, ensure the target backend is in a **clean state** (contains no existing data). Importing to a non-empty backend may result in data corruption or conflicts. If you need to import to a backend with existing data, use the `--force` flag to bypass this safety check. However, exercise extreme caution as this can lead to data loss or inconsistencies. ::: ### Import from S3 Cloud Storage Restore metadata from S3 backup to PostgreSQL storage backend: ```bash greptime cli meta snapshot restore \ --store-addrs 'password=password dbname=postgres user=postgres host=localhost port=5432' \ --backend postgres-store \ --s3 \ --s3-bucket your-bucket-name \ --s3-region ap-southeast-1 \ --s3-access-key-id \ --s3-secret-access-key ``` ### Import from Local File #### To PostgreSQL Backend Restore metadata from local backup file to PostgreSQL: ```bash greptime cli meta snapshot restore \ --store-addrs 'password=password dbname=postgres user=postgres host=localhost port=5432' \ --backend postgres-store ``` #### To MySQL Backend Restore metadata from local backup file to MySQL: ```bash greptime cli meta snapshot restore \ --store-addrs 'mysql://user:password@127.0.0.1:3306/database' \ --backend mysql-store ``` #### To etcd Backend Restore metadata from local backup file to etcd: ```bash greptime cli meta snapshot restore \ --store-addrs 127.0.0.1:2379 \ --backend etcd-store ``` #### To RaftEngine Backend Restore metadata from local backup file to RaftEngine: ```bash greptime cli meta snapshot restore \ --store-addrs "raftengine:///path/to/metadata" \ --backend raft-engine-store ``` --- ## DR Solution Based on Cross-Region Deployment in a Single Cluster ## How disaster recovery works in GreptimeDB GreptimeDB is well-suited for cross-region disaster recovery. You may have varying regional characteristics and business needs, and GreptimeDB offers tailored solutions to meet these diverse requirements. GreptimeDB resource management involves the concept of Availability Zones (AZs). An AZ is a logical unit of disaster recovery. It can be a Data Center (DC), a compartment of a DC. This depends on your specific DC conditions and deployment design. In the cross region disaster recovery solutions, a GreptimeDB region is a city. When two DC are in the same region and one DC becomes unavailable, the other DC can take over the services of the unavailable DC. This is a localization strategy. Before understanding the details of each DR solution, it is necessary to first understand the following knowledge: 1. The DR solution for the remote wal component is also very important. Essentially, it forms the foundation of the entire DR solution. Therefore, for each DR solution of GreptimeDB, we will let the remote wal component in the diagram. Currently, GreptimeDB's default remote wal component is implemented based on Kafka, and other implementations will be provided in the future; however, there won't be significant differences in deployment. 2. The table of GreptimeDB: Each table can be divided into multiple partitions according to a certain range, and each partition may be distributed on different datanodes. When writing or querying, the specified node will be called according to the corresponding rules. A table's partitions might look like this: ``` Table name: T1 Table partition count: 4 T1-1 T1-2 T1-3 T1-4 Table name: T2 Table partition count: 3 T2-1 T2-2 T2-3 ``` ### Metadata across 2 regions, data in the same region ![DR-across-2dc-1region](/DR-across-2dc-1region.png) In this solution, the data is in one region (2 DCs), while the metadata across 2 regions. DC1 and DC2 are used together to handle read and write services, while DC3 (located in region2) is a replica used to meet the majority protocol. This architecture is also called the "2-2-1" solution. Both DC1 and DC2 must be able to handle all requests in extreme situations, so please ensure that sufficient resources are allocated. Latencies: - 2ms latency in the same region - 30ms latency in two regions Supports High Availability: - A single AZ is unavailable with the same performance - A single DC is unavailable with almost the same performance If you want a regional-level disaster recovery solution, you can take it a step further by providing read and write services on DC3. So, the next solution is: ### Data across 2 regions ![DR-across-3dc-2region](/DR-across-3dc-2region.png) In this solution, the data across 2 regions. Each DC must be able to handle all requests in extreme situations, so please ensure that sufficient resources are allocated. Latencies: - 2ms latency in the same region - 30ms latency in two regions Supports High Availability: - A single AZ is unavailable with the same performance - A single DC is unavailable with degraded performance If you can't tolerate performance degradation from a single DC failure, consider upgrading to the five-DC and three-region solution. ### Metadata across 3 regions, data across 2 regions ![DR-across-5dc-2region](/DR-across-5dc-2region.png) In this solution, the data across 2 regions, while the metadata across 3 regions. Region1 and region2 are used together to handle read and write services, while region3 is a replica used to meet the majority protocol. This architecture is also called the "2-2-1" solution. Each of the two adjacent regions must be able to handle all requests in extreme situations, so please ensure that sufficient resources are allocated. Latencies: - 2ms latency in the same region - 7ms latency in two adjacent regions - 30ms latency in two distant regions Supports High Availability: - A single AZ is unavailable with the same performance - A single DC is unavailable with the same performance - A single region(city) is unavailable with slightly degraded performance You can take it a step further by providing read and write services on both 3 regions. So, the next solution is: (This solution may have higher latency, so if that's unacceptable, it's not recommended.) ### Data across 3 regions ![DR-across-5dc-3region](/DR-across-5dc-3region.png) In this solution, the data across 3 regions. In the event of a failure in one region, the other two regions must be able to handle all requests, so please ensure sufficient resources are allocated. Latencies: - 2ms latency in the same region - 7ms latency in two adjacent regions - 30ms latency in two distant regions Supports High Availability: - A single AZ is unavailable with the same performance - A single DC is unavailable with the same performance - A single region(city) is unavailable with degraded performance ## Solution Comparison The goal of the above solutions is to meet the high requirements for availability and reliability in medium to large-scale scenarios. However, in specific implementations, the cost and effectiveness of each solution may vary. The table below compares each solution to help you choose the final plan based on your specific scenario, needs, and costs. Here is the content formatted into a table: | Solution | Latencies | High Availability | | --- | --- | --- | | Metadata across 2 regions, data in the same region | - 2ms latency in the same region- 30ms latency in two regions | - A single AZ is unavailable with the same performance- A single DC is unavailable with almost the same performance | | Data across 2 regions | - 2ms latency in the same region- 30ms latency in two regions | - A single AZ is unavailable with the same performance- A single DC is unavailable with degraded performance | | Metadata across 3 regions, data across 2 regions | - 2ms latency in the same region- 7ms latency in two adjacent regions- 30ms latency in two distant regions | - A single AZ is unavailable with the same performance- A single DC is unavailable with the same performance- A single region(city) is unavailable with slightly degraded performance | | Data across 3 regions | - 2ms latency in the same region- 7ms latency in two adjacent regions- 30ms latency in two distant regions | - A single AZ is unavailable with the same performance - A single DC is unavailable with the same performance- A single region(city) is unavailable with degraded performance | --- ## DR solution for GreptimeDB Standalone --- ## Disaster Recovery GreptimeDB is a distributed database designed to withstand disasters. It provides different solutions for disaster recovery (DR). This document contains: * Basic concepts in DR. * The deployment architecture of GreptimeDB and Backup & Restore (BR). * GreptimeDB provides the DR solutions. * Compares these DR solutions. ## Basic Concepts * **Recovery Time Objective (RTO)**: refers to the maximum acceptable amount of time that a business process can be down after a disaster occurs before it negatively impacts the organization. * **Recovery Point Objective (RPO)**: refers to the maximum acceptable amount of time since the last data recovery point. This determines what is considered an acceptable loss of data between the last recovery point and the interruption of service. The following figure illustrates these two concepts: ![RTO-RPO-explain](/RTO-RPO-explain.png) * **Write-Ahead Logging (WAL)**: persistently records every data modification to ensure data integrity and consistency. GreptimeDB storage engine is a typical [LSM Tree](https://en.wikipedia.org/wiki/Log-structured_merge-tree) : ![LSM-tree-explain](/LSM-tree-explain.png) The data written is going firstly persisted into WAL, then applied into Memtable in memory. Under specific conditions (e.g., exceeding the memory threshold), the Memtable will be flushed and persisted as an SSTable. So the DR of WAL and SSTable is key to the DR of GreptimeDB. * **Region**: a contiguous segment of a table, and also could be regarded as a partition in some relational databases. Read [Table Sharding](/contributor-guide/frontend/table-sharding.md#region) for more details. ## Component architecture ### GreptimeDB Before digging into the specific DR solution, let's explain the architecture of GreptimeDB components in the perspective of DR: ![Component-architecture](/Component-architecture.png) GreptimeDB is designed with a cloud-native architecture based on storage-compute separation: * **Frontend**: the ingestion and query service layer, which forwards requests to Datanode and processes, and merges responses from Datanode. * **Datanode**: the storage layer of GreptimeDB, and is an LSM storage engine. Region is the basic unit for storing and scheduling data in Datanode. A region is a table partition, a collection of data rows. The data in region is saved into Object Storage (such as AWS S3). Unflushed Memtable data is written into WAL and can be recovered in DR. * **WAL**: persists the unflushed Memtable data in memory. It will be truncated when the Memtable is flushed into SSTable files. It can be local disk-based (local WAL) or Kafka cluster-based (remote WAL). * **Object Storage**: persists the SSTable data and index. The GreptimeDB stores data in object storage such as [AWS S3](https://docs.aws.amazon.com/AmazonS3/latest/userguide/DataDurability.html) or its compatible services, which is designed to provide 99.999999999% durability and 99.99% availability of objects over a given year. And services such as S3 provide [replications in Single-Region or Cross-Region](https://docs.aws.amazon.com/AmazonS3/latest/userguide/replication.html), which is naturally capable of DR. At the same time, the WAL component is pluggable, e.g. using Kafka as the WAL service that offers a mature [DR solution](https://www.confluent.io/blog/disaster-recovery-multi-datacenter-apache-kafka-deployments/). ### Backup and restore ![BR-explain](/BR-explain.png) The Backup & Restore (BR) tool can perform a full snapshot backup of databases or tables at a specific time and supports incremental backup. When a cluster encounters a disaster, you can restore the cluster from backup data. Generally speaking, BR is the last resort for disaster recovery. ## Solutions introduction ### DR solution for GreptimeDB Standalone If the Standalone is running on the local disk for WAL and data, then: * RPO: depends on backup frequency. * RTO: doesn't make sense in standalone mode, mostly depends on the size of the data to be restored, your failure response time, and the operational infrastructure. A good start is to deploy GreptimeDB Standalone into an IaaS platform that has a backup and recovery solution. For example, Amazon EC2 with EBS volumes provides a comprehensive [Backup and Recovery solution](https://docs.aws.amazon.com/prescriptive-guidance/latest/backup-recovery/backup-recovery-ec2-ebs.html). But if running the Standalone with remote WAL and object storage, there is a better DR solution: ![DR-Standalone](/DR-Standalone.png) Write the WAL to the Kafka cluster and store the data in object storage, so the database itself is stateless. In the event of a disaster affecting the standalone database, you can restore it using the remote WAL and object storage. This solution can achieve **RPO=0** and **RTO in minutes**. ### DR solution based on Active-Active Failover ![Active-active failover](/active-active-failover.png) In some edge or small-to-medium scale scenarios, or if you lack the resources to deploy remote WAL or object storage, Active-Active Failover offers a better solution compared to Standalone DR. By replicating requests synchronously between two actively serving standalone nodes, high availability is ensured. The failure of any single node will not lead to data loss or a decrease in service availability even when using local disk-based WAL and data storage. Deploying nodes in different regions can also meet region-level DR requirements, but the scalability is limited. :::tip NOTE **Active-Active Failover is only available in GreptimeDB Enterprise.** ::: For more information about this solution, see [DR solution based on Active-Active Failover](/enterprise/deployments-administration/disaster-recovery/dr-solution-based-on-active-active-failover.md). ### DR solution based on cross-region deployment in a single cluster ![Cross-region-single-cluster](/Cross-region-single-cluster.png) For medium-to-large scale scenarios requiring zero RPO, this solution is highly recommended. In this deployment architecture, the entire cluster spans across three regions, with each region capable of handling both read and write requests. Data replication is achieved using remote WAL and object storage, both of which must have cross-region DR enabled. If Region 1 becomes completely unavailable due to a disaster, the table regions within it will be opened and recovered in the other regions. In the event that Region 1 becomes completely unavailable due to a disaster, the table regions within it will be opened and recovered in the other regions. Region 3 serves as a replica to adhere to the majority protocol of Metasrv. This solution provides region-level error tolerance, scalable write capability, zero RPO, and minute-level RTO or even lower. For more information about this solution, see [DR solution based on cross-region deployment in a single cluster](./dr-solution-based-on-cross-region-deployment-in-single-cluster.md). ### DR solution based on BR ![/BR-DR](/BR-DR.png) In this architecture, GreptimeDB Cluster 1 is deployed in region 1. The BR process continuously and regularly backs up the data from Cluster 1 to region 2. If region 1 experiences a disaster rendering Cluster 1 unrecoverable, you can use the backup data to restore a new cluster (Cluster 2) in region 2 to resume services. The DR solution based on BR provides an RPO depending on the backup frequency and an RTO that varies with the size of the data to be restored. Read [Backup & restore data](./back-up-&-restore-data.md) for details. ### Solution Comparison By comparing these DR solutions, you can decide on the final option based on their specific scenarios, requirements, and cost. | DR solution | Error Tolerance Objective | RPO | RTO | TCO | Scenarios | Remote WAL & Object Storage | Notes | | ------------- | ------------------------- | ----- | ----- | ----- | ---------------- | --------- | --------| | DR solution for Standalone| Single-Region | Backup Interval | Minute or Hour level | Low | Low requirements for availability and reliability in small scenarios | Optional | | | DR solution based on Active-Active Failover | Cross-Region | Configurable | Minute level | Low | High requirements for availability and reliability in small-to-medium scenarios | Optional | Commercial feature | | DR solution based on cross-region deployment in a single cluster| Multi-Regions | 0 | Minute level | High | High requirements for availability and reliability in medium-to-large scenarios | Required | | | DR solution based on BR | Single-Region | Backup Interval | Minute or Hour level | Low | Acceptable requirements for availability and reliability | Optional | | ## References * [Backup & restore data](./back-up-&-restore-data.md) * [DR solution based on Active-Active Failover ](/enterprise/deployments-administration/disaster-recovery/dr-solution-based-on-active-active-failover.md) * [DR solution based on cross-region deployment in a single cluster](./dr-solution-based-on-cross-region-deployment-in-single-cluster.md) * [S3 Replicating objects overview](https://docs.aws.amazon.com/AmazonS3/latest/userguide/replication.html) --- ## Cluster Maintenance Mode Maintenance mode is a safety feature in GreptimeDB that temporarily disables automatic cluster management operations. This mode is particularly useful during: - Cluster deployment - Cluster upgrades - Planned downtime - Any operation that might temporarily affect cluster stability ## When to Use Maintenance Mode ### With GreptimeDB Operator If you are upgrading a cluster using GreptimeDB Operator, you don't need to enable the maintenance mode manually. The operator handles this automatically. ### Without GreptimeDB Operator When upgrading a cluster without using GreptimeDB Operator, **you must manually enable Metasrv's maintenance mode before**: 1. Deploying a new cluster (maintenance mode should be enabled after metasrv nodes are ready) 2. Rolling upgrades of Datanode nodes 3. Metasrv nodes upgrades 4. Frontend nodes upgrades 5. Any operation that might cause temporary node unavailability After the cluster is deployed/upgraded, you can disable the maintenance mode. ## Impact of Maintenance Mode When maintenance mode is enabled: - Auto Balancing (if enabled) will be paused - Region Failover (if enabled) will be paused - Manual region operations are still possible - Read and write operations continue to work normally - Monitoring and metrics collection continue to function ## Managing Maintenance Mode The maintenance mode can be enabled and disabled through Metasrv's HTTP interface at: `http://{METASRV}:{HTTP_PORT}/admin/maintenance/enable` and `http://{METASRV}:{HTTP_PORT}/admin/maintenance/disable`. Note that this interface listens on Metasrv's `HTTP_PORT`, which defaults to `4000`. ### Enable Maintenance Mode :::danger After calling the maintenance mode interface, ensure you check that the HTTP status code returned is 200 and confirm that the response content meets expectations. If there are any exceptions or the interface behavior does not meet expectations, proceed with caution and avoid continuing with high-risk operations such as cluster upgrades. ::: Enable maintenance mode by sending a POST request to the `/admin/maintenance/enable` endpoint. ```bash curl -X POST 'http://localhost:4000/admin/maintenance/enable' ``` The expected output is: ```bash {"enabled":true} ``` If you encounter any issues or unexpected behavior, do not proceed with maintenance operations. ### Disable Maintenance Mode :::danger Before disabling maintenance mode, you must confirm that **all components have returned to normal status**. ::: Disable maintenance mode by sending a POST request to the `/admin/maintenance/disable` endpoint. Before disabling maintenance mode: 1. Ensure all components are healthy and operational 2. Verify that all nodes are properly joined to the cluster ```bash curl -X POST 'http://localhost:4000/admin/maintenance/disable' ``` The expected output is: ```bash {"enabled":false} ``` ### Check Maintenance Mode Status Check maintenance mode status by sending a GET request to the `/admin/maintenance/status` endpoint. ```bash curl -X GET http://localhost:4000/admin/maintenance/status ``` The expected output is: ```bash {"enabled":false} ``` ## Troubleshooting ### Common Issues 1. **Maintenance mode cannot be enabled** - Verify Metasrv is running and accessible - Check if you have the correct permissions - Ensure the HTTP port is correct ### Best Practices 1. Always verify the maintenance mode status before and after operations 2. Have a rollback plan ready 3. Monitor cluster health during maintenance 4. Document all changes made during maintenance --- ## Prevent Metadata Changes To prevent metadata changes, you can pause the Procedure Manager. This mechanism rejects all new procedures (i.e., new metadata-changing operations) while allowing existing procedures to continue running. Once enabled, the Metasrv will reject the following procedures (including but not limited to): **DDL procedures:** - Create table - Drop table - Alter table - Create database - Drop database - Create view - Create flow - Drop flow **Region procedures:** - Region Migration - Region Failover (if enabled) - Auto Balancing (if enabled) You may see error messages if you or Metasrv try to perform these procedures after metadata changes are paused. For region procedures, you can enable [Cluster Maintenance Mode](/user-guide/deployments-administration/maintenance/maintenance-mode.md) to temporarily disable them. ## Managing Procedure Manager The Procedure Manager can be paused and resumed through Metasrv's HTTP interface at: `http://{METASRV}:{HTTP_PORT}/admin/procedure-manager/pause` and `http://{METASRV}:{HTTP_PORT}/admin/procedure-manager/resume`. Note that this interface listens on Metasrv's `HTTP_PORT`, which defaults to `4000`. ### Pause Procedure Manager Pause Procedure Manager by sending a POST request to the `/admin/procedure-manager/pause` endpoint. ```bash curl -X POST 'http://localhost:4000/admin/procedure-manager/pause' ``` The expected output is: ```bash {"status":"paused"} ``` ### Resume Procedure Manager Resume Procedure Manager by sending a POST request to the `/admin/procedure-manager/resume` endpoint. ```bash curl -X POST 'http://localhost:4000/admin/procedure-manager/resume' ``` The expected output is: ```bash {"status":"running"} ``` ### Check Procedure Manager Status Check Procedure Manager status by sending a GET request to the `/admin/procedure-manager/status` endpoint. ```bash curl -X GET 'http://localhost:4000/admin/procedure-manager/status' ``` The expected output is: ```bash {"status":"running"} ``` --- ## Cluster Recovery Mode Recovery mode is a safety feature in GreptimeDB that allows developers to manually recover the cluster from a failed state. ## When to Use Recovery Mode Recovery mode is particularly useful when the Datanode fails to start due to an "Empty region directory" error, often caused by: - Data corruption (Missing region data directory) - Recover the cluster from a metadata snapshot. ## Recovery Mode Management Recovery mode can be enabled and disabled through Metasrv's HTTP interface at: `http://{METASRV}:{HTTP_PORT}/admin/recovery/enable` and `http://{METASRV}:{HTTP_PORT}/admin/recovery/disable`. Note that this interface listens on Metasrv's `HTTP_PORT`, which defaults to `4000`. ### Enable Recovery Mode Enable recovery mode by sending a POST request to the `/admin/recovery/enable` endpoint. ```bash curl -X POST 'http://localhost:4000/admin/recovery/enable' ``` The expected output is: ```bash {"enabled":true} ``` ### Disable Recovery Mode Disable recovery mode by sending a POST request to the `/admin/recovery/disable` endpoint. ```bash curl -X POST 'http://localhost:4000/admin/recovery/disable' ``` The expected output is: ```bash {"enabled":false} ``` ### Check Recovery Mode Status Check recovery mode status by sending a GET request to the `/admin/recovery/status` endpoint. ```bash curl -X GET 'http://localhost:4000/admin/recovery/status' ``` The expected output is: ```bash {"enabled":false} ``` --- ## Resource ID Management Resource ID management is primarily used to manually set resource identifiers (such as table IDs) when restoring a cluster from a [Metadata Backup](/user-guide/deployments-administration/manage-metadata/restore-backup.md). This is because the backup file may not contain the latest `next table ID` value, which could lead to resource conflicts or data inconsistencies if not properly reset. ### Understanding the Relationship Between Table ID and Next Table ID In GreptimeDB: - **Table ID**: Each table has a unique numeric identifier used internally by the database to identify and manage tables - **Next Table ID**: The system-reserved next available table ID value. When creating a new table, the system automatically assigns this ID to the new table and then increments the `next table ID` **Example:** - Suppose the current cluster has tables with IDs 1001, 1002, and 1003 - The `next table ID` should be 1004 - When creating a new table, the system assigns ID 1004 to the new table and updates the `next table ID` to 1005 - If during backup restoration, the `next table ID` is still 1002, it would conflict with existing table IDs 1002 and 1003 (you would encounter the error `Region 1024 is corrupted, reason: ` when starting the Datanode) Under normal circumstances, resource IDs are automatically maintained by the database and require no manual intervention. However, in certain special scenarios (such as restoring a cluster from metadata backup where new tables were created after the backup), the `next table ID` in the backup may lag behind the actual cluster state, requiring manual adjustment. **How to determine if manual `next table ID` setting is needed:** 1. Query all table IDs in the current cluster: `SELECT TABLE_ID FROM INFORMATION_SCHEMA.TABLES ORDER BY TABLE_ID DESC LIMIT 1;` 2. Get the current `next table ID` via API (see interface description below) 3. If the maximum existing table ID is greater than or equal to the current `next table ID`, you need to manually set the `next table ID` to a larger value, typically the maximum existing table ID plus 1. You can get or set the `next table ID` using Metasrv's HTTP interface at the following endpoints: `http://{METASRV}:{HTTP_PORT}/admin/sequence/table/next-id` (to get) and `http://{METASRV}:{HTTP_PORT}/admin/sequence/table/set-next-id` (to set). This interface listens on Metasrv's `HTTP_PORT`, which defaults to `4000`. ### Set next table ID To safely update the `next table ID`, follow this step-by-step process: 1. **Enable cluster recovery mode** - This prevents new table creation during the update process. See [Cluster Recovery Mode](/user-guide/deployments-administration/maintenance/recovery-mode.md) for more details. 2. **Set the next table ID** - Use the HTTP interface to set the `next table ID`. 3. **Restart metasrv nodes** - This ensures the new `next table ID` is properly applied. 4. **Disable cluster recovery mode** - Resume normal cluster operations. Set the `next table ID` by sending a POST request to the `/admin/sequence/table/set-next-id` endpoint: ```bash curl -X POST 'http://localhost:4000/admin/sequence/table/set-next-id' \ -H 'Content-Type: application/json' \ -d '{"next_table_id": 2048}' ``` The expected output is (the `next_table_id` may be different): ```bash {"next_table_id":2048} ``` ### Get next table ID ```bash curl -X GET 'http://localhost:4000/admin/sequence/table/next-id' ``` The expected output is (the `next_table_id` may be different): ```bash {"next_table_id":1254} ``` --- ## Table Reconciliation ## Overview GreptimeDB uses a layered metadata management architecture in distributed environments: - **Metasrv**: Acts as the metadata management layer, responsible for maintaining metadata information for all tables in the cluster - **Datanode**: Handles actual data storage and query execution, while also persisting some table metadata Under ideal conditions, table metadata between Metasrv and Datanode should remain perfectly consistent. However, in real production environments, restore from a [metadata backup](/user-guide/deployments-administration/manage-metadata/restore-backup.md) may cause metadata inconsistencies. **Table Reconciliation** is a table metadata repair mechanism provided by GreptimeDB that: - Detects metadata differences between Metasrv and Datanode - Repairs inconsistency issues according to predefined strategies - Ensures the system can recover from abnormal states to a consistent, available state ## Before starting Before starting the table reconciliation process, you need to: 1. Restore the cluster from a specific [metadata backup](/user-guide/deployments-administration/manage-metadata/restore-backup.md) 2. Set the [Next Table ID](/user-guide/deployments-administration/maintenance/sequence-management.md) to the original cluster's next table ID ## Repair Scenarios ### `Table not found` Error After a cluster is restored from specific metadata, write and query operations may encounter `Table not found` errors. - **Scenario 1**: The original cluster created new tables after the metadata backup, causing the new table metadata to not be included in the backup. This results in `Table not found` errors when querying these new tables. In this case, the new created table will be lost, and you must to manually set the [Next Table ID](/user-guide/deployments-administration/maintenance/sequence-management.md) to ensure that the restored cluster won't fail to create tables due to table ID conflicts when creating new tables. - **Scenario 2**: The original cluster renamed existing tables after the metadata backup. In this case, the new table names will be lost. ### `Empty region directory` Error After a cluster is restored from specific metadata, starting the Datanode may result in an `Empty region directory` error. This usually occurs because the original cluster deleted tables (executed `DROP TABLE`) after the metadata backup, causing the deleted table metadata to not be included in the backup, resulting in this error when starting the Datanode. For this situation, you need to enable [Recovery Mode](/user-guide/deployments-administration/maintenance/recovery-mode.md) after starting Metasrv when starting the cluster to ensure the Datanode can start normally. - **Mito Engine tables**: Table metadata cannot be repaired, you need to manually execute the `DROP TABLE` command to delete the non-existent table. - **Metric Engine tables**: Table metadata can be repaired, you need to manually execute the `ADMIN reconcile_table('table_name')` command to repair the table metadata. ### `No field named` Error After a cluster is restored from specific metadata, write and query operations may encounter `No field named` errors. This usually occurs because the original cluster deleted columns (executed `DROP COLUMN`) after the metadata backup, causing the deleted column metadata to not be included in the backup, resulting in this error when querying these deleted columns. For this situation, you need to manually execute the `ADMIN reconcile_table('table_name')` command to repair the table metadata. ### `schema has a different type` Error After a cluster is restored from specific metadata, write and query operations may encounter `schema has a different type` errors. This usually occurs because the original cluster modified column types (executed `MODIFY COLUMN [column_name] [type]`) after the metadata backup, causing the modified column type metadata to not be included in the backup, resulting in this error when querying these modified columns. For this situation, you need to manually execute the `ADMIN reconcile_table('table_name')` command to repair the table metadata. ### Missing Specific Columns After a cluster is restored from specific metadata, write and query operations may run normally but not include some columns. This occurs because the original cluster added columns (executed `ADD COLUMN`) after the metadata backup, causing the new column metadata to not be included in the backup, making these columns unavailable during queries. For this situation, you need to manually execute the `ADMIN reconcile_table('table_name')` command to repair the table metadata. ### Missing Column Indexes After a cluster is restored from specific metadata, write and query operations may run normally, but `SHOW CREATE TABLE`/`SHOW INDEX FROM [table_name]` shows that certain columns don't include expected indexes. This occurs because the original cluster modified indexes (executed `MODIFY INDEX [column_name] SET [index_type] INDEX`) after the metadata backup, causing the index change metadata to not be included in the backup. For this situation, you need to manually execute the `ADMIN reconcile_table('table_name')` command to repair the table metadata. ## Repair operations GreptimeDB provides the following Admin functions to trigger table metadata repair: ### Repair All Tables Repair the metadata inconsistency of all tables in the entire cluster: ```sql ADMIN reconcile_catalog() ``` ### Repair a Specific Database Repair the metadata inconsistency of all tables in a specific database: ```sql ADMIN reconcile_database('database_name') ``` ### Repair a Specific Table Repair the metadata inconsistency of a single table: ```sql ADMIN reconcile_table('table_name') ``` ### View Repair Progress After the Admin function is executed, it will return a `ProcedureID`, you can use the following command to view the progress of the repair task: ```sql ADMIN procedure_state('procedure_id') ``` When `procedure_state` returns Done, it indicates that the repair task has completed. ## Important Notes When performing table metadata repair operations, please note the following: - Repair operations are executed asynchronously, and you can check the execution progress through the `procedure_id` - It is recommended to perform repair operations during low-traffic periods to reduce the impact on system performance - For large-scale repair operations (such as `reconcile_catalog()`), it is recommended to validate in a test environment first --- ## Basic Table Operations [Data Model](/user-guide/concepts/data-model.md) should be read before this guide. GreptimeDB provides table management functionalities via SQL. The following guide uses [MySQL Command-Line Client](https://dev.mysql.com/doc/refman/8.0/en/mysql.html) to demonstrate it. For more explanations of the `SQL` syntax, please see the [SQL reference](/reference/sql/overview.md). ## Create a database The default database is `public`. You can create a database manually. ```sql CREATE DATABASE test; ``` ```sql Query OK, 1 row affected (0.05 sec) ``` Create a database with a `TTL` (Time-To-Live) of seven days, which means all the tables in this database will inherit this option if they don't have their own `TTL` setting: ```sql CREATE DATABASE test with(ttl='7d'); ``` You can list all the existing databases. ```sql SHOW DATABASES; ``` ```sql +--------------------+ | Database | +--------------------+ | greptime_private | | information_schema | | public | | test | +--------------------+ 4 rows in set (0.00 sec) ``` Using `like` syntax: ```sql SHOW DATABASES LIKE 'p%'; ``` ```sql +----------+ | Database | +----------+ | public | +----------+ 1 row in set (0.00 sec) ``` Then change the database: ```sql USE test; ``` ## Create a table :::tip NOTE GreptimeDB offers a schemaless approach to writing data that eliminates the need to manually create tables using additional protocols. See [Automatic Schema Generation](/user-guide/ingest-data/overview.md#automatic-schema-generation). ::: You can still create a table manually via SQL if you have specific requirements. Suppose we want to create a table named monitor with the following data model: - `host` is the hostname of the collected standalone machine, which should be a `Tag` that used to filter data when querying. - `ts` is the time when the data is collected, which should be the `Timestamp`. It can also used as a filter when querying data with a time range. - `cpu` and `memory` are the CPU utilization and memory utilization of the machine, which should be `Field` columns that contain the actual data and are not indexed. The SQL code for creating the table is shown below. In SQL, we use the primary key to specify `Tag`s and the `TIME INDEX` to specify the `Timestamp` column. The remaining columns are `Field`s. ```sql CREATE TABLE monitor ( host STRING, ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP() TIME INDEX, cpu FLOAT64 DEFAULT 0, memory FLOAT64, PRIMARY KEY(host)); ``` ```sql Query OK, 0 row affected (0.03 sec) ``` Create the table with a `TTL` (Time-To-Live) of seven days: ```sql CREATE TABLE monitor ( host STRING, ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP() TIME INDEX, cpu FLOAT64 DEFAULT 0, memory FLOAT64, PRIMARY KEY(host) ) WITH (ttl='7d'); ``` :::warning NOTE GreptimeDB does not currently support changing the TIME INDEX after a table has been created. Therefore, it is important to carefully choose your TIME INDEX column before creating tables. ::: ### `CREATE TABLE` syntax - Timestamp column: GreptimeDB is a time-series database system, a timestamp column must be explicitly specified by `TIME INDEX` keyword when creating tables. The data type of the timestamp column must be `TIMESTAMP`type. - Primary key: The columns in primary key are similar to tags in other other time-series systems like [InfluxDB][1]. The primary key columns with the time index column are used to uniquely define a series of data, which is similar to time series like [InfluxDB][2]. - Table options: when creating a table, you can specify a set of table options, click [here](/reference/sql/create.md#table-options) for more details. ### Table name constraints GreptimeDB supports a limited set of special characters in table names, but they must adhere to the following constraints: - A valid GreptimeDB table name must start with a letter (either lowercase or uppercase) or `-` / `_` / `:`. - The rest part of table name can be alphanumeric or special characters within: `-` / `_` / `:` / `@` / `#`. - Any table name containing special characters must be quoted with backquotes. - Any table name containing uppercase letters must be quoted with backquotes. Here are some examples: ```sql -- ✅ Ok create table a (ts timestamp time index); -- ✅ Ok create table a0 (ts timestamp time index); -- 🚫 Invalid table name create table 0a (ts timestamp time index); -- 🚫 Invalid table name create table -a (ts timestamp time index); -- ✅ Ok create table `-a` (ts timestamp time index); -- ✅ Ok create table `a@b` (ts timestamp time index); -- 🚫 Invalid table name create table memory_HugePages (ts timestamp time index); -- ✅ Ok create table `memory_HugePages` (ts timestamp time index); ``` [1]: https://docs.influxdata.com/influxdb/v1.8/concepts/glossary/#tag-key [2]: https://docs.influxdata.com/influxdb/v1/concepts/glossary/#series ## Describe a table Show table information in detail: ```sql DESC TABLE monitor; ``` ```sql +--------+----------------------+------+------+---------------------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +--------+----------------------+------+------+---------------------+---------------+ | host | String | PRI | YES | | TAG | | ts | TimestampMillisecond | PRI | NO | current_timestamp() | TIMESTAMP | | cpu | Float64 | | YES | 0 | FIELD | | memory | Float64 | | YES | | FIELD | +--------+----------------------+------+------+---------------------+---------------+ 4 rows in set (0.01 sec) ``` The Semantic Type column describes the data model of the table. The `host` is a `Tag` column, `ts` is a `Timestamp` column, and cpu and memory are `Field` columns. ## Show Table Definition and Indexes Use `SHOW CREATE TABLE table_name` to get the statement when creating the table: ```sql SHOW CREATE TABLE monitor; ``` ``` +---------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Table | Create Table | +---------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | monitor | CREATE TABLE IF NOT EXISTS `monitor` ( `host` STRING NULL, `ts` TIMESTAMP(3) NOT NULL DEFAULT current_timestamp(), `cpu` DOUBLE NULL DEFAULT 0, `memory` DOUBLE NULL, TIME INDEX (`ts`), PRIMARY KEY (`host`) ) ENGINE=mito | +---------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ``` List all indexes in a table: ```sql SHOW INDEXES FROM monitor; ``` ```sql +---------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+-------------------------+---------+---------------+---------+------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression | +---------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+-------------------------+---------+---------------+---------+------------+ | monitor | 1 | PRIMARY | 1 | host | A | NULL | NULL | NULL | YES | greptime-primary-key-v1 | | | YES | NULL | | monitor | 1 | TIME INDEX | 1 | ts | A | NULL | NULL | NULL | NO | | | | YES | NULL | +---------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+-------------------------+---------+---------------+---------+------------+ ``` For more info about `SHOW` statement, please read the [SHOW reference](/reference/sql/show.md#show). ## List Existing Tables You can use `show tables` statement to list existing tables ```sql SHOW TABLES; ``` ```sql +----------------+ | Tables_in_test | +----------------+ | monitor | +----------------+ 1 row in set (0.00 sec) ``` Currently only table name filtering is supported. You can filter existing tables by their names. ```sql SHOW TABLES LIKE monitor; ``` ```sql +----------------+ | Tables_in_test | +----------------+ | monitor | +----------------+ 1 row in set (0.00 sec) ``` List tables in a specific database: ```sql SHOW TABLES FROM test; ``` ```sql +----------------+ | Tables_in_test | +----------------+ | monitor | +----------------+ 1 row in set (0.01 sec) ``` ## Alter a table You can alter the schema of existing tables just like in MySQL database ```sql ALTER TABLE monitor ADD COLUMN label VARCHAR; ``` ```sql Query OK, 0 rows affected (0.03 sec) ``` ```sql ALTER TABLE monitor DROP COLUMN label; ``` ```sql Query OK, 0 rows affected (0.03 sec) ``` The `ALTER TABLE` statement also supports adding, removing, and renaming columns, as well as modifying the column datatype, etc. Please refer to the [ALTER reference](/reference/sql/alter.md) for more information. ## Drop a table :::danger danger `DROP TABLE` cannot be undone. Use it with care! ::: `DROP TABLE [db.]table` is used to drop the table in `db` or the current database in-use.Drop the table `monitor` in the current database: ```sql DROP TABLE monitor; ``` ```sql Query OK, 1 row affected (0.01 sec) ``` ## Drop a database :::danger danger `DROP DATABASE` cannot be undone. Use it with care! ::: You can use `DROP DATABASE` to drop a database. For example, change back to `public` database and drop the `test` database: ```sql USE public; DROP DATABASE test; ``` Please refer to the [DROP](/reference/sql/drop.md#drop-database) document for more details. ## HTTP API You can execute the SQL statements through the HTTP API. For example, using the following code to create a table through POST method: ```shell curl -X POST \ -H 'authorization: Basic {{authorization if exists}}' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'sql=CREATE TABLE monitor (host STRING, ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP(), cpu FLOAT64 DEFAULT 0, memory FLOAT64, TIME INDEX (ts), PRIMARY KEY(host))' \ http://localhost:4000/v1/sql?db=public ``` ```json { "output": [{ "affectedrows": 0 }], "execution_time_ms": 10 } ``` For more information about SQL HTTP request, please refer to [API document](/user-guide/protocols/http.md#post-sql-statements). ## Time zone The specified time zone in the SQL client session will affect the default timestamp value when creating or altering a table. If you set the default value of a timestamp column to a string without a time zone, the client's time zone information will be automatically added. For more information about the effect of the client time zone, please refer to the [time zone](/user-guide/ingest-data/for-iot/sql.md#time-zone) section in the write data document. --- ## Compaction For databases based on the LSM Tree, compaction is extremely critical. It merges overlapping fragmented SST files into a single ordered file, discards deleted data while significantly improves query performance. Since v0.9.1, GreptimeDB provides compaction strategies to control how SST files are compacted: Time Windowed Compaction Strategy (TWCS) and Strict Window Compaction Strategy (SWCS). ## Concepts Let us start with those core concepts of compaction in GreptimeDB. ### SST files SSTs are sorted files generated when memtables are flushed to persistent storage, such as disks and object stores. In GreptimeDB, data rows in SST files are organized by [tags](/user-guide/concepts/data-model.md) and timestamps, as illustrated below. Each SST file covers a specific time range. When a query specifies a time range, GreptimeDB retrieves only the relevant SST files that may contain data within that range, rather than loading all persisted files. ![SST layout](/compaction-sst-file-layout.jpg) Typically, the time ranges of SST files do not overlap during real-time writing workloads. However, due to factors like row deletions and out-of-order writes, SST files may have overlapping time ranges, which can affect query performance. ### Time window Time-series workloads present prominent "windowed" pattern in that most recently inserted rows are more possible to be read. Thus GreptimeDB logically partitioned the time axis into different time windows and we are more interested in compacting those SST files fall into the same time window. Time window for some specific table is usually inferred from the most-recently flushed SST files or users may manually specify the time window if TWCS is chosen. GreptimeDB has a preset collection of window sizes that are: - 1 hour - 2 hours - 12 hours - 1 day - 1 week If time window is not specified, GreptimeDB will use `1hour` as the initial time window size and split all inserted rows to those time windows and will infer a proper time window size when the first compaction happens by selecting the minimum time window size for the above collection that can cover the whole time span of all files to be compacted. For example, during the first compaction, the time span for all SST files is 4 hours, then GreptimeDB will choose 12 hours as the time window for that table and persist it for later compactions. ### Sorted runs Sorted runs is a collection of SST files that have sorted and non-overlapping time ranges. For example, a table contains 5 SSTs with following time ranges (all inclusive): `[0, 10]`, `[12, 23]`, `[22, 25]`,`[24, 30]`,`[26,33]` and we can find 2 sorted runs: ![num-of-sorted-runs](/compaction-num-sorted-runs.jpg) The number of sorted runs indicates the orderliness of SST files. More sorted runs typically lead to worse query performance. The main goal of compactions is to reduce the number of sorted runs. ### Levels Databases based on LSM trees may also have levels, keys are merged level by level. GreptimeDB only has 2 levels which are 0 (uncompacted) and 1 (compacted). ## Compaction strategies GreptimeDB provides two compaction strategies as mentioned above, but only Time Windowed Compaction Strategy (TWCS) can be chosen when creating tables. Strict Window Compaction Strategy (SWCS) is only available when executing manual compactions. ## Time Windowed Compaction Strategy (TWCS) TWCS primarily aims to reduce read/write amplification during compaction. It assigns files to be compacted into different time windows. For each window, TWCS identifies the sorted runs. If there are more than 1 sorted runs, TWCS finds a solution to merge the overlapping files in those runs with merging penalties taken into consideration. If there's only 1 sorted run, TWCS checks for excessive file fragmentation and merges fragmented files if necessary since SST file count also impacts query performance. For window assignment, SST files may span multiple time windows. TWCS assigns SSTs based on their maximum timestamps to ensure they are not affected by stale data. In time-series workloads, out-of-order writes are infrequent, and even when they occur, recent data's query performance is more critical than that of stale data. Common TWCS table options include: - `trigger_file_num`: number of files in a specific time window to trigger a compaction (default 4). - `time_window`: time window size for TWCS compaction. - `max_output_file_size`: max allowed compaction output file size (default 512MB). Following diagrams show how files in a window get compacted when `trigger_file_num = 3`: - In A, there're two SST files `[0, 3]` and `[5, 6, 9]` but there's only one sorted run since those two files have disjoint time ranges. - In B, a new SST file `[1, 4]` is flushed therefore forms two sorted runs that exceeds the threshold. Then `[0, 3]` and `[1, 4]` are merged to `[0, 1, 3, 4]`. - In C, a new SST file `[9, 10]` is flushed, and it will be merged with `[5, 6, 10]` to create `[5, 6, 9, 10]`, and after compaction the files will be like D. - In E, a new file `[11, 12]` is flushed. Though there's still only one sorted run, but the number of files reaches `trigger_file_num`(3), so `[5, 6, 9, 10]` will be merged with `[11, 12]` to form `[5, 6, 9, 10, 11, 12]`. ![compaction-trigger-file-num.png](/compaction-trigger-file-num.png) ### Specifying TWCS parameters TWCS parameters can be specified at two levels: 1. **Table level**: Explicitly set when creating or altering a table 2. **Database level**: Set as defaults for all tables in the database The effective compaction settings are resolved dynamically at compaction scheduling time with the following priority: - Table-level settings (if specified) - Database-level settings (if specified and no table-level override) - Built-in defaults #### Table-level compaction settings You can specify TWCS parameters when creating tables: ```sql CREATE TABLE monitor ( host STRING, ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP() TIME INDEX, cpu FLOAT64 DEFAULT 0, memory FLOAT64, PRIMARY KEY(host)) WITH ( 'compaction.type'='twcs', 'compaction.twcs.trigger_file_num'='8', 'compaction.twcs.time_window'='1h', 'compaction.twcs.max_output_file_size'='500MB' ); ``` #### Database-level compaction settings You can also set default compaction parameters for all tables in a database. These settings will be inherited by tables that don't have explicit compaction settings. See [ALTER DATABASE](/reference/sql/alter.md#modify-compaction-options-of-database) for examples. :::note Unlike table-level settings which are stored with the table metadata, database-level compaction settings are dynamically resolved at runtime. Changing database-level compaction options will immediately affect all tables in the database that don't have their own explicit compaction settings. This behavior is similar to how [database-level TTL](/reference/sql/create.md#create-database) works. ::: ## Strict Window Compaction Strategy (SWCS) and manual compaction Unlike TWCS, which assigns one window per SST file based on their maximum timestamps, SWCS assigns SST files to **all** overlapping windows. Consequently, a single SST file may be included in multiple compaction outputs, as its name suggests. Due to its high read amplification during compaction, SWCS is not the default compaction strategy. However, it is useful when you need to manually trigger compaction to reorganize the layout of SST files—especially if an individual SST file spans a large time range that significantly slows down queries. GreptimeDB offers a simple SQL function for triggering compaction: ```sql ADMIN COMPACT_TABLE( , , [] ); ``` The `` parameter can be `regular` (or `twcs`) for regular TWCS compaction, or `swcs` (or `strict_window`) for Strict Window Compaction Strategy. The value is case-insensitive. For the `swcs` strategy, the `` can specify: - The window size (in seconds) for splitting SST files - The `parallelism` parameter to control the level of parallelism for compaction (defaults to 1) For example, to trigger compaction with a 1-hour window: ```sql ADMIN COMPACT_TABLE( "monitor", "swcs", "3600" ); +------------------------------------------------+ | ADMIN COMPACT_TABLE("monitor", "swcs", "3600") | +------------------------------------------------+ | 0 | +------------------------------------------------+ 1 row in set (0.01 sec) ``` When executing this statement, GreptimeDB will split each SST file into segments with a time span of 1 hour (3600 seconds) and merge these segments into a single output, ensuring no overlapping files remain. You can also specify the `parallelism` parameter to speed up compaction by processing multiple files concurrently: ```sql -- SWCS compaction with default time window and parallelism set to 2 ADMIN COMPACT_TABLE("monitor", "swcs", "parallelism=2"); -- SWCS compaction with custom time window and parallelism ADMIN COMPACT_TABLE("monitor", "swcs", "window=1800,parallelism=2"); ``` The `parallelism` parameter is also available for regular compaction: ```sql -- Regular compaction with parallelism set to 2 ADMIN COMPACT_TABLE("monitor", "regular", "parallelism=2"); ``` The following diagram shows the process of strict window compression: In Figure A, there are 3 overlapping SST files: `[0, 3]` (which includes timestamps 0, 1, 2, and 3), `[3, 8]`, and `[8, 10]`. The strict window compaction strategy will assign the file `[3, 8]` that covers windows 0, 4, and 8 to three separate windows respectively. This allows it to merge with `[0, 3]` and `[8, 10]` separately. Figure B shows the final compaction result with three files: `[0, 3]`, `[4, 7]`, and `[8, 10]`. These files do not overlap with each other. ![compaction-strict-window.jpg](/compaction-strict-window.jpg) --- ## Garbage Collection (GC) GreptimeDB GC delays physical deletion of SST/index files until all references (running queries, [repartition](./repartition.md) cross-region file refs) are released. The configuration contains two parts: - Metasrv Configuration - Datanode Configuration ## How it works - **Roles**: Meta decides when/where to clean; datanodes perform the actual delete while keeping in-use files safe. - **Safety windows**: `lingering_time` holds known-removed files a bit longer; `unknown_file_lingering_time` is a rare-case guard. - **Listing modes**: Fast mode removes files the system already marked; full listing walks storage to catch stragglers/orphans. ![GC workflow](/gc-flow.svg) ## Metasrv Configuration On the Metasrv side, GC schedules cleanup tasks for regions and coordinates when to run GC. ```toml [gc] enable = true # Enable meta GC scheduler. default to be false; must match datanode. gc_cooldown_period = "5m" # Minimum gap before the same region is GCed again. ``` ### Options | Configuration Option | Description | | --- | --- | | `enable` | Enable the meta GC scheduler. Must match datanode GC enablement. | | `gc_cooldown_period` | Minimum interval before the same region is scheduled for GC again; keep datanode `lingering_time` longer than this. | ## Datanode Configuration The Datanode side performs the actual deletion while protecting files still in use. ```toml [[region_engine]] [region_engine.mito] [region_engine.mito.gc] enable = true # Turn on datanode GC worker; must match meta. lingering_time = "10m" # Keep known-removed files this long for active queries. unknown_file_lingering_time = "1h" # Keep files without expel time; rare safeguard. ``` ### Options | Configuration Option | Description | | --- | --- | | `enable` | Enable the datanode GC worker. Must match meta GC `enable`. | | `lingering_time` | How long to keep manifest-removed files before deletion to protect long follower-region queries/cross-region references; set longer than `gc_cooldown_period`. Use `"0s"` to delete immediately. | | `unknown_file_lingering_time` | Safety hold for files without expel time (not tracked in manifest). Should be generous; these cases are rare. | :::warning `gc.enable` must be set consistently on metasrv and all datanodes. Mismatched flags cause GC to be skipped or stuck. ::: ## When to enable - GC only applies when tables use object storage; tables on local filesystems ignore GC settings. - Turn on GC if need to repartition so cross-region references can drain safely before deletion. - For clusters with long-running follower-region queries, turn on GC and set `lingering_time` longer than `gc_cooldown_period` so files created or referenced during a GC cycle stay alive (in-use or lingering) until at least the next cycle. - Leave GC off if you are not repartitioning and do not need delayed deletion. ## Operational notes - GC is designed for object storage backends (with list/delete support); ensure your store credentials and permissions allow listing and deletion. - Deleted files live in object storage until GC removes them; ensure storage listing/deletion permissions are in place. - After enabling, restart metasrv and datanodes to apply config changes. --- ## Manage Data --- ## Region Failover Region Failover provides the ability to recover regions from region failures. With Kafka WAL (Remote WAL) and shared storage, Region Failover can recover regions without losing data. This is implemented via [Region Migration](/user-guide/deployments-administration/manage-data/region-migration.md). ## Enable the Region Failover This feature is only available on GreptimeDB running on distributed mode and - Using Kafka WAL (Remote WAL) or Local WAL with `allow_region_failover_on_local_wal=true` (enabling region failover on Local WAL may lead to data loss during failover) - Using [shared storage](/user-guide/deployments-administration/configuration.md#storage-options) (e.g., AWS S3) If you want to enable region failover on local WAL, you need to set `allow_region_failover_on_local_wal=true` in [metasrv](/user-guide/deployments-administration/configuration.md#metasrv-only-configuration) configuration file. It's not recommended to enable this option, because it may lead to data loss. ### Via configuration file Set `enable_region_failover=true` in the [metasrv](/user-guide/deployments-administration/configuration.md#metasrv-only-configuration) configuration file. Additionally, set `region_failure_detector_initialization_delay` to a larger value and enable [Cluster Maintenance Mode](/user-guide/deployments-administration/maintenance/maintenance-mode.md) within the `region_failure_detector_initialization_delay` period to avoid triggering unnecessary Region Failover during datanode startup or upgrades. ### Via GreptimeDB Operator To enable region failover via GreptimeDB Operator, you can refer to [Common Helm Chart Configurations](/user-guide/deployments-administration/deploy-on-kubernetes/common-helm-chart-configurations.md#enable-region-failover) for more details. ## The recovery time of Region Failover The recovery time of Region Failover with Kafka WAL (Remote WAL) depends on: - number of regions per Topic. - the Kafka cluster read throughput performance. ### The read amplification In best practices, [the number of topics/partitions supported by a Kafka cluster is limited](https://docs.aws.amazon.com/msk/latest/developerguide/bestpractices.html) (exceeding this number can degrade Kafka cluster performance). Therefore, we allow multiple regions to share a single topic as the WAL. However, this may cause to the read amplification issue. The data belonging to a specific region consists of data files plus data in the WAL (typically `WAL[LastCheckpoint...Latest]`). The failover of a specific region only requires reading the region's WAL data to reconstruct the memory state, which is called region replaying. However, If multiple regions share a single topic, replaying data for a specific region from the topic requires filtering out unrelated data (i.e., data from other regions). This means replaying data for a specific region from the topic requires reading more data than the actual size of the region's data in the topic, a phenomenon known as read amplification. Although multiple regions share the same topic, allowing the Datanode to support more regions, the cost of this approach is read amplification during WAL replay. For example, configure 128 topics for [metasrv](/user-guide/deployments-administration/configuration.md#metasrv-only-configuration), and if the whole cluster holds 1024 regions (physical regions), every 8 regions will share one topic. ![Read Amplification](/remote-wal-read-amplification.png) (Figure1: recovery Region 3 need to read redundant data 7 times larger than the actual size) A simple model to estimate the redundant read amplification factor (redundant replay data size/actual data size): - For a single topic, if we try to replay all regions that belong to the topic, then the amplification factor would be 7+6+...+1 = 28 times. (The Region WAL data distribution is shown in the Figure 1. Replaying Region 3 will read 7 times redundant data larger than the actual size; Region 6 will read 6 times, and so on) - When recovering 100 regions (requiring about 13 topics), the amplification factor is approximately 28 \* 13 = 364 times. Assuming we have 100 regions to recover, and the actual data size of all regions is 0.5GB, the following table shows the replay data size based on the number of regions per topic. | Number of regions per Topic | Number of topics required for 100 Regions | Single topic redundant read factor | Total redundant read factor | Replay data size (GB) | | --------------------------- | ----------------------------------------- | -------------------------------------- | ---------------------------------- | ---------------- | | 1 | 100 | 0 | 0 | 0.5 | | 2 | 50 | 1 | 50 | 25.5 | | 4 | 25 | 6 | 150 | 75.5 | | 8 | 13 | 28 | 364 | 182.5 | | 16 | 7 | 120 | 840 | 420.5 | The following table shows the recovery time of 100 regions under different read throughput conditions of the Kafka cluster. For example, when providing a read throughput of 300MB/s, recovering 100 regions requires approximately 10 minutes (182.5GB/0.3GB = 10m). | Number of regions per Topic | Replay data size (GB) | Kafka throughput 300MB/s- Recovery time (secs) | Kafka throughput 1000MB/s- Recovery time (secs) | | --------------------------- | ---------------- | --------------------------------------------- | ---------------------------------------------- | | 1 | 0.5 | 2 | 1 | | 2 | 25.5 | 85 | 26 | | 4 | 75.5 | 252 | 76 | | 8 | 182.5 | 608 | 183 | | 16 | 420.5 | 1402 | 421 | ### Suggestions for improving recovery time In the above example, we calculated the recovery time based on the number of Regions contained in each Topic for reference. We have calculated the recovery time under different Number of regions per Topic configuration for reference. In actual scenarios, the read amplification may be larger than this model. If you use Kafka WAL and are very sensitive to recovery time, we recommend that each region have its own topic (i.e., Number of regions per Topic is 1). --- ## Region Migration Region Migration allows users to move regions between the Datanode. :::warning Warning This feature is only available on GreptimeDB running on distributed mode and - Using [shared storage](/user-guide/deployments-administration/configuration.md#storage-options) (e.g., AWS S3) Otherwise, you can't perform a region migration. ::: ## Figure out the region distribution of the table. You need to first query the region distribution of the table, i.e., find out on which Datanode the Regions in the table are located. ```sql select b.peer_id as datanode_id, a.greptime_partition_id as region_id from information_schema.partitions a left join information_schema.region_peers b on a.greptime_partition_id = b.region_id where a.table_name='migration_target' order by datanode_id asc; ``` For example, have the following region distribution: ```sql +-------------+---------------+ | datanode_id | region_id | +-------------+---------------+ | 1 | 4398046511104 | +-------------+---------------+ 1 row in set (0.01 sec) ``` For more info about the `region_peers` table, please read the [REGION-PEERS](/reference/sql/information-schema/region-peers.md). ## Select a Datanode as the migration destination. :::warning Warning The region migration won't be performed if the `from_peer_id` equals the `to_peer_id`. ::: Remember, if you deploy the cluster via the GreptimeDB operator, the `peer_id` of Datanode always starts from 0. For example, if you have a 3 Datanode GreptimeDB cluster, the available `peer_id` will be 0,1,2. Finally, you can do a Region migration request via the following SQL: ```sql ADMIN migrate_region(4398046511104, 1, 2, 60); ``` The parameters of `migrate_region`: ```sql ADMIN migrate_region(region_id, from_peer_id, to_peer_id); ADMIN migrate_region(region_id, from_peer_id, to_peer_id, replay_timeout); ``` | Option | Description | Required | | | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------ | --- | | `region_id` | The region id. | **Required** | | | `from_peer_id` | The peer id of the migration source(Datanode). | **Required** | | | `to_peer_id` | The peer id of the migration destination(Datanode). | **Required** | | | `replay_timeout` | The timeout (in seconds) for replaying data. Defaults to 300 seconds if omitted. If the new Region fails to replay the data within the specified timeout, the migration will fail, however the data in the old Region will not be lost. | Optional | | ## Query the migration state The `migrate_region` function returns the procedure id that executes the migration, queries the procedure state by it: ```sql ADMIN procedure_state('538b7476-9f79-4e50-aa9c-b1de90710839') ``` If it's done, outputs the state in JSON: ```json {"status":"Done"} ``` Of course, you can confirm the region distribution by querying from `region_peers` and `partitions` in `information_schema`. --- ## Repartition Repartition lets you adjust partition rules after a table has been created. GreptimeDB does this through `ALTER TABLE` partition split and merge operations; see [ALTER TABLE](/reference/sql/alter.md#split-or-merge-partitions) for the syntax. Repartition is only supported in distributed clusters. ## How it works The core idea is to adjust partition rules and Region routing online instead of manually moving data into a new table. GreptimeDB switches to the new partition layout by updating manifest file references for each Region, so the rules can better match the current data distribution. This approach is useful when traffic patterns change over time and you want to keep partition rules aligned with the workload without rebuilding the table. During repartitioning, writes may be briefly affected, so client-side retries are recommended. ## When to repartition Consider repartitioning when: - Some regions are consistently hotter than others. - Your data distribution changes and the current partition boundaries no longer fit. - Some regions become very small and cold, and you want to reduce resource usage by merging them. - You want to further split a partition to improve write concurrency or query performance. In general, when partition rules no longer reflect the current data distribution well, it is worth considering repartitioning. ## How to identify hot partitions Before repartitioning, confirm which regions are hot. Join region statistics with partition metadata to find the hottest rules: ```sql SELECT t.table_name, r.region_id, r.region_number, p.partition_name, p.partition_description, r.region_role, r.written_bytes_since_open, r.region_rows FROM information_schema.region_statistics r JOIN information_schema.tables t ON r.table_id = t.table_id JOIN information_schema.partitions p ON p.table_schema = t.table_schema AND p.table_name = t.table_name AND p.greptime_partition_id = r.region_id WHERE t.table_schema = 'public' AND t.table_name = 'your_table' ORDER BY r.written_bytes_since_open DESC LIMIT 10; ``` If some regions have a much higher `written_bytes_since_open` value over time, that partition rule is usually a good candidate for splitting. Also check whether the region peers are healthy so node issues are not mistaken for hotspots: ```sql SELECT p.region_id, p.peer_addr, p.status, p.down_seconds FROM information_schema.region_peers p WHERE p.table_schema = 'public' AND p.table_name = 'your_table' ORDER BY p.region_id, p.peer_addr; ``` If the nodes are healthy and the hotspot signal persists, you can move on to designing the repartition plan. ## Prerequisites :::warning Warning This feature is only available in distributed clusters and requires: - Using [shared object storage](/user-guide/deployments-administration/configuration.md#storage-options) (e.g., AWS S3) - Using [GC](/user-guide/deployments-administration/manage-data/gc.md) on both metasrv and all datanodes Otherwise, you can't perform repartitioning. ::: GreptimeDB supports repartitioning through repeated `SPLIT PARTITION` and `MERGE PARTITION` operations. The most common cases are 1-to-2 splits and 2-to-1 merges. More complex changes can also be done step by step. Object storage stores region files, while GC reclaims old files only after references are released. This helps prevent accidental deletion of data still in use. ### Through GreptimeDB Operator If you deploy GreptimeDB with the GreptimeDB Operator, refer to [Common Helm Chart Configurations](/user-guide/deployments-administration/deploy-on-kubernetes/common-helm-chart-configurations.md) for GC and object storage setup. ## Example You can repartition a table by merging existing partitions and then splitting them with new rules. The following example changes the `area` partition key from `South` to `North` for devices with `device_id < 100`: ```sql ALTER TABLE sensor_readings MERGE PARTITION ( device_id < 100 AND area < 'South', device_id < 100 AND area >= 'South' ); ALTER TABLE sensor_readings SPLIT PARTITION ( device_id < 100 ) INTO ( device_id < 100 AND area < 'North', device_id < 100 AND area >= 'North' ); ``` ## Further reading For a step-by-step tutorial with more background and examples, see [How to Split and Merge Partitions Online in GreptimeDB](https://greptime.com/blogs/2026-03-19-greptimedb-repartition-guide). --- ## Table Sharding Table sharding is a technique used to distribute a large table into multiple smaller tables. This practice is commonly employed to enhance the performance of database systems. In GreptimeDB, data is logically sharded into partitions. Since GreptimeDB uses "tables" to group data and SQL to query them, we adopt the term "partition," a concept frequently used in OLTP databases. ## When to shard a table Inside GreptimeDB, both data management and scheduling are based on the region level, and each region is corresponding to a table partition. Thus when you have a table that is too large to fit into a single node, or the table is too hot to be served by a single node, you should consider sharding it. A region in GreptimeDB has a relative fixed throughput capacity, and the number of regions in a table determines the total throughput capacity of the table. If you want to increase the throughput capacity of a table, you can increase the number of regions in the table. Ideally the overall throughput of a table should be proportional to the number of regions. As for which specific partition column to use or how many regions to create, it depends on the data distribution and the query pattern. A general goal is to make the data distribution among regions as even as possible. And the query pattern should be considered when designing the partition rule set as one query can be processed in parallel among regions. In other word the query latency is depends on the "slowest" region's latency. But notice that the increase of regions will bring some basic consumption and increase the complexity of the system. You need to consider the requirement of data ingest rate, the query performance, the data distribution on storage system. You should shard a table only when necessary. For more information on the relationship between partitions and regions, refer to the [Table Sharding](/contributor-guide/frontend/table-sharding.md) section in the contributor guide. ## Partition In GreptimeDB, a table can be horizontally partitioned by column value ranges. Currently, GreptimeDB supports range partitioning with the `PARTITION ON COLUMNS` syntax. Each partition includes only a portion of the data from the table, and is grouped by some column(s) value range. For example, we can partition a table in GreptimeDB like this: ```sql CREATE TABLE (...) PARTITION ON COLUMNS () ( ); ``` The syntax mainly consists of two parts: 1. `PARTITION ON COLUMNS` followed by a comma-separated list of column names. This specifies which columns will be used for partitioning. The columns specified here must be of the Tag type (as specified by the PRIMARY KEY). Note that the ranges of all partitions must **not** overlap. 2. `RULE LIST` is a list of multiple partition rules. Each rule is a partition condition, and GreptimeDB generates partition names such as `p0`, `p1`, and so on for these rules. The expressions here can use `=`, `!=`, `>`, `>=`, `<`, `<=`, `AND`, `OR`, column names, and literals. :::tip Note The parentheses in `PARTITION ON COLUMNS (...)` only accept column names (e.g., `device_id`, `area`), not expressions like `device_id + 1`. GreptimeDB does not support MySQL's `PARTITION BY RANGE` syntax. ::: ### Example ## Create a distributed table You can use the MySQL CLI to [connect to GreptimeDB](/user-guide/protocols/mysql.md) and create a distributed table. The following example creates a table and partitions it based on the `device_id` column. ```SQL CREATE TABLE sensor_readings ( device_id INT16, reading_value FLOAT64, ts TIMESTAMP DEFAULT current_timestamp(), PRIMARY KEY (device_id), TIME INDEX (ts) ) PARTITION ON COLUMNS (device_id) ( device_id < 100, device_id >= 100 AND device_id < 200, device_id >= 200 ); ``` More partition columns can be used to create more complex partition rules: ```sql CREATE TABLE sensor_readings ( device_id INT, area STRING, reading_value FLOAT64, ts TIMESTAMP DEFAULT current_timestamp(), PRIMARY KEY (device_id, area), TIME INDEX (ts) ) PARTITION ON COLUMNS (device_id, area) ( device_id < 100 AND area < 'South', device_id < 100 AND area >= 'South', device_id >= 100 AND area <= 'East', device_id >= 100 AND area > 'East' ); ``` The following content uses the `sensor_readings` table with two partition columns as an example. ## Repartition a sharded table If you need to modify partition rules for an existing table, refer to the separate [Repartition](/user-guide/deployments-administration/manage-data/repartition.md) page. ## Insert data into the table The following code inserts 3 rows into each partition of the `sensor_readings` table. ```sql INSERT INTO sensor_readings (device_id, area, reading_value, ts) VALUES (1, 'North', 22.5, '2023-09-19 08:30:00'), (10, 'North', 21.8, '2023-09-19 09:45:00'), (50, 'North', 23.4, '2023-09-19 10:00:00'); INSERT INTO sensor_readings (device_id, area, reading_value, ts) VALUES (20, 'South', 20.1, '2023-09-19 11:15:00'), (40, 'South', 19.7, '2023-09-19 12:30:00'), (90, 'South', 18.9, '2023-09-19 13:45:00'); INSERT INTO sensor_readings (device_id, area, reading_value, ts) VALUES (110, 'East', 25.3, '2023-09-19 14:00:00'), (120, 'East', 26.5, '2023-09-19 15:30:00'), (130, 'East', 27.8, '2023-09-19 16:45:00'); INSERT INTO sensor_readings (device_id, area, reading_value, ts) VALUES (150, 'West', 24.1, '2023-09-19 17:00:00'), (170, 'West', 22.9, '2023-09-19 18:15:00'), (180, 'West', 23.7, '2023-09-19 19:30:00'); ``` :::tip NOTE Note that when the written data does not meet any of the rules in the partitioning scheme, it will be assigned to the default partition (i.e., the first partition 0 of the table). ::: ## Distributed Read Simply use the `SELECT` statement to query the data: ```sql SELECT * FROM sensor_readings order by reading_value desc LIMIT 5; ``` ```sql +-----------+------+---------------+---------------------+ | device_id | area | reading_value | ts | +-----------+------+---------------+---------------------+ | 130 | East | 27.8 | 2023-09-19 16:45:00 | | 120 | East | 26.5 | 2023-09-19 15:30:00 | | 110 | East | 25.3 | 2023-09-19 14:00:00 | | 150 | West | 24.1 | 2023-09-19 17:00:00 | | 180 | West | 23.7 | 2023-09-19 19:30:00 | +-----------+------+---------------+---------------------+ 5 rows in set (0.02 sec) ``` ```sql SELECT MAX(reading_value) AS max_reading FROM sensor_readings; ``` ```sql +-------------+ | max_reading | +-------------+ | 27.8 | +-------------+ 1 row in set (0.03 sec) ``` ```sql SELECT * FROM sensor_readings WHERE area = 'North' AND device_id < 50 ORDER BY device_id; ``` ```sql +-----------+-------+---------------+---------------------+ | device_id | area | reading_value | ts | +-----------+-------+---------------+---------------------+ | 1 | North | 22.5 | 2023-09-19 08:30:00 | | 10 | North | 21.8 | 2023-09-19 09:45:00 | +-----------+-------+---------------+---------------------+ 2 rows in set (0.03 sec) ``` ## Inspect a sharded table GreptimeDB provides severals system table to check DB's state. For table sharding information, you can query [`information_schema.partitions`](/reference/sql/information-schema/partitions.md) which gives the detail of partitions inside one table, and [`information_schema.region_peers`](/reference/sql/information-schema/region-peers.md) which gives the runtime distribution of regions. --- ## Metadata Storage Configuration This section describes how to configure different metadata storage backends for the GreptimeDB Metasrv component. The metadata storage is used to store critical system information including catalogs, schemas, tables, regions, and other metadata that are essential for the operation of GreptimeDB. ## Available Storage Backends GreptimeDB supports the following metadata storage backends: - **etcd**: The default and recommended backend for development and testing environments, offering simplicity and ease of setup - **MySQL/PostgreSQL**: Production-ready backend options that integrate well with existing database infrastructure and cloud RDS services This documentation describes the TOML configuration for each backend. You can use these configurations when deploying GreptimeDB without Helm Chart. If you are using Helm Chart to deploy GreptimeDB, please refer to [Common Helm Chart Configurations](/user-guide/deployments-administration/deploy-on-kubernetes/common-helm-chart-configurations.md#configuring-metasrv-backend-storage) for more details. ## Use etcd as metadata storage While etcd is suitable for development and testing environments, it may not be ideal for production deployments requiring high availability and scalability. Configure the metasrv component to use etcd as metadata storage: ```toml # The metadata storage backend for metasrv backend = "etcd_store" # Store server addresses # You can specify multiple etcd endpoints for high availability store_addrs = ["127.0.0.1:2379"] # Backend client options for etcd [backend_client] # The keep alive timeout for backend client keep_alive_timeout = "3s" # The keep alive interval for backend client keep_alive_interval = "10s" # The connect timeout for backend client connect_timeout = "3s" [backend_tls] # - "disable" - No TLS # - "require" - Require TLS mode = "prefer" # Path to client certificate file (for client authentication) # Like "/path/to/client.crt" cert_path = "" # Path to client private key file (for client authentication) # Like "/path/to/client.key" key_path = "" # Path to CA certificate file (for server certificate verification) # Required when using custom CAs or self-signed certificates # Leave empty to use system root certificates only # Like "/path/to/ca.crt" ca_cert_path = "" ``` ### Best Practices While etcd can be used as metadata storage, we recommend against using it in production environments unless you have extensive experience with etcd operations and maintenance. For detailed guidance on etcd management, including installation, backup, and maintenance procedures, please refer to [Manage etcd](/user-guide/deployments-administration/manage-metadata/manage-etcd.md). When using etcd as metadata storage: - Deploy multiple endpoints across different availability zones for high availability - Configure appropriate auto-compaction settings to manage storage growth - Implement regular maintenance procedures: - Run `Defrag` command periodically to reclaim disk space - Monitor etcd cluster health metrics - Review and adjust resource limits based on usage patterns ## Use MySQL as metadata storage MySQL serves as a viable metadata storage backend option. This choice is particularly beneficial when you need to integrate with existing MySQL infrastructure or have specific MySQL-related requirements. For production deployments, we strongly recommend utilizing cloud providers' Relational Database Service (RDS) solutions for enhanced reliability and managed service benefits. Configure the metasrv component to use MySQL as metadata storage: ```toml # The metadata storage backend for metasrv backend = "mysql_store" # Store server address # Format: mysql://user:password@ip:port/dbname store_addrs = ["mysql://user:password@ip:port/dbname"] # Optional: Custom table name for storing metadata # Default: greptime_metakv meta_table_name = "greptime_metakv" [backend_tls] # - "disable" - No TLS # - "prefer" (default) - Try TLS, fallback to plain # - "require" - Require TLS # - "verify_ca" - Require TLS and verify CA # - "verify_full" - Require TLS and verify hostname mode = "prefer" # Path to client certificate file (for client authentication) # Like "/path/to/client.crt" cert_path = "" # Path to client private key file (for client authentication) # Like "/path/to/client.key" key_path = "" # Path to CA certificate file (for server certificate verification) # Required when using custom CAs or self-signed certificates # Leave empty to use system root certificates only # Like "/path/to/ca.crt" ca_cert_path = "" ``` When sharing a MySQL instance between multiple GreptimeDB clusters, you must set a unique `meta_table_name` for each GreptimeDB cluster to avoid metadata conflicts. ## Use PostgreSQL as metadata storage PostgreSQL serves as a viable metadata storage backend option. This choice is particularly beneficial when you need to integrate with existing PostgreSQL infrastructure or have specific PostgreSQL-related requirements. For production deployments, we strongly recommend utilizing cloud providers' Relational Database Service (RDS) solutions for enhanced reliability and managed service benefits. Configure the metasrv component to use PostgreSQL as metadata storage: ```toml # The metadata storage backend for metasrv backend = "postgres_store" # Store server address # Format: password=password dbname=postgres user=postgres host=localhost port=5432 store_addrs = ["password=password dbname=postgres user=postgres host=localhost port=5432"] # Optional: Custom table name for storing metadata # Default: greptime_metakv meta_table_name = "greptime_metakv" # Optional: The schema for metadata table and election table name. # In PostgreSQL 15 and later, the default public schema is restricted by default, # and non-superusers are no longer allowed to create tables in the public schema. # When encountering permission restrictions, use this parameter to specify a writable schema. meta_schema_name = "greptime_schema" # Optional: Automatically create PostgreSQL schema if it doesn't exist. # When enabled, the system will execute `CREATE SCHEMA IF NOT EXISTS ` # before creating metadata tables. This is useful in production environments where # manual schema creation may be restricted. # Default: true # Note: The PostgreSQL user must have CREATE SCHEMA permission for this to work. auto_create_schema = true # Optional: Advisory lock ID for election # Default: 1 meta_election_lock_id = 1 [backend_tls] # - "disable" - No TLS # - "prefer" (default) - Try TLS, fallback to plain # - "require" - Require TLS # - "verify_ca" - Require TLS and verify CA # - "verify_full" - Require TLS and verify hostname mode = "prefer" # Path to client certificate file (for client authentication) # Like "/path/to/client.crt" cert_path = "" # Path to client private key file (for client authentication) # Like "/path/to/client.key" key_path = "" # Path to CA certificate file (for server certificate verification) # Required when using custom CAs or self-signed certificates # Leave empty to use system root certificates only # Like "/path/to/ca.crt" ca_cert_path = "" ``` When sharing a PostgreSQL instance between multiple GreptimeDB clusters or with other applications, you must configure two unique identifiers to prevent conflicts: 1. Set a unique `meta_table_name` for each GreptimeDB cluster to avoid metadata conflicts 2. Assign a unique `meta_election_lock_id` to each GreptimeDB cluster to prevent advisory lock conflicts with other applications using the same PostgreSQL instance --- ## Manage etcd The GreptimeDB cluster requires an etcd cluster for [metadata storage](https://docs.greptime.com/nightly/contributor-guide/metasrv/overview) by default. Let's install an etcd cluster using Bitnami's etcd Helm [chart](https://github.com/bitnami/charts/tree/main/bitnami/etcd). ## Prerequisites - [Kubernetes](https://kubernetes.io/docs/setup/) >= v1.23 - [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) >= v1.18.0 - [Helm](https://helm.sh/docs/intro/install/) >= v3.0.0 ## Install Save the following configuration as a file `etcd.yaml`: ```yaml global: security: allowInsecureImages: true replicaCount: 3 image: registry: docker.io repository: greptime/etcd tag: 3.6.1-debian-12-r3 auth: rbac: create: false token: enabled: false persistence: storageClass: null size: 8Gi resources: limits: cpu: '2' memory: 8Gi requests: cpu: '2' memory: 8Gi autoCompactionMode: "periodic" autoCompactionRetention: "1h" extraEnvVars: - name: ETCD_QUOTA_BACKEND_BYTES value: "8589934592" - name: ETCD_ELECTION_TIMEOUT value: "2000" - name: ETCD_SNAPSHOT_COUNT value: "10000" ``` Install etcd cluster: ```bash helm upgrade --install etcd \ oci://registry-1.docker.io/bitnamicharts/etcd \ --create-namespace \ --version 12.0.8 \ -n etcd-cluster \ --values etcd.yaml ``` Wait for etcd cluster to be running: ```bash kubectl get pod -n etcd-cluster ```
Expected Output ```bash NAME READY STATUS RESTARTS AGE etcd-0 1/1 Running 0 64s etcd-1 1/1 Running 0 65s etcd-2 1/1 Running 0 72s ```
When the etcd cluster is running, use the following command to check the health status of etcd cluster: ```bash kubectl -n etcd-cluster \ exec etcd-0 -- etcdctl \ --endpoints etcd-0.etcd-headless.etcd-cluster:2379,etcd-1.etcd-headless.etcd-cluster:2379,etcd-2.etcd-headless.etcd-cluster:2379 \ endpoint status -w table ```
Expected Output ```bash +----------------------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+ | ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS | +----------------------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+ | etcd-0.etcd-headless.etcd-cluster:2379 | 680910587385ae31 | 3.5.15 | 20 kB | false | false | 4 | 73991 | 73991 | | | etcd-1.etcd-headless.etcd-cluster:2379 | d6980d56f5e3d817 | 3.5.15 | 20 kB | false | false | 4 | 73991 | 73991 | | | etcd-2.etcd-headless.etcd-cluster:2379 | 12664fc67659db0a | 3.5.15 | 20 kB | true | false | 4 | 73991 | 73991 | | +----------------------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+ ```
## Backup In the bitnami etcd chart, a shared storage volume Network File System (NFS) is used to store etcd backup data. By using CronJob in Kubernetes to perform etcd snapshot backups and mount NFS PersistentVolumeClaim (PVC), snapshots can be transferred to NFS. Add the following configuration and name it `etcd-backup.yaml` file, Note that you need to modify **existingClaim** to your NFS PVC name: ```yaml global: security: allowInsecureImages: true replicaCount: 3 image: registry: docker.io repository: greptime/etcd tag: 3.6.1-debian-12-r3 auth: rbac: create: false token: enabled: false persistence: storageClass: null size: 8Gi resources: limits: cpu: '2' memory: 8Gi requests: cpu: '2' memory: 8Gi autoCompactionMode: "periodic" autoCompactionRetention: "1h" extraEnvVars: - name: ETCD_QUOTA_BACKEND_BYTES value: "8589934592" - name: ETCD_ELECTION_TIMEOUT value: "2000" - name: ETCD_SNAPSHOT_COUNT value: "10000" # Backup settings disasterRecovery: enabled: true cronjob: schedule: "*/30 * * * *" historyLimit: 2 snapshotHistoryLimit: 2 pvc: existingClaim: "${YOUR_NFS_PVC_NAME_HERE}" ``` Redeploy etcd cluster: ```bash helm upgrade --install etcd \ oci://registry-1.docker.io/bitnamicharts/etcd \ --create-namespace \ --version 12.0.8 \ -n etcd-cluster \ --values etcd-backup.yaml ``` You can see the etcd backup scheduled task: ```bash kubectl get cronjob -n etcd-cluster ```
Expected Output ```bash NAME SCHEDULE TIMEZONE SUSPEND ACTIVE LAST SCHEDULE AGE etcd-snapshotter */30 * * * * False 0 36s ```
```bash kubectl get pod -n etcd-cluster ```
Expected Output ```bash NAME READY STATUS RESTARTS AGE etcd-0 1/1 Running 0 35m etcd-1 1/1 Running 0 36m etcd-2 0/1 Running 0 6m28s etcd-snapshotter-28936038-tsck8 0/1 Completed 0 4m49s ```
```bash kubectl logs etcd-snapshotter-28936038-tsck8 -n etcd-cluster ```
Expected Output ```log etcd-0.etcd-headless.etcd-cluster.svc.cluster.local:2379 is healthy: successfully committed proposal: took = 2.698457ms etcd 11:18:07.47 INFO ==> Snapshotting the keyspace {"level":"info","ts":"2025-01-06T11:18:07.579095Z","caller":"snapshot/v3_snapshot.go:65","msg":"created temporary db file","path":"/snapshots/db-2025-01-06_11-18.part"} {"level":"info","ts":"2025-01-06T11:18:07.580335Z","logger":"client","caller":"v3@v3.5.15/maintenance.go:212","msg":"opened snapshot stream; downloading"} {"level":"info","ts":"2025-01-06T11:18:07.580359Z","caller":"snapshot/v3_snapshot.go:73","msg":"fetching snapshot","endpoint":"etcd-0.etcd-headless.etcd-cluster.svc.cluster.local:2379"} {"level":"info","ts":"2025-01-06T11:18:07.582124Z","logger":"client","caller":"v3@v3.5.15/maintenance.go:220","msg":"completed snapshot read; closing"} {"level":"info","ts":"2025-01-06T11:18:07.582688Z","caller":"snapshot/v3_snapshot.go:88","msg":"fetched snapshot","endpoint":"etcd-0.etcd-headless.etcd-cluster.svc.cluster.local:2379","size":"20 kB","took":"now"} {"level":"info","ts":"2025-01-06T11:18:07.583008Z","caller":"snapshot/v3_snapshot.go:97","msg":"saved","path":"/snapshots/db-2025-01-06_11-18"} Snapshot saved at /snapshots/db-2025-01-06_11-18 ```
Next, you can see the etcd backup snapshot in the NFS server: ```bash ls ${NFS_SERVER_DIRECTORY} ```
Expected Output ```bash db-2025-01-06_11-18 db-2025-01-06_11-20 db-2025-01-06_11-22 ```
## Restore When you encounter etcd data loss or corruption, such as critical information stored in etcd being accidentally deleted, or catastrophic cluster failure that prevents recovery, you need to perform an etcd restore. Additionally, restoring etcd can also be useful for development and testing purposes. Before recovery, you need to stop writing data to the etcd cluster (stop GreptimeDB Metasrv writing) and create the latest snapshot file use for recovery. Add the following configuration file and name it `etcd-restore.yaml`. Note that **existingClaim** is the name of your NFS PVC, and **snapshotFilename** is change to the etcd snapshot file name: ```yaml global: security: allowInsecureImages: true replicaCount: 3 image: registry: docker.io repository: greptime/etcd tag: 3.6.1-debian-12-r3 auth: rbac: create: false token: enabled: false persistence: storageClass: null size: 8Gi resources: limits: cpu: '2' memory: 8Gi requests: cpu: '2' memory: 8Gi autoCompactionMode: "periodic" autoCompactionRetention: "1h" extraEnvVars: - name: ETCD_QUOTA_BACKEND_BYTES value: "8589934592" - name: ETCD_ELECTION_TIMEOUT value: "2000" - name: ETCD_SNAPSHOT_COUNT value: "10000" # Restore settings startFromSnapshot: enabled: true existingClaim: "${YOUR_NFS_PVC_NAME_HERE}" snapshotFilename: "${YOUR_ETCD_SNAPSHOT_FILE_NAME}" ``` Deploy etcd recover cluster: ```bash helm upgrade --install etcd-recover \ oci://registry-1.docker.io/bitnamicharts/etcd \ --create-namespace \ --version 12.0.8 \ -n etcd-cluster \ --values etcd-restore.yaml ``` After waiting for the etcd recover cluster to be Running: ```bash kubectl get pod -n etcd-cluster -l app.kubernetes.io/instance=etcd-recover ```
Expected Output ```bash NAME READY STATUS RESTARTS AGE etcd-recover-0 1/1 Running 0 91s etcd-recover-1 1/1 Running 0 91s etcd-recover-2 1/1 Running 0 91s ```
:::tip NOTE The configuration structure has changed between chart versions: - In older version: `meta.etcdEndpoints` - In newer version: `meta.backendStorage.etcd.endpoints` Always refer to the latest [values.yaml](https://github.com/GreptimeTeam/helm-charts/blob/main/charts/greptimedb-cluster/values.yaml) in the Helm chart repository for the most up-to-date configuration structure. ::: Next, change Metasrv [backendStorage.etcd.endpoints](https://github.com/GreptimeTeam/helm-charts/tree/main/charts/greptimedb-cluster) to the new etcd recover cluster, in this example is `"etcd-recover.etcd-cluster.svc.cluster.local:2379"`: ```yaml apiVersion: greptime.io/v1alpha1 kind: GreptimeDBCluster metadata: name: greptimedb spec: # Other configuration here meta: backendStorage: etcd: endpoints: - "etcd-recover.etcd-cluster.svc.cluster.local:2379" ``` Restart GreptimeDB Metasrv to complete etcd restore. ## Monitoring - Prometheus Operator installed (e.g. via [kube-prometheus-stack](https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack)). - podmonitor CRD installed (automatically installed with Prometheus Operator). Add the following to your `etcd-monitoring.yaml` to enable monitoring: ```yaml global: security: allowInsecureImages: true replicaCount: 3 image: registry: docker.io repository: greptime/etcd tag: 3.6.1-debian-12-r3 auth: rbac: create: false token: enabled: false persistence: storageClass: null size: 8Gi resources: limits: cpu: '2' memory: 8Gi requests: cpu: '2' memory: 8Gi autoCompactionMode: "periodic" autoCompactionRetention: "1h" extraEnvVars: - name: ETCD_QUOTA_BACKEND_BYTES value: "8589934592" - name: ETCD_ELECTION_TIMEOUT value: "2000" - name: ETCD_SNAPSHOT_COUNT value: "10000" # Monitoring settings metrics: enabled: true podMonitor: enabled: true namespace: etcd-cluster interval: 10s scrapeTimeout: 10s additionalLabels: release: prometheus ``` Deploy etcd with Monitoring: ```bash helm upgrade --install etcd \ oci://registry-1.docker.io/bitnamicharts/etcd \ --create-namespace \ --version 12.0.8 \ -n etcd-cluster \ --values etcd-monitoring.yaml ``` ### Grafana dashboard Use the [ETCD Cluster Overview dashboard](https://grafana.com/grafana/dashboards/15308-etcd-cluster-overview/) (ID: 15308) for monitoring key metrics. 1. Log in your Grafana. 2. Navigate to Dashboards -> New -> Import. 3. Enter Dashboard ID: 15308, select the data source and load. ![ETCD Cluster Overview dashboard](/etcd-cluster-overview-dashboard.png) ## ⚠️ Defrag - Critical Warning Defragmentation is a HIGH-RISK operation that can severely impact your ETCD cluster and dependent systems (like GreptimeDB): 1. Blocks ALL read/write operations during execution (cluster becomes unavailable). 2. High I/O usage may cause timeouts in client applications. 3. May trigger leader elections if defrag takes too long. 4. Can cause OOM kills if not properly resourced. 5. May corrupt data if interrupted mid-process. ETCD uses a multi-version concurrency control (MVCC) mechanism that stores multiple versions of KV. Over time, as data is updated and deleted, the backend database can become fragmented, leading to increased storage usage and reduced performance. Defragmentation is the process of compacting this storage to reclaim space and improve performance. Add the following defrag-related configuration to `etcd-defrag.yaml` file: ```yaml global: security: allowInsecureImages: true replicaCount: 3 image: registry: docker.io repository: greptime/etcd tag: 3.6.1-debian-12-r3 auth: rbac: create: false token: enabled: false persistence: storageClass: null size: 8Gi resources: limits: cpu: '2' memory: 8Gi requests: cpu: '2' memory: 8Gi autoCompactionMode: "periodic" autoCompactionRetention: "1h" extraEnvVars: - name: ETCD_QUOTA_BACKEND_BYTES value: "8589934592" - name: ETCD_ELECTION_TIMEOUT value: "2000" - name: ETCD_SNAPSHOT_COUNT value: "10000" # Defragmentation settings defrag: enabled: true cronjob: schedule: "0 3 * * *" # Daily at 3:00 AM suspend: false successfulJobsHistoryLimit: 1 failedJobsHistoryLimit: 1 ``` Deploying with Defrag Configuration: ```bash helm upgrade --install etcd \ oci://registry-1.docker.io/bitnamicharts/etcd \ --create-namespace \ --version 12.0.8 \ -n etcd-cluster \ --values etcd-defrag.yaml ``` You can see the etcd defrag scheduled task: ```bash kubectl get cronjob -n etcd-cluster ```
Expected Output ```bash NAME SCHEDULE TIMEZONE SUSPEND ACTIVE LAST SCHEDULE AGE etcd-defrag 0 3 * * * False 0 34s ```
```bash kubectl get pod -n etcd-cluster ```
Expected Output ```bash NAME READY STATUS RESTARTS AGE etcd-0 1/1 Running 0 4m30s etcd-1 1/1 Running 0 4m29s etcd-2 1/1 Running 0 4m29s etcd-defrag-29128518-sstbf 0/1 Completed 0 90s ```
```bash kubectl logs etcd-defrag-29128518-sstbf -n etcd-cluster ```
Expected Output ```log Finished defragmenting etcd member[http://etcd-0.etcd-headless.etcd-cluster.svc.cluster.local:2379] Finished defragmenting etcd member[http://etcd-1.etcd-headless.etcd-cluster.svc.cluster.local:2379] Finished defragmenting etcd member[http://etcd-2.etcd-headless.etcd-cluster.svc.cluster.local:2379] ```
--- ## GreptimeDB Metasrv Metadata Management Overview # Overview GreptimeDB cluster Metasrv component requires a metadata storage to store metadata. GreptimeDB offers flexible metadata storage options with [etcd](https://etcd.io/), [MySQL](https://www.mysql.com/), and [PostgreSQL](https://www.postgresql.org/). Each option is designed for different deployment scenarios, balancing factors like scalability, reliability, and operational overhead. - [etcd](https://etcd.io/): A lightweight distributed key-value store perfect for metadata management. Its simplicity and ease of setup make it an excellent choice for development and testing environments. - [MySQL](https://www.mysql.com/) and [PostgreSQL](https://www.postgresql.org/): Enterprise-grade relational databases that deliver robust metadata storage capabilities. They provide essential features including ACID transactions, replication, and comprehensive backup solutions, making them ideal for production environments. Both are widely available as managed database services (RDS) across major cloud platforms. ## Recommendation For test and development environments, [etcd](https://etcd.io/) provides a lightweight and straightforward metadata storage solution. **For production deployments, we strongly recommend using cloud providers' Relational Database Service (RDS) for metadata storage.** This approach offers several advantages: - Managed service with built-in high availability and disaster recovery - Automated backups and maintenance - Professional monitoring and support - Reduced operational complexity compared to self-hosted solutions - Seamless integration with other cloud services ## Best Practices - Implement regular backup schedules for your metadata storage - Set up comprehensive monitoring for storage health and performance metrics - Establish clear disaster recovery procedures - Document your metadata storage configuration and maintenance procedures ## Next steps - To configure the metadata storage backend, please refer to [Configuration](/user-guide/deployments-administration/manage-metadata/configuration.md). - To setup etcd for testing and development environments, please refer to [Manage etcd](/user-guide/deployments-administration/manage-metadata/manage-etcd.md). --- ## Backup and Restore, Migrate GreptimeDB provides metadata backup and restore capabilities through its CLI tool. This functionality supports all major metadata storage backends including etcd, MySQL, and PostgreSQL. For detailed instructions on using these features, refer to the [Backup and Restore](/user-guide/deployments-administration/disaster-recovery/back-up-&-restore-data.md) guide. ## Backup For optimal backup reliability, schedule metadata backups during periods of low DDL (Data Definition Language) activity. This helps ensure data consistency and reduces the risk of partial or incomplete backups. To perform a backup: 1. Verify that your GreptimeDB cluster is operational 2. Execute the backup using the CLI tool, follows the export metadata steps in [Backup and Restore](/user-guide/deployments-administration/disaster-recovery/back-up-&-restore-meta-data.md) guide. 3. Ensure the backup output file is created, and the file size is greater than 0. ## Restore To restore from a backup: 1. Use the CLI tool to restore the metadata, follows the import metadata steps in [Backup and Restore](/user-guide/deployments-administration/disaster-recovery/back-up-&-restore-meta-data.md) guide. 2. Restart the GreptimeDB cluster to apply the restored metadata. 3. Set the [Next Table ID](/user-guide/deployments-administration/maintenance/sequence-management.md) to the original cluster's next table ID. 4. Call the [Table Reconciliation](/user-guide/deployments-administration/maintenance/table-reconciliation.md) function to repair the table metadata inconsistency. ## Migrate We recommend to migrate metadata during periods of low DDL (Data Definition Language) activity to ensure data consistency and minimize the risk of partial or incomplete migrations. Migrate metadata from one metadata storage to another. 1. Backup the metadata from the source storage. 2. Restore the metadata to the target storage. 3. Restart the whole GreptimeDB cluster(all components) to apply the restored metadata. --- ## Check GreptimeDB Status GreptimeDB provides a series of HTTP endpoints to query the operational status of GreptimeDB. The following HTTP requests assume that GreptimeDB is running on node `127.0.0.1` with the HTTP service listening on the default port `4000`. ## Check if GreptimeDB is running normally You can use the `/health` endpoint to check if GreptimeDB is running normally. An HTTP status code `200 OK` indicates that GreptimeDB is running normally. Example: ```bash curl -i -X GET http://127.0.0.1:4000/health ``` Output: ```text HTTP/1.1 200 OK content-type: application/json vary: origin, access-control-request-method, access-control-request-headers access-control-allow-origin: * content-length: 2 date: Sun, 26 Apr 2026 13:46:41 GMT {} ``` For more information about the health check endpoint, please refer to [the Health endpoint](/reference/http-endpoints.md#health-check). ## Check GreptimeDB status You can use the `/status` endpoint to check the deployment status of GreptimeDB. ```bash curl -X GET http://127.0.0.1:4000/status | jq ``` Output: ```json { "commit": "8d2f92c01ae762287a3cac587156519a536ae134", "branch": "", "rustc_version": "rustc 1.96.0-nightly (ac7f9ec7d 2026-03-20)", "hostname": "127.0.0.1", "version": "1.0.1" } ``` Please refer to [the Status endpoint](/reference/http-endpoints.md#status) for more details. --- ## Self-Monitoring GreptimeDB Clusters Before reading this document, ensure you understand how to [deploy a GreptimeDB cluster on Kubernetes](/user-guide/deployments-administration/deploy-on-kubernetes/deploy-greptimedb-cluster.md). This guide will walk you through configuring monitoring when deploying a GreptimeDB cluster. ## Quick Start You can enable monitoring and Grafana by adding configurations to the `values.yaml` file when deploying the GreptimeDB cluster using Helm Chart. Here's a complete example of `values.yaml` for deploying a minimal GreptimeDB cluster with monitoring and Grafana: ```yaml image: # Image registry: # Use `docker.io` for OSS GreptimeDB, # consult staff for Enterprise GreptimeDB registry: # Image repository: # Use `greptime/greptimedb` for OSS GreptimeDB # Consult staff for GreptimeDB Enterprise repository: # Image tag: # Use database version `v1.0.2` for OSS GreptimeDB # Consult staff for GreptimeDB Enterprise tag: pullSecrets: [] initializer: registry: docker.io repository: greptime/greptimedb-initializer tag: "v0.5.6" monitoring: # Enable monitoring enabled: true grafana: # Enable Grafana deployment # Requires monitoring to be enabled first (monitoring.enabled: true) enabled: true frontend: replicas: 1 meta: replicas: 1 backendStorage: etcd: endpoints: ["etcd.etcd-cluster.svc.cluster.local:2379"] datanode: replicas: 1 flownode: replicas: 1 ``` When `monitoring` is enabled, GreptimeDB Operator launches an additional GreptimeDB Standalone instance to collect metrics and logs from the GreptimeDB cluster. To collect log data, GreptimeDB Operator starts a [Vector](https://vector.dev/) sidecar container in each Pod. When `grafana` is enabled, a Grafana instance is deployed that uses the GreptimeDB Standalone instance configured for cluster monitoring as its data source. This enables visualization of the GreptimeDB cluster's monitoring data out of the box using both Prometheus and MySQL protocols. Then install the GreptimeDB cluster with the above `values.yaml` file: ```bash helm upgrade --install mycluster \ greptime/greptimedb-cluster \ --values /path/to/values.yaml \ -n default ``` After installation, you can check the Pod status of the GreptimeDB cluster: ```bash kubectl -n default get pods ```
Expected Output ```bash NAME READY STATUS RESTARTS AGE mycluster-datanode-0 2/2 Running 0 77s mycluster-flownode-0 2/2 Running 0 2m26s mycluster-frontend-6ffdd549b-9s7gx 2/2 Running 0 66s mycluster-grafana-675b64786-ktqps 1/1 Running 0 6m35s mycluster-meta-58bc88b597-ppzvj 2/2 Running 0 86s mycluster-monitor-standalone-0 1/1 Running 0 6m35s ```
You can then access the Grafana dashboard by port-forwarding the Grafana service to your local machine: ```shell kubectl -n default port-forward svc/mycluster-grafana 18080:80 ``` Then refer to the [Access Grafana Dashboard](#access-grafana-dashboard) section below for details on accessing Grafana. ## Monitoring Configuration This section covers the details of monitoring configurations. ### Enable Monitoring Add the following configuration to [`values.yaml`](/user-guide/deployments-administration/deploy-on-kubernetes/deploy-greptimedb-cluster.md#setup-valuesyaml) to enable monitoring when deploying the GreptimeDB cluster: ```yaml monitoring: enabled: true ``` This deploys a GreptimeDB Standalone instance named `${cluster-name}-monitoring` to collect metrics and logs. You can verify the deployment with: ```bash kubectl get greptimedbstandalones.greptime.io ${cluster-name}-monitoring -n ${namespace} ``` The GreptimeDB Standalone instance exposes services using `${cluster-name}-monitoring-standalone` as the Kubernetes Service name. You can use the following addresses to access monitoring data: - **Prometheus metrics**: `http://${cluster-name}-monitor-standalone.${namespace}.svc.cluster.local:4000/v1/prometheus` - **SQL logs**: `${cluster-name}-monitor-standalone.${namespace}.svc.cluster.local:4002`. By default, cluster logs are stored in the `public._gt_logs` table. ### Customize Monitoring Storage By default, the GreptimeDB Standalone instance stores monitoring data using the Kubernetes default StorageClass in local storage. You can configure the GreptimeDB Standalone instance through the `monitoring.standalone` field in `values.yaml`. For example, the following configuration uses S3 object storage to store monitoring data: ```yaml monitoring: enabled: true standalone: base: main: # Configure GreptimeDB Standalone instance image image: "greptime/greptimedb:v1.0.2" # Configure GreptimeDB Standalone instance resources resources: requests: cpu: "2" memory: "4Gi" limits: cpu: "2" memory: "4Gi" # Configure object storage for GreptimeDB Standalone instance objectStorage: s3: # Configure bucket bucket: "monitoring" # Configure region region: "ap-southeast-1" # Configure secret name secretName: "s3-credentials" # Configure root path root: "standalone-with-s3-data" ``` ### Customize Vector Sidecar The Vector sidecar configuration for log collection can be customized via the `monitoring.vector` field. For example, you can adjust the Vector image and resource limits as follows: ```yaml monitoring: enabled: true vector: # Configure Vector image registry registry: docker.io # Configure Vector image repository repository: timberio/vector # Configure Vector image tag tag: nightly-alpine # Configure Vector resources resources: requests: cpu: "50m" memory: "64Mi" limits: cpu: "50m" memory: "64Mi" ``` ### YAML Configuration with `kubectl` Deployment If you're not using Helm Chart, you can also use the `monitoring` field to manually configure self-monitoring mode in the `GreptimeDBCluster` YAML: ```yaml monitoring: enabled: true ``` For detailed configuration options, refer to the [`GreptimeDBCluster` API documentation](https://github.com/GreptimeTeam/greptimedb-operator/blob/main/docs/api-references/docs.md#monitoringspec). ## Grafana Configuration ### Enable Grafana To enable Grafana deployment, add the following configuration to `values.yaml`. Note that monitoring must be enabled first [(`monitoring.enabled: true`)](#enable-monitoring): ```yaml monitoring: enabled: true grafana: enabled: true ``` ### Customize Grafana Data Sources By default, Grafana uses `mycluster` and `default` as the cluster name and namespace to create data sources. To monitor clusters with different names or namespaces, you need to create custom data source configurations based on the actual cluster names and namespaces. Here's an example `values.yaml` configuration: ```yaml monitoring: enabled: true grafana: enabled: true datasources: datasources.yaml: datasources: # Query the cluster metrics. - name: greptimedb-metrics type: prometheus url: http://${cluster-name}-monitor-standalone.${namespace}.svc.cluster.local:4000/v1/prometheus access: proxy # Query the cluster traces. - name: greptimedb-traces type: jaeger url: http://${cluster-name}-monitor-standalone.${namespace}.svc.cluster.local:4000/v1/jaeger access: proxy # Query the cluster logs and slow queries. - name: greptimedb-logs type: mysql url: ${cluster-name}-monitor-standalone.${namespace}.svc.cluster.local:4002 access: proxy database: public # Query the information schema from the cluster. - name: information_schema type: mysql url: ${cluster-name}-frontend.${namespace}.svc.cluster.local:4002 access: proxy database: information_schema ``` This configuration creates the following data sources for GreptimeDB cluster monitoring in Grafana: - **`greptimedb-metrics`**: Cluster metrics stored in the standalone monitoring database, exposed via Prometheus protocol (`type: prometheus`) - **`greptimedb-logs`**: Cluster logs stored in the standalone monitoring database, exposed via MySQL protocol (`type: mysql`). Uses the `public` database by default - **`greptimedb-traces`**: Cluster traces stored in the standalone monitoring database, exposed via Jaeger protocol (`type: jaeger`). Uses the `public` database by default - **`information_schema`**: Cluster information stored in the frontend database, exposed via MySQL protocol (`type: mysql`). Uses the `information_schema` database by default ### Access Grafana Dashboard You can access the Grafana dashboard by port-forwarding the Grafana service to your local machine: ```bash kubectl -n ${namespace} port-forward svc/${cluster-name}-grafana 18080:80 ``` Then open `http://localhost:18080` to access the Grafana dashboard. The default login credentials for Grafana are: - **Username**: `admin` - **Password**: `gt-operator` Navigate to the `Dashboards` section to explore the pre-configured dashboards for monitoring your GreptimeDB cluster. ![Grafana Dashboard](/kubernetes-cluster-grafana-dashboard.jpg) ## Cleanup the PVCs :::danger The cleanup operation will remove the metadata and data of the GreptimeDB cluster. Please make sure you have backed up the data before proceeding. ::: To uninstall the GreptimeDB cluster, please refer to the [Cleanup GreptimeDB Cluster](/user-guide/deployments-administration/deploy-on-kubernetes/deploy-greptimedb-cluster.md#cleanup) documentation. To clean up the Persistent Volume Claims (PVCs) used by the GreptimeDB standalone monitoring instance, delete the PVCs using the following command: ```bash kubectl -n default delete pvc -l app.greptime.io/component=${cluster-name}-monitor-standalone ``` --- ## Key Logs During operation, GreptimeDB outputs key operations and unexpected error information to logs. You can use these logs to understand GreptimeDB's operational status and troubleshoot errors. ## Log Location GreptimeDB components default to outputting INFO level logs to the following locations: - Standard output - `greptimedb_data/logs` directory under GreptimeDB's current working directory The log output directory can also be modified through the `[logging]` section in the configuration file or the `--log_dir` startup parameter: ```toml [logging] dir = "/path/to/logs" ``` Log file formats are: - `greptimedb.YYYY-MM-DD-HH` contains logs of INFO level and above - `greptimedb-err.YYYY-MM-DD-HH` contains error logs For example: ```bash greptimedb.2025-04-11-06 greptimedb-err.2025-04-11-06 ``` Currently, GreptimeDB components include: - frontend - datanode - metasrv - flownode If you need to adjust log levels, such as viewing DEBUG level logs for a component, you can refer to [this document](https://github.com/GreptimeTeam/greptimedb/blob/main/docs/how-to/how-to-change-log-level-on-the-fly.md) to modify them at runtime. ## Important Logs The following lists recommended logs to monitor: ### Error Logs When the database is running normally and stably, it will not output error logs. If database operations encounter exceptions or panics occur, error logs will be printed. It is recommended that users check error logs from all components. #### Panic If the database encounters a panic, it is recommended to collect the panic logs and report them to the official team. Typical panic logs look like this, with the keyword `panicked at`: ```bash 2025-04-02T14:44:24.485935Z ERROR common_telemetry::panic_hook: panicked at /greptime/.cargo/git/checkouts/datafusion-11a8b534adb6bd68-shallow/2464703/datafusion/expr/src/logical_plan/plan.rs:1035:25: with_new_exprs for Distinct does not support sort expressions backtrace= 0: backtrace::backtrace::libunwind::trace at /greptime/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/backtrace-0.3.74/src/backtrace/libunwind.rs:116:5 backtrace::backtrace::trace_unsynchronized at /greptime/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/backtrace-0.3.74/src/backtrace/mod.rs:66:5 1: backtrace::backtrace::trace at /greptime/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/backtrace-0.3.74/src/backtrace/mod.rs:53:14 2: backtrace::capture::Backtrace::create at /greptime/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/backtrace-0.3.74/src/capture.rs:292:9 3: backtrace::capture::Backtrace::new at /greptime/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/backtrace-0.3.74/src/capture.rs:257:22 4: common_telemetry::panic_hook::set_panic_hook::{{closure}} at /greptime/codes/greptime/procedure-traits/src/common/telemetry/src/panic_hook.rs:37:25 5: as core::ops::function::Fn>::call at /rustc/409998c4e8cae45344fd434b358b697cc93870d0/library/alloc/src/boxed.rs:1984:9 std::panicking::rust_panic_with_hook at /rustc/409998c4e8cae45344fd434b358b697cc93870d0/library/std/src/panicking.rs:820:13 6: std::panicking::begin_panic_handler::{{closure}} at /rustc/409998c4e8cae45344fd434b358b697cc93870d0/library/std/src/panicking.rs:678:13 7: std::sys::backtrace::__rust_end_short_backtrace at /rustc/409998c4e8cae45344fd434b358b697cc93870d0/library/std/src/sys/backtrace.rs:168:18 8: rust_begin_unwind at /rustc/409998c4e8cae45344fd434b358b697cc93870d0/library/std/src/panicking.rs:676:5 9: core::panicking::panic_fmt at /rustc/409998c4e8cae45344fd434b358b697cc93870d0/library/core/src/panicking.rs:75:14 10: datafusion_expr::logical_plan::plan::LogicalPlan::with_new_exprs at /greptime/.cargo/git/checkouts/datafusion-11a8b534adb6bd68-shallow/2464703/datafusion/expr/src/logical_plan/plan.rs:1035:25 11: ::analyze::{{closure}} at /greptime/codes/greptime/procedure-traits/src/query/src/optimizer/type_conversion.rs:105:17 12: core::ops::function::impls::::call_mut at /greptime/.rustup/toolchains/nightly-2024-12-25-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/ops/function.rs:272:13 13: core::ops::function::impls::::call_once at /greptime/.rustup/toolchains/nightly-2024-12-25-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/ops/function.rs:305:13 14: datafusion_common::tree_node::Transformed::transform_parent at /greptime/.cargo/git/checkouts/datafusion-11a8b534adb6bd68-shallow/2464703/datafusion/common/src/tree_node.rs:764:44 15: datafusion_common::tree_node::TreeNode::transform_up::transform_up_impl::{{closure}} at /greptime/.cargo/git/checkouts/datafusion-11a8b534adb6bd68-shallow/2464703/datafusion/common/src/tree_node.rs:265:13 16: stacker::maybe_grow at /greptime/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/stacker-0.1.17/src/lib.rs:55:9 datafusion_common::tree_node::TreeNode::transform_up::transform_up_impl at /greptime/.cargo/git/checkouts/datafusion-11a8b534adb6bd68-shallow/2464703/datafusion/common/src/tree_node.rs:260:9 17: datafusion_common::tree_node::TreeNode::transform_up at /greptime/.cargo/git/checkouts/datafusion-11a8b534adb6bd68-shallow/2464703/datafusion/common/src/tree_node.rs:269:9 18: datafusion_common::tree_node::TreeNode::transform at /greptime/.cargo/git/checkouts/datafusion-11a8b534adb6bd68-shallow/2464703/datafusion/common/src/tree_node.rs:220:9 19: ::analyze at /greptime/codes/greptime/procedure-traits/src/query/src/optimizer/type_conversion.rs:46:9 20: query::query_engine::state::QueryEngineState::optimize_by_extension_rules::{{closure}} at /greptime/codes/greptime/procedure-traits/src/query/src/query_engine/state.rs:195:17 21: core::iter::traits::iterator::Iterator::try_fold at /greptime/.rustup/toolchains/nightly-2024-12-25-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/iter/traits/iterator.rs:2370:21 22: query::query_engine::state::QueryEngineState::optimize_by_extension_rules at /greptime/codes/greptime/procedure-traits/src/query/src/query_engine/state.rs:192:9 23: query::planner::DfLogicalPlanner::plan_sql::{{closure}}::{{closure}} at /greptime/codes/greptime/procedure-traits/src/query/src/planner.rs:119:20 24: as core::future::future::Future>::poll at /greptime/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tracing-0.1.40/src/instrument.rs:321:9 25: query::planner::DfLogicalPlanner::plan_sql::{{closure}} at /greptime/codes/greptime/procedure-traits/src/query/src/planner.rs:71:5 26: ::plan::{{closure}}::{{closure}} at /greptime/codes/greptime/procedure-traits/src/query/src/planner.rs:198:73 27: as core::future::future::Future>::poll at /greptime/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tracing-0.1.40/src/instrument.rs:321:9 28: ::plan::{{closure}} at /greptime/codes/greptime/procedure-traits/src/query/src/planner.rs:195:5 ... ``` ### Metasrv When the GreptimeDB cluster experiences node online/offline events, region migration, schema changes, etc., metasrv will record corresponding logs. Therefore, in addition to error logs from each component, it is also recommended to monitor the following metasrv log keywords: #### Metasrv Leader Step Down/Election ```bash // Error level, indicates current leader stepped down, new election will follow. Note the {:?} part is the leader identifier "Leader :{:?} step down" ``` #### Region Lease Renewal Failure ```bash // Warning level, indicates a region lease renewal was denied. Region lease requests will be rejected when the region is not properly closed/scheduled on a datanode. Denied to renew region lease for datanode: {datanode_id}, region_id: {region_id} ``` ```bash // Info level, datanode receives lease renewal failure and attempts to close target region Closing staled region: ``` #### Region Failover ```bash // Warning level, detects some regions failed Phi health check, need to execute failover operation. Region IDs will be printed after the colon Detects region failures: // A region migration failed Failed to wait region migration procedure // Info level, when maintenance mode is enabled, failover procedure will be skipped Maintenance mode is enabled, skip failover ``` #### Region Migration ```bash // Info level, indicates a region starts migration. Region information will be printed after the log Starting region migration procedure // Error level, a region migration failed Failed to wait region migration procedure ``` #### Procedure Metasrv internally uses a component called "procedure" to execute distributed operations. You can monitor error logs from this component: ```bash Failed to execute procedure ``` #### Flow Creation Failure When flow creation fails, the failure reason can usually be seen in procedure error logs. Logs may contain the following keywords: ```bash Failed to execute procedure metasrv-procedure:: CreateFlow ``` ### Datanode #### Compaction When compaction starts and ends, datanode will log the following information: ```bash 2025-05-16T06:01:08.794415Z INFO mito2::compaction::task: Compacted SST files, region_id: 4612794875904(1074, 0), input: [FileMeta { region_id: 4612794875904(1074, 0), file_id: FileId(a29500fb-cae0-4f3f-8376-cb3f14653378), time_range: (1686455010000000000::Nanosecond, 1686468410000000000::Nanosecond), level: 0, file_size: 45893329, available_indexes: [], index_file_size: 0, num_rows: 5364000, num_row_groups: 53, sequence: Some(114408000) }, FileMeta { region_id: 4612794875904(1074, 0), file_id: FileId(a31dcb1b-19ae-432f-8482-9e1b7db7b53b), time_range: (1686468420000000000::Nanosecond, 1686481820000000000::Nanosecond), level: 0, file_size: 45900506, available_indexes: [], index_file_size: 0, num_rows: 5364000, num_row_groups: 53, sequence: Some(119772000) }], output: [FileMeta { region_id: 4612794875904(1074, 0), file_id: FileId(5d105ca7-9e3c-4298-afb3-e85baae3b2e8), time_range: (1686455010000000000::Nanosecond, 1686481820000000000::Nanosecond), level: 1, file_size: 91549797, available_indexes: [], index_file_size: 0, num_rows: 10728000, num_row_groups: 105, sequence: Some(119772000) }], window: Some(86400), waiter_num: 0, merge_time: 3.034328293s ``` ```bash 2025-05-16T06:01:08.805366Z INFO mito2::request: Successfully compacted region: 4612794875904(1074, 0) ``` --- ## Prometheus-Monitoring GreptimeDB Cluster Before reading this document, ensure you understand how to [deploy a GreptimeDB cluster on Kubernetes](/user-guide/deployments-administration/deploy-on-kubernetes/deploy-greptimedb-cluster.md). It is recommended to use [self-monitoring mode](cluster-monitoring-deployment.md) to monitor GreptimeDB cluster, as it's simple to set up and provides out-of-the-box Grafana dashboards. However, if you already have a Prometheus instance deployed in your Kubernetes cluster and want to integrate GreptimeDB cluster metrics into it, follow the steps below. ## Check the Prometheus Instance Configuration Ensure you have deployed the Prometheus Operator and created a Prometheus instance. For example, you can use [kube-prometheus-stack](https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack) to deploy the Prometheus stack. Refer to its [official documentation](https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack) for more details. When deploying the Prometheus instance, ensure you set the labels used for scraping GreptimeDB cluster metrics. For example, your existing Prometheus instance may contain the following configuration: ```yaml apiVersion: monitoring.coreos.com/v1 kind: PodMonitor metadata: name: greptime-podmonitor namespace: default spec: selector: matchLabels: release: prometheus # other configurations... ``` When the `PodMonitor` is deployed, the Prometheus Operator continuously watches for pods in the `default` namespace that match all labels defined in `spec.selector.matchLabels` (in this example, `release: prometheus`). ## Enable `prometheusMonitor` for GreptimeDB Cluster When deploying a GreptimeDB cluster using a Helm Chart, enable the `prometheusMonitor` field in your `values.yaml` file. For example: ```yaml prometheusMonitor: # Enable Prometheus monitoring - this will create PodMonitor resources enabled: true # Configure scrape interval interval: "30s" # Configure labels labels: release: prometheus ``` **Important:** The `labels` field value (`release: prometheus`) must match the `matchLabels` field used to create the Prometheus instance, otherwise metrics collection won't work properly. After configuring `prometheusMonitor`, the GreptimeDB Operator will automatically create `PodMonitor` resources and import metrics into Prometheus at the specified `interval`. You can check the `PodMonitor` resources with: ``` kubectl get podmonitors.monitoring.coreos.com -n ${namespace} ``` :::note If you're not using a Helm Chart, you can manually configure Prometheus monitoring in the `GreptimeDBCluster` YAML: ```yaml apiVersion: greptime.io/v1alpha1 kind: GreptimeDBCluster metadata: name: basic spec: base: main: image: greptime/greptimedb:v1.0.2 frontend: replicas: 1 meta: replicas: 1 backendStorage: etcd: endpoints: - "etcd.etcd-cluster.svc.cluster.local:2379" datanode: replicas: 1 prometheusMonitor: enabled: true interval: "30s" labels: release: prometheus ``` ::: ## Grafana Dashboards You need to deploy Grafana by yourself, then import the dashboards. ### Add Data Sources After deploying Grafana, refer to Grafana's [data sources](https://grafana.com/docs/grafana/latest/datasources/) documentation to add the following two type data sources: - **Prometheus**: Name it `metrics`. This data source connects to your Prometheus instance, which collects GreptimeDB cluster monitoring metrics. Use your Prometheus instance URL as the connection URL. - **MySQL**: Name it `information-schema`. This data source connects to your GreptimeDB cluster to access cluster metadata via the SQL protocol. If you have deployed GreptimeDB following the [Deploy a GreptimeDB Cluster on Kubernetes](/user-guide/deployments-administration/deploy-on-kubernetes/deploy-greptimedb-cluster.md) guide, use `${cluster-name}-frontend.${namespace}.svc.cluster.local:4002` as the server address with database `information_schema`. ### Import Dashboards The [GreptimeDB Cluster Metrics Dashboard](https://github.com/GreptimeTeam/greptimedb/tree/v1.0.2/grafana/dashboards/metrics/cluster) uses the `metrics` and `information-schema` data sources to display GreptimeDB cluster metrics. Refer to Grafana's [Import dashboards](https://grafana.com/docs/grafana/latest/dashboards/build-dashboards/import-dashboards/) documentation to learn how to import dashboards. --- ## Monitoring Effective database administration relies heavily on monitoring. You can monitor GreptimeDB using the following methods: --- ## Runtime Information The `INFORMATION_SCHEMA` database provides access to system metadata, such as the name of a database or table, the data type of a column, etc. * Find the topology information of the cluster though [CLUSTER_INFO](/reference/sql/information-schema/cluster-info.md) table. * Find the table regions distribution though [PARTITIONS](/reference/sql/information-schema/partitions.md) and [REGION_PEERS](/reference/sql/information-schema/region-peers.md) tables. For example, find all the region id of a table: ```sql SELECT greptime_partition_id FROM PARTITIONS WHERE table_name = 'monitor' ``` Find the distribution of all regions in a table: ```sql SELECT b.peer_id as datanode_id, a.greptime_partition_id as region_id FROM information_schema.partitions a LEFT JOIN information_schema.region_peers b ON a.greptime_partition_id = b.region_id WHERE a.table_name='monitor' ORDER BY datanode_id ASC ``` For more information about the `INFORMATION_SCHEMA` database, Please read the [reference](/reference/sql/information-schema/overview.md). --- ## Slow Query (Experimental) GreptimeDB provides a slow query log to help you find and fix slow queries. By default, the slow queries are output to the system table `greptime_private.slow_queries` with `30s` threshold and `1.0` sample ratio with `30d` TTL. The schema of the `greptime_private.slow_queries` table is as follows: ```sql +--------------+----------------------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +--------------+----------------------+------+------+---------+---------------+ | cost | UInt64 | | NO | | FIELD | | threshold | UInt64 | | NO | | FIELD | | query | String | | NO | | FIELD | | is_promql | Boolean | | NO | | FIELD | | timestamp | TimestampNanosecond | PRI | NO | | TIMESTAMP | | promql_range | UInt64 | | NO | | FIELD | | promql_step | UInt64 | | NO | | FIELD | | promql_start | TimestampMillisecond | | NO | | FIELD | | promql_end | TimestampMillisecond | | NO | | FIELD | +--------------+----------------------+------+------+---------+---------------+ ``` - `cost`: The cost of the query in milliseconds. - `threshold`: The threshold of the query in milliseconds. - `query`: The query string. - `is_promql`: Whether the query is a PromQL query. - `timestamp`: The timestamp of the query. - `promql_range`: The range of the query. Only used when `is_promql` is `true`. - `promql_step`: The step of the query. Only used when `is_promql` is `true`. - `promql_start`: The start time of the query. Only used when `is_promql` is `true`. - `promql_end`: The end time of the query. Only used when `is_promql` is `true`. In cluster mode, you can configure the slow query in frontend configs (same as in standalone mode), for example: ```toml [slow_query] ## Whether to enable slow query log. enable = true ## The record type of slow queries. It can be `system_table` or `log`. ## If `system_table` is selected, the slow queries will be recorded in a system table `greptime_private.slow_queries`. ## If `log` is selected, the slow queries will be logged in a log file `greptimedb-slow-queries.*`. record_type = "system_table" ## The threshold of slow query. It can be human readable time string, for example: `10s`, `100ms`, `1s`. threshold = "30s" ## The sampling ratio of slow query log. The value should be in the range of (0, 1]. For example, `0.1` means 10% of the slow queries will be logged and `1.0` means all slow queries will be logged. sample_ratio = 1.0 ## The TTL of the `slow_queries` system table. Default is `30d` when `record_type` is `system_table`. ttl = "30d" ``` If you use the Helm chart to deploy GreptimeDB, you can configure the slow query in the `values.yaml` file, for example: ```yaml slowQuery: enable: true recordType: "system_table" threshold: "30s" sampleRatio: "1.0" ttl: "30d" ``` If you use `log` as the record type, the slow queries will be logged in a log file `greptimedb-slow-queries.*`. By default, the log file is located in the `${data_home}/logs` directory. --- ## Standalone Monitoring GreptimeDB standalone provides a `/metrics` endpoint on the HTTP port (default `4000`) that exposes [Prometheus metrics](/reference/http-endpoints.md#metrics). You can use Prometheus to scrape these metrics and Grafana to visualize them. ## Grafana Dashboard Integration GreptimeDB provides pre-built Grafana dashboards for monitoring standalone deployments. You can access the dashboard JSON files from the [GreptimeDB repository](https://github.com/GreptimeTeam/greptimedb/tree/v1.0.2/grafana/dashboards/metrics/standalone). --- ## Tracing GreptimeDB supports distributed tracing. GreptimeDB exports all collected spans using the gRPC-based OTLP protocol. Users can use [Jaeger](https://www.jaegertracing.io/), [Tempo](https://grafana.com/oss/tempo/) and other OTLP protocol backends that support gRPC to collect the span instrument by GreptimeDB. In the [logging section](/user-guide/deployments-administration/configuration.md#logging-options) in the configuration, there are descriptions of configuration items related to tracing, [standalone.example.toml](https://github.com/GreptimeTeam/greptimedb/blob/v1.0.2/config/standalone.example.toml) provide a reference configuration in the logging section. ## Dynamic Tracing Control GreptimeDB provides the ability to enable or disable tracing dynamically at runtime using the HTTP API without requiring a server restart. This is useful for troubleshooting production issues or temporarily enabling tracing for debugging purposes. To enable tracing: ```bash curl --data "true" http://127.0.0.1:4000/debug/enable_trace # Output: trace enabled ``` To disable tracing: ```bash curl --data "false" http://127.0.0.1:4000/debug/enable_trace # Output: trace disabled ``` ## Tutorial: Use Jaeger to trace GreptimeDB [Jaeger](https://www.jaegertracing.io/) is an open source, end-to-end distributed tracing system, originally developed and open sourced by Uber. Its goal is to help developers monitor and debug the request flow in complex microservice architectures. Jaeger supports gRPC-based OTLP protocol, so GreptimeDB can export trace data to Jaeger. The following tutorial shows you how to deploy and use Jaeger to track GreptimeDB. ### Step 1: Deploy Jaeger Start a Jaeger instance using the `all-in-one` docker image officially provided by jaeger: ```bash docker run --rm -d --name jaeger \ -e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \ -p 6831:6831/udp \ -p 6832:6832/udp \ -p 5778:5778 \ -p 16686:16686 \ -p 4317:4317 \ -p 4318:4318 \ -p 14250:14250 \ -p 14268:14268 \ -p 14269:14269 \ -p 9411:9411 \ jaegertracing/all-in-one:latest ``` ### Step 2: Deploy GreptimeDB Write configuration files to allow GreptimeDB to perform tracing. Save the following configuration items as the file `config.toml` ```Toml [logging] enable_otlp_tracing = true ``` Then start GreptimeDB using standalone mode ```bash greptime standalone start -c config.toml ``` Refer to the chapter [MySQL](/user-guide/protocols/mysql.md) on how to connect to GreptimeDB. Run the following SQL statement in MySQL Client: ```sql CREATE TABLE host ( ts timestamp(3) time index, host STRING PRIMARY KEY, val BIGINT, ); INSERT INTO TABLE host VALUES (0, 'host1', 0), (20000, 'host2', 5); SELECT * FROM host ORDER BY ts; DROP TABLE host; ``` ### Step 3: Obtain trace information in Jaeger 1. Go to http://127.0.0.1:16686/ and select the Search tab. 2. Select the `greptime-standalone` service in the service drop-down list. 3. Click **Find Traces** to display trace information. ![JaegerUI](/jaegerui.png) ![Select-tracing](/select-tracing.png) ## Guide: How to configure tracing sampling rate GreptimeDB provides many protocols and interfaces for data insertion, query and other functions. You can collect the calling chains of each operation through tracing. However, for some high-frequency operations, collecting all tracing of the operation may be unnecessary and waste storage space. At this time, you can use `tracing_sample_ratio` to set the sampling rate of tracing for various operations, which can greatly reduce the number of exported tracing and facilitate system observation. All tracing within GreptimeDB is classified according to the protocol it is connected to and the corresponding operations of that protocol: | **protocol** | **request_type** | |--------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | grpc | inserts / query.sql / query.logical_plan / query.prom_range / query.empty / ddl.create_database / ddl.create_table / ddl.alter / ddl.drop_table / ddl.truncate_table / ddl.empty / deletes / row_inserts / row_deletes | | mysql | | | postgres | | | otlp | metrics / traces | | opentsdb | | | influxdb | write_v1 / write_v2 | | prometheus | remote_read / remote_write / format_query / instant_query / range_query / labels_query / series_query / label_values_query | | http | sql / promql You can configure different tracing sampling rates through `tracing_sample_ratio`. ```toml [logging] enable_otlp_tracing = true [logging.tracing_sample_ratio] default_ratio = 0.0 [[logging.tracing_sample_ratio.rules]] protocol = "mysql" ratio = 1.0 [[logging.tracing_sample_ratio.rules]] protocol = "grpc" request_types = ["inserts"] ratio = 0.3 ``` The above configuration formulates two sampling rules and sets a default sampling rate. GreptimeDB will start matching from the first one according to the sampling rules, and use the first matching sampling rule as the sampling rate of the tracing. If no rule matches, `default_ratio` will be used as the default sampling rate. The range of sampling rate is `[0.0, 1.0]`, `0.0` means not sampling, `1.0` means sampling all tracing. For example, according to the rules provided above, all calls accessed using the mysql protocol will be sampled, data inserted using grpc will be sampled 30%, and all remaining tracing will not be sampled. --- ## Deployments & Administration GreptimeDB can be deployed and managed either on your own infrastructure or through GreptimeCloud. This guide provides an overview of deployment strategies, configuration, monitoring, and administration. ## GreptimeDB Architecture Before diving into the deployment and administration of GreptimeDB, it's important to understand its [architecture](/user-guide/concepts/architecture.md). ## Self-Managed GreptimeDB Deployment This section outlines the key aspects of deploying and administering GreptimeDB in your own environment. ### Configuration and Deployment - **Configuration:** Before deployment, [check the configuration](configuration.md) to suit your requirements, including protocol settings, storage options, and more. - **Authentication:** By default, authentication is not enabled. Learn how to [enable and configure authentication](./authentication/overview.md) for secure deployments. - **Kubernetes Deployment:** Follow the [step-by-step guide](./deploy-on-kubernetes/overview.md) to deploy GreptimeDB on Kubernetes. - **Capacity Planning:** Ensure your deployment can handle your workload by [planning for capacity](/user-guide/deployments-administration/capacity-plan.md). ### Component Management - **Cluster Failover:** Set up [Remote WAL](./wal/remote-wal/configuration.md) for high availability. - **Manage Metadata:** Set up [Metadata Storage](./manage-data/overview.md) for GreptimeDB. ### Monitoring - **Monitoring:** [Monitor cluster's health and performance](./monitoring/overview.md) through metrics, tracing, and runtime information. ### Data Management and Performance - **Data Management:** [Manage your data](/user-guide/deployments-administration/manage-data/overview.md) to prevent data loss, reduce costs, and optimize performance. - **Performance Tuning:** Review [performance tuning tips](/user-guide/deployments-administration/performance-tuning/performance-tuning-tips.md) and learn how to [design your table schema](/user-guide/deployments-administration/performance-tuning/design-table.md) for optimal efficiency. ### Disaster Recovery - **Disaster Recovery:** Implement [disaster recovery strategies](/user-guide/deployments-administration/disaster-recovery/overview.md) to protect your data and ensure business continuity. ### Additional Topics - **Run on Android:** Learn how to [run GreptimeDB on Android devices](run-on-android.md). - **Upgrade:** Follow the [upgrade guide](/user-guide/deployments-administration/upgrade.md) to keep the version of GreptimeDB up to date. --- ## Design Your Table Schema The design of your table schema significantly impacts both write and query performance. Before writing data, it is crucial to understand the data types, scale, and common queries relevant to your business, then model the data accordingly. This document provides a comprehensive guide on GreptimeDB's data model and table schema design for various scenarios. ## Understanding GreptimeDB's Data Model Before proceeding, please review the GreptimeDB [Data Model Documentation](/user-guide/concepts/data-model.md). ## Basic Concepts ### Cardinality **Cardinality**: Refers to the number of unique values in a dataset. It can be classified as "high cardinality" or "low cardinality": - **Low Cardinality**: Low cardinality columns usually have constant values. The total number of unique values usually no more than 10 thousand. For example, `namespace`, `cluster`, `http_method` are usually low cardinality. - **High Cardinality**: High cardinality columns contain a large number of unique values. For example, `trace_id`, `span_id`, `user_id`, `uri`, `ip`, `uuid`, `request_id`, table auto increment id, timestamps are usually high cardinality. ### Column Types In GreptimeDB, columns are categorized into three semantic types: `Tag`, `Field`, and `Timestamp`. The timestamp usually represents the time of data sampling or the occurrence time of logs/events. GreptimeDB uses the `TIME INDEX` constraint to identify the `Timestamp` column. So the `Timestamp` column is also called the `TIME INDEX` column. If you have multiple columns with timestamp data type, you can only define one as `TIME INDEX` and others as `Field` columns. In GreptimeDB, tag columns are optional. The main purposes of tag columns include: 1. Defining the ordering of data in storage. GreptimeDB reuses the `PRIMARY KEY` constraint to define tag columns and the ordering of tags. Unlike traditional databases, GreptimeDB defines time-series by the primary key. Tables in GreptimeDB sort rows in the order of `(primary key, timestamp)`. This improves the locality of data with the same tags. If there are no tag columns, GreptimeDB sorts rows by timestamp. 2. Identifying a unique time-series. When the table is not append-only, GreptimeDB can deduplicate rows by timestamp under the same time-series (primary key). 3. Smoothing migration from other TSDBs that use tags or labels. ## Primary key ### Primary key is optional Bad primary key or index may significantly degrade performance. Generally you can create an append-only table without a primary key since ordering data by timestamp is sufficient for many workloads. It can also serve as a baseline. ```sql CREATE TABLE http_logs ( access_time TIMESTAMP TIME INDEX, application STRING, remote_addr STRING, http_status STRING, http_method STRING, http_refer STRING, user_agent STRING, request_id STRING, request STRING, ) with ('append_mode'='true'); ``` The `http_logs` table is an example for storing HTTP server logs. - The `'append_mode'='true'` option creates the table as an append-only table. This ensures a log doesn't override another one with the same timestamp. - The table sorts logs by time so it is efficient to search logs by time. ### Primary key design and SST format You can use primary key when there are suitable columns and one of the following conditions is met: - Most queries can benefit from the ordering. - You need to deduplicate (including delete) rows by the primary key and time index. For example, if you always only query logs of a specific application, you may set the `application` column as primary key (tag). ```sql SELECT message FROM http_logs WHERE application = 'greptimedb' AND access_time > now() - '5 minute'::INTERVAL; ``` The number of applications is usually limited. Table `http_logs_v2` uses `application` as the primary key. It sorts logs by application so querying logs under the same application is faster as it only has to scan a small number of rows. Setting tags may also reduce disk space usage as it improves the locality of data. ```sql CREATE TABLE http_logs_v2 ( access_time TIMESTAMP TIME INDEX, application STRING, remote_addr STRING, http_status STRING, http_method STRING, http_refer STRING, user_agent STRING, request_id STRING, request STRING, PRIMARY KEY(application), ) with ('append_mode'='true'); ``` A long primary key will negatively affect the insert performance and enlarge the memory footprint. It's recommended to define a primary key with no more than 5 columns. #### Choosing the SST format GreptimeDB supports two [SST formats](/reference/sql/create.md#create-a-table-with-sst-format): `flat` (the default) and `primary_key`. They are tuned for different primary key cardinalities. The default `flat` format works well across a wide range of primary key cardinalities, including high cardinality columns such as `trace_id`, `span_id`, or `user_id`. With `flat`, you can put high cardinality columns into the primary key when ordering by them benefits queries, or when you need to deduplicate by them. Note that deduplication on high cardinality primary keys is always expensive — if you can tolerate duplication, use an append-only table for the best performance. ```sql CREATE TABLE http_logs_v3 ( access_time TIMESTAMP TIME INDEX, application STRING, remote_addr STRING, http_status STRING, http_method STRING, http_refer STRING, user_agent STRING, request_id STRING, request STRING, PRIMARY KEY(application, request_id), ) with ('append_mode'='true'); ``` The `primary_key` format may deliver better performance when the primary key cardinality is low (typically no more than 100 thousand unique values). In general, prefer the default `flat` format unless you have measured that `primary_key` is a better fit. You can switch the format on an existing table with `ALTER TABLE`. Older versions of GreptimeDB used `primary_key` as the default, so if you upgraded from an older version or are not sure which format a table currently uses, you can switch it to `flat`: ```sql -- Switch to flat (the default). ALTER TABLE http_logs_v3 SET 'sst_format' = 'flat'; -- Opt into primary_key for low cardinality primary keys. ALTER TABLE http_logs_v3 SET 'sst_format' = 'primary_key'; ``` Recommendations for tags: - Low cardinality columns that occur in `WHERE`/`GROUP BY`/`ORDER BY` frequently. These columns usually remain constant. For example, `namespace`, `cluster`, or an AWS `region`. - No need to set all low cardinality columns as tags since this may impact the performance of ingestion and querying. - Typically use short strings and integers for tags, avoiding `FLOAT`, `DOUBLE`, `TIMESTAMP`. - High cardinality columns such as `trace_id`, `span_id`, and `user_id` can also be used as tags under the default `flat` format. ## Index Besides primary key, you can also use index to accelerate specific queries on demand. ### Inverted Index GreptimeDB supports inverted index that may speed up filtering low cardinality columns. When creating a table, you can specify the [inverted index](/contributor-guide/datanode/data-persistence-indexing.md#inverted-index) columns using the `INVERTED INDEX` clause. For example, `http_logs_v3` adds an inverted index for the `http_method` column. ```sql CREATE TABLE http_logs_v3 ( access_time TIMESTAMP TIME INDEX, application STRING, remote_addr STRING, http_status STRING, http_method STRING INVERTED INDEX, http_refer STRING, user_agent STRING, request_id STRING, request STRING, PRIMARY KEY(application), ) with ('append_mode'='true'); ``` The following query can use the inverted index on the `http_method` column. ```sql SELECT message FROM http_logs_v3 WHERE application = 'greptimedb' AND http_method = `GET` AND access_time > now() - '5 minute'::INTERVAL; ``` Inverted index supports the following operators: - `=` - `<` - `<=` - `>` - `>=` - `IN` - `BETWEEN` - `~` ### Skipping Index For high cardinality columns like `trace_id`, `request_id`, using a [skipping index](/user-guide/manage-data/data-index.md#skipping-index) is more appropriate. This method has lower storage overhead and resource usage, particularly in terms of memory and disk consumption. Example: ```sql CREATE TABLE http_logs_v4 ( access_time TIMESTAMP TIME INDEX, application STRING, remote_addr STRING, http_status STRING, http_method STRING INVERTED INDEX, http_refer STRING, user_agent STRING, request_id STRING SKIPPING INDEX, request STRING, PRIMARY KEY(application), ) with ('append_mode'='true'); ``` The following query can use the skipping index to filter the `request_id` column. ```sql SELECT message FROM http_logs_v4 WHERE application = 'greptimedb' AND request_id = `25b6f398-41cf-4965-aa19-e1c63a88a7a9` AND access_time > now() - '5 minute'::INTERVAL; ``` However, note that the query capabilities of the skipping index are generally inferior to those of the inverted index. Skipping index can't handle complex filter conditions and may have a lower filtering performance on low cardinality columns. It only supports the equal operator. ### Full-Text Index For unstructured log messages that require tokenization and searching by terms, GreptimeDB provides full-text index. For example, the `raw_logs` table stores unstructured logs in the `message` field. ```sql CREATE TABLE IF NOT EXISTS `raw_logs` ( message STRING NULL FULLTEXT INDEX WITH(analyzer = 'English', case_sensitive = 'false'), ts TIMESTAMP(9) NOT NULL, TIME INDEX (ts), ) with ('append_mode'='true'); ``` The `message` field is full-text indexed using the `FULLTEXT INDEX` option. See [fulltext column options](/reference/sql/create.md#fulltext-column-option) for more information. Storing and querying structured logs usually have better performance than unstructured logs with full-text index. It's recommended to [use Pipeline](/user-guide/logs/quick-start.md#create-a-pipeline) to convert logs into structured logs. ### When to use index Index in GreptimeDB is flexible and powerful. You can create an index for any column, no matter if the column is a tag or a field. It's meaningless to create additional index for the timestamp column. Generally you don't need to create indexes for all columns. Maintaining indexes may introduce additional cost and stall ingestion. A bad index may occupy too much disk space and make queries slower. You can use a table without additional index as a baseline. There is no need to create an index for the table if the query performance is already acceptable. You can create an index for a column when: - The column occurs in the filter frequently. - Filtering the column without an index isn't fast enough. - There is a suitable index for the column. The following table lists the suitable scenarios of all index types. | | Inverted Index | Full-Text Index | Skip Index| | ----- | ----------- | ------------- |------------- | | Suitable Scenarios | - Filtering low cardinality columns | - Text content search | - Precise filtering high cardinality columns | | Creation Method | - Specified using `INVERTED INDEX` |- Specified using `FULLTEXT INDEX` in column options | - Specified using `SKIPPING INDEX` in column options | ## Deduplication If deduplication is necessary, you can use the default table options, which sets the `append_mode` to `false` and enables deduplication. ```sql CREATE TABLE IF NOT EXISTS system_metrics ( host STRING, cpu_util DOUBLE, memory_util DOUBLE, disk_util DOUBLE, ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY(host), TIME INDEX(ts) ); ``` GreptimeDB deduplicates rows by the same primary key and timestamp if the table isn't append-only. For example, the `system_metrics` table removes duplicate rows by `host` and `ts`. ### Data updating and merging GreptimeDB supports two different strategies for deduplication: `last_row` and `last_non_null`. You can specify the strategy by the `merge_mode` table option. GreptimeDB uses an LSM Tree-based storage engine, which does not overwrite old data in place but allows multiple versions of data to coexist. These versions are merged during the query process. The default merge behavior is `last_row`, meaning the most recently inserted row takes precedence. ![merge-mode-last-row](/merge-mode-last-row.png) In `last_row` merge mode, the latest row is returned for queries with the same primary key and time value, requiring all Field values to be provided during updates. For scenarios where only specific Field values need updating while others remain unchanged, the `merge_mode` option can be set to `last_non_null`. This mode retains the latest non-null value for each field during queries, allowing updates to provide only the values that need to change. ![merge-mode-last-non-null](/merge-mode-last-non-null.png) The `last_non_null` merge mode is the default for tables created automatically via the InfluxDB line protocol, aligning with InfluxDB's update behavior. The `last_row` merge mode doesn't have to check each individual field value so it is usually faster than the `last_non_null` mode. Note that `merge_mode` cannot be set for Append-Only tables, as they do not perform merges. ### When to use append-only tables If you don't need the following features, you can use append-only tables: - Deduplication - Deletion GreptimeDB implements `DELETE` via deduplicating rows so append-only tables don't support deletion now. Deduplication requires more computation and restricts the parallelism of ingestion and querying. Using append-only tables usually has better query performance. ## Wide Table vs. Multiple Tables In monitoring or IoT scenarios, multiple metrics are often collected simultaneously. We recommend placing metrics collected simultaneously into a single table to improve read/write throughput and data compression efficiency. ![wide_table](/wide_table.png) Although Prometheus uses single-value model for metrics, GreptimeDB's Prometheus Remote Storage protocol supports sharing a wide table for metrics at the underlying layer through the [Metric Engine](/contributor-guide/datanode/metric-engine.md). ## Distributed Tables GreptimeDB supports partitioning data tables to distribute read/write hotspots and achieve horizontal scaling. ### Two misunderstandings about distributed tables As a time-series database, GreptimeDB automatically partitions data based on the TIME INDEX column at the storage layer. Therefore, it is unnecessary and not recommended for you to partition data by time (e.g., one partition per day or one table per week). Additionally, GreptimeDB is a columnar storage database, so partitioning a table refers to horizontal partitioning by rows, with each partition containing all columns. ### When to Partition and Determining the Number of Partitions A table can utilize all the resources in the machine, especially during query. Partitioning a table may not always improve the performance: - A distributed query plan isn't always as efficient as a local query plan. - Distributed query may introduce additional data transmission across the network. There is no need to partition a table unless a single machine isn't enough to serve the table. For example: - There is not enough local disk space to store the data or to cache the data when using object stores. - You need more CPU cores to improve the query performance or more memory for costly queries. - The disk throughput becomes the bottleneck. - The ingestion rate is larger than the throughput of a single node. GreptimeDB releases a [benchmark report](https://github.com/GreptimeTeam/greptimedb/tree/v1.0.2/docs/benchmarks/tsbs) with each major version update, detailing the ingestion throughput of a single partition. Use this report alongside your target scenario to estimate if the write volume approaches the single partition's limit. To estimate the total number of partitions, consider the write throughput and reserve an additional 50% resource of CPU to ensure query performance and stability. Adjust this ratio as necessary. You can reserve more CPU cores if there are more queries. ### Partitioning Methods GreptimeDB employs expressions to define partitioning rules. For optimal performance, select partition keys that are evenly distributed, stable, and align with query conditions. Examples include: - Partitioning by the prefix of a trace id. - Partitioning by data center name. - Partitioning by business name. The partition key should closely match the query conditions. For instance, if most queries target data from a specific data center, using the data center name as a partition key is appropriate. If the data distribution is not well understood, perform aggregate queries on existing data to gather relevant information. For more details, refer to the [table partition guide](/user-guide/deployments-administration/manage-data/table-sharding.md#partition). --- ## Performance Tuning Tips A GreptimeDB instance's default configuration may not fit all use cases. It's important to tune the database configurations and usage according to the scenario. GreptimeDB provides various metrics to help monitor and troubleshoot performance issues. The official repository provides [Grafana dashboard templates](https://github.com/GreptimeTeam/greptimedb/tree/main/grafana) for both standalone and cluster modes. ## Query ### ANALYZE QUERY GreptimeDB supports query analysis functionality. Using the `EXPLAIN ANALYZE [VERBOSE] ` statement, you can view step-by-step query execution times. ### Metrics The following metrics help diagnose query performance issues: | Metric | Type | Description | |---|---|---| | greptime_mito_read_stage_elapsed_bucket | histogram | The elapsed time of different phases of a query in the storage engine. | | greptime_mito_cache_bytes | gauge | Size of cached contents | | greptime_mito_cache_hit | counter | Total count of cache hit | | greptime_mito_cache_miss | counter | Total count of cache miss | ### Enlarging cache size You can monitor the `greptime_mito_cache_bytes` and `greptime_mito_cache_miss` metrics to determine if you need to increase the cache size. The `type` label in these metrics indicates the type of cache. If the `greptime_mito_cache_miss` metric is consistently high and increasing, or if the `greptime_mito_cache_bytes` metric reaches the cache capacity, you may need to adjust the cache size configurations of the storage engine. Here is an example: ```toml [[region_engine]] [region_engine.mito] # Cache size for the write cache. The `type` label value for this cache is `file`. write_cache_size = "10G" # Download files from object storage to fill the cache on write cache miss enable_refill_cache_on_read = true # Cache size for SST metadata. The `type` label value for this cache is `sst_meta`. sst_meta_cache_size = "128MB" # Cache size for vectors and arrow arrays. The `type` label value for this cache is `vector`. vector_cache_size = "512MB" # Cache size for pages of SST row groups. The `type` label value for this cache is `page`. page_cache_size = "512MB" # Cache size for time series selector (e.g. `last_value()`). The `type` label value for this cache is `selector_result`. selector_result_cache_size = "512MB" [region_engine.mito.index] ## The max capacity of the index staging directory. staging_size = "10GB" ``` Some tips: - 1/10 of disk space for the write cache at least. It's recommended to use a large write cache when using object storage. - When using object storage, GreptimeDB automatically downloads files to fill the write cache on cache misses by default (`enable_refill_cache_on_read = true`). This improves query performance but may increase network traffic. Consider disabling this if you want to minimize network usage or storage costs. - 1/4 of total memory for the `page_cache_size` at least if the memory usage is under 20% - Double the cache size if the cache hit ratio is less than 50% - If using full-text index, leave 1/10 of disk space for the `staging_size` at least ### Choosing the right SST format GreptimeDB supports two [SST formats](/reference/sql/create.md#create-a-table-with-sst-format): `flat` and `primary_key`. Choosing the right one based on the cardinality of your primary key can significantly improve performance. - **`flat` format (default)**: Optimized for high cardinality primary keys. If your primary key contains columns like `trace_id` or `uuid`, the `flat` format delivers better write and query performance. For tables with high cardinality primary keys, also consider using an [append-only table](/reference/sql/create.md#create-an-append-only-table) to further improve performance. - **`primary_key` format**: May offer better performance when the primary key cardinality is not high. See [Choosing the SST format](/user-guide/deployments-administration/performance-tuning/design-table.md#choosing-the-sst-format) for more details, including how to switch the format on existing tables. ### Using append-only table if possible In general, append-only tables have a higher scan performance as the storage engine can skip merging and deduplication. What's more, the query engine can use statistics to speed up some queries if the table is append-only. We recommend enabling the [append_mode](/reference/sql/create.md#create-an-append-only-table) for the table if it doesn't require deduplication or performance is prioritized over deduplication. For example, a log table should be append-only as log messages may have the same timestamp. ### Disable Write-Ahead-Log(WAL) If you are consuming and writing to GreptimeDB from replayable data sources such as Kafka, you can further improve write throughput by disabling WAL. Please note that when WAL is disabled, unflushed data to disk or object storage will not be recoverable and will need to be restored from the original data source, such as re-reading from Kafka or re-fetching logs. Disable WAL by setting the table option `skip_wal='true'`: ```sql CREATE TABLE logs( message STRING, ts TIMESTAMP TIME INDEX ) WITH (skip_wal = 'true'); ``` ## Ingestion ### Metrics The following metrics help diagnose ingestion issues: | Metric | Type | Description | | -------------------------------------------- | --------- | ---------------------------------------------------------------------------------------- | | greptime_mito_write_stage_elapsed_bucket | histogram | The elapsed time of different phases of processing a write request in the storage engine | | greptime_mito_write_buffer_bytes | gauge | The current estimated bytes allocated for the write buffer (memtables). | | greptime_mito_write_rows_total | counter | The number of rows written to the storage engine | | greptime_mito_write_stall_total | gauge | The number of rows currently stalled due to high memory pressure | | greptime_mito_write_reject_total | counter | The number of rows rejected due to high memory pressure | | raft_engine_sync_log_duration_seconds_bucket | histogram | The elapsed time of flushing the WAL to the disk | | greptime_mito_flush_elapsed | histogram | The elapsed time of flushing the SST files | ### Batching rows Batching means sending multiple rows to the database over the same request. This can significantly improve ingestion throughput. A recommended starting point is 1000 rows per batch. You can enlarge the batch size if latency and resource usage are still acceptable. ### Writing by time window Although GreptimeDB can handle out-of-order data, it still affects performance. GreptimeDB infers a time window size from ingested data and partitions the data into multiple time windows according to their timestamps. If the written rows are not within the same time window, GreptimeDB needs to split them, which affects write performance. Generally, real-time data doesn't have the issues mentioned above as they always use the latest timestamp. If you need to import data with a long time range into the database, we recommend creating the table in advance and [specifying the compaction.twcs.time_window option](/reference/sql/create.md#create-a-table-with-custom-compaction-options). ## Schema ### Using multiple fields While designing the schema, we recommend putting related metrics that can be collected together in the same table. This can also improve the write throughput and compression ratio. For example, the following three tables collect the CPU usage metrics. ```sql CREATE TABLE IF NOT EXISTS cpu_usage_user ( hostname STRING NULL, usage_value BIGINT NULL, ts TIMESTAMP(9) NOT NULL, TIME INDEX (ts), PRIMARY KEY (hostname) ); CREATE TABLE IF NOT EXISTS cpu_usage_system ( hostname STRING NULL, usage_value BIGINT NULL, ts TIMESTAMP(9) NOT NULL, TIME INDEX (ts), PRIMARY KEY (hostname) ); CREATE TABLE IF NOT EXISTS cpu_usage_idle ( hostname STRING NULL, usage_value BIGINT NULL, ts TIMESTAMP(9) NOT NULL, TIME INDEX (ts), PRIMARY KEY (hostname) ); ``` We can merge them into one table with three fields. ```sql CREATE TABLE IF NOT EXISTS cpu ( hostname STRING NULL, usage_user BIGINT NULL, usage_system BIGINT NULL, usage_idle BIGINT NULL, ts TIMESTAMP(9) NOT NULL, TIME INDEX (ts), PRIMARY KEY (hostname) ); ``` --- ## Run on Android Platforms Since v0.4.0, GreptimeDB supports running on Android platforms with ARM64 CPU and Android API level >= 23. ## Install terminal emulator on Android You can install [Termux](https://termux.dev/) from [GitHub release page](https://github.com/termux/termux-app/releases/latest). ## Download GreptimeDB Android binary. ```bash VERSION=$(curl -sL \ -H "Accept: application/vnd.github+json" \ -H "X-GitHub-Api-Version: 2022-11-28" \ "https://api.github.com/repos/GreptimeTeam/greptimedb/releases/latest" | sed -n 's/.*"tag_name": "\([^"]*\)".*/\1/p') curl -sOL "https://github.com/GreptimeTeam/greptimedb/releases/download/${VERSION}/greptime-android-arm64-${VERSION}.tar.gz" tar zxvf ./greptime-android-arm64-${VERSION}.tar.gz ./greptime -V ``` If binary's downloaded correctly, the command is expected to print the version of downloaded binary. ## Create GreptimeDB configuration file You can create a minimal configuration file that allows access from local network. ```bash DATA_DIR="$(pwd)/greptimedb-data" mkdir -p ${DATA_DIR} cat < ./config.toml [http] addr = "0.0.0.0:4000" [grpc] bind_addr = "0.0.0.0:4001" [mysql] addr = "0.0.0.0:4002" [storage] data_home = "${DATA_DIR}" type = "File" EOF ``` ## Start GreptimeDB from command line ```bash ./greptime --log-dir=$(pwd)/logs standalone start -c ./config.toml ``` ## Connect to GreptimeDB running on Android > You can find the IP address of your Android device from system settings or `ifconfig`. You can now connect to the GreptimeDB instance running on Android from another device with MySQL client installed. ```bash mysql -h -P 4002 ``` And play like on any other platforms! ``` Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 8 Server version: 5.1.10-alpha-msql-proxy Greptime Copyright (c) 2000, 2023, Oracle and/or its affiliates. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> CREATE TABLE monitor (env STRING, host STRING, ts TIMESTAMP, cpu DOUBLE DEFAULT 0, memory DOUBLE, TIME INDEX (ts), PRIMARY KEY(env,host)); Query OK, 0 rows affected (0.14 sec) mysql> INSERT INTO monitor(ts, env, host, cpu, memory) VALUES -> (1655276557000,'prod', 'host1', 66.6, 1024), -> (1655276557000,'prod', 'host2', 66.6, 1024), -> (1655276557000,'prod', 'host3', 66.6, 1024), -> (1655276558000,'prod', 'host1', 77.7, 2048), -> (1655276558000,'prod', 'host2', 77.7, 2048), -> (1655276558000,'test', 'host3', 77.7, 2048), -> (1655276559000,'test', 'host1', 88.8, 4096), -> (1655276559000,'test', 'host2', 88.8, 4096), -> (1655276559000,'test', 'host3', 88.8, 4096); Query OK, 9 rows affected (0.14 sec) mysql> mysql> select * from monitor where env='test' and host='host3'; +------+-------+---------------------+------+--------+ | env | host | ts | cpu | memory | +------+-------+---------------------+------+--------+ | test | host3 | 2022-06-15 15:02:38 | 77.7 | 2048 | | test | host3 | 2022-06-15 15:02:39 | 88.8 | 4096 | +------+-------+---------------------+------+--------+ 2 rows in set (0.20 sec) ``` --- ## Troubleshooting When encountering errors or performance issues, you can understand GreptimeDB's status through metrics and logs. This information can also help further investigate the root causes of problems. The following lists troubleshooting methods for some common abnormal situations. For cases where the cause cannot be easily identified, providing metrics and logs to the official team can also improve the efficiency of official troubleshooting. ## Checking CPU and Memory Load You can directly view the CPU and Memory load of corresponding components from the Dashboard. CPU is displayed in millicores, while Memory shows the current process RSS. You need to pay attention to whether the corresponding CPU and Memory load exceeds the Pod's Limit. If CPU has reached the Pod's Limit, throttling will be triggered, and clients will experience slower request processing. If Memory reaches over 70% of the Limit, it may result in OOM (Out of Memory). ## Flow Creation Failure When flow creation fails, one common scenario is that flownode is not deployed. You can check: - Whether flownode is deployed in the cluster - Whether the flownode status in the cluster is READY If flownode is already deployed, you can further investigate by examining metasrv and flownode logs, or check whether the flow node was successfully created through internal tables: ```sql select * from information_schema.cluster_info; ``` ## Object Storage Configuration Issues When object storage is misconfigured, GreptimeDB will encounter exceptions when accessing object storage. If GreptimeDB hasn't stored any data, it generally doesn't need to access object storage, so errors might not be observable immediately after deployment. Once you create a table or start writing data to GreptimeDB through write protocols, you can observe request errors. Typically, DB error messages will include object storage error details. You can find specific object storage error information through DB error logs. Some common error causes include: - Incorrect Access Key or Secret Access Key - Improper object storage permission configuration - If using Tencent Cloud COS's S3-compatible API, since Tencent Cloud has [disabled path-style domains](https://cloud.tencent.com/document/product/436/102489), you need to set `enable_virtual_host_style = true` in GreptimeDB's S3 configuration For S3 as an example, GreptimeDB requires the following permissions: ```txt "s3:PutObject", "s3:ListBucket", "s3:GetObject", "s3:DeleteObject" ``` ## Low Write Throughput You can observe write throughput through the Ingestion-related panels in the dashboard: ![ingestion rate](/ingestion-rate.jpg) If write throughput is lower than expected load it might be due to high write latency causing DB backlog. The dashboard provides panels in the `Frontend Requests` area to observe request latency: ![p99-latencies](/dashboard-p99-latencies.jpg) You can check if any nodes are experiencing stall through the `Write Stall` panel in the `Mito Engine` area (stall values remaining above 0 for extended periods). If so, it indicates that node writes have encountered bottlenecks. ![write-stall](/write-stall.jpg) By observing the `Write Buffer` panel, you can also monitor size changes in buffers used for writing. If buffers fill up quickly, consider proportionally increasing `global_write_buffer_size` and `global_write_buffer_reject_size`: ![write-buffer](/write-buffer.jpg) The Write Stage panel shows which stages have high write latency: ![write-stage](/write-stage.jpg) You can check background task status through Compaction/Flush related panels: - Whether frequent flush operations occur; if so, consider proportionally increasing `global_write_buffer_size` and `global_write_buffer_reject_size` - Whether there are long-running compaction and flush operations; if so, writes might be affected by these background tasks Additionally, logs related to `flush memtables` can show the latency of individual flush operations. ## High Memory Consumption During Writes During DB write operations, the total size of all memtables is estimated. You can view memtable memory usage through the `Write Buffer` panel. ![write-buffer-memtable](/write-buffer-memtable.jpg) Note that these values might be smaller than the actual allocated memory. If you notice that DB memory grows too quickly during writes, or if writes frequently encounter OOM situations, this might be related to unreasonable table schema design. A common cause is improper Primary Key design. If there are too many primary keys, it will consume excessive memory during writes, potentially causing database memory usage to become too high. In such cases, `Write Buffer` often remains at high levels. Increasing write buffer size generally won't improve this issue; you need to reduce the number of primary key columns or remove high-cardinality primary key columns. ## High Query Latency If query latency is high, you can add `EXPLAIN ANALYZE` or `EXPLAIN ANALYZE VERBOSE` before the query and re-execute it. The query results will include execution time for each stage to assist in troubleshooting. Additionally, the `Read Stage` panel can help understand query latency across different stages: ![read-stage](/read-stage.jpg) ## Cache Full To understand the size of various caches, you can check the used size of different caches on nodes through the `Cached Bytes` panel: ![cached-bytes](/cached-bytes.jpg) For nodes with high query latency, you can also determine if caches are full by checking cache sizes. ## Object Storage Latency You can view object storage operation latency through panels in the `OpenDAL` area of the dashboard. For example, the following panel shows response latency for object storage write operations: ![opendal](/opendal.jpg) If you suspect object storage operations are experiencing jitter, you can observe the related panels. --- ## Upgrade ## Overview This guide provides upgrade instructions for GreptimeDB, including compatibility information and breaking changes for each version. Before upgrading, ensure you review the relevant breaking changes for your upgrade path. For complete version history and feature additions, see the [Release Notes](/release-notes/). ## Upgrade Paths to v1.0 ### From v0.16 to v1.0 If you are currently running v0.16, you can upgrade directly to v1.0. See [Upgrading from v0.16 to v1.0](#upgrading-from-v016-to-v10) for all relevant breaking changes. ### From v0.17 to v1.0 If you are currently running v0.17, you can upgrade directly to v1.0. See [Upgrading from v0.17 to v1.0](#upgrading-from-v017-to-v10) for breaking changes. ### From Earlier Versions **Important:** This guide only covers upgrades from v0.16 and later versions. If you are running a version earlier than v0.16, you must first upgrade to v0.16 by following the upgrade documentation for your current version. Once you have successfully upgraded to v0.16, you can then use this guide to upgrade to v1.0. ## Breaking Changes by Version ### Upgrading from v0.17 to v1.0 #### Jaeger HTTP Header Removal **Impact:** HTTP header deprecation The HTTP header `x-greptime-jaeger-time-range-for-operations` has been deprecated and removed. **Action Required:** - If you configured this header in your Jaeger data source or proxy, remove it from your configuration - The header will no longer have any effect #### Metric Engine Default Sparse Primary Key Encoding **Impact:** Default configuration change with performance improvements Metric Engine now enables **sparse primary key encoding** by default to improve storage efficiency and query performance for metric scenarios. **Configuration Changes:** - **NEW default:** `sparse_primary_key_encoding = true` - **DEPRECATED:** `experimental_sparse_primary_key_encoding` (use `sparse_primary_key_encoding` instead) **Action Required:** - This change does not cause data format compatibility issues - All metric tables will automatically use sparse encoding by default - If you want to continue using the old encoding method, explicitly set: ```toml [metric_engine] sparse_primary_key_encoding = false ``` #### `greptime_identity` Pipeline JSON Behavior Change **Impact:** JSON processing logic change The JSON processing logic in `greptime_identity` pipeline has changed significantly: **New Behavior:** - Nested JSON objects are automatically flattened into separate columns using dot notation (e.g., `object.a`, `object.b`) - Arrays are stored as JSON strings instead of JSON objects - The `flatten_json_object` parameter has been removed - A new `max_nested_levels` parameter controls flattening depth (default: 10 levels) - When the depth limit is exceeded, remaining nested structures are serialized as JSON strings **Action Required:** 1. Review your pipeline configurations that use `greptime_identity` 2. Remove any usage of the deprecated `flatten_json_object` parameter 3. Adjust queries that reference nested JSON fields to use the new dot notation 4. If you have deeply nested JSON (>10 levels), consider setting `max_nested_levels` appropriately **Example:** Before (v0.17): ```json { "user": { "name": "Alice", "age": 30 } } ``` Stored as a single JSON column. After (v1.0): ``` user.name = "Alice" user.age = 30 ``` Stored as separate columns. #### Metric Engine TSID Generation Algorithm Change **Impact:** Time Series ID generation optimization with query implications The TSID (Time Series ID) generation algorithm has been optimized by replacing `mur3::Hasher128` with the higher-performance `fxhash::FxHasher`, including a fast-path for series without NULL labels. **Performance Improvements:** - Regular scenarios: 5-6x faster - Scenarios with NULL labels: ~2.5x faster **Breaking Change Impact:** This is a **breaking change** that affects time series identification: - **Before upgrade (time < t):** Data uses the old algorithm to generate TSIDs - **After upgrade (time > t):** Data uses the new algorithm to generate TSIDs **Query Behavior:** - Queries with time ranges that **span the upgrade time `t`** may experience slight discrepancies in time series matching near time `t` - Queries with time ranges that **do not include `t`** are not affected **Action Required:** Choose one of the following upgrade strategies: 1. **Direct Upgrade (Recommended for most users):** - Accept minor query discrepancies near the upgrade time - Suitable if approximate results near the upgrade time are acceptable 2. **Export-Upgrade-Import (For zero tolerance):** - If you cannot accept any discrepancies, use this fully compatible upgrade method: 1. Export all data before upgrading 2. Upgrade to v1.0 3. Import data back into the new version - Refer to [Backup & Restore Documentation](/user-guide/deployments-administration/disaster-recovery/back-up-&-restore-data/) ### Upgrading from v0.16 to v1.0 If you are upgrading from v0.16, you need to review: 1. **All breaking changes from v0.17 to v1.0** (listed above) 2. **v0.17.0 breaking changes** (listed below) This ensures you're aware of all changes that occurred between v0.16 and v1.0. ### v0.17.0 Breaking Changes #### Ordered-Set Aggregate Functions **Impact:** SQL syntax change Ordered-set aggregate functions now require a `WITHIN GROUP (ORDER BY …)` clause. **Before:** ```sql SELECT approx_percentile_cont(latency, 0.95) FROM metrics; ``` **After:** ```sql SELECT approx_percentile_cont(0.95) WITHIN GROUP (ORDER BY latency) FROM metrics; ``` **Action Required:** Update all queries using ordered-set aggregate functions (`approx_percentile_cont`, `approx_percentile_cont_weight`, etc.) to include the `WITHIN GROUP (ORDER BY …)` clause. #### MySQL Protocol Comment Styling **Impact:** Comment syntax strictness Incorrect comment styling is no longer allowed in MySQL protocol. Comments must start with `--` instead of `---`. **Before:** ```sql --- This is a comment SELECT * FROM table; ``` **After:** ```sql -- This is a comment SELECT * FROM table; ``` **Action Required:** Update any SQL scripts or queries that use `---` style comments to use the standard `--` format. ## Additional v1.0 Changes (Non-Breaking) ### v1.0.0-beta.3 #### Cache Configuration Improvements The cache architecture has been refactored for better performance: **New Configuration:** - `region_engine.mito.manifest_cache_size` (default: 256MB) - specialized manifest file cache **Removed Configuration:** - `storage.cache_path` - `storage.enable_read_cache` - `storage.cache_capacity` **Action Required:** Update your configuration files to use the new `manifest_cache_size` setting and remove the deprecated storage cache options. ### v1.0.0-beta.2 #### Improved Database Compatibility - Numeric type aliases aligned with PostgreSQL and MySQL standards - Better PostgreSQL extended query support - Improved MySQL binary protocol handling **Action Required:** Test your applications to ensure compatibility with the improved behavior. ## Minimizing Business Impact During Upgrade Before upgrading GreptimeDB, it is essential to perform a comprehensive backup of your data to safeguard against potential data loss. This backup acts as a safety measure in the event of any issues during the upgrade process. ### Best Practices #### Rolling Upgrade Utilize [rolling upgrades](https://kubernetes.io/docs/tutorials/kubernetes-basics/update/update-intro/) on Kubernetes to update GreptimeDB instances incrementally. This approach replaces old instances with new ones while maintaining service availability and minimizing downtime. #### Automatic Retries Configure client applications to enable automatic retries with exponential backoff. This helps handle temporary service interruptions gracefully. #### Temporary Pause of Write Operations For applications that can tolerate brief maintenance windows, consider pausing write operations during the upgrade to ensure data consistency. #### Double Writing Implement double writing to both the old and new versions of GreptimeDB, then switch to the new version once you have verified that it is functioning correctly. This allows you to verify data consistency and gradually redirect read traffic to the upgraded version. ## Upgrade Checklist Before upgrading to v1.0, complete the following checklist: ### Pre-Upgrade - [ ] Review all breaking changes relevant to your upgrade path - [ ] **Backup all data and configurations** - [ ] Identify queries using ordered-set aggregate functions (if upgrading from v0.16 or earlier) - [ ] Identify pipelines using `greptime_identity` with JSON data - [ ] Check for usage of deprecated Jaeger HTTP header (if upgrading from v0.17 or earlier) - [ ] Review metric tables if using Metric Engine ### Configuration Updates - [ ] Update configuration files (remove deprecated cache settings) - [ ] Update metric engine configuration if needed (`sparse_primary_key_encoding`) - [ ] Update pipeline configurations (remove `flatten_json_object`, add `max_nested_levels` if needed) ### Code Updates - [ ] Update SQL queries with ordered-set aggregates to use `WITHIN GROUP (ORDER BY ...)` - [ ] Update SQL scripts using `---` comments to use `--` - [ ] Update queries that access nested JSON fields to use dot notation - [ ] Remove Jaeger header configuration if present ### Testing & Deployment - [ ] Test the upgrade in a non-production environment - [ ] Verify query results, especially for: - Ordered-set aggregate functions - Nested JSON data access - Metric queries (if affected by TSID change) - [ ] Plan for rolling upgrade or maintenance window - [ ] Prepare rollback plan in case of issues - [ ] Monitor system behavior after upgrade ### Special Considerations for Metric Engine Users If you cannot accept query discrepancies near the upgrade time due to TSID algorithm change: - [ ] Plan for export-upgrade-import process - [ ] Allocate sufficient time for data export and import - [ ] Refer to [Backup & Restore Documentation](/user-guide/deployments-administration/disaster-recovery/back-up-&-restore-data/) --- ## Local WAL This section describes how to configure the local WAL for GreptimeDB Datanode component. ```toml [wal] provider = "raft_engine" file_size = "128MB" purge_threshold = "1GB" purge_interval = "1m" read_batch_size = 128 sync_write = false ``` ## Options If you are using Helm Chart to deploy GreptimeDB, you can refer to [Common Helm Chart Configurations](/user-guide/deployments-administration/deploy-on-kubernetes/common-helm-chart-configurations.md) to learn how to configure the Datanode by injecting configuration files. | Configuration Option | Description | Default Value | | -------------------- | -------------------------------------------------------------------------------------------------------------------- | ----------------- | | `provider` | The provider of the WAL. Options: `raft_engine` (local file system storage), `kafka` (remote WAL storage in Kafka), or `noop` (no-op WAL provider) | `"raft_engine"` | | `dir` | The directory where to write logs | `{data_home}/wal` | | `file_size` | The size of single WAL log file | `128MB` | | `purge_threshold` | The threshold of the WAL size to trigger purging | `1GB` | | `purge_interval` | The interval to trigger purging | `1m` | | `read_batch_size` | The read batch size | `128` | | `sync_write` | Whether to call fsync when writing every log | `false` | ## Best practices ### Using a separate High-Performance Volume for WAL It is beneficial to configure a separate volume for the WAL (Write-Ahead Log) directory when deploying GreptimeDB. This setup allows you to: - Leverage a high-performance disk—either a dedicated physical volume or one provisioned via a custom `StorageClass`. - Isolate WAL I/O from cache file access, reducing I/O contention and enhancing overall system performance. If you are using Helm Chart to deploy GreptimeDB, you can refer to [Common Helm Chart Configurations](/user-guide/deployments-administration/deploy-on-kubernetes/common-helm-chart-configurations.md) to learn how to configure a dedicated WAL volume. --- ## Noop WAL Noop WAL is a special WAL provider for emergency situations when the configured WAL provider becomes temporarily unavailable. It does not store any WAL data. ## Availability Noop WAL is **only available in cluster mode**, not in standalone mode. ## Use Cases - **Temporary WAL Unavailability**: When the WAL provider (e.g., Kafka) is temporarily unavailable, switch the Datanode to Noop WAL to keep the cluster running. - **Testing and Development**: Useful for testing scenarios where WAL persistence is not required. ## Data Loss Warning **When using Noop WAL, all unflushed data will be lost when the Datanode is shutdown or restarted.** Only use this provider temporarily when the normal WAL provider is unavailable. Not recommended for production use except in emergency situations. ## Configuration To configure Noop WAL for a Datanode: ```toml [wal] provider = "noop" ``` In a GreptimeDB cluster, WAL configuration has two parts: - **Metasrv** - Generates WAL metadata for new regions. Should be set to `raft_engine` or `kafka`. - **Datanode** - Reads and writes WAL data. Configure as `noop` when the WAL provider is unavailable. Note: Noop WAL can only be configured on Datanode, not on Metasrv. When using Noop WAL on Datanode, Metasrv continues using its configured WAL provider. ## Best Practices - Flush regions regularly using `admin flush_table()` or `admin flush_region()` to minimize data loss. - Switch back to the normal WAL provider as soon as it becomes available. --- ## GreptimeDB WAL Overview # Overview The [Write-Ahead Logging](/contributor-guide/datanode/wal.md#introduction)(WAL) is a crucial component in GreptimeDB that persistently records every data modification to ensure no memory-cached data loss. GreptimeDB provides three WAL storage options: - **Local WAL**: Uses an embedded storage engine([raft-engine](https://github.com/tikv/raft-engine)) within the [Datanode](/user-guide/concepts/why-greptimedb.md). - **Remote WAL**: Uses [Apache Kafka](https://kafka.apache.org/) as the external(remote) WAL storage component. - **Noop WAL**: A no-op WAL provider for emergency situations when WAL becomes unavailable. Does not store any data. ## Local WAL ### Advantages - **Low latency**: The local WAL is stored within the same process as the Datanode, eliminating network overhead and providing low write latency. - **Easy to deploy**: Since the WAL is co-located with the Datanode, no additional components are required, simplifying deployment and operations. - **Zero RPO**: When deploying GreptimeDB in the cloud, you can configure persistent storage for WAL data using cloud storage services such as AWS EBS or GCP Persistent Disk. This ensures zero [Recovery Point Objective](https://en.wikipedia.org/wiki/Disaster_recovery#Recovery_Point_Objective) (RPO), meaning no data loss, even in the event of system failure. ### Disadvantages - **High RTO**: Because the WAL resides on the same node as the Datanode, the [Recovery Time Objective](https://en.wikipedia.org/wiki/Disaster_recovery#Recovery_Time_Objective) (RTO) is relatively high. After a Datanode restarts, it must replay the WAL to restore the latest data, during which time the node remains unavailable. - **Single-Point Access Limitation**: The local WAL is tightly coupled with the Datanode process and only supports a single consumer, which limits features such as region hot standby and [Region Migration](/user-guide/deployments-administration/manage-data/region-migration.md). ## Remote WAL ### Advantages - **Low RTO**: By decoupling WAL from the Datanode, [Recovery Time Objective](https://en.wikipedia.org/wiki/Disaster_recovery#Recovery_Time_Objective) (RTO) is minimized. If a Datanode crashes, the Metasrv can quickly trigger a [Region Failover](/user-guide/deployments-administration/manage-data/region-failover.md) to migrate affected regions to healthy nodes—without the need to replay WAL locally. - **Multi-Consumer Subscriptions**: Remote WAL supports multiple consumers subscribing to WAL logs simultaneously, enabling features such as region hot standby and [Region Migration](/user-guide/deployments-administration/manage-data/region-migration.md), thereby enhancing system availability and flexibility. ### Disadvantages - **External dependencies**: Remote WAL relies on an external Kafka cluster, which increases the complexity of deployment, operation, and maintenance. - **Network overhead**: Since WAL data needs to be transmitted over the network, careful planning of cluster network bandwidth is required to ensure low latency and high throughput, especially under write-heavy workloads. ## Noop WAL Noop WAL is a special WAL provider for emergency situations when the configured WAL provider becomes temporarily unavailable. It does not store any WAL data and is only available in cluster mode. For detailed configuration, see the [Noop WAL](/user-guide/deployments-administration/wal/noop-wal.md) page. ## Next steps - To configure the Local WAL storage, please refer to [Local WAL](/user-guide/deployments-administration/wal/local-wal.md). - To learn more about the Remote WAL, please refer to [Remote WAL](/user-guide/deployments-administration/wal/remote-wal/configuration.md). - To learn more about the Noop WAL, please refer to [Noop WAL](/user-guide/deployments-administration/wal/noop-wal.md). --- ## GreptimeDB Remote WAL Configuration # Configuration The configuration of Remote WAL contains two parts: - Metasrv Configuration - Datanode Configuration If you are using Helm Chart to deploy GreptimeDB, you can refer to [Common Helm Chart Configurations](/user-guide/deployments-administration/deploy-on-kubernetes/common-helm-chart-configurations.md) to learn how to configure Remote WAL. ## Metasrv Configuration On the Metasrv side, Remote WAL is primarily responsible for managing Kafka topics and periodically pruning stale WAL data. ```toml [wal] provider = "kafka" broker_endpoints = ["kafka.kafka-cluster.svc.cluster.local:9092"] # WAL data pruning options auto_prune_interval = "30m" auto_prune_parallelism = 10 flush_trigger_size = "512MB" checkpoint_trigger_size = "128MB" # Topic creation options auto_create_topics = true num_topics = 64 replication_factor = 1 topic_name_prefix = "greptimedb_wal_topic" create_topic_timeout = "30s" ``` ### Options | Configuration Option | Description | |----------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `provider` | The WAL provider to use. Set to `"kafka"` to enable Remote WAL with Kafka. | | `broker_endpoints` | List of Kafka broker addresses to connect to. Example: `["kafka.kafka-cluster.svc:9092"]`. | | `auto_prune_interval` | How often to automatically prune (delete) stale WAL data. Specify as a duration string (e.g., `"30m"`). Set to `"0s"` to disable automatic pruning. | | `auto_prune_parallelism` | Maximum number of concurrent pruning tasks. Increasing this value may speed up pruning but will use more resources. | | `auto_create_topics` | If `true`, Metasrv will automatically create required Kafka topics. If `false`, you must manually create all topics before starting Metasrv. | | `num_topics` | Number of Kafka topics to use for WAL storage. More topics can improve scalability and performance. | | `replication_factor` | Replication factor for Kafka topics. Determines how many Kafka brokers will store copies of each topic's data. | | `topic_name_prefix` | Prefix for Kafka topic names. WAL topics will be named as `{topic_name_prefix}_{index}` (e.g., `greptimedb_wal_topic_0`). The prefix must match the regex `[a-zA-Z_:-][a-zA-Z0-9_:\-\.@#]*`. | | `flush_trigger_size` | Estimated size threshold (e.g., `"512MB"`) for triggering a flush operation in a region. Calculated as `(latest_entry_id - flushed_entry_id) * avg_record_size`. When this value exceeds `flush_trigger_size`, MetaSrv initiates a flush. Set to `"0"` to let the system automatically determine the flush trigger size. This also controls the maximum replay size from a topic during region replay; using a smaller value can help reduce region replay time during Datanode startup. | | `checkpoint_trigger_size` | Estimated size threshold (e.g., `"128MB"`) for triggering a checkpoint operation in a region. Calculated as `(latest_entry_id - last_checkpoint_entry_id) * avg_record_size`. When this value exceeds `checkpoint_trigger_size`, MetaSrv initiates a checkpoint. Set to `"0"` to let the system automatically determine the checkpoint trigger size. Using a smaller value can help reduce region replay time during Datanode startup. | | `create_topic_timeout` | The timeout for creating a Kafka topic. Default is `"30s"`. | #### Topic Setup and Kafka Permissions To ensure Remote WAL works correctly with Kafka, please check the following: - If `auto_create_topics = false`: - All required topics must be created manually **before** starting Metasrv. - Topic names must follow the pattern `{topic_name_prefix}_{index}` where `index` ranges from `0` to `{num_topics - 1}`. For example, with the default prefix `greptimedb_wal_topic` and `num_topics = 64`, you need to create topics from `greptimedb_wal_topic_0` to `greptimedb_wal_topic_63`. - Topics must be configured to support **LZ4 compression**. - The Kafka user must have the following permissions: - **Append** records to WAL topics (requires LZ4 compression support). - **Read** records from WAL topics (requires LZ4 compression support). - **Delete** records from WAL topics. - **Create** topics (only required if `auto_create_topics = true`). ## Datanode Configuration The Datanode side is mainly used to write the data to the Kafka topics and read the data from the Kafka topics. ```toml [wal] provider = "kafka" broker_endpoints = ["kafka.kafka-cluster.svc:9092"] max_batch_bytes = "1MB" overwrite_entry_start_id = true connect_timeout = "3s" timeout = "3s" ``` ### Options | Configuration Option | Description | | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | | `provider` | Set to "kafka" to enable Remote WAL via Kafka. | | `broker_endpoints` | List of Kafka broker addresses. | | `max_batch_bytes` | Maximum size for each Kafka producer batch. | | `overwrite_entry_start_id` | If true, the Datanode will skip over missing entries during WAL replay. Prevents out-of-range errors, but may hide data loss. | | `connect_timeout` | The connect timeout for Kafka client. Default is `"3s"`. | | `timeout` | The timeout for Kafka client operations. Default is `"3s"`. | #### Required Settings and Limitations :::warning IMPORTANT: Kafka Retention Policy Configuration Please configure Kafka retention policy very carefully to avoid data loss. GreptimeDB will automatically recycle unneeded WAL data, so in most cases you don't need to set the retention policy. However, if you do set it, please ensure the following: - **Size-based retention**: Typically not needed, as the database manages its own data lifecycle - **Time-based retention**: If you choose to set this, ensure it's **significantly greater than the auto-flush-interval** to prevent premature data deletion Improper retention settings can lead to data loss if WAL data is deleted before GreptimeDB has processed it. ::: - If you set `overwrite_entry_start_id = true`: - Ensure that `auto_prune_interval` is enabled in Metasrv to allow automatic WAL pruning. - Kafka topics **must not use size-based retention policies**. - If time-based retention is enabled, the retention period should be set to a value significantly greater than auto-flush-interval, preferably at least 2 times its value. - Ensure the Kafka user used by Datanode has the following permissions: - **Append** records to WAL topics (requires LZ4 compression support). - **Read** records from WAL topics (requires LZ4 compression support). - Ensure that `max_batch_bytes` does not exceed Kafka’s maximum message size (typically 1MB by default). ## Kafka Authentication Configuration Kafka authentication settings apply to both Metasrv and Datanode under the `[wal]` section. ### SASL Kafka supports several SASL mechanisms: `PLAIN`, `SCRAM-SHA-256`, and `SCRAM-SHA-512`. ```toml [wal] broker_endpoints = ["kafka.kafka-cluster.svc.cluster.local:9092"] [wal.sasl] type = "SCRAM-SHA-512" username = "user" password = "secret" ``` ### TLS You can enable TLS encryption for Kafka connections by configuring the `[wal.tls]` section. There are three common modes: #### Using System CA Certificate To use system-wide trusted CAs, enable TLS without providing any certificate paths: ```toml [wal] broker_endpoints = ["kafka.kafka-cluster.svc.cluster.local:9092"] [wal.tls] ``` #### Using Custom CA Certificate If your Kafka cluster uses a private CA, specify the server CA certificate explicitly: ```toml [wal] broker_endpoints = ["kafka.kafka-cluster.svc.cluster.local:9092"] [wal.tls] server_ca_cert_path = "/path/to/server.crt" ``` #### Using Mutual TLS (mTLS) To enable mutual authentication, provide both the client certificate and private key along with the server CA: ```toml [wal] broker_endpoints = ["kafka.kafka-cluster.svc.cluster.local:9092"] [wal.tls] server_ca_cert_path = "/path/to/server_cert" client_cert_path = "/path/to/client_cert" client_key_path = "/path/to/key" ``` --- ## Manage Kafka The GreptimeDB cluster uses Kafka as the [Remote WAL](/user-guide/deployments-administration/wal/remote-wal/configuration.md) storage. This guide describes how to manage Kafka cluster. This guide will use Bitnami's Kafka Helm [chart](https://github.com/bitnami/charts/tree/main/bitnami/kafka) as an example. ## Prerequisites - [Kubernetes](https://kubernetes.io/docs/setup/) >= v1.23 - [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) >= v1.18.0 - [Helm](https://helm.sh/docs/intro/install/) >= v3.0.0 ## Install Save the following configuration as a file `kafka.yaml`: ```yaml global: security: allowInsecureImages: true image: registry: docker.io repository: greptime/kafka tag: 3.9.0-debian-12-r12 controller: replicaCount: 3 resources: requests: cpu: 2 memory: 2Gi limits: cpu: 2 memory: 2Gi persistence: enabled: true size: 200Gi broker: replicaCount: 3 resources: requests: cpu: 2 memory: 2Gi limits: cpu: 2 memory: 2Gi persistence: enabled: true size: 200Gi listeners: client: # When deploying on production environment, you normally want to use a more secure protocol like SASL. # Please refer to the chart's docs for the "how-to": https://artifacthub.io/packages/helm/bitnami/kafka#enable-security-for-kafka # Here for the sake of example's simplicity, we use plaintext (no authentications). protocol: plaintext ``` Install Kafka cluster: ```bash helm upgrade --install kafka \ oci://registry-1.docker.io/bitnamicharts/kafka \ --values kafka.yaml \ --version 32.4.3 \ --create-namespace \ -n kafka-cluster ``` Wait for Kafka cluster to be ready: ```bash kubectl wait --for=condition=ready pod \ -l app.kubernetes.io/instance=kafka \ -n kafka-cluster \ ``` Check the status of the Kafka cluster: ```bash kubectl get pods -n kafka-cluster ```
Expected Output ```bash NAME READY STATUS RESTARTS AGE kafka-controller-0 1/1 Running 0 64s kafka-controller-1 1/1 Running 0 64s kafka-controller-2 1/1 Running 0 64s kafka-broker-0 1/1 Running 0 63s kafka-broker-1 1/1 Running 0 62s kafka-broker-2 1/1 Running 0 61s ```
--- ## Continuous Aggregation Continuous aggregation is a crucial aspect of processing time-series data to deliver real-time insights. The Flow engine empowers developers to perform continuous aggregations, such as calculating sums, averages, and other metrics, seamlessly. It efficiently updates the aggregated data within specified time windows, making it an invaluable tool for analytics. Following are three major usecase examples for continuous aggregation: 1. **Real-time Analytics**: A real-time analytics platform that continuously aggregates data from a stream of events, delivering immediate insights while optionally downsampling the data to a lower resolution. For instance, this system can compile data from a high-frequency stream of log events (e.g., occurring every millisecond) to provide up-to-the-minute insights such as the number of requests per minute, average response times, and error rates per minute. 2. **Real-time Monitoring**: A real-time monitoring system that continuously aggregates data from a stream of events and provides real-time alerts based on the aggregated data. For example, a system that aggregates data from a stream of sensor events and provides real-time alerts when the temperature exceeds a certain threshold. 3. **Real-time Dashboard**: A real-time dashboard that shows the number of requests per minute, the average response time, and the number of errors per minute. This dashboard can be used to monitor the health of the system and to detect any anomalies in the system. In all these usecases, the continuous aggregation system continuously aggregates data from a stream of events and provides real-time insights and alerts based on the aggregated data. The system can also downsample the data to a lower resolution to reduce the amount of data stored and processed. This allows the system to provide real-time insights and alerts while keeping the data storage and processing costs low. ## Real-time Analytics Example ### Calculate the Log Statistics This use case is to calculate the total number of logs, the minimum size, the maximum size, the average size, and the number of packets with the size greater than 550 for each status code in a 1-minute fixed window for access logs. First, create a source table `ngx_access_log` and a sink table `ngx_statistics` with following clauses: ```sql CREATE TABLE `ngx_access_log` ( `client` STRING NULL, `ua_platform` STRING NULL, `referer` STRING NULL, `method` STRING NULL, `endpoint` STRING NULL, `trace_id` STRING NULL FULLTEXT INDEX, `protocol` STRING NULL, `status` SMALLINT UNSIGNED NULL, `size` DOUBLE NULL, `agent` STRING NULL, `access_time` TIMESTAMP(3) NOT NULL, TIME INDEX (`access_time`) ) WITH( append_mode = 'true' ); ``` ```sql CREATE TABLE `ngx_statistics` ( `status` SMALLINT UNSIGNED NULL, `total_logs` BIGINT NULL, `min_size` DOUBLE NULL, `max_size` DOUBLE NULL, `avg_size` DOUBLE NULL, `high_size_count` BIGINT NULL, `time_window` TIMESTAMP time index, `update_at` TIMESTAMP NULL, PRIMARY KEY (`status`) ); ``` Then create the flow `ngx_aggregation` to aggregate a series of aggregate functions, including `count`, `min`, `max`, `avg` of the `size` column, and the sum of all packets of size great than 550. The aggregation is calculated in 1-minute fixed windows of `access_time` column and also grouped by the `status` column. So you can be made aware in real time the information about packet size and action upon it, i.e. if the `high_size_count` became too high at a certain point, you can further examine if anything goes wrong, or if the `max_size` column suddenly spike in a 1 minute time window, you can then trying to locate that packet and further inspect it. The `EXPIRE AFTER '6h'` in the following SQL ensures that the flow computation only uses source data from the last 6 hours. Data older than 6 hours in the sink table will not be modified by this flow. For more details, see [manage-flow](manage-flow.md#expire-after). ```sql CREATE FLOW ngx_aggregation SINK TO ngx_statistics EXPIRE AFTER '6h' COMMENT 'aggregate nginx access logs' AS SELECT status, count(client) AS total_logs, min(size) as min_size, max(size) as max_size, avg(size) as avg_size, sum(case when `size` > 550 then 1 else 0 end) as high_size_count, date_bin('1 minutes'::INTERVAL, access_time) as time_window, FROM ngx_access_log GROUP BY status, time_window; ``` To observe the outcome of the continuous aggregation in the `ngx_statistics` table, insert some data into the source table `ngx_access_log`. ```sql INSERT INTO ngx_access_log VALUES ('android', 'Android', 'referer', 'GET', '/api/v1', 'trace_id', 'HTTP', 200, 1000, 'agent', now() - INTERVAL '1' minute), ('ios', 'iOS', 'referer', 'GET', '/api/v1', 'trace_id', 'HTTP', 200, 500, 'agent', now() - INTERVAL '1' minute), ('android', 'Android', 'referer', 'GET', '/api/v1', 'trace_id', 'HTTP', 200, 600, 'agent', now()), ('ios', 'iOS', 'referer', 'GET', '/api/v1', 'trace_id', 'HTTP', 404, 700, 'agent', now()); ``` Then the sink table `ngx_statistics` will be incremental updated and contain the following data: ```sql SELECT * FROM ngx_statistics; ``` ```sql +--------+------------+----------+----------+----------+-----------------+---------------------+----------------------------+ | status | total_logs | min_size | max_size | avg_size | high_size_count | time_window | update_at | +--------+------------+----------+----------+----------+-----------------+---------------------+----------------------------+ | 200 | 2 | 500 | 1000 | 750 | 1 | 2025-04-24 06:46:00 | 2025-04-24 06:47:06.680000 | | 200 | 1 | 600 | 600 | 600 | 1 | 2025-04-24 06:47:00 | 2025-04-24 06:47:06.680000 | | 404 | 1 | 700 | 700 | 700 | 1 | 2025-04-24 06:47:00 | 2025-04-24 06:47:06.680000 | +--------+------------+----------+----------+----------+-----------------+---------------------+----------------------------+ 3 rows in set (0.01 sec) ``` Try to insert more data into the `ngx_access_log` table: ```sql INSERT INTO ngx_access_log VALUES ('android', 'Android', 'referer', 'GET', '/api/v1', 'trace_id', 'HTTP', 200, 500, 'agent', now()), ('ios', 'iOS', 'referer', 'GET', '/api/v1', 'trace_id', 'HTTP', 404, 800, 'agent', now()); ``` The sink table `ngx_statistics` now have corresponding rows updated, notes how `max_size`, `avg_size` and `high_size_count` are updated: ```sql SELECT * FROM ngx_statistics; ``` ```sql +--------+------------+----------+----------+----------+-----------------+---------------------+----------------------------+ | status | total_logs | min_size | max_size | avg_size | high_size_count | time_window | update_at | +--------+------------+----------+----------+----------+-----------------+---------------------+----------------------------+ | 200 | 2 | 500 | 1000 | 750 | 1 | 2025-04-24 06:46:00 | 2025-04-24 06:47:06.680000 | | 200 | 2 | 500 | 600 | 550 | 1 | 2025-04-24 06:47:00 | 2025-04-24 06:47:21.720000 | | 404 | 2 | 700 | 800 | 750 | 2 | 2025-04-24 06:47:00 | 2025-04-24 06:47:21.720000 | +--------+------------+----------+----------+----------+-----------------+---------------------+----------------------------+ 3 rows in set (0.01 sec) ``` Here is the explanation of the columns in the `ngx_statistics` table: - `status`: The status code of the HTTP response. - `total_logs`: The total number of logs with the same status code. - `min_size`: The minimum size of the packets with the same status code. - `max_size`: The maximum size of the packets with the same status code. - `avg_size`: The average size of the packets with the same status code. - `high_size_count`: The number of packets with the size greater than 550. - `time_window`: The time window of the aggregation. - `update_at`: The time when the aggregation is updated. ### Retrieve Distinct Countries by Time Window Another example of real-time analytics is to retrieve all distinct countries from the `ngx_access_log` table. You can use the following query to group countries by time window: ```sql /* input table */ CREATE TABLE ngx_access_log ( client STRING, country STRING, access_time TIMESTAMP TIME INDEX, PRIMARY KEY(client) ) WITH( append_mode = 'true' ); /* sink table */ CREATE TABLE ngx_country ( country STRING, time_window TIMESTAMP TIME INDEX, update_at TIMESTAMP, PRIMARY KEY(country) ); /* create flow task to calculate the distinct country */ CREATE FLOW calc_ngx_country SINK TO ngx_country EXPIRE AFTER '7days'::INTERVAL COMMENT 'aggregate for distinct country' AS SELECT DISTINCT country, date_bin('1 hour'::INTERVAL, access_time) as time_window, FROM ngx_access_log GROUP BY country, time_window; ``` The above query puts the data from the `ngx_access_log` table into the `ngx_country` table. It calculates the distinct country for each time window. The `date_bin` function is used to group the data into one-hour intervals. The `ngx_country` table will be continuously updated with the aggregated data, providing real-time insights into the distinct countries that are accessing the system. The `EXPIRE AFTER` make flow ignore data with `access_time` older than 7 days and no longer calculate them anymore, see more explain in [manage-flow](manage-flow.md#expire-after). You can insert some data into the source table `ngx_access_log`: ```sql INSERT INTO ngx_access_log VALUES ('client1', 'US', now() - '2 hour'::INTERVAL), ('client2', 'US', now() - '2 hour'::INTERVAL), ('client3', 'UK', now() - '2 hour'::INTERVAL), ('client4', 'UK', now() - '1 hour'::INTERVAL), ('client5', 'CN', now() - '1 hour'::INTERVAL), ('client6', 'CN', now() - '1 hour'::INTERVAL), ('client7', 'JP', now()), ('client8', 'JP', now()), ('client9', 'KR', now()), ('client10', 'KR', now()); ``` Wait for few seconds for the Flow to write the result to the sink table and then query: ```sql select * from ngx_country; ``` ```sql +---------+---------------------+----------------------------+ | country | time_window | update_at | +---------+---------------------+----------------------------+ | CN | 2025-04-24 05:00:00 | 2025-04-24 06:55:17.217000 | | JP | 2025-04-24 06:00:00 | 2025-04-24 06:55:17.217000 | | KR | 2025-04-24 06:00:00 | 2025-04-24 06:55:17.217000 | | UK | 2025-04-24 04:00:00 | 2025-04-24 06:55:17.217000 | | UK | 2025-04-24 05:00:00 | 2025-04-24 06:55:17.217000 | | US | 2025-04-24 04:00:00 | 2025-04-24 06:55:17.217000 | +---------+---------------------+----------------------------+ 6 rows in set (0.00 sec) ``` ## Real-Time Monitoring Example Consider a usecase where you have a stream of sensor events from a network of temperature sensors that you want to monitor in real-time. The sensor events contain information such as the sensor ID, the temperature reading, the timestamp of the reading, and the location of the sensor. You want to continuously aggregate this data to provide real-time alerts when the temperature exceeds a certain threshold. Then the query for continuous aggregation would be: ```sql /* create input table */ CREATE TABLE temp_sensor_data ( sensor_id INT, loc STRING, temperature DOUBLE, ts TIMESTAMP TIME INDEX, PRIMARY KEY(sensor_id, loc) ) WITH( append_mode = 'true' ); /* create sink table */ CREATE TABLE temp_alerts ( sensor_id INT, loc STRING, max_temp DOUBLE, time_window TIMESTAMP TIME INDEX, update_at TIMESTAMP, PRIMARY KEY(sensor_id, loc) ); CREATE FLOW temp_monitoring SINK TO temp_alerts EXPIRE AFTER '1h' AS SELECT sensor_id, loc, max(temperature) as max_temp, date_bin('10 seconds'::INTERVAL, ts) as time_window, FROM temp_sensor_data GROUP BY sensor_id, loc, time_window HAVING max_temp > 100; ``` The above query continuously aggregates data from the `temp_sensor_data` table into the `temp_alerts` table. It calculates the maximum temperature reading for each sensor and location, filtering out data where the maximum temperature exceeds 100 degrees. The `temp_alerts` table will be continuously updated with the aggregated data, providing real-time alerts (in the form of new rows in the `temp_alerts` table) when the temperature exceeds the threshold. The `EXPIRE AFTER '1h'` makes flow only calculate source data with `ts` in `(now - 1h, now)` range, see more explain in [manage-flow](manage-flow.md#expire-after). Now that we have created the flow task, we can insert some data into the source table `temp_sensor_data`: ```sql INSERT INTO temp_sensor_data VALUES (1, 'room1', 98.5, now() - '10 second'::INTERVAL), (2, 'room2', 99.5, now()); ``` table should be empty now, but still wait at least few seconds for flow to update results to sink table: ```sql SELECT * FROM temp_alerts; ``` ```sql Empty set (0.00 sec) ``` Now insert some data that will trigger the alert: ```sql INSERT INTO temp_sensor_data VALUES (1, 'room1', 101.5, now()), (2, 'room2', 102.5, now()); ``` wait at least few seconds for flow to update results to sink table: ```sql SELECT * FROM temp_alerts; ``` ```sql +-----------+-------+----------+---------------------+----------------------------+ | sensor_id | loc | max_temp | time_window | update_at | +-----------+-------+----------+---------------------+----------------------------+ | 1 | room1 | 101.5 | 2025-04-24 06:58:20 | 2025-04-24 06:58:32.379000 | | 2 | room2 | 102.5 | 2025-04-24 06:58:20 | 2025-04-24 06:58:32.379000 | +-----------+-------+----------+---------------------+----------------------------+ 2 rows in set (0.01 sec) ``` ## Real-Time Dashboard Consider a usecase in which you need a bar graph that show the distribution of packet sizes for each status code to monitor the health of the system. The query for continuous aggregation would be: ```sql /* create input table */ CREATE TABLE ngx_access_log ( client STRING, stat INT, size INT, access_time TIMESTAMP TIME INDEX ) WITH( append_mode = 'true' ); /* create sink table */ CREATE TABLE ngx_distribution ( stat INT, bucket_size INT, total_logs BIGINT, time_window TIMESTAMP TIME INDEX, update_at TIMESTAMP, PRIMARY KEY(stat, bucket_size) ); /* create flow task to calculate the distribution of packet sizes for each status code */ CREATE FLOW calc_ngx_distribution SINK TO ngx_distribution EXPIRE AFTER '6h' AS SELECT stat, trunc(size, -1)::INT as bucket_size, count(client) AS total_logs, date_bin('1 minutes'::INTERVAL, access_time) as time_window, FROM ngx_access_log GROUP BY stat, time_window, bucket_size; ``` The query aggregates data from the `ngx_access_log` table into the `ngx_distribution` table. It computes the total number of logs for each status code and packet size bucket (bucket size of 10, as specified by `trunc` with a second argument of -1) within each time window. The `date_bin` function groups the data into one-minute intervals. The `EXPIRE AFTER '6h'` ensures that the flow computation only uses source data from the last 6 hours. See more details in [manage-flow](manage-flow.md#expire-after). Consequently, the `ngx_distribution` table is continuously updated, offering real-time insights into the distribution of packet sizes per status code. Now that we have created the flow task, we can insert some data into the source table `ngx_access_log`: ```sql INSERT INTO ngx_access_log VALUES ('cli1', 200, 100, now()), ('cli2', 200, 104, now()), ('cli3', 200, 120, now()), ('cli4', 200, 124, now()), ('cli5', 200, 140, now()), ('cli6', 404, 144, now()), ('cli7', 404, 160, now()), ('cli8', 404, 164, now()), ('cli9', 404, 180, now()), ('cli10', 404, 184, now()); ``` wait at least few seconds for flow to update results to sink table: ```sql SELECT * FROM ngx_distribution; ``` ```sql +------+-------------+------------+---------------------+----------------------------+ | stat | bucket_size | total_logs | time_window | update_at | +------+-------------+------------+---------------------+----------------------------+ | 200 | 100 | 2 | 2025-04-24 07:05:00 | 2025-04-24 07:05:56.308000 | | 200 | 120 | 2 | 2025-04-24 07:05:00 | 2025-04-24 07:05:56.308000 | | 200 | 140 | 1 | 2025-04-24 07:05:00 | 2025-04-24 07:05:56.308000 | | 404 | 140 | 1 | 2025-04-24 07:05:00 | 2025-04-24 07:05:56.308000 | | 404 | 160 | 2 | 2025-04-24 07:05:00 | 2025-04-24 07:05:56.308000 | | 404 | 180 | 2 | 2025-04-24 07:05:00 | 2025-04-24 07:05:56.308000 | +------+-------------+------------+---------------------+----------------------------+ 6 rows in set (0.00 sec) ``` ## Using TQL with Flow for Advanced Time-Series Analysis :::warning Experimental Feature This experimental feature may contain unexpected behavior and have its functionality change in the future. ::: TQL (Time Query Language) can be seamlessly integrated with Flow to perform advanced time-series computations like rate calculations, moving averages, and other complex time-window operations. This combination allows you to create continuous aggregation flows that leverage TQL's powerful analytical functions for real-time insights. ### Understanding TQL Flow Components The TQL integration with Flow provides several advantages: 1. **Time Range Specification**: The `EVAL (start_time, end_time, step)` syntax allows precise control over the evaluation window, see [TQL](/reference/sql/tql.md). 2. **Automatic Schema Generation**: GreptimeDB creates appropriate sink tables based on TQL function outputs 3. **Continuous Processing**: Combined with Flow's scheduling, TQL functions run continuously on incoming data 4. **Advanced Analytics**: Access to sophisticated time-series functions like `rate()`, `increase()`, and statistical aggregations ### Setting Up the Source Table First, let's create a source table to store HTTP request metrics: ```sql CREATE TABLE http_requests_total ( host STRING, job STRING, instance STRING, byte DOUBLE, ts TIMESTAMP TIME INDEX, PRIMARY KEY (host, job, instance) ); ``` This table will serve as the data source for our TQL-based Flow computations. The `ts` column acts as the time index, while `byte` represents the metric values we want to analyze. ### Creating a Rate Calculation Flow Now we'll create a Flow that uses TQL to calculate the rate of `byte` over time: ```sql CREATE FLOW calc_rate SINK TO rate_reqs EVAL INTERVAL '1m' AS TQL EVAL (now() - '1m'::interval, now(), '30s') rate(http_requests_total{job="my_service"}[1m]); ``` This Flow definition includes several key components: - **EVAL INTERVAL '1m'**: Executes the Flow every minute for continuous updates - **TQL EVAL**: Specifies the time range for evaluation from 1 minute ago to now, see [TQL](/reference/sql/tql.md). - **rate()**: TQL function that calculates the rate of change - **[1m]**: Defines a 1-minute lookback window for the rate calculation ### Wrapping TQL with a CTE If you want a cleaner flow definition or need stable output column names, you can wrap `TQL EVAL` in a simple CTE inside `CREATE FLOW`: ```sql CREATE FLOW calc_rate_cte SINK TO rate_reqs_cte EVAL INTERVAL '1m' AS WITH rate_data (ts, req_rate, host, job, instance) AS ( TQL EVAL (now() - '1m'::interval, now(), '30s') rate(http_requests_total{job="my_service"}[1m]) AS req_rate ) SELECT * FROM rate_data; ``` This pattern is useful when you want to rename columns before GreptimeDB infers the sink table schema. It is especially handy for TQL expressions whose generated value column names are verbose. The supported shape is intentionally limited: - Use exactly one TQL CTE. - End the flow query with `SELECT * FROM `. - Do not add `WHERE`, joins, extra projections, or additional CTEs around it. - If you quote the CTE name, keep the same quoted form in the outer query. ### Examining the Generated Sink Table You can inspect the automatically created sink table structure: ```sql SHOW CREATE TABLE rate_reqs; ``` ```sql +-----------+-------------------------------------+ | Table | Create Table | +-----------+-------------------------------------+ | rate_reqs | CREATE TABLE IF NOT EXISTS `rate_reqs` ( `ts` TIMESTAMP(3) NOT NULL, `prom_rate(ts_range,byte,ts,Int64(60000))` DOUBLE NULL, `host` STRING NULL, `job` STRING NULL, `instance` STRING NULL, TIME INDEX (`ts`), PRIMARY KEY (`host`, `job`, `instance`) ) ENGINE=mito | +-----------+-------------------------------------+ ``` This shows how GreptimeDB automatically generates the appropriate schema for storing TQL computation results, creating a table with the same structure as the prom ql query result. ### Testing with Sample Data Let's insert some test data to see the Flow in action: ```sql INSERT INTO TABLE http_requests_total VALUES ('localhost', 'my_service', 'instance1', 100, now() - INTERVAL '2' minute), ('localhost', 'my_service', 'instance1', 200, now() - INTERVAL '1' minute), ('remotehost', 'my_service', 'instance1', 300, now() - INTERVAL '30' second), ('remotehost', 'their_service', 'instance1', 300, now() - INTERVAL '30' second), ('localhost', 'my_service', 'instance1', 400, now()); ``` This creates a simple increasing sequence of values over time, which will produce a measurable rate when processed by our TQL Flow. ### Triggering Flow Execution To manually trigger the Flow computation and see immediate results: ```sql ADMIN FLUSH_FLOW('calc_rate'); ``` This command forces the Flow to process all available data immediately, rather than waiting for the next scheduled interval. ### Verifying Results Finally, verify that the Flow has successfully processed the data: ```sql SELECT count(*) > 0 FROM rate_reqs; ``` ```sql +---------------------+ | count(*) > Int64(0) | +---------------------+ | true | +---------------------+ ``` This query confirms that the rate calculation has produced results and populated the sink table with computed rate values. You can also examine the actual computed rate values: ```sql SELECT * FROM rate_reqs; ``` ```sql +---------------------+------------------------------------------+-----------+------------+-----------+ | ts | prom_rate(ts_range,byte,ts,Int64(60000)) | host | job | instance | +---------------------+------------------------------------------+-----------+------------+-----------+ | 2025-09-01 13:14:34 | 4.166666666666666 | localhost | my_service | instance1 | | 2025-09-01 13:15:04 | 4.444444444444444 | localhost | my_service | instance1 | +---------------------+------------------------------------------+-----------+------------+-----------+ 2 rows in set (0.03 sec) ``` Note that the timestamps and exact rate values may vary depending on when you run the example, but you should see similar rate calculations based on the input data pattern. ### Cleanup When you're done experimenting, clean up the resources: ```sql DROP FLOW calc_rate; DROP TABLE http_requests; DROP TABLE rate_reqs; ``` ## Next Steps - [Manage Flow](manage-flow.md): Gain insights into the mechanisms of the Flow engine and the SQL syntax for defining a Flow. - [Expressions](expressions.md): Learn about the expressions supported by the Flow engine for data transformation. --- ## Expressions ## Aggregate functions Flow support all aggregate functions that a normal sql query supports such as `COUNT`, `SUM`, `MIN`, `MAX`, etc. For a detailed list, please refer to [Aggregate Functions](/reference/sql/functions/df-functions.md#aggregate-functions). ## Scalar functions Flow support all scalar functions that a normal sql query supports in our [SQL reference](/reference/sql/functions/overview.md). And here are some of the most commonly used scalar functions in flow: - [`date_bin`](/reference/sql/functions/df-functions.md#date_bin): calculate time intervals and returns the start of the interval nearest to the specified timestamp. - [`date_trunc`](/reference/sql/functions/df-functions.md#date_trunc): truncate a timestamp value to a specified precision. - [`trunc`](/reference/sql/functions/df-functions.md#trunc): truncate a number to a whole number or truncated to the specified decimal places. --- ## Manage Flows Each `flow` is a continuous aggregation query in GreptimeDB. It continuously updates the aggregated data based on the incoming data. This document describes how to create, and delete a flow. ## Create a Source Table Before creating a flow, you need to create a source table to store the raw data. Like this: ```sql CREATE TABLE temp_sensor_data ( sensor_id INT, loc STRING, temperature DOUBLE, ts TIMESTAMP TIME INDEX, PRIMARY KEY(sensor_id, loc) ); ``` However, if you don't want to store the raw data, you can use a temporary table as the source table by creating table using `WITH ('ttl' = 'instant')` table option: ```sql CREATE TABLE temp_sensor_data ( sensor_id INT, loc STRING, temperature DOUBLE, ts TIMESTAMP TIME INDEX, PRIMARY KEY(sensor_id, loc) ) WITH ('ttl' = 'instant'); ``` Setting `'ttl'` to `'instant'` will make the table a temporary table, which means it will automatically discard all inserted data and the table will always be empty, only sending them to flow task for computation. ## Create a Sink Table Before creating a flow, you need a sink table to store the aggregated data generated by the flow. While it is the same to a regular time series table, there are a few important considerations: - **Column order and type**: Ensure the order and type of the columns in the sink table match the query result of the flow. - **Time index**: Specify the `TIME INDEX` for the sink table, typically using the time window column generated by the time window function. - **Update time**: The Flow engine automatically appends the update time to the end of each computation result row. This update time is stored in the `update_at` column. Ensure that this column is included in the sink table schema. - **Tags**: Use `PRIMARY KEY` to specify Tags, which together with the time index serves as a unique identifier for row data and optimizes query performance. For example: ```sql /* Create sink table */ CREATE TABLE temp_alerts ( sensor_id INT, loc STRING, max_temp DOUBLE, time_window TIMESTAMP TIME INDEX, update_at TIMESTAMP, PRIMARY KEY(sensor_id, loc) ); CREATE FLOW temp_monitoring SINK TO temp_alerts AS SELECT sensor_id, loc, max(temperature) AS max_temp, date_bin('10 seconds'::INTERVAL, ts) AS time_window FROM temp_sensor_data GROUP BY sensor_id, loc, time_window HAVING max_temp > 100; ``` The sink table has the columns `sensor_id`, `loc`, `max_temp`, `time_window`, and `update_at`. - The first four columns correspond to the query result columns of flow: `sensor_id`, `loc`, `max(temperature)` and `date_bin('10 seconds'::INTERVAL, ts)` respectively. - The `time_window` column is specified as the `TIME INDEX` for the sink table. - The `update_at` column is the last one in the schema to store the update time of the data. - The `PRIMARY KEY` at the end of the schema definition specifies `sensor_id` and `loc` as the tag columns. This means the flow will insert or update data based on the tags `sensor_id` and `loc` along with the time index `time_window`. ## Create a flow The grammar to create a flow is: ```sql CREATE [ OR REPLACE ] FLOW [ IF NOT EXISTS ] SINK TO [ EXPIRE AFTER ] [ COMMENT '' ] AS ; ``` When `OR REPLACE` is specified, any existing flow with the same name will be updated to the new version. It's important to note that this only affects the flow task itself; the source and sink tables will remain unchanged. Conversely, when `IF NOT EXISTS` is specified, the command will have no effect if the flow already exists, rather than reporting an error. Additionally, please note that `OR REPLACE` cannot be used in conjunction with `IF NOT EXISTS`. - `flow-name` is an unique identifier in the catalog level. - `sink-table-name` is the table name where the materialized aggregated data is stored. It can be an existing table or a new one. `flow` will create the sink table if it doesn't exist. - `EXPIRE AFTER` is an optional interval to expire the data from the Flow engine. For more details, please refer to the [`EXPIRE AFTER`](#expire-after) part. - `COMMENT` is the description of the flow. - `SQL` part defines the continuous aggregation query. It defines the source tables provide data for the flow. Each flow can have multiple source tables. Please Refer to [Write a Query](#write-a-sql-query) for the details. A simple example to create a flow: ```sql CREATE FLOW IF NOT EXISTS my_flow SINK TO my_sink_table EXPIRE AFTER '1 hour'::INTERVAL COMMENT 'My first flow in GreptimeDB' AS SELECT max(temperature) as max_temp, date_bin('10 seconds'::INTERVAL, ts) as time_window, FROM temp_sensor_data GROUP BY time_window; ``` The created flow will compute `max(temperature)` for every 10 seconds and store the result in `my_sink_table`. All data comes within 1 hour will be used in the flow. ### EXPIRE AFTER The `EXPIRE AFTER` clause specifies the interval after which data will expire from the flow engine. Data in the source table that exceeds the specified expiration time will no longer be included in the flow's calculations. Similarly, data in the sink table that is older than the expiration time will not be updated. This means the flow engine will ignore data older than the specified interval during aggregation. This mechanism helps to manage the state size for stateful queries, such as those involving `GROUP BY`. It is important to note that the `EXPIRE AFTER` clause does not delete data from either the source table or the sink table. It only controls how the flow engine processes the data. If you want to delete data from the source or sink table, please [set the `TTL` option](/user-guide/manage-data/overview.md#manage-data-retention-with-ttl-policies) when creating tables. Setting a reasonable time interval for `EXPIRE AFTER` is helpful to limit state size and avoid memory overflow. This is somewhere similar to the ["Watermarks"](https://docs.risingwave.com/processing/watermarks) concept in streaming processing. For example, if the flow engine processes the aggregation at 10:00:00 and the `'1 hour'::INTERVAL` is set, any input data that arrive now with a time index older than 1 hour (before 09:00:00) will expire and be ignore. Only data timestamped from 09:00:00 onwards will be used in the aggregation and update to sink table. ### Write a SQL query The `SQL` part of the flow is similar to a standard `SELECT` clause with a few differences. The syntax of the query is as follows: ```sql SELECT AGGR_FUNCTION(column1, column2,..) [, TIME_WINDOW_FUNCTION() as time_window] FROM GROUP BY {time_window | column1, column2,.. }; ``` Only the following types of expressions are allowed after the `SELECT` keyword: - Aggregate functions: Refer to the [Expressions](expressions.md) documentation for details. - Time window functions: Refer to the [define time window](#define-time-window) section for details. - Scalar functions: Such as `col`, `to_lowercase(col)`, `col + 1`, etc. This part is the same as in a standard `SELECT` clause in GreptimeDB. The following points should be noted about the rest of the query syntax: - The query must include a `FROM` clause to specify the source table. As join clauses are currently not supported, the query can only aggregate columns from a single table. - `WHERE` and `HAVING` clauses are supported. The `WHERE` clause filters data before aggregation, while the `HAVING` clause filters data after aggregation. - `DISTINCT` currently only works with the `SELECT DISTINCT column1 ..` syntax. It is used to remove duplicate rows from the result set. Support for `SELECT count(DISTINCT column1) ...` is not available yet but will be added in the future. - The `GROUP BY` clause works the same as a standard queries, grouping data by specified columns. The time window column in the `GROUP BY` clause is crucial for continuous aggregation scenarios. Other expressions in `GROUP BY` can include literals, columns, or scalar expressions. - `ORDER BY`, `LIMIT`, and `OFFSET` are not supported. Refer to [Continuous Aggregation](continuous-aggregation.md) for more examples of how to use continuous aggregation in real-time analytics, monitoring, and dashboards. ### Define time window A time window is a crucial attribute of your continuous aggregation query. It determines how data is aggregated within the flow. These time windows are left-closed and right-open intervals. A time window represents a specific range of time. Data from the source table is mapped to the corresponding window based on the time index column. The time window also defines the scope for each calculation of an aggregation expression, resulting in one row per time window in the result table. You can use `date_bin()` after the `SELECT` keyword to define fixed time windows. For example: ```sql SELECT max(temperature) as max_temp, date_bin('10 seconds'::INTERVAL, ts) as time_window FROM temp_sensor_data GROUP BY time_window; ``` In this example, the `date_bin('10 seconds'::INTERVAL, ts)` function creates 10-second time windows starting from UTC 00:00:00. The `max(temperature)` function calculates the maximum temperature value within each time window. For more details on the behavior of the function, please refer to [`date_bin`](/reference/sql/functions/df-functions.md#date_bin). :::tip NOTE Currently, flow rely on the time window expr to determine how to incrementally update the result. So it's better to use a relatively small time window when possible. ::: ## Flush a flow The flow engine automatically processes aggregation operations within a short period(i.e. few seconds) when new data arrives in the source table. However, you can manually trigger the flow engine to process the aggregation operation immediately using the `ADMIN FLUSH_FLOW` command. ```sql ADMIN FLUSH_FLOW('') ``` ## Delete a flow To delete a flow, use the following `DROP FLOW` clause: ```sql DROP FLOW [IF EXISTS] ``` For example: ```sql DROP FLOW IF EXISTS my_flow; ``` --- ## Flow Computation GreptimeDB's Flow engine enables real-time computation of data streams. It is particularly beneficial for Extract-Transform-Load (ETL) processes or for performing on-the-fly filtering, calculations and queries such as sum, average, and other aggregations. The Flow engine ensures that data is processed incrementally and continuously, updating the final results as new streaming data arrives. You can think of it as a clever materialized views that know when to update result view table and how to update it with minimal effort. Use cases include: - Real-time analytics that deliver actionable insights almost instantaneously. - Downsampling data points, such as using average pooling, to reduce the volume of data for storage and analysis. ## Programming Model Upon data insertion into the source table, the data is concurrently ingested to the Flow engine. At each trigger interval (one second), the Flow engine executes the specified computations and updates the sink table with the results. Both the source and sink tables are time-series tables within GreptimeDB. Before creating a Flow, it is crucial to define the schemas for these tables and design the Flow to specify the computation logic. This process is visually represented in the following image: ![Continuous Aggregation](/flow-ani.svg) ## Quick Start Example To illustrate the capabilities of GreptimeDB's Flow engine, consider the task of calculating user agent statistics from nginx logs. The source table is `nginx_access_log`, and the sink table is `user_agent_statistics`. First, create the source table `nginx_access_log`. To optimize performance for counting the `user_agent` field, specify it as a `TAG` column type using the `PRIMARY KEY` keyword. ```sql CREATE TABLE ngx_http_log ( ip_address STRING, http_method STRING, request STRING, status_code INT16, body_bytes_sent INT32, user_agent STRING, response_size INT32, ts TIMESTAMP TIME INDEX, PRIMARY KEY (ip_address, http_method, user_agent, status_code) ) WITH ('append_mode'='true'); ``` Next, create the sink table `user_agent_statistics`. The `update_at` column tracks the last update time of the record, which is automatically updated by the Flow engine. Although all tables in GreptimeDB are time-series tables, this computation does not require time windows. Therefore, the `__ts_placeholder` column is included as a time index placeholder. ```sql CREATE TABLE user_agent_statistics ( user_agent STRING, total_count INT64, update_at TIMESTAMP, __ts_placeholder TIMESTAMP TIME INDEX, PRIMARY KEY (user_agent) ); ``` Finally, create the Flow `user_agent_flow` to count the occurrences of each user agent in the `ngx_http_log` table. ```sql CREATE FLOW user_agent_flow SINK TO user_agent_statistics AS SELECT user_agent, COUNT(user_agent) AS total_count FROM ngx_http_log GROUP BY user_agent; ``` Once the Flow is created, the Flow engine will continuously process data from the `ngx_http_log` table and update the `user_agent_statistics` table with the computed results. To observe the results, insert sample data into the `ngx_http_log` table. ```sql INSERT INTO ngx_http_log VALUES ('192.168.1.1', 'GET', '/index.html', 200, 512, 'Mozilla/5.0', 1024, '2023-10-01T10:00:00Z'), ('192.168.1.2', 'POST', '/submit', 201, 256, 'curl/7.68.0', 512, '2023-10-01T10:01:00Z'), ('192.168.1.1', 'GET', '/about.html', 200, 128, 'Mozilla/5.0', 256, '2023-10-01T10:02:00Z'), ('192.168.1.3', 'GET', '/contact', 404, 64, 'curl/7.68.0', 128, '2023-10-01T10:03:00Z'); ``` After inserting the data, query the `user_agent_statistics` table to view the results. ```sql SELECT * FROM user_agent_statistics; ``` The query results will display the total count of each user agent in the `user_agent_statistics` table. ```sql +-------------+-------------+----------------------------+---------------------+ | user_agent | total_count | update_at | __ts_placeholder | +-------------+-------------+----------------------------+---------------------+ | Mozilla/5.0 | 2 | 2024-12-12 06:45:33.228000 | 1970-01-01 00:00:00 | | curl/7.68.0 | 2 | 2024-12-12 06:45:33.228000 | 1970-01-01 00:00:00 | +-------------+-------------+----------------------------+---------------------+ ``` ## Next Steps - [Continuous Aggregation](./continuous-aggregation.md): Explore the primary scenario in time-series data processing, with three common use cases for continuous aggregation. - [Manage Flow](manage-flow.md): Gain insights into the mechanisms of the Flow engine and the SQL syntax for defining a Flow. - [Expressions](expressions.md): Learn about the expressions supported by the Flow engine for data transformation. --- ## EMQX [EMQX](https://www.emqx.io/) is an open-source, highly scalable, and feature-rich MQTT broker designed for IoT and real-time messaging applications. It supports various protocols, including MQTT (3.1, 3.1.1, and 5.0), HTTP, QUIC, and WebSocket. GreptimeDB can be used as a data system for EMQX. To learn how to integrate GreptimeDB with EMQX, please refer to [Ingest MQTT Data into GreptimeDB](https://docs.emqx.com/en/emqx/latest/data-integration/data-bridge-greptimedb.html). --- ## Go GreptimeDB offers ingester libraries for high-throughput data writing. It utilizes the gRPC protocol, which supports schemaless writing and eliminates the need to create tables before writing data. For more information, refer to [Automatic Schema Generation](/user-guide/ingest-data/overview.md#automatic-schema-generation). The Go ingester SDK provided by GreptimeDB is a lightweight, concurrent-safe library that is easy to use with the metric struct. ## Quick start demos To quickly get started, you can explore the [quick start demos](https://github.com/GreptimeTeam/greptimedb-ingester-go/tree/main/examples) to understand how to use the GreptimeDB Go ingester SDK. ## Installation Use the following command to install the GreptimeDB client library for Go: ```shell go get -u github.com/GreptimeTeam/greptimedb-ingester-go@v0.7.2 ``` Import the library in your code: ```go greptime "github.com/GreptimeTeam/greptimedb-ingester-go" ingesterContext "github.com/GreptimeTeam/greptimedb-ingester-go/context" "github.com/GreptimeTeam/greptimedb-ingester-go/table" "github.com/GreptimeTeam/greptimedb-ingester-go/table/types" ) ``` ## Connect to database If you have set the [`--user-provider` configuration](/user-guide/deployments-administration/authentication/overview.md) when starting GreptimeDB, you will need to provide a username and password to connect to GreptimeDB. The following example shows how to set the username and password when using the library to connect to GreptimeDB. ```go cfg := greptime.NewConfig("127.0.0.1"). // change the database name to your database name WithDatabase("public"). // Default port 4001 // WithPort(4001). // Enable secure connection if your server is secured by TLS // WithInsecure(false). // set authentication information // If the database doesn't require authentication, just remove the WithAuth method WithAuth("username", "password") cli, _ := greptime.NewClient(cfg) defer cli.Close() ``` ## Data model Each row item in a table consists of three types of columns: `Tag`, `Timestamp`, and `Field`. For more information, see [Data Model](/user-guide/concepts/data-model.md). The types of column values could be `String`, `Float`, `Int`, `Timestamp`, `JSON` etc. For more information, see [Data Types](/reference/sql/data-types.md). ## Set table options Although the time series table is created automatically when writing data to GreptimeDB via the SDK, you can still configure table options. The SDK supports the following table options: - `auto_create_table`: Default is `True`. If set to `False`, it indicates that the table already exists and does not need automatic creation, which can improve write performance. - `ttl`, `append_mode`, `merge_mode`: For more details, refer to the [table options](/reference/sql/create.md#table-options). You can set table options using the `ingesterContext` context. For example, to set the `ttl` option, use the following code: ```go hints := []*ingesterContext.Hint{ { Key: "ttl", Value: "3d", }, } ctx, cancel := context.WithTimeout(context.Background(), time.Second*3) ctx = ingesterContext.New(ctx, ingesterContext.WithHint(hints)) // Use the ingesterContext when writing data to GreptimeDB. // The `data` object is described in the following sections. resp, err := cli.Write(ctx, data) if err != nil { return err } ``` For how to write data to GreptimeDB, see the following sections. ## Low-level API The GreptimeDB low-level API provides a straightforward method to write data to GreptimeDB by adding rows to the table object with a predefined schema. ### Create row objects This following code snippet begins by constructing a table named `cpu_metric`, which includes columns `host`, `cpu_user`, `cpu_sys`, and `ts`. Subsequently, it inserts a single row into the table. The table consists of three types of columns: - `Tag`: The `host` column, with values of type `String`. - `Field`: The `cpu_user` and `cpu_sys` columns, with values of type `Float`. - `Timestamp`: The `ts` column, with values of type `Timestamp`. ```go // Construct the table schema for CPU metrics cpuMetric, err := table.New("cpu_metric") if err != nil { // Handle error appropriately } // Add a 'Tag' column for host identifiers cpuMetric.AddTagColumn("host", types.STRING) // Add a 'Timestamp' column for recording the time of data collection cpuMetric.AddTimestampColumn("ts", types.TIMESTAMP_MILLISECOND) // Add 'Field' columns for user and system CPU usage measurements cpuMetric.AddFieldColumn("cpu_user", types.FLOAT) cpuMetric.AddFieldColumn("cpu_sys", types.FLOAT) // Insert example data // NOTE: The arguments must be in the same order as the columns in the defined schema: host, ts, cpu_user, cpu_sys err = cpuMetric.AddRow("127.0.0.1", time.Now(), 0.1, 0.12) err = cpuMetric.AddRow("127.0.0.1", time.Now(), 0.11, 0.13) if err != nil { // Handle error appropriately } ``` To improve the efficiency of writing data, you can create multiple rows at once to write to GreptimeDB. ```go cpuMetric, err := table.New("cpu_metric") if err != nil { // Handle error appropriately } cpuMetric.AddTagColumn("host", types.STRING) cpuMetric.AddTimestampColumn("ts", types.TIMESTAMP_MILLISECOND) cpuMetric.AddFieldColumn("cpu_user", types.FLOAT) cpuMetric.AddFieldColumn("cpu_sys", types.FLOAT) err = cpuMetric.AddRow("127.0.0.1", time.Now(), 0.1, 0.12) if err != nil { // Handle error appropriately } memMetric, err := table.New("mem_metric") if err != nil { // Handle error appropriately } memMetric.AddTagColumn("host", types.STRING) memMetric.AddTimestampColumn("ts", types.TIMESTAMP_MILLISECOND) memMetric.AddFieldColumn("mem_usage", types.FLOAT) err = memMetric.AddRow("127.0.0.1", time.Now(), 112) if err != nil { // Handle error appropriately } ``` ### Insert data The following example shows how to insert rows to tables in GreptimeDB. ```go resp, err := cli.Write(ctx, cpuMetric, memMetric) if err != nil { // Handle error appropriately } log.Printf("affected rows: %d\n", resp.GetAffectedRows().GetValue()) ``` ### Streaming insert Streaming insert is useful when you want to insert a large amount of data such as importing historical data. ```go err := cli.StreamWrite(ctx, cpuMetric, memMetric) if err != nil { // Handle error appropriately } ``` Close the stream writing after all data has been written. In general, you do not need to close the stream writing when continuously writing data. ```go affected, err := cli.CloseStream(ctx) ``` ## High-level API The high-level API uses an ORM style object to write data to GreptimeDB. It allows you to create, insert, and update data in a more object-oriented way, providing developers with a friendlier experience. However, it is not as efficient as the low-level API. This is because the ORM style object may consume more resources and time when converting the objects. ### Create row objects ```go type CpuMetric struct { Host string `greptime:"tag;column:host;type:string"` CpuUser float64 `greptime:"field;column:cpu_user;type:float64"` CpuSys float64 `greptime:"field;column:cpu_sys;type:float64"` Ts time.Time `greptime:"timestamp;column:ts;type:timestamp;precision:millisecond"` } func (CpuMetric) TableName() string { return "cpu_metric" } cpuMetrics := []CpuMetric{ { Host: "127.0.0.1", CpuUser: 0.10, CpuSys: 0.12, Ts: time.Now(), } } ``` ### Insert data ```go resp, err := cli.WriteObject(ctx, cpuMetrics) log.Printf("affected rows: %d\n", resp.GetAffectedRows().GetValue()) ``` ### Streaming insert Streaming insert is useful when you want to insert a large amount of data such as importing historical data. ```go err := cli.StreamWriteObject(ctx, cpuMetrics) ``` Close the stream writing after all data has been written. In general, you do not need to close the stream writing when continuously writing data. ```go affected, err := cli.CloseStream(ctx) ``` ## Insert data in JSON type GreptimeDB supports storing complex data structures using [JSON type data](/reference/sql/data-types.md#json-type-experimental). With this ingester library, you can insert JSON data using string values. For instance, if you have a table named `sensor_readings` and wish to add a JSON column named `attributes`, refer to the following code snippet. In the [low-level API](#low-level-api), you can specify the column type as `types.JSON` using the `AddFieldColumn` method to add a JSON column. Then, use a `struct` or `map` to insert JSON data. ```go sensorReadings, err := table.New("sensor_readings") // The code for creating other columns is omitted // ... // specify the column type as JSON sensorReadings.AddFieldColumn("attributes", types.JSON) // Use struct to insert JSON data type Attributes struct { Location string `json:"location"` Action string `json:"action"` } attributes := Attributes{ Location: "factory-1" } sensorReadings.AddRow(... , attributes) // The following code for writing data is omitted // ... ``` In the [high-level API](#high-level-api), you can specify the column type as JSON using the `greptime:"field;column:details;type:json"` tag. ```go type SensorReadings struct { // The code for creating other columns is omitted // ... // specify the column type as JSON Attributes string `greptime:"field;column:details;type:json"` // ... } // Use struct to insert JSON data type Attributes struct { Location string `json:"location"` Action string `json:"action"` } attributes := Attributes{ Action: "running" } sensor := SensorReadings{ // ... Attributes: attributes, } // The following code for writing data is omitted // ... ``` For the executable code for inserting JSON data, please refer to the [example](https://github.com/GreptimeTeam/greptimedb-ingester-go/tree/main/examples/jsondata) in the SDK repository. ## Bulk Write When you need to import data in bulk and require high ingestion throughput, you can use the Bulk Write API. It is designed for batch loading scenarios, where large volumes of data are written efficiently. By using Arrow IPC encoding to aggregate multiple tables or objects on the client side and sending them in a single gRPC request, it significantly reduces network overhead and improves overall write performance compared to the regular Write API. ### Adding Data You can build data objects and add them to the bulk writer. ```go // Build the CPU metrics table cpuMetric, err := table.New("cpu_metric") if err != nil { // Handle error appropriately } cpuMetric.AddTagColumn("host", types.STRING) cpuMetric.AddTimestampColumn("ts", types.TIMESTAMP_MILLISECOND) cpuMetric.AddFieldColumn("cpu_user", types.FLOAT64) cpuMetric.AddFieldColumn("cpu_sys", types.FLOAT64) // Add multiple rows of data cpuMetric.AddRow("127.0.0.1", time.Now(), 0.1, 0.12) cpuMetric.AddRow("127.0.0.2", time.Now(), 0.2, 0.15) ``` ### Insert data ```go resp, err := cli.BulkWrite(context.TODO(), cpuMetric) if err != nil { // Handle error appropriately } log.Printf("Bulk write affected rows: %d\n", resp.GetAffectedRows().GetValue()) ``` Please refer to the [example](https://github.com/GreptimeTeam/greptimedb-ingester-go/tree/main/examples/bulkwrite) in the SDK repository for runnable code demonstrating bulk write. ## Ingester library reference - [API Documentation](https://pkg.go.dev/github.com/GreptimeTeam/greptimedb-ingester-go) --- ## Java Ingester for GreptimeDB GreptimeDB offers ingester libraries for high-throughput data writing. It utilizes the gRPC protocol, which supports schemaless writing and eliminates the need to create tables before writing data. For more information, refer to [Automatic Schema Generation](/user-guide/ingest-data/overview.md#automatic-schema-generation). The Java ingester SDK provided by GreptimeDB is a lightweight, high-performance client designed for efficient time-series data ingestion. It leverages the gRPC protocol to provide a non-blocking, purely asynchronous API that delivers exceptional throughput while maintaining seamless integration with your applications. This client offers multiple ingestion methods optimized for various performance requirements and use cases. You can select the approach that best suits your specific needs—whether you require simple unary writes for low-latency operations or high-throughput bulk streaming for maximum efficiency when handling large volumes of time-series data. ## High Level Architecture ``` +-----------------------------------+ | Client Applications | | +------------------+ | | | Application Code | | | +------------------+ | +-------------+---------------------+ | v +-------------+---------------------+ | API Layer | | +---------------+ | | | GreptimeDB | | | +---------------+ | | / \ | | v v | | +-------------+ +-------------+ | +------------------+ | | BulkWrite | | Write | | | Data Model | | | Interface | | Interface | |------->| | | +-------------+ +-------------+ | | +------------+ | +-------|----------------|----------+ | | Table | | | | | +------------+ | v v | | | +-------|----------------|----------+ | v | | Transport Layer | | +------------+ | | +-------------+ +-------------+ | | | TableSchema| | | | BulkWrite | | Write | | | +------------+ | | | Client | | Client | | +------------------+ | +-------------+ +-------------+ | | | \ / | | | | \ / | | | | v v | | | | +-------------+ | | | | |RouterClient | | | +-----|--+-------------|---+--------+ | | | | | | | | v v v | +-----|----------------|---|--------+ | Network Layer | | +-------------+ +-------------+ | | | Arrow Flight| | gRPC Client | | | | Client | | | | | +-------------+ +-------------+ | | | | | +-----|----------------|------------+ | | v v +-------------------------+ | GreptimeDB Server | +-------------------------+ ``` - **API Layer**: Provides high-level interfaces for client applications to interact with GreptimeDB - **Data Model**: Defines the structure and organization of time series data with tables and schemas - **Transport Layer**: Handles communication logistics, request routing, and client management - **Network Layer**: Manages low-level protocol communications using Arrow Flight and gRPC ## How To Use ### Installation 1. Install the Java Development Kit(JDK) Make sure that your system has JDK 8 or later installed. For more information on how to check your version of Java and install the JDK, see the [Oracle Overview of JDK Installation documentation](https://www.oracle.com/java/technologies/javase-downloads.html) 2. Add GreptimeDB Java SDK as a Dependency If you are using [Maven](https://maven.apache.org/), add the following to your pom.xml dependencies list: ```xml io.greptime ingester-all 0.15.0 ``` The latest version can be viewed [here](https://central.sonatype.com/search?q=io.greptime&name=ingester-all). After configuring your dependencies, make sure they are available to your project. This may require refreshing the project in your IDE or running the dependency manager. ### Client Initialization The entry point to the GreptimeDB Ingester Java client is the `GreptimeDB` class. You create a client instance by calling the static create method with appropriate configuration options. ```java // GreptimeDB has a default database named "public" in the default catalog "greptime", // we can use it as the test database String database = "public"; // By default, GreptimeDB listens on port 4001 using the gRPC protocol. // We can provide multiple endpoints that point to the same GreptimeDB cluster. // The client will make calls to these endpoints based on a load balancing strategy. // The client performs regular health checks and automatically routes requests to healthy nodes, // providing fault tolerance and improved reliability for your application. String[] endpoints = {"127.0.0.1:4001"}; // Sets authentication information. AuthInfo authInfo = new AuthInfo("username", "password"); GreptimeOptions opts = GreptimeOptions.newBuilder(endpoints, database) // If the database does not require authentication, we can use `AuthInfo.noAuthorization()` as the parameter. .authInfo(authInfo) // Enable secure connection if your server is secured by TLS //.tlsOptions(new TlsOptions()) // A good start ^_^ .build(); // Initialize the client // NOTE: The client instance is thread-safe and should be reused as a global singleton // for better performance and resource utilization. GreptimeDB client = GreptimeDB.create(opts); ``` ### Writing Data The ingester provides a unified approach for writing data to GreptimeDB through the `Table` abstraction. All data writing operations, including high-level APIs, are built on top of this fundamental structure. To write data, you create a `Table` with your time series data and write it to the database. #### Creating and Writing Tables Define a table schema and create a table: ```java // Create a table schema TableSchema schema = TableSchema.newBuilder("metrics") .addTag("host", DataType.String) .addTag("region", DataType.String) .addField("cpu_util", DataType.Float64) .addField("memory_util", DataType.Float64) .addTimestamp("ts", DataType.TimestampMillisecond) .build(); // Create a table from the schema Table table = Table.from(schema); // Add rows to the table // The values must be provided in the same order as defined in the schema // In this case: addRow(host, region, cpu_util, memory_util, ts) table.addRow("host1", "us-west-1", 0.42, 0.78, System.currentTimeMillis()); table.addRow("host2", "us-west-2", 0.46, 0.66, System.currentTimeMillis()); // Add more rows // .. // Complete the table to make it immutable. This finalizes the table for writing. // If users forget to call this method, it will automatically be called internally // before the table data is written. table.complete(); // Write the table to the database CompletableFuture> future = client.write(table); ``` GreptimeDB supports storing complex data structures using [JSON type data](/reference/sql/data-types.md#json-type-experimental). You can define JSON columns in your table schema and insert data using Map objects: ```java // Construct the table schema for sensor_readings TableSchema sensorReadings = TableSchema.newBuilder("sensor_readings") // The code for creating other columns is omitted // ... // specify the column type as JSON .addField("attributes", DataType.Json) .build(); // ... // Use map to insert JSON data Map attr = new HashMap<>(); attr.put("location", "factory-1"); Table table = Table.from(sensorReadings); table.addRow(... , attr); ``` ##### TableSchema The `TableSchema` defines the structure for writing data to GreptimeDB. It specifies the table structure including column names, semantic types, and data types. For detailed information about column semantic types (`Tag`, `Timestamp`, `Field`), refer to the [Data Model](/user-guide/concepts/data-model.md) documentation. ##### Table The `Table` interface represents data that can be written to GreptimeDB. It provides methods for adding rows and manipulating the data. Essentially, `Table` temporarily stores data in memory, allowing you to accumulate multiple rows for batch processing before sending them to the database, which significantly improves write efficiency compared to writing individual rows. A table goes through several distinct lifecycle stages: 1. **Creation**: Initialize a table from a schema using `Table.from(schema)` 2. **Data Addition**: Populate the table with rows using `addRow()` method 3. **Completion**: Finalize the table with `complete()` when all rows have been added 4. **Writing**: Send the completed table to the database Important considerations: - Tables are not thread-safe and should be accessed from a single thread - Tables cannot be reused after writing - create a new instance for each write operation - The associated `TableSchema` is immutable and can be safely reused across multiple operations ### Write Operations Although the time series table is created automatically when writing data to GreptimeDB via the SDK, you can still configure table options. The SDK supports the following table options: - `auto_create_table`: Default is `True`. If set to `False`, it indicates that the table already exists and does not need automatic creation, which can improve write performance. - `ttl`, `append_mode`, `merge_mode`: For more details, refer to the [table options](/reference/sql/create.md#table-options). You can set table options using the `Context`. For example, to set the `ttl` option, use the following code: ```java Context ctx = Context.newDefault(); // Add a hint to make the database create a table with the specified TTL (time-to-live) ctx = ctx.withHint("ttl", "3d"); // Set the compression algorithm to Zstd. ctx = ctx.withCompression(Compression.Zstd); // Use the ctx when writing data to GreptimeDB CompletableFuture> future = client.write(Arrays.asList(table1, table2), WriteOp.Insert, ctx); ``` For how to write data to GreptimeDB, see the following sections. ### Batching Write Batching write allows you to write data to multiple tables in a single request. It returns a `CompletableFuture>` and provides good performance through asynchronous execution. This is the recommended way to write data to GreptimeDB for most use cases. ```java // The batching write API CompletableFuture> future = client.write(table1, table2, table3); // For performance reasons, the SDK is designed to be purely asynchronous. // The return value is a CompletableFuture object. If you want to immediately obtain // the result, you can call `future.get()`, which will block until the operation completes. // For production environments, consider using non-blocking approaches with callbacks or // the CompletableFuture API. Result result = future.get(); ``` ### Streaming Write The streaming write API maintains a persistent connection to GreptimeDB for continuous data ingestion with rate limiting. It allows writing data from multiple tables through a single stream. Use this API when you need: - Continuous data collection with moderate volume - Writing to multiple tables via one connection - Cases where simplicity and convenience are more important than maximum throughput ```java // Create a stream writer StreamWriter writer = client.streamWriter(); // Write multiple tables writer.write(table1) .write(table2) .write(table3); // Complete the stream and get the result CompletableFuture result = writer.completed(); ``` You can also set a rate limit for stream writing: ```java // Limit to 1000 points per second StreamWriter writer = client.streamWriter(1000); ``` ### Bulk Write The Bulk Write API provides a high-performance, memory-efficient mechanism for ingesting large volumes of time-series data into GreptimeDB. It leverages off-heap memory management to achieve optimal throughput when writing batches of data. **Important**: 1. **Manual Table Creation Required**: Bulk API does **not** create tables automatically. You must create the table beforehand using either: - Insert API (which supports auto table creation), or - SQL DDL statements (CREATE TABLE) 2. **Schema Matching**: The table template in bulk API must exactly match the existing table schema. This API supports writing to one table per stream and handles large data volumes (up to 200MB per write) with adaptive flow control. Performance advantages include: - Off-heap memory management with Arrow buffers - Efficient binary serialization and data transfer - Optional compression - Batched operations This approach is particularly well-suited for: - Large-scale batch processing and data migrations - High-throughput log and sensor data ingestion - Time-series applications with demanding performance requirements - Systems processing high-frequency data collection Here's a typical pattern for using the Bulk Write API: ```java // Create a BulkStreamWriter with the table schema try (BulkStreamWriter writer = greptimeDB.bulkStreamWriter(schema)) { // Write multiple batches for (int batch = 0; batch < batchCount; batch++) { // Get a TableBufferRoot for this batch Table.TableBufferRoot table = writer.tableBufferRoot(1000); // column buffer size // Add rows to the batch for (int row = 0; row < rowsPerBatch; row++) { Object[] rowData = generateRow(batch, row); table.addRow(rowData); } // Complete the table to prepare for transmission table.complete(); // Send the batch and get a future for completion CompletableFuture future = writer.writeNext(); // Wait for the batch to be processed (optional) Integer affectedRows = future.get(); System.out.println("Batch " + batch + " wrote " + affectedRows + " rows"); } // Signal completion of the stream writer.completed(); } ``` #### Configuration The Bulk Write API can be configured with several options to optimize performance: ```java BulkWrite.Config cfg = BulkWrite.Config.newBuilder() .allocatorInitReservation(64 * 1024 * 1024L) // Customize memory allocation: 64MB initial reservation .allocatorMaxAllocation(4 * 1024 * 1024 * 1024L) // Customize memory allocation: 4GB max allocation .timeoutMsPerMessage(60 * 1000) // 60 seconds timeout per request .maxRequestsInFlight(8) // Concurrency Control: Configure with 8 maximum in-flight requests .build(); // Enable Zstd compression Context ctx = Context.newDefault().withCompression(Compression.Zstd); BulkStreamWriter writer = greptimeDB.bulkStreamWriter(schema, cfg, ctx); ``` ### Resource Management It's important to properly shut down the client when you're finished using it: ```java // Gracefully shut down the client client.shutdownGracefully(); ``` ### Performance Tuning #### Compression Options The ingester supports various compression algorithms to reduce network bandwidth and improve throughput. ```java // Set the compression algorithm to Zstd Context ctx = Context.newDefault().withCompression(Compression.Zstd); ``` #### Write Operation Comparison Understanding the performance characteristics of different write methods is crucial for optimizing data ingestion. | Write Method | API | Throughput | Latency | Memory Efficiency | CPU Usage | Best For | Limitations | |--------------|-----|------------|---------|-------------------|-----------|----------|-------------| | Batching Write | `write(tables)` | Better | Good | High | Higher | Simple applications, low latency requirements | Lower throughput for large volumes | | Streaming Write | `streamWriter()` | Moderate | Good | Moderate | Moderate | Continuous data streams, moderate throughput | More complex to use than regular writes | | Bulk Write | `bulkStreamWriter()` | Best | Higher | Best | Moderate | Maximum throughput, large batch operations | Higher latency, requires manual table creation | #### Buffer Size Optimization When using `BulkStreamWriter`, you can configure the column buffer size: ```java // Get the table buffer with a specific column buffer size Table.TableBufferRoot table = bulkStreamWriter.tableBufferRoot(columnBufferSize); ``` This option can significantly improve the speed of data conversion to the underlying format. For optimal performance, we recommend setting the column buffer size to 1024 or larger, depending on your specific workload characteristics and available memory. ### Export Metrics The ingester exposes comprehensive metrics that enable you to monitor its performance, health, and operational status. For detailed information about available metrics and their usage, refer to the [Ingester Prometheus Metrics](https://github.com/GreptimeTeam/greptimedb-ingester-java/tree/main/ingester-prometheus-metrics) documentation. ## Key Configuration Options `GreptimeOptions` is the main configuration class for the GreptimeDB Java client, used to configure client connections, write options, RPC settings, and various other parameters. For production environments, you may need to configure these commonly used options. Complete reference: [GreptimeOptions JavaDoc](https://javadoc.io/static/io.greptime/ingester-protocol/0.15.0/io/greptime/options/GreptimeOptions.html). **Key Options:** - `database`: Target database name, format `[catalog-]schema` (default: `public`) - `authInfo`: Authentication credentials for production environments - `rpcOptions.defaultRpcTimeout`: RPC request timeout (default: 60 seconds) - `writeMaxRetries`: Maximum retries for failed writes (default: 1) - `maxInFlightWritePoints`: Maximum data points in-flight for write flow control (default: 655360) - `writeLimitedPolicy`: Policy when write flow limit exceeded (default: AbortOnBlockingTimeoutPolicy 3s) - `defaultStreamMaxWritePointsPerSecond`: Rate limit for StreamWriter (default: 655360) ```java // Production-ready configuration RpcOptions rpcOpts = RpcOptions.newDefault(); rpcOpts.setDefaultRpcTimeout(30000); // 30 seconds timeout AuthInfo authInfo = new AuthInfo("username", "password"); GreptimeOptions options = GreptimeOptions.newBuilder("127.0.0.1:4001", "production_db") .authInfo(authInfo) .rpcOptions(rpcOpts) .writeMaxRetries(3) .maxInFlightWritePoints(1000000) .writeLimitedPolicy(new LimitedPolicy.AbortOnBlockingTimeoutPolicy(5, TimeUnit.SECONDS)) .defaultStreamMaxWritePointsPerSecond(50000) .build(); ``` ## FAQ ### Why am I getting some connection exceptions? When using the GreptimeDB Java ingester SDK, you may encounter some connection exceptions. For example, exceptions that are "`Caused by: java.nio.channels.UnsupportedAddressTypeException`", "`Caused by: java.net.ConnectException: connect(..) failed: Address family not supported by protocol`", or "`Caused by: java.net.ConnectException: connect(..) failed: Invalid argument`". While you are certain that the GreptimeDB server is running, and its endpoint is reachable. These connection exceptions could be all because the gRPC's `io.grpc.NameResolverProvider` service provider is not packaged into the final JAR, during the assembling process. So the fix can be: - If you are using Maven Assembly plugin, add the `metaInf-services` container descriptor handler to your assembly file, like this: ```xml ... metaInf-services ``` - And if you are using Maven Shade plugin, you can add the `ServicesResourceTransformer` instead: ```xml ... org.apache.maven.plugins maven-shade-plugin 3.6.0 shade ... ``` ## API Documentation and Examples - [API Reference](https://javadoc.io/doc/io.greptime/ingester-protocol/latest/index.html) - [Examples](https://github.com/GreptimeTeam/greptimedb-ingester-java/tree/main/ingester-example/) --- ## gRPC SDKs This guide will demonstrate how to use client libraries to write data in GreptimeDB. - [Go](go.md) - [Java](java.md) - [Rust](https://github.com/GreptimeTeam/greptimedb-ingester-rust) - [.NET](https://github.com/GreptimeTeam/greptimedb-ingester-dotnet) - [Erlang](https://github.com/GreptimeTeam/greptimedb-ingester-erl) - [TypeScript](https://github.com/GreptimeTeam/greptimedb-ingester-ts) --- ## InfluxDB Line Protocol GreptimeDB supports HTTP InfluxDB Line protocol. ## Ingest data ### Protocols #### Post metrics You can write data to GreptimeDB using the `/influxdb/write` API. Here's an example of how to use this API: ```shell curl -i -XPOST "http://localhost:4000/v1/influxdb/api/v2/write?db=public&precision=ms" \ -H "authorization: token {{greptime_user:greptimedb_password}}" \ --data-binary \ 'monitor,host=127.0.0.1 cpu=0.1,memory=0.4 1667446797450 monitor,host=127.0.0.2 cpu=0.2,memory=0.3 1667446798450 monitor,host=127.0.0.1 cpu=0.5,memory=0.2 1667446798450' ``` ```shell curl -i -XPOST "http://localhost:4000/v1/influxdb/write?db=public&precision=ms&u={{greptime_user}}&p={{greptimedb_password}}" \ --data-binary \ 'monitor,host=127.0.0.1 cpu=0.1,memory=0.4 1667446797450 monitor,host=127.0.0.2 cpu=0.2,memory=0.3 1667446798450 monitor,host=127.0.0.1 cpu=0.5,memory=0.2 1667446798450' ``` The `/influxdb/write` supports query params including: * `db`: Specifies the database to write to. The default value is `public`. * `precision`: Defines the precision of the timestamp provided in the request body. Accepted values are `ns` (nanoseconds), `us` (microseconds), `ms` (milliseconds), and `s` (seconds). The data type of timestamps written by this API is `TimestampNanosecond`, so the default precision is `ns` (nanoseconds). If you use timestamps with other precisions in the request body, you need to specify the precision using this parameter. This parameter ensures that timestamp values are accurately interpreted and stored with nanosecond precision. You can also omit the timestamp when sending requests. GreptimeDB will use the current system time (in UTC) of the host machine as the timestamp. For example: ```shell curl -i -XPOST "http://localhost:4000/v1/influxdb/api/v2/write?db=public" \ -H "authorization: token {{greptime_user:greptimedb_password}}" \ --data-binary \ 'monitor,host=127.0.0.1 cpu=0.1,memory=0.4 monitor,host=127.0.0.2 cpu=0.2,memory=0.3 monitor,host=127.0.0.1 cpu=0.5,memory=0.2' ``` ```shell curl -i -XPOST "http://localhost:4000/v1/influxdb/write?db=public&u={{greptime_user}}&p={{greptimedb_password}}" \ --data-binary \ 'monitor,host=127.0.0.1 cpu=0.1,memory=0.4 monitor,host=127.0.0.2 cpu=0.2,memory=0.3 monitor,host=127.0.0.1 cpu=0.5,memory=0.2' ``` #### Authentication GreptimeDB is compatible with InfluxDB's line protocol authentication format, both V1 and V2. If you have [configured authentication](/user-guide/deployments-administration/authentication/overview.md) in GreptimeDB, you need to provide the username and password in the HTTP request. InfluxDB's [V2 protocol](https://docs.influxdata.com/influxdb/v1.8/tools/api/?t=Auth+Enabled#apiv2query-http-endpoint) uses a format much like HTTP's standard basic authentication scheme. ```shell curl 'http://localhost:4000/v1/influxdb/api/v2/write?db=public' \ -H 'authorization: token {{username:password}}' \ -d 'monitor,host=127.0.0.1 cpu=0.1,memory=0.4' ``` For the authentication format of InfluxDB's [V1 protocol](https://docs.influxdata.com/influxdb/v1.8/tools/api/?t=Auth+Enabled#query-string-parameters-1). Add `u` for user and `p` for password to the HTTP query string as shown below: ```shell curl 'http://localhost:4000/v1/influxdb/write?db=public&u=&p=' \ -d 'monitor,host=127.0.0.1 cpu=0.1,memory=0.4' ``` ### Telegraf GreptimeDB's support for the [InfluxDB line protocol](../for-iot/influxdb-line-protocol.md) ensures its compatibility with Telegraf. To configure Telegraf, simply add GreptimeDB URL into Telegraf configurations: ```toml [[outputs.influxdb_v2]] urls = ["http://:4000/v1/influxdb"] token = ":" bucket = "" ## Leave empty organization = "" ``` ```toml [[outputs.influxdb]] urls = ["http://:4000/v1/influxdb"] database = "" username = "" password = "" ``` ## Data model While you may already be familiar with [InfluxDB key concepts](https://docs.influxdata.com/influxdb/v2/reference/key-concepts/), the [data model](/user-guide/concepts/data-model.md) of GreptimeDB is something new to explore. Here are the similarities and differences between the data models of GreptimeDB and InfluxDB: - Both solutions are [schemaless](/user-guide/ingest-data/overview.md#automatic-schema-generation), eliminating the need to define a schema before writing data. - The GreptimeDB table is automatically created with the [`merge_mode` option](/reference/sql/create.md#create-a-table-with-merge-mode) set to `last_non_null`. That means the table merges rows with the same tags and timestamp by keeping the latest value of each field, which is the same behavior as InfluxDB. - In InfluxDB, a point represents a single data record with a measurement, tag set, field set, and a timestamp. In GreptimeDB, it is represented as a row of data in the time-series table, where the table name aligns with the measurement, and the columns are divided into three types: Tag, Field, and Timestamp. - GreptimeDB uses `TimestampNanosecond` as the data type for timestamp data from the [InfluxDB line protocol API](/user-guide/ingest-data/for-iot/influxdb-line-protocol.md). - GreptimeDB uses `Float64` as the data type for numeric data from the InfluxDB line protocol API. Consider the following [sample data](https://docs.influxdata.com/influxdb/v2/reference/key-concepts/data-elements/#sample-data) borrowed from InfluxDB docs as an example: |_time|_measurement|location|scientist|_field|_value| |---|---|---|---|---|---| |2019-08-18T00:00:00Z|census|klamath|anderson|bees|23| |2019-08-18T00:00:00Z|census|portland|mullen|ants|30| |2019-08-18T00:06:00Z|census|klamath|anderson|bees|28| |2019-08-18T00:06:00Z|census|portland|mullen|ants|32| The data mentioned above is formatted as follows in the InfluxDB line protocol: ```shell census,location=klamath,scientist=anderson bees=23 1566086400000000000 census,location=portland,scientist=mullen ants=30 1566086400000000000 census,location=klamath,scientist=anderson bees=28 1566086760000000000 census,location=portland,scientist=mullen ants=32 1566086760000000000 ``` In the GreptimeDB data model, the data is represented as follows in the `census` table: ```sql +---------------------+----------+-----------+------+------+ | greptime_timestamp | location | scientist | bees | ants | +---------------------+----------+-----------+------+------+ | 2019-08-18 00:00:00 | klamath | anderson | 23 | NULL | | 2019-08-18 00:06:00 | klamath | anderson | 28 | NULL | | 2019-08-18 00:00:00 | portland | mullen | NULL | 30 | | 2019-08-18 00:06:00 | portland | mullen | NULL | 32 | +---------------------+----------+-----------+------+------+ ``` The schema of the `census` table is as follows: ```sql +--------------------+----------------------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +--------------------+----------------------+------+------+---------+---------------+ | location | String | PRI | YES | | TAG | | scientist | String | PRI | YES | | TAG | | bees | Float64 | | YES | | FIELD | | greptime_timestamp | TimestampNanosecond | PRI | NO | | TIMESTAMP | | ants | Float64 | | YES | | FIELD | +--------------------+----------------------+------+------+---------+---------------+ ``` ## Reference - [InfluxDB Line protocol](https://docs.influxdata.com/influxdb/v2.7/reference/syntax/line-protocol/) --- ## Kafka Please refer to the [Kafka documentation](/user-guide/ingest-data/for-observability/kafka.md) for instructions on how to ingest data from Kafka into GreptimeDB. --- ## OpenTSDB GreptimeDB supports ingesting OpenTSDB via HTTP API. GreptimeDB also supports inserting OpenTSDB metrics via HTTP endpoints. We use the request and response format described in OpenTSDB's `/api/put`. The HTTP endpoint in GreptimeDB for handling metrics is `/opentsdb/api/put` > Note: remember to prefix the path with GreptimeDB's http API version, `v1`. Starting GreptimeDB, the HTTP server is listening on port `4000` by default. Use curl to insert one metric point: ```shell curl -X POST http://127.0.0.1:4000/v1/opentsdb/api/put \ -H 'Authorization: Basic {{authentication}}' \ -d ' { "metric": "sys.cpu.nice", "timestamp": 1667898896, "value": 18, "tags": { "host": "web01", "dc": "hz" } } ' ``` Or insert multiple metric points: ```shell curl -X POST http://127.0.0.1:4000/v1/opentsdb/api/put \ -H 'Authorization: Basic {{authentication}}' \ -d ' [ { "metric": "sys.cpu.nice", "timestamp": 1667898896, "value": 1, "tags": { "host": "web02", "dc": "hz" } }, { "metric": "sys.cpu.nice", "timestamp": 1667898897, "value": 9, "tags": { "host": "web03", "dc": "sh" } } ] ' ``` --- ## Ingest Data for IoT The data ingestion is a critical part of the IoT data pipeline. It is the process of collecting data from various sources, such as sensors, devices, and applications, and storing it in a central location for further processing and analysis. The data ingestion is essential for ensuring that the data is accurate, reliable, and secure. GreptimeDB can handle large volumes of data, process it in real-time, and store it efficiently for future analysis. It also supports various data formats, protocols, and interfaces, making it easy to integrate with different IoT devices and systems. --- ## SQL You can execute SQL statements using [MySQL](/user-guide/protocols/mysql.md) or [PostgreSQL](/user-guide/protocols/postgresql.md) clients, and access GreptimeDB using the MySQL or PostgreSQL protocol with any programming language of your preference, such as Java JDBC. We will use the `monitor` table as an example to show how to write data. ## Create a table Before inserting data, you need to create a table. For example, create a table named `monitor`: ```sql CREATE TABLE monitor ( host STRING, ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP() TIME INDEX, cpu FLOAT64 DEFAULT 0, memory FLOAT64, PRIMARY KEY(host)); ``` The above statement will create a table with the following schema: ```sql +--------+----------------------+------+------+---------------------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +--------+----------------------+------+------+---------------------+---------------+ | host | String | PRI | YES | | TAG | | ts | TimestampMillisecond | PRI | NO | current_timestamp() | TIMESTAMP | | cpu | Float64 | | YES | 0 | FIELD | | memory | Float64 | | YES | | FIELD | +--------+----------------------+------+------+---------------------+---------------+ 4 rows in set (0.01 sec) ``` For more information about the `CREATE TABLE` statement, please refer to [table management](/user-guide/deployments-administration/manage-data/basic-table-operations.md#create-a-table). ## Insert data Let's insert some testing data to the `monitor` table. You can use the `INSERT INTO` SQL statements: ```sql INSERT INTO monitor VALUES ("127.0.0.1", 1702433141000, 0.5, 0.2), ("127.0.0.2", 1702433141000, 0.3, 0.1), ("127.0.0.1", 1702433146000, 0.3, 0.2), ("127.0.0.2", 1702433146000, 0.2, 0.4), ("127.0.0.1", 1702433151000, 0.4, 0.3), ("127.0.0.2", 1702433151000, 0.2, 0.4); ``` ```sql Query OK, 6 rows affected (0.01 sec) ``` You can also insert data by specifying the column names: ```sql INSERT INTO monitor (host, ts, cpu, memory) VALUES ("127.0.0.1", 1702433141000, 0.5, 0.2), ("127.0.0.2", 1702433141000, 0.3, 0.1), ("127.0.0.1", 1702433146000, 0.3, 0.2), ("127.0.0.2", 1702433146000, 0.2, 0.4), ("127.0.0.1", 1702433151000, 0.4, 0.3), ("127.0.0.2", 1702433151000, 0.2, 0.4); ``` Through the above statement, we have inserted six rows into the `monitor` table. For more information about the `INSERT` statement, please refer to [`INSERT`](/reference/sql/insert.md). ## Time zone The time zone specified in the SQL client will affect the timestamp with a string format that does not have time zone information. The timestamp value will automatically have the client's time zone information added. For example, the following SQL set the time zone to `+8:00`: ```sql SET time_zone = '+8:00'; ``` Then insert values into the `monitor` table: ```sql INSERT INTO monitor (host, ts, cpu, memory) VALUES ("127.0.0.1", "2024-01-01 00:00:00", 0.4, 0.1), ("127.0.0.2", "2024-01-01 00:00:00+08:00", 0.5, 0.1); ``` The first timestamp value `2024-01-01 00:00:00` does not have time zone information, so it will automatically have the client's time zone information added. After inserting, it will be equivalent to the second value `2024-01-01 00:00:00+08:00`. The result in the `+8:00` time zone client is as follows: ```sql +-----------+---------------------+------+--------+ | host | ts | cpu | memory | +-----------+---------------------+------+--------+ | 127.0.0.1 | 2024-01-01 00:00:00 | 0.4 | 0.1 | | 127.0.0.2 | 2024-01-01 00:00:00 | 0.5 | 0.1 | +-----------+---------------------+------+--------+ ``` The result in the `UTC` time zone client is as follows: ```sql +-----------+---------------------+------+--------+ | host | ts | cpu | memory | +-----------+---------------------+------+--------+ | 127.0.0.1 | 2023-12-31 16:00:00 | 0.4 | 0.1 | | 127.0.0.2 | 2023-12-31 16:00:00 | 0.5 | 0.1 | +-----------+---------------------+------+--------+ ``` --- ## Grafana Alloy [Grafana Alloy](https://grafana.com/docs/alloy/latest/) is an observability data pipeline for OpenTelemetry (OTel), Prometheus, Pyroscope, Loki, and many other metrics, logs, traces, and profiling tools. You can integrate GreptimeDB as a data sink for Alloy. ## Prometheus Remote Write Configure GreptimeDB as remote write target: ```hcl prometheus.remote_write "greptimedb" { endpoint { url = "${GREPTIME_SCHEME:=http}://${GREPTIME_HOST:=greptimedb}:${GREPTIME_PORT:=4000}/v1/prometheus/write?db=${GREPTIME_DB:=public}" basic_auth { username = "${GREPTIME_USERNAME}" password = "${GREPTIME_PASSWORD}" } } } ``` - `GREPTIME_HOST`: GreptimeDB host address, e.g., `localhost`. - `GREPTIME_DB`: GreptimeDB database name, default is `public`. - `GREPTIME_USERNAME` and `GREPTIME_PASSWORD`: The [authentication credentials](/user-guide/deployments-administration/authentication/static.md) for GreptimeDB. For details on the data model transformation from Prometheus to GreptimeDB, refer to the [Data Model](/user-guide/ingest-data/for-observability/prometheus.md#data-model) section in the Prometheus Remote Write guide. ## OpenTelemetry GreptimeDB can also be configured as OpenTelemetry collector. ### Metrics ```hcl otelcol.exporter.otlphttp "greptimedb" { client { endpoint = "${GREPTIME_SCHEME:=http}://${GREPTIME_HOST:=greptimedb}:${GREPTIME_PORT:=4000}/v1/otlp/" headers = { "X-Greptime-DB-Name" = "${GREPTIME_DB:=public}", } auth = otelcol.auth.basic.credentials.handler } } otelcol.auth.basic "credentials" { username = "${GREPTIME_USERNAME}" password = "${GREPTIME_PASSWORD}" } ``` - `GREPTIME_HOST`: GreptimeDB host address, e.g., `localhost`. - `GREPTIME_DB`: GreptimeDB database name, default is `public`. - `GREPTIME_USERNAME` and `GREPTIME_PASSWORD`: The [authentication credentials](/user-guide/deployments-administration/authentication/static.md) for GreptimeDB. For details on the metrics data model transformation from OpenTelemetry to GreptimeDB, refer to the [Data Model](/user-guide/ingest-data/for-observability/opentelemetry.md#data-model) section in the OpenTelemetry guide. ### Logs This example sends logs to GreptimeDB through an OpenTelemetry pipeline. For production log pipelines, add an explicit batch processor before the exporter. See the [Batching](#batching) section for details. ```hcl loki.source.file "greptime" { targets = [ {__path__ = "/tmp/foo.txt"}, ] forward_to = [otelcol.receiver.loki.greptime.receiver] } otelcol.receiver.loki "greptime" { output { logs = [otelcol.processor.batch.greptimedb_logs.input] } } otelcol.processor.batch "greptimedb_logs" { send_batch_size = 5000 send_batch_max_size = 10000 timeout = "1s" output { logs = [otelcol.exporter.otlphttp.greptimedb_logs.input] } } otelcol.auth.basic "credentials" { username = "${GREPTIME_USERNAME}" password = "${GREPTIME_PASSWORD}" } otelcol.exporter.otlphttp "greptimedb_logs" { client { endpoint = "${GREPTIME_SCHEME:=http}://${GREPTIME_HOST:=greptimedb}:${GREPTIME_PORT:=4000}/v1/otlp/" headers = { "X-Greptime-DB-Name" = "${GREPTIME_DB:=public}", "X-Greptime-Log-Table-Name" = "${GREPTIME_LOG_TABLE_NAME:=demo_logs}", "X-Greptime-Log-Extract-Keys" = "filename,log.file.name,loki.attribute.labels", } auth = otelcol.auth.basic.credentials.handler } sending_queue { queue_size = 10000 num_consumers = 10 } } ``` - `GREPTIME_HOST`: GreptimeDB host address, such as `localhost`. - `GREPTIME_DB`: GreptimeDB database name, default is `public`. - `GREPTIME_LOG_TABLE_NAME`: Target log table name, default is `demo_logs`. - `GREPTIME_USERNAME` and `GREPTIME_PASSWORD`: The [authentication credentials](/user-guide/deployments-administration/authentication/static.md) for GreptimeDB. - `X-Greptime-Log-Extract-Keys`: Keys extracted from OTLP log attributes. See the [OTLP/HTTP API documentation](/user-guide/ingest-data/for-observability/opentelemetry.md#otlphttp-api-1) for details. For details on the log data model transformation from OpenTelemetry to GreptimeDB, refer to the [Data Model](/user-guide/ingest-data/for-observability/opentelemetry.md#data-model-1) section in the OpenTelemetry guide. ## Loki GreptimeDB also supports the Loki push protocol for logs. If your Alloy pipeline is already built with Loki components, we recommend using the native Loki ingestion path first. See the [Loki guide](/user-guide/ingest-data/for-observability/loki.md) for the Loki protocol details and data model mapping. ### Logs This example uses only Loki components to read, process, and send logs to GreptimeDB through the Loki push API: ```hcl loki.source.file "greptime" { targets = [ {__path__ = "/tmp/foo.txt"}, ] forward_to = [loki.process.greptime.receiver] } loki.process "greptime" { forward_to = [loki.write.greptimedb.receiver] stage.static_labels { values = { job = "greptime", from = "alloy", } } } loki.write "greptimedb" { endpoint { url = "${GREPTIME_SCHEME:=http}://${GREPTIME_HOST:=greptimedb}:${GREPTIME_PORT:=4000}/v1/loki/api/v1/push" headers = { "X-Greptime-DB-Name" = "${GREPTIME_DB:=public}", "X-Greptime-Log-Table-Name" = "${GREPTIME_LOG_TABLE_NAME:=loki_demo_logs}", } basic_auth { username = "${GREPTIME_USERNAME}" password = "${GREPTIME_PASSWORD}" } } } ``` - `GREPTIME_HOST`: GreptimeDB host address, such as `localhost`. - `GREPTIME_DB`: GreptimeDB database name, default is `public`. - `GREPTIME_LOG_TABLE_NAME`: Target log table name, default is `loki_demo_logs`. - `GREPTIME_USERNAME` and `GREPTIME_PASSWORD`: The [authentication credentials](/user-guide/deployments-administration/authentication/static.md) for GreptimeDB. This configuration tails `/tmp/foo.txt`, adds two static labels, and sends the logs directly to GreptimeDB with `loki.write`. ## Batching `otelcol.exporter.otlphttp` does not enable batching by default. When Alloy reads a burst of logs, such as a large backlog from files or Docker containers, the exporter queue can fill before enough records are grouped together, which leads to errors like `sending queue is full`. Based on the behavior reported in production testing, enabling the exporter's internal `sending_queue.batch` block alone may still be insufficient for bursty log workloads. Putting `otelcol.processor.batch` in front of the exporter is a more reliable pattern for logs because the exporter receives larger bundled batches instead of many individual log records. If you use OTLP/HTTP for logs, we recommend this order: 1. `loki.source.*` 2. `otelcol.receiver.loki` 3. `otelcol.processor.batch` 4. `otelcol.exporter.otlphttp` If your pipeline is already Loki-native and you do not need OpenTelemetry processing, prefer `loki.write` and the Loki push protocol instead. :::tip NOTE Refer to the official Grafana Alloy documentation for the latest component behavior and tuning guidance, especially for `loki.write`, `otelcol.processor.batch`, and `otelcol.exporter.otlphttp`. ::: --- ## Elasticsearch ## Overview GreptimeDB supports data ingestion through Elasticsearch's [`_bulk` API](https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html). We map Elasticsearch's Index concept to GreptimeDB's Table, and users can specify the database name using the `db` URL parameter. **Unlike native Elasticsearch, this API only supports data insertion, not modification or deletion**. At the implementation level, both `index` and `create` commands in native Elasticsearch `_bulk` API requests are treated as **creation operations** by GreptimeDB. Additionally, GreptimeDB only parses the `_index` field from native `_bulk` API command requests while ignoring other fields. ## HTTP API In most log collectors(such as Logstash and Filebeat mentioned below), you only need to configure the HTTP endpoint like `http://${db_host}:${db_http_port}/v1/elasticsearch`, for example `http://localhost:4000/v1/elasticsearch`. GreptimeDB supports data ingestion through Elasticsearch protocol by implementing the following two HTTP endpoints: - **`/v1/elasticsearch/_bulk`**: Users can use the POST method to write data in NDJSON format to GreptimeDB. For example, the following request will create a table named `test` and insert two records: ```json POST /v1/elasticsearch/_bulk {"create": {"_index": "test", "_id": "1"}} {"name": "John", "age": 30} {"create": {"_index": "test", "_id": "2"}} {"name": "Jane", "age": 25} ``` - **`/v1/elasticsearch/${index}/_bulk`**: Users can use the POST method to write data in NDJSON format to the `${index}` table in GreptimeDB. If the POST request also contains an `_index` field, the `${index}` in the URL will be ignored. For example, the following request will create tables named `test` and `another_index`, and insert corresponding data: ```json POST /v1/elasticsearch/test/_bulk {"create": {"_id": "1"}} {"name": "John", "age": 30} {"create": {"_index": "another_index", "_id": "2"}} {"name": "Jane", "age": 25} ``` ### HTTP Headers - `x-greptime-db-name`: Specifies the database name. Defaults to `public` if not specified. - `x-greptime-pipeline-name`: Specifies the pipeline name. Defaults to GreptimeDB's internal pipeline `greptime_identity` if not specified. - `x-greptime-pipeline-version`: Specifies the pipeline version. Defaults to the latest version of the corresponding pipeline if not specified. For more details about Pipeline, please refer to the [Manage Pipelines](/user-guide/logs/manage-pipelines.md) documentation. ### URL Parameters You can use the following HTTP URL parameters: - `db`: Specifies the database name. Defaults to `public` if not specified. - `pipeline_name`: Specifies the pipeline name. Defaults to GreptimeDB's internal pipeline `greptime_identity` if not specified. - `version`: Specifies the pipeline version. Defaults to the latest version of the corresponding pipeline if not specified. - `msg_field`: Specifies the JSON field name containing the original log data. For example, in Logstash and Filebeat, this field is typically `message`. If specified, GreptimeDB will attempt to parse the data in this field as JSON format. If parsing fails, the field will be treated as a string. This configuration option currently only takes effect in URL parameters. ### Authentication Header For detailed information about the authentication header, please refer to the [Authorization](/user-guide/protocols/http.md#authentication) documentation. ## Usage ### Use HTTP API to ingest data You can create a `request.json` file with the following content: ```json {"create": {"_index": "es_test", "_id": "1"}} {"name": "John", "age": 30} {"create": {"_index": "es_test", "_id": "2"}} {"name": "Jane", "age": 25} ``` Then use the `curl` command to send this file as a request body to GreptimeDB: ```bash curl -XPOST http://localhost:4000/v1/elasticsearch/_bulk \ -H "Authorization: Basic {{authentication}}" \ -H "Content-Type: application/json" -d @request.json ``` We can use a `mysql` client to connect to GreptimeDB and execute the following SQL to view the inserted data: ```sql SELECT * FROM es_test; ``` We will see the following results: ``` mysql> SELECT * FROM es_test; +------+------+----------------------------+ | age | name | greptime_timestamp | +------+------+----------------------------+ | 30 | John | 2025-01-15 08:26:06.516665 | | 25 | Jane | 2025-01-15 08:26:06.521510 | +------+------+----------------------------+ 2 rows in set (0.13 sec) ``` ### Logstash If you are using [Logstash](https://www.elastic.co/logstash) to collect logs, you can use the following configuration to write data to GreptimeDB: ``` output { elasticsearch { hosts => ["http://localhost:4000/v1/elasticsearch"] index => "my_index" parameters => { "pipeline_name" => "my_pipeline" "msg_field" => "message" } } } ``` Please pay attention to the following GreptimeDB-related configurations: - `hosts`: Specifies the HTTP address of GreptimeDB's Elasticsearch protocol, which is `http://${db_host}:${db_http_port}/v1/elasticsearch`. - `index`: Specifies the table name that will be written to. - `parameters`: Specifies the URL parameters for writing, where the example above specifies two parameters: `pipeline_name` and `msg_field`. ### Filebeat If you are using [Filebeat](https://github.com/elastic/beats/tree/main/filebeat) to collect logs, you can use the following configuration to write data to GreptimeDB: ``` output.elasticsearch: hosts: ["http://localhost:4000/v1/elasticsearch"] index: "my_index" parameters: pipeline_name: my_pipeline msg_field: message ``` Please pay attention to the following GreptimeDB-related configurations: - `hosts`: Specifies the HTTP address of GreptimeDB's Elasticsearch protocol, which is `http://${db_host}:${db_http_port}/v1/elasticsearch`. - `index`: Specifies the table name that will be written to. - `parameters`: Specifies the URL parameters for writing, where the example above specifies two parameters: `pipeline_name` and `msg_field`. ### Telegraf If you are using [Telegraf](https://github.com/influxdata/telegraf) to collect logs, you can use its Elasticsearch plugin to write data to GreptimeDB, as shown below: ```toml [[outputs.elasticsearch]] urls = [ "http://localhost:4000/v1/elasticsearch" ] index_name = "test_table" health_check_interval = "0s" enable_sniffer = false flush_interval = "1s" manage_template = false template_name = "telegraf" overwrite_template = false namepass = ["tail"] [outputs.elasticsearch.headers] "X-GREPTIME-DB-NAME" = "public" "X-GREPTIME-PIPELINE-NAME" = "greptime_identity" [[inputs.tail]] files = ["/tmp/test.log"] from_beginning = true data_format = "value" data_type = "string" character_encoding = "utf-8" interval = "1s" pipe = false watch_method = "inotify" ``` Please pay attention to the following GreptimeDB-related configurations: - `urls`: Specifies the HTTP address of GreptimeDB's Elasticsearch protocol, which is `http://${db_host}:${db_http_port}/v1/elasticsearch`. - `index_name`: Specifies the table name that will be written to. - `outputs.elasticsearch.header`: Specifies the HTTP Header for writing, where the example above specifies two parameters: `X-GREPTIME-DB-NAME` and `X-GREPTIME-PIPELINE-NAME`. --- ## Fluent Bit [Fluent Bit](http://fluentbit.io/) is a fast and lightweight telemetry agent for logs, metrics, and traces for Linux, macOS, Windows, and BSD family operating systems. Fluent Bit has been made with a strong focus on performance to allow the collection and processing of telemetry data from different sources without complexity. You can forward Fluent Bit data to GreptimeDB. This document describes how to configure Fluent Bit to send logs, metrics, and traces to GreptimeDB. ## Http Using Fluent Bit's [HTTP Output Plugin](https://docs.fluentbit.io/manual/pipeline/outputs/http), you can send logs to GreptimeDB. Before configuring Fluent Bit, ensure that you understand the [log ingestion flow](/user-guide/logs/overview.md) and [how to use pipelines](/user-guide/logs/use-custom-pipelines.md). ```conf [OUTPUT] Name http Match * Host greptimedb Port 4000 Uri /v1/ingest?db=public&table=your_table&pipeline_name=greptime_identity Format json Json_date_key scrape_timestamp Json_date_format iso8601 compress gzip http_User http_Passwd ``` - `host`: GreptimeDB host address, e.g., `localhost`. - `port`: GreptimeDB port, default is `4000`. - `uri`: The endpoint to send logs to. - `format`: The format of the logs, needs to be `json`. - `json_date_key`: The key in the JSON object that contains the timestamp. - `json_date_format`: The format of the timestamp. - `compress`: The compression method to use, e.g., `gzip`. - `header`: The header to send with the request, e.g., `Authorization` for authentication. - `http_user` and `http_passwd`: The [authentication credentials](/user-guide/deployments-administration/authentication/static.md) for GreptimeDB. In params Uri, - `db` is the database name you want to write logs to. - `table` is the table name you want to write logs to. - `pipeline_name` is the pipeline name you want to use for processing logs. ## OpenTelemetry GreptimeDB can also be configured as OpenTelemetry collector. Using Fluent Bit's [OpenTelemetry Output Plugin](https://docs.fluentbit.io/manual/pipeline/outputs/opentelemetry), you can send metrics, logs, and traces to GreptimeDB. ``` [OUTPUT] Name opentelemetry Match * Host 127.0.0.1 Port 4000 Metrics_uri /v1/otlp/v1/metrics Logs_uri /v1/otlp/v1/logs Traces_uri /v1/otlp/v1/traces Log_response_payload True Tls Off Tls.verify Off logs_body_key message http_User http_Passwd ``` - `Metrics_uri`, `Logs_uri`, and `Traces_uri`: The endpoint to send metrics, logs, and traces to. - `http_user` and `http_passwd`: The [authentication credentials](/user-guide/deployments-administration/authentication/static.md) for GreptimeDB. We recommend not writing metrics, logs, and traces to a single output simultaneously, as each has specific header options for specifying parameters. We suggest creating a separate OpenTelemetry output for metrics, logs, and traces. for example: ``` # Only for metrics [OUTPUT] Name opentelemetry Alias opentelemetry_metrics Match * Host 127.0.0.1 Port 4000 Metrics_uri /v1/otlp/v1/metrics Log_response_payload True Tls Off Tls.verify Off # Only for logs [OUTPUT] Name opentelemetry Alias opentelemetry_logs Match * Host 127.0.0.1 Port 4000 Logs_uri /v1/otlp/v1/logs Log_response_payload True Tls Off Tls.verify Off Header X-Greptime-Log-Table-Name "" Header X-Greptime-Log-Pipeline-Name "" Header X-Greptime-DB-Name "" ``` In this example, the [OpenTelemetry OTLP/HTTP API](/user-guide/ingest-data/for-observability/opentelemetry.md#opentelemetry-collectors) interface is used. For more information, and extra options, refer to the [OpenTelemetry](/user-guide/ingest-data/for-observability/opentelemetry.md) guide. ## Prometheus Remote Write Configure GreptimeDB as remote write target: ``` [OUTPUT] Name prometheus_remote_write Match internal_metrics Host 127.0.0.1 Port 4000 Uri /v1/prometheus/write?db= Tls Off http_user http_passwd ``` - `Uri`: The endpoint to send metrics to. - `http_user` and `http_passwd`: The [authentication credentials](/user-guide/deployments-administration/authentication/static.md) for GreptimeDB. In params Uri, - `db` is the database name you want to write metrics to. For details on the data model transformation from Prometheus to GreptimeDB, refer to the [Data Model](/user-guide/ingest-data/for-observability/prometheus.md#data-model) section in the Prometheus Remote Write guide. --- ## InfluxDB Line Protocol(For-observability) Please refer to the [InfluxDB Line Protocol documentation](../for-iot/influxdb-line-protocol.md) for instructions on how to write data to GreptimeDB using the InfluxDB Line Protocol. --- ## Kafka(For-observability) If you are using Kafka or Kafka-compatible message queue for observability data transporting, it's possible to ingest data into GreptimeDB directly. Here we are using Vector as the tool to transport data from Kafka to GreptimeDB. ## Metrics When ingesting metrics from Kafka into GreptimeDB, messages should be formatted in InfluxDB line protocol. For example: ```txt census,location=klamath,scientist=anderson bees=23 1566086400000000000 ``` Then configure Vector to use the `influxdb` decoding codec to process these messages. ```toml [sources.metrics_mq] # Specifies that the source type is Kafka type = "kafka" # The consumer group ID for Kafka group_id = "vector0" # The list of Kafka topics to consume messages from topics = ["test_metric_topic"] # The address of the Kafka broker to connect to bootstrap_servers = "kafka:9092" # The `influxdb` means the messages are expected to be in InfluxDB line protocol format. decoding.codec = "influxdb" [sinks.metrics_in] inputs = ["metrics_mq"] # Specifies that the sink type is `greptimedb_metrics` type = "greptimedb_metrics" # The endpoint of the GreptimeDB server. # Replace with the actual hostname or IP address. endpoint = ":4001" dbname = "" username = "" password = "" tls = {} ``` For details on how InfluxDB line protocol metrics are mapped to GreptimeDB data, please refer to the [Data Model](/user-guide/ingest-data/for-iot/influxdb-line-protocol.md#data-model) section in the InfluxDB line protocol documentation. ## Logs Developers commonly work with two types of logs: JSON logs and plain text logs. Consider the following examples sent from Kafka. A plain text log: ```txt 127.0.0.1 - - [25/May/2024:20:16:37 +0000] "GET /index.html HTTP/1.1" 200 612 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36" ``` Or a JSON log: ```json { "timestamp": "2024-12-23T10:00:00Z", "level": "INFO", "message": "Service started" } ``` GreptimeDB transforms these logs into structured data with multiple columns and automatically creates the necessary tables. A pipeline processes the logs into structured data before ingestion into GreptimeDB. Different log formats require different [Pipelines](/user-guide/logs/quick-start.md#write-logs-by-pipeline) for parsing. See the following sections for details. ### Logs with JSON format For logs in JSON format (e.g., `{"timestamp": "2024-12-23T10:00:00Z", "level": "INFO", "message": "Service started"}`), you can use the built-in [`greptime_identity`](/user-guide/logs/manage-pipelines.md#greptime_identity) pipeline for direct ingestion. This pipeline creates columns automatically based on the fields in your JSON log message. Simply configure Vector's `transforms` settings to parse the JSON message and use the `greptime_identity` pipeline as shown in the following example: ```toml [sources.logs_in] type = "kafka" # The consumer group ID for Kafka group_id = "vector0" # The list of Kafka topics to consume messages from topics = ["test_log_topic"] # The address of the Kafka broker to connect to bootstrap_servers = "kafka:9092" # transform the log to JSON format [transforms.logs_json] type = "remap" inputs = ["logs_in"] source = ''' . = parse_json!(.message) ''' [sinks.logs_out] # Specifies that this sink will receive data from the `logs_json` source inputs = ["logs_json"] # Specifies that the sink type is `greptimedb_logs` type = "greptimedb_logs" # The endpoint of the GreptimeDB server endpoint = "http://:4000" compression = "gzip" # Replace , , and with the actual values dbname = "" username = "" password = "" # The table name in GreptimeDB, if it doesn't exist, it will be created automatically table = "demo_logs" # Use the built-in `greptime_identity` pipeline pipeline_name = "greptime_identity" ``` ### Logs with text format For logs in text format, such as the access log format below, you'll need to create a custom pipeline to parse them: ``` 127.0.0.1 - - [25/May/2024:20:16:37 +0000] "GET /index.html HTTP/1.1" 200 612 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36" ``` #### Create a pipeline To create a custom pipeline, please refer to the [using custom pipelines](/user-guide/logs/use-custom-pipelines.md) documentation for detailed instructions. #### Ingest data After creating the pipeline, configure it to the `pipeline_name` field in the Vector configuration file. ```toml # sample.toml [sources.log_mq] # Specifies that the source type is Kafka type = "kafka" # The consumer group ID for Kafka group_id = "vector0" # The list of Kafka topics to consume messages from topics = ["test_log_topic"] # The address of the Kafka broker to connect to bootstrap_servers = "kafka:9092" [sinks.sink_greptime_logs] # Specifies that the sink type is `greptimedb_logs` type = "greptimedb_logs" # Specifies that this sink will receive data from the `log_mq` source inputs = [ "log_mq" ] # Use `gzip` compression to save bandwidth compression = "gzip" # The endpoint of the GreptimeDB server # Replace with the actual hostname or IP address endpoint = "http://:4000" dbname = "" username = "" password = "" # The table name in GreptimeDB, if it doesn't exist, it will be created automatically table = "demo_logs" # The custom pipeline name that you created pipeline_name = "your_custom_pipeline" ``` ## Demo For a runnable demo of data transformation and ingestion, please refer to the [Kafka Ingestion Demo](https://github.com/GreptimeTeam/demo-scene/tree/main/kafka-ingestion). --- ## Loki ## Usage ### API To send logs to GreptimeDB through the raw HTTP API, use the following information: * **URL**: `http{s}:///v1/loki/api/v1/push` * **Headers**: * `X-Greptime-DB-Name`: `` * `Authorization`: `Basic` authentication, which is a Base64 encoded string of `:`. For more information, please refer to [Authentication](https://docs.greptime.com/user-guide/deployments-administration/authentication/static/) and [HTTP API](https://docs.greptime.com/user-guide/protocols/http#authentication). * `X-Greptime-Log-Table-Name`: `` (optional) - The table name to store the logs. If not provided, the default table name is `loki_logs`. The request uses binary protobuf to encode the payload. The defined schema is the same as the [logproto.proto](https://github.com/grafana/loki/blob/main/pkg/logproto/logproto.proto). ### Example Code [Grafana Alloy](https://grafana.com/docs/alloy/latest/) is a vendor-neutral distribution of the OpenTelemetry (OTel) Collector. Alloy uniquely combines the very best OSS observability signals in the community. It supplies a Loki exporter that can be used to send logs to GreptimeDB. Here is an example configuration: ``` loki.source.file "greptime" { targets = [ {__path__ = "/tmp/foo.txt"}, ] forward_to = [loki.write.greptime_loki.receiver] } loki.write "greptime_loki" { endpoint { url = "${GREPTIME_SCHEME:=http}://${GREPTIME_HOST:=greptimedb}:${GREPTIME_PORT:=4000}/v1/loki/api/v1/push" headers = { "x-greptime-db-name" = "${GREPTIME_DB:=public}", "x-greptime-log-table-name" = "${GREPTIME_LOG_TABLE_NAME:=loki_demo_logs}", } } external_labels = { "job" = "greptime", "from" = "alloy", } } ``` This configuration reads logs from the file `/tmp/foo.txt` and sends them to GreptimeDB. The logs are stored in the table `loki_demo_logs` with the external labels `job` and `from`. For more information, please refer to the [Grafana Alloy loki.write documentation](https://grafana.com/docs/alloy/latest/reference/components/loki/loki.write/). You can run the following command to check the data in the table: ```sql SELECT * FROM loki_demo_logs; +----------------------------+------------------------+--------------+-------+----------+ | greptime_timestamp | line | filename | from | job | +----------------------------+------------------------+--------------+-------+----------+ | 2024-11-25 11:02:31.256251 | Greptime is very cool! | /tmp/foo.txt | alloy | greptime | +----------------------------+------------------------+--------------+-------+----------+ 1 row in set (0.01 sec) ``` ## Data Model The Loki logs data model is mapped to the GreptimeDB data model according to the following rules: **Default table schema without external labels:** ```sql DESC loki_demo_logs; +---------------------+---------------------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +---------------------+---------------------+------+------+---------+---------------+ | greptime_timestamp | TimestampNanosecond | PRI | NO | | TIMESTAMP | | line | String | | YES | | FIELD | | structured_metadata | Json | | YES | | FIELD | +---------------------+---------------------+------+------+---------+---------------+ 3 rows in set (0.00 sec) ``` - `greptime_timestamp`: The timestamp of the log entry - `line`: The log message content - `structured_metadata`: The structured metadata of the log entry in JSON format If the Loki Push request contains labels, they will be added as tags to the table schema (like `job` and `from` in the above example). **Important notes:** - All labels are treated as tags with string type - Do not attempt to pre-create the table using SQL to specify tag columns, as this will cause a type mismatch and write failure ### Example Table Schema The following is an example of the table schema with external labels: ```sql DESC loki_demo_logs; +---------------------+---------------------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +---------------------+---------------------+------+------+---------+---------------+ | greptime_timestamp | TimestampNanosecond | PRI | NO | | TIMESTAMP | | line | String | | YES | | FIELD | | structured_metadata | Json | | YES | | FIELD | | filename | String | PRI | YES | | TAG | | from | String | PRI | YES | | TAG | | job | String | PRI | YES | | TAG | +---------------------+---------------------+------+------+---------+---------------+ 6 rows in set (0.00 sec) ``` ```sql SHOW CREATE TABLE loki_demo_logs\G *************************** 1. row *************************** Table: loki_demo_logs Create Table: CREATE TABLE IF NOT EXISTS `loki_demo_logs` ( `greptime_timestamp` TIMESTAMP(9) NOT NULL, `line` STRING NULL, `filename` STRING NULL, `from` STRING NULL, `job` STRING NULL, TIME INDEX (`greptime_timestamp`), PRIMARY KEY (`filename`, `from`, `job`) ) ENGINE=mito WITH( append_mode = 'true' ) 1 row in set (0.00 sec) ``` ## Using Pipeline with Loki Push API :::warning Experimental Feature This experimental feature may contain unexpected behavior and have its functionality change in the future. ::: Starting from version `v0.15`, GreptimeDB supports using pipelines to process Loki push requests. You can simply set the HTTP header `x-greptime-pipeline-name` to the target pipeline name to enable pipeline processing. **Note:** When request data goes through the pipeline engine, GreptimeDB adds prefixes to the label and metadata column names: - `loki_label_` before each label name - `loki_metadata_` before each structured metadata name - The original Loki log line is named `loki_line` ### Pipeline Example Here is a complete example demonstrating how to use pipelines with Loki push API. **Step 1: Prepare the log file** Suppose we have a log file named `logs.json` with JSON-formatted log entries: ```json {"timestamp":"2025-08-21 14:23:17.892","logger":"sdk.tool.DatabaseUtil","level":"ERROR","message":"Connection timeout exceeded for database pool","trace_id":"a7f8c92d1e4b4c6f9d2e5a8b3f7c1d9e","source":"application"} {"timestamp":"2025-08-21 14:23:18.156","logger":"core.scheduler.TaskManager","level":"WARN","message":"Task queue capacity reached 85% threshold","trace_id":"b3e9f4a6c8d2e5f7a1b4c7d9e2f5a8b3","source":"scheduler"} {"timestamp":"2025-08-21 14:23:18.423","logger":"sdk.tool.NetworkUtil","level":"INFO","message":"Successfully established connection to remote endpoint","trace_id":"c5d8e7f2a9b4c6d8e1f4a7b9c2e5f8d1","source":"network"} ``` Each line is a separate JSON object containing log information. **Step 2: Create the pipeline configuration** Here is a pipeline configuration that parses the JSON log entries: ```yaml # pipeline.yaml version: 2 processors: - vrl: source: | message = parse_json!(.loki_line) target = { "log_time": parse_timestamp!(message.timestamp, "%Y-%m-%d %T%.3f"), "log_level": message.level, "log_source": message.source, "logger": message.logger, "message": message.message, "trace_id": message.trace_id, } . = target transform: - field: log_time type: time, ms index: timestamp ``` The pipeline content is straightforward: we use `vrl` processor to parse the line into a JSON object, then extract the fields to the root level. `log_time` is specified as the time index in the transform section, other fields will be auto-inferred by the pipeline engine, see [pipeline version 2](/reference/pipeline/pipeline-config.md#transform-in-version-2) for details. Note that the input field name is `loki_line`, which contains the original log line from Loki. **Step 3: Configure Grafana Alloy** Prepare an Alloy configuration file to read the log file and send it to GreptimeDB: ``` loki.source.file "greptime" { targets = [ {__path__ = "/logs.json"}, ] forward_to = [loki.write.greptime_loki.receiver] } loki.write "greptime_loki" { endpoint { url = "http://127.0.0.1:4000/v1/loki/api/v1/push" headers = { "x-greptime-pipeline-name" = "pp", } } external_labels = { "job" = "greptime", "from" = "alloy", } } ``` In the `greptime_loki`, the `x-greptime-pipeline-name` header is added to indicating the input data should be processed by the pipeline engine. **Step 4: Deploy and run** 1. First, start your GreptimeDB instance. See [here](/getting-started/installation/overview.md) for quick startup. 2. [Upload](/user-guide/logs/manage-pipelines.md#create-a-pipeline) the pipeline configuration to the database using `curl`: ```bash curl -X "POST" "http://localhost:4000/v1/pipelines/pp" -F "file=@pipeline.yaml" ``` 3. Start the Alloy Docker container to process the logs: ```shell docker run --rm \ -v ./config.alloy:/etc/alloy/config.alloy \ -v ./logs.json:/logs.json \ --network host \ grafana/alloy:latest \ run --server.http.listen-addr=0.0.0.0:12345 --storage.path=/var/lib/alloy/data \ /etc/alloy/config.alloy ``` **Step 5: Verify the results** After the logs are processed, you can verify that they have been successfully ingested and parsed. The database logs will show the ingestion activity. Query the table using a MySQL client to see the parsed log data: ```sql mysql> show tables; +-----------+ | Tables | +-----------+ | loki_logs | | numbers | +-----------+ 2 rows in set (0.00 sec) mysql> select * from loki_logs limit 1 \G *************************** 1. row *************************** log_time: 2025-08-21 14:23:17.892000 log_level: ERROR log_source: application logger: sdk.tool.DatabaseUtil message: Connection timeout exceeded for database pool trace_id: a7f8c92d1e4b4c6f9d2e5a8b3f7c1d9e 1 row in set (0.01 sec) ``` This output demonstrates that the pipeline engine has successfully parsed the original JSON log lines and extracted the structured data into separate columns. For more details about pipeline configuration and features, refer to the [pipeline documentation](/reference/pipeline/pipeline-config.md). --- ## OpenTelemetry Protocol (OTLP) [OpenTelemetry](https://opentelemetry.io/) is a vendor-neutral open-source observability framework for instrumenting, generating, collecting, and exporting telemetry data such as traces, metrics, logs. The OpenTelemetry Protocol (OTLP) defines the encoding, transport, and delivery mechanism of telemetry data between telemetry sources, intermediate processes such as collectors and telemetry backends. ## OpenTelemetry Collectors You can easily configure GreptimeDB as the target for your OpenTelemetry collector. For more information, please refer to the [OTel Collector](otel-collector.md) and [Grafana Alloy](alloy.md) example. ## HTTP Base Endpoint [Base endpoint URL](https://opentelemetry.io/docs/languages/sdk-configuration/otlp-exporter/#otel_exporter_otlp_endpoint) for all signal types: `http{s}:///v1/otlp` This unified endpoint is useful when sending multiple signal types (metrics, logs, and traces) to the same destination, simplifying your OpenTelemetry configuration. ## Metrics GreptimeDB is an observability backend to consume OpenTelemetry Metrics natively via [OTLP/HTTP](https://opentelemetry.io/docs/specs/otlp/#otlphttp) protocol. ### OTLP/HTTP API To send OpenTelemetry Metrics to GreptimeDB through OpenTelemetry SDK libraries, use the following information: - URL: `http{s}:///v1/otlp/v1/metrics` - Headers: - `X-Greptime-DB-Name`: `` - `Authorization`: `Basic` authentication, which is a Base64 encoded string of `:`. For more information, please refer to [Authentication](https://docs.greptime.com/user-guide/deployments-administration/authentication/static/) and [HTTP API](https://docs.greptime.com/user-guide/protocols/http#authentication) The request uses binary protobuf to encode the payload, so you need to use packages that support `HTTP/protobuf`. For example, in Node.js, you can use [`exporter-trace-otlp-proto`](https://www.npmjs.com/package/@opentelemetry/exporter-trace-otlp-proto); in Go, you can use [`go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp`](https://pkg.go.dev/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp); in Java, you can use [`io.opentelemetry:opentelemetry-exporter-otlp`](https://mvnrepository.com/artifact/io.opentelemetry/opentelemetry-exporter-otlp); and in Python, you can use [`opentelemetry-exporter-otlp-proto-http`](https://pypi.org/project/opentelemetry-exporter-otlp-proto-http/). :::tip NOTE The package names may change according to OpenTelemetry, so we recommend that you refer to the official OpenTelemetry documentation for the most up-to-date information. ::: For more information about the OpenTelemetry SDK, please refer to the official documentation for your preferred programming language. ### Example Code Here are some example codes about how to setup the request in different languages: ```ts const auth = Buffer.from(`${username}:${password}`).toString('base64') const exporter = new OTLPMetricExporter({ url: `https://${dbHost}/v1/otlp/v1/metrics`, headers: { Authorization: `Basic ${auth}`, 'X-Greptime-DB-Name': db, }, timeoutMillis: 5000, }) ``` ```Go auth := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", *username, *password))) exporter, err := otlpmetrichttp.New( context.Background(), otlpmetrichttp.WithEndpoint(*dbHost), otlpmetrichttp.WithURLPath("/v1/otlp/v1/metrics"), otlpmetrichttp.WithHeaders(map[string]string{ "X-Greptime-DB-Name": *dbName, "Authorization": "Basic " + auth, }), otlpmetrichttp.WithTimeout(time.Second*5), ) ``` ```Java String endpoint = String.format("https://%s/v1/otlp/v1/metrics", dbHost); String auth = username + ":" + password; String b64Auth = new String(Base64.getEncoder().encode(auth.getBytes())); OtlpHttpMetricExporter exporter = OtlpHttpMetricExporter.builder() .setEndpoint(endpoint) .addHeader("X-Greptime-DB-Name", db) .addHeader("Authorization", String.format("Basic %s", b64Auth)) .setTimeout(Duration.ofSeconds(5)) .build(); ``` ```python auth = f"{username}:{password}" b64_auth = base64.b64encode(auth.encode()).decode("ascii") endpoint = f"https://{host}/v1/otlp/v1/metrics" exporter = OTLPMetricExporter( endpoint=endpoint, headers={"Authorization": f"Basic {b64_auth}", "X-Greptime-DB-Name": db}, timeout=5) ``` For more information on the example code, please refer to the official documentation for your preferred programming language. ### Prometheus Compatibility Starting from `v0.16`, GreptimeDB is introducing a Prometheus-compatible mode for the OTLP metrics ingestion. If the metrics data is persisted using the Prometheus-compatible format, you should be able to query them using PromQL, just like any Prometheus metrics. If you have not ingested any OTLP metrics before, it will automatically use the Prometheus-compatible format. Otherwise, it will remain the old data format with the existing table, but use the new data format for any newly created tables. GreptimeDB pre-processes the incoming data before persisting them, including: 1. Converting the metric names(table names) and the label names to the Prometheus style(e.g: replace `.` with `_`). See [here](https://opentelemetry.io/docs/specs/otel/compatibility/prometheus_and_openmetrics/#metric-metadata-1) for details. Here are some examples of the conversion: | OTLP Metric / Attribute | OTLP Type / Unit | Prometheus Equivalent | | :--- | :--- | :--- | | `cache.hit_ratio` | Gauge / `1` | `cache_hit_ratio` | | `memory.usage` | Gauge / `By` | `memory_usage_bytes` | | `queue.length` | Gauge / `{item}` | `queue_length` | | `http.server.request.duration` | Histogram / `s` | `http_server_request_duration_seconds` | | `rpc.server.duration` | Histogram / `ms` | `rpc_server_duration_seconds` | | `http.client.request.size` | Sum (Monotonic) / `By` | `http_client_request_size_bytes_total` | | `system.network.io` | Sum (Monotonic) / `By` | `system_network_io_bytes_total` | | `http.status_code` (Attribute) | - | `http_status_code` | | `service.name` (Attribute) | - | `service_name` | 2. Discarding some resource attributes and all scope attributes by default. The kept resource attributes name list can be found [here](https://prometheus.io/docs/guides/opentelemetry/#promoting-resource-attributes). This behavior is configurable. Note, `Sum` and `Histogram` data in OTLP can have delta temporality. GreptimeDB saves their value directly without calculating the cumulative value. See [here](https://grafana.com/blog/2023/09/26/opentelemetry-metrics-a-guide-to-delta-vs.-cumulative-temporality-trade-offs/) for some context. You can set the HTTP headers to configure the pre-processing behaviors. Here are the options: 1. `x-greptime-otlp-metric-promote-all-resource-attrs`: Persist all resource attributes. Default to `false`. 2. `x-greptime-otlp-metric-promote-resource-attrs`: If not persisting all resource attributes, the attribute name list to be kept. Use `;` to join the name list. 3. `x-greptime-otlp-metric-ignore-resource-attrs`: If persisting all resource attributes, the attribute name list to be ignored. Use `;` to join the name list. 4. `x-greptime-otlp-metric-promote-scope-attrs`: Whether to persist the scope attributes. Default to `false`. ### Data Model The Prometheus-compatible OTLP metrics data model is mapped to the GreptimeDB data model according to the following rules: - The name of the Metric will be used as the name of the GreptimeDB table, and the table will be automatically created if it does not exist. - Only selected resource attributes are kept by default. See above for details and configuration options. Attributes are used as tag columns in the GreptimeDB table. - You can refer to the [Prometheus Data Model](./prometheus.md#data-model) for other details. - ExponentialHistogram is not supported yet. If you're using OTLP metrics before `v0.16`, you're ingesting the data without the Prometheus compatibility. Here are some mapping differences: - All attributes, including resource attributes, scope attributes, and data point attributes, will be used as tag columns of the GreptimeDB table. - Each quantile of the Summary data type will be used as a separated data column of GreptimeDB, and the column name is `greptime_pxx`, where xx is the quantile, such as 90/99, etc. ## Logs GreptimeDB consumes OpenTelemetry Logs natively via [OTLP/HTTP](https://opentelemetry.io/docs/specs/otlp/#otlphttp) protocol. ### OTLP/HTTP API To send OpenTelemetry Logs to GreptimeDB through OpenTelemetry SDK libraries, use the following information: - URL: `http{s}:///v1/otlp/v1/logs` - Headers: - `X-Greptime-DB-Name`: `` - `Authorization`: `Basic` authentication, which is a Base64 encoded string of `:`. For more information, please refer to [Authentication](/user-guide/deployments-administration/authentication/static.md) and [HTTP API](/user-guide/protocols/http.md#authentication). - `X-Greptime-Log-Table-Name`: `` (optional) - The table name to store the logs. If not provided, the default table name is `opentelemetry_logs`. - `X-Greptime-Log-Extract-Keys`: `` (optional) - The keys to extract from the attributes. The keys should be separated by commas (`,`). For example, `key1,key2,key3` will extract the keys `key1`, `key2`, and `key3` from the attributes and promote them to the top level of the log, setting them as tags. If the field type is array, float, or object, an error will be returned. If a pipeline is provided, this setting will be ignored. - `X-Greptime-Log-Pipeline-Name`: `` (optional) - The pipeline name to process the logs. If not provided, the extract keys will be used to process the logs. - `X-Greptime-Log-Pipeline-Version`: `` (optional) - The pipeline version to process the logs. If not provided, the latest version of the pipeline will be used. The request uses binary protobuf to encode the payload, so you need to use packages that support `HTTP/protobuf`. :::tip NOTE The package names may change according to OpenTelemetry, so we recommend that you refer to the official OpenTelemetry documentation for the most up-to-date information. ::: For more information about the OpenTelemetry SDK, please refer to the official documentation for your preferred programming language. ### Example Code Please refer to the sample code in the [OpenTelemetry Collector documentation](otel-collector.md), which includes how to send OpenTelemetry logs to GreptimeDB. You can also refer to the sample code in the [Alloy documentation](alloy.md#logs) to learn how to send OpenTelemetry logs to GreptimeDB. ### Data Model The OTLP logs data model is mapped to the GreptimeDB data model according to the following rules: Default table schema: ```sql +-----------------------+---------------------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +-----------------------+---------------------+------+------+---------+---------------+ | timestamp | TimestampNanosecond | PRI | NO | | TIMESTAMP | | trace_id | String | | YES | | FIELD | | span_id | String | | YES | | FIELD | | severity_text | String | | YES | | FIELD | | severity_number | Int32 | | YES | | FIELD | | body | String | | YES | | FIELD | | log_attributes | Json | | YES | | FIELD | | trace_flags | UInt32 | | YES | | FIELD | | scope_name | String | PRI | YES | | TAG | | scope_version | String | | YES | | FIELD | | scope_attributes | Json | | YES | | FIELD | | scope_schema_url | String | | YES | | FIELD | | resource_attributes | Json | | YES | | FIELD | | resource_schema_url | String | | YES | | FIELD | +-----------------------+---------------------+------+------+---------+---------------+ 14 rows in set (0.00 sec) ``` - You can use `X-Greptime-Log-Table-Name` to specify the table name for storing the logs. If not provided, the default table name is `opentelemetry_logs`. - All attributes, including resource attributes, scope attributes, and log attributes, will be stored as a JSON column in the GreptimeDB table. - The timestamp of the log will be used as the timestamp index in GreptimeDB, with the column name `timestamp`. It is preferred to use `time_unix_nano` as the timestamp column. If `time_unix_nano` is not provided, `observed_time_unix_nano` will be used instead. ### Append Only By default, log table created by OpenTelemetry API are in [append only mode](/user-guide/deployments-administration/performance-tuning/design-table.md#when-to-use-append-only-tables). ## Traces GreptimeDB supports writing OpenTelemetry traces data directly via the [OTLP/HTTP](https://opentelemetry.io/docs/specs/otlp/#otlphttp) protocol, and it also provides a table model of OpenTelemetry traces for users to query and analyze traces data conveniently. ### OTLP/HTTP API You can use [OpenTelemetry SDK](https://opentelemetry.io/docs/languages/) or other similar technologies to add traces data to your application. You can also use [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/) to collect traces data and use GreptimeDB as the backend storage. To send OpenTelemetry traces data to GreptimeDB through OpenTelemetry SDK libraries, please use the following information: - URL: `http{s}:///v1/otlp/v1/traces` - Headers: - `Content-Type`: `application/x-protobuf` - `Authorization`: `Basic` authentication. - `X-Greptime-DB-Name`: `` - `X-Greptime-Trace-Table-Name`: `` (optional) - The table name to store the traces. If not provided, the default table name is `opentelemetry_traces`. - `X-Greptime-Pipeline-Name`: `greptime_trace_v1` (required) - The pipeline name to process the traces. GreptimeDB accepts **protobuf encoded traces data** via **HTTP protocol**. ### Example Code You can directly send OpenTelemetry traces data to GreptimeDB, or use OpenTelemetry Collector to collect traces data and use GreptimeDB as the backend storage. Please refer to the example code in the [OpenTelemetry Collector documentation](/user-guide/traces/read-write.md#opentelemetry-collector) to learn how to send OpenTelemetry traces data to GreptimeDB. ### Data Model GreptimeDB maps the OTLP traces data model to a table schema. By default, trace data is stored in the `opentelemetry_traces` table. ```sql +------------------------------------+---------------------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +------------------------------------+---------------------+------+------+---------+---------------+ | timestamp | TimestampNanosecond | PRI | NO | | TIMESTAMP | | timestamp_end | TimestampNanosecond | | YES | | FIELD | | duration_nano | UInt64 | | YES | | FIELD | | parent_span_id | String | | YES | | FIELD | | trace_id | String | | YES | | FIELD | | span_id | String | | YES | | FIELD | | span_kind | String | | YES | | FIELD | | span_name | String | | YES | | FIELD | | span_status_code | String | | YES | | FIELD | | span_status_message | String | | YES | | FIELD | | trace_state | String | | YES | | FIELD | | scope_name | String | | YES | | FIELD | | scope_version | String | | YES | | FIELD | | service_name | String | PRI | YES | | TAG | | span_attributes.net.sock.peer.addr | String | | YES | | FIELD | | span_attributes.peer.service | String | | YES | | FIELD | | span_events | Json | | YES | | FIELD | | span_links | Json | | YES | | FIELD | +------------------------------------+---------------------+------+------+---------+---------------+ ``` - Each row represents a single span. - `service_name` is used as a **Tag** (part of the **Primary Key**). - `timestamp` is used as the **Time Index**. - Resource attributes and span attributes are automatically flattened into separate columns. - Note: `resource_attributes.service.name` is excluded from flattening as it is already stored in the `service_name` column. - `span_events` and `span_links` are stored as `JSON` data types by default. For more details on the data model and auxiliary tables, please refer to [Trace Data Modeling](/user-guide/traces/data-model.md). Note: 1. The `greptime_trace_v1` process uses the `trace_id` field to divide data into partitions for better performance. **Please make sure the first letter of the `trace_id` is evenly distributed**. 2. For non-test scenarios, you might want to set a `ttl` to the trace table to avoid data overload. Set the HTTP header `x-greptime-hints: ttl=7d` would set a `ttl` of 7 days during the table creation, see [here](/reference/sql/create.md#table-options) for more details about `ttl` in table option. ### Auxiliary Tables GreptimeDB automatically creates auxiliary tables (e.g., `opentelemetry_traces_services` and `opentelemetry_traces_operations`) to facilitate searching for services and operations. See [Auxiliary Tables](/user-guide/traces/data-model.md#auxiliary-tables) for details. ### Append-only Mode By default, trace tables created by the OpenTelemetry API are in [append-only mode](/user-guide/deployments-administration/performance-tuning/design-table.md#when-to-use-append-only-tables). --- ## OTel Collector [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/) offers a vendor-agnostic implementation of how to receive, process and export telemetry data. It can act as an intermediate layer to send data from different sources to GreptimeDB. Below is a sample configuration for sending data to GreptimeDB using OpenTelemetry Collector. ```yaml extensions: basicauth/client: client_auth: username: password: receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 http: endpoint: 0.0.0.0:4318 exporters: otlphttp/traces: endpoint: 'http://127.0.0.1:4000/v1/otlp' # auth: # authenticator: basicauth/client headers: # x-greptime-db-name: '' x-greptime-pipeline-name: 'greptime_trace_v1' tls: insecure: true otlphttp/logs: endpoint: 'http://127.0.0.1:4000/v1/otlp' # auth: # authenticator: basicauth/client headers: # x-greptime-db-name: '' # x-greptime-log-table-name: '' # x-greptime-pipeline-name: '' tls: insecure: true otlphttp/metrics: endpoint: 'http://127.0.0.1:4000/v1/otlp' # auth: # authenticator: basicauth/client headers: # x-greptime-db-name: '' tls: insecure: true service: # extensions: [basicauth/client] pipelines: traces: receivers: [otlp] exporters: [otlphttp/traces] logs: receivers: [otlp] exporters: [otlphttp/logs] metrics: receivers: [otlp] exporters: [otlphttp/metrics] ``` In the above configuration, we define a receiver `otlp` that can receive data from OpenTelemetry. We also define three exporters: `otlphttp/traces`, `otlphttp/logs`, and `otlphttp/metrics`, which send data to the OTLP endpoint of GreptimeDB. Based on the otlphttp protocol, we have added some headers to specify certain parameters, such as `x-greptime-pipeline-name` and `x-greptime-log-table-name`: * The `x-greptime-pipeline-name` header is used to specify the pipeline name to use, and, * the `x-greptime-log-table-name` header is used to specify the table name in GreptimeDB where the data will be written. If you have enabled [authentication](/user-guide/deployments-administration/authentication/overview.md) in GreptimeDB, you need to use the `basicauth/client` extension to handle basic authentication. Here, we strongly recommend using different exporters to handle traces, logs, and metrics separately. On one hand, GreptimeDB supports some specific headers to customize processing flows; on the other hand, this also helps with data isolation. For more about OpenTelemetry protocols, please read the [doc](/user-guide/ingest-data/for-observability/opentelemetry.md). --- ## Ingest Data for Observability In observability scenarios, the ability to monitor and analyze system performance in real-time is crucial. GreptimeDB integrates seamlessly with leading observability tools to provide a comprehensive view of your system's health and performance metrics. - [Store and analyze trillions of logs in GreptimeDB and gain insights within minutes](/user-guide/logs/overview.md). - [Prometheus Remote Write](prometheus.md): Integrate GreptimeDB as remote storage for Prometheus, suitable for real-time monitoring and alerting. - [Vector](vector.md): Use GreptimeDB as a sink for Vector, ideal for complex data pipelines and diverse data sources. - [OpenTelemetry](opentelemetry.md): Collect and export telemetry data to GreptimeDB for detailed observability insights. - [InfluxDB Line Protocol](influxdb-line-protocol.md): A widely-used protocol for time-series data, facilitating migration from InfluxDB to GreptimeDB. The Telegraf integration method is also introduced in this document. - [Loki](loki.md): A widely-used log write protocol, facilitating migration from Loki to GreptimeDB. The Alloy integration method is also introduced in this document. --- ## Prometheus GreptimeDB can serve as a long-term storage solution for Prometheus, providing a seamless integration experience. ## Remote write configuration ### Prometheus configuration file To configure Prometheus with GreptimeDB, update your [Prometheus configuration file](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#configuration-file) (`prometheus.yml`) as follows: ```yaml remote_write: - url: http://localhost:4000/v1/prometheus/write?db=public # Uncomment and set credentials if authentication is enabled # basic_auth: # username: greptime_user # password: greptime_pwd remote_read: - url: http://localhost:4000/v1/prometheus/read?db=public # Uncomment and set credentials if authentication is enabled # basic_auth: # username: greptime_user # password: greptime_pwd ``` - The host and port in the URL represent the GreptimeDB server. In this example, the server is running on `localhost:4000`. You can replace it with your own server address. For the HTTP protocol configuration in GreptimeDB, please refer to the [protocol options](/user-guide/deployments-administration/configuration.md#protocol-options). - The `db` parameter in the URL represents the database to which we want to write data. It is optional. By default, the database is set to `public`. - `basic_auth` is the authentication configuration. Fill in the username and password if GreptimeDB authentication is enabled. Please refer to the [authentication document](/user-guide/deployments-administration/authentication/overview.md). ### Grafana Alloy configuration file If you are using Grafana Alloy, configure the remote write endpoint in the Alloy configuration file (`config.alloy`). For more information, refer to the [Alloy documentation](alloy.md#prometheus-remote-write). ### Vector configuration file If you use Vector, configure Remote Write in Vector's configuration file (vector.toml). For more information, see the [Vector documentation](vector.md#using-prometheus-remote-write-protocol). ## Data Model In the [data model](/user-guide/concepts/data-model.md) of GreptimeDB, data is organized into tables with columns for tags, time index, and fields. GreptimeDB can be thought of as a multi-value data model, automatically grouping multiple Prometheus metrics into corresponding tables. This allows for efficient data management and querying. ![Data Model](/PromQL-multi-value-data-model.png) When the metrics are written into GreptimeDB by remote write endpoint, they will be transformed as follows: | Sample Metrics | In GreptimeDB | GreptimeDB Data Types | | -------------- | ------------------------- | --------------------- | | Name | Table (Auto-created) Name | String | | Value | Column (Field) | Double | | Timestamp | Column (Time Index) | Timestamp | | Label | Column (Tag) | String | For example, the following Prometheus metric: ```txt prometheus_remote_storage_samples_total{instance="localhost:9090", job="prometheus", remote_name="648f0c", url="http://localhost:4000/v1/prometheus/write"} 500 ``` will be transformed as a row in the table `prometheus_remote_storage_samples_total`: | Column | Value | Column Data Type | | :----------------- | :------------------------------------------ | :----------------- | | instance | localhost:9090 | String | | job | prometheus | String | | remote_name | 648f0c | String | | url | `http://localhost:4000/v1/prometheus/write` | String | | greptime_value | 500 | Double | | greptime_timestamp | The sample's unix timestamp | Timestamp | ## Improve efficiency by using metric engine The Prometheus remote writing always creates a large number of small tables. These tables are classified as logical tables in GreptimeDB. However, having a large number of small tables can be inefficient for both data storage and query performance. To address this, GreptimeDB introduces the [metric engine](/contributor-guide/datanode/metric-engine.md) feature, which stores the data represented by the logical tables in a single physical table. This approach reduces storage overhead and improves columnar compression efficiency. The metric engine is enabled by default in GreptimeDB, and you don't need to specify any additional configuration. By default, the physical table used is `greptime_physical_table`. If you want to use a specific physical table, you can specify the `physical_table` parameter in the remote write URL. If the specified physical table doesn't exist, it will be automatically created. ```yaml remote_write: - url: http://localhost:4000/v1/prometheus/write?db=public&physical_table=greptime_physical_table ``` Data is stored in the physical table, while queries are performed on logical tables to provide an intuitive view from a metric perspective. For instance, when successfully writing data, you can use the following command to display the logical tables: ```sql show tables; ``` ```sql +---------------------------------------------------------------+ | Tables | +---------------------------------------------------------------+ | prometheus_remote_storage_enqueue_retries_total | | prometheus_remote_storage_exemplars_pending | | prometheus_remote_storage_read_request_duration_seconds_count | | prometheus_rule_group_duration_seconds | | ...... | +---------------------------------------------------------------+ ``` The physical table itself can also be queried. It contains columns from all the logical tables, making it convenient for multi-join analysis and computation. To view the schema of the physical table, use the `DESC TABLE` command: ```sql DESC TABLE greptime_physical_table; ``` The physical table includes all the columns from the logical tables: ```sql +--------------------+----------------------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +--------------------+----------------------+------+------+---------+---------------+ | greptime_timestamp | TimestampMillisecond | PRI | NO | | TIMESTAMP | | greptime_value | Float64 | | YES | | FIELD | | __table_id | UInt32 | PRI | NO | | TAG | | __tsid | UInt64 | PRI | NO | | TAG | | device | String | PRI | YES | | TAG | | instance | String | PRI | YES | | TAG | | job | String | PRI | YES | | TAG | | error | String | PRI | YES | | TAG | ... ``` You can use the `SELECT` statement to filter data from the physical table as needed. For example, you can filter data based on the `device` condition from logical table A and the `job` condition from logical table B: ```sql SELECT * FROM greptime_physical_table WHERE greptime_timestamp > "2024-08-07 03:27:26.964000" AND device = "device1" AND job = "job1"; ``` ### GreptimeDB cluster with metric engine If you are using GreptimeDB cluster for Prometheus remote write, you may notice that only 1 datanode taking all the workload and other datanodes receives no traffic. This is because with default settings, there is only 1 metric engine physical table, and only 1 partition(region) in that table. The datanode that serves the partition will take all the data ingestion. Why we are not creating more partitions by default? [GreptimeDB's table partition](/user-guide/deployments-administration/manage-data/table-sharding.md) is based pre-configured partition columns. However, in Prometheus ecosystem, there is no common column (label, as in Prometheus) that is suitable for good partition rules. To fix this, we recommend you to define your own partition rule based on your data model. For example, it can be `namespace` if your are monitoring a kubernetes cluster. The partition columns should have enough cardinality to divide data. Also we recommend you to create 2x-3x partitions on initial datanode count, so when you scaling more datanodes in your cluster, just migrate those partitions to new ones. An example DDL of partitioned physical table based on `namespace` label: ```sql CREATE TABLE greptime_physical_table ( greptime_timestamp TIMESTAMP(3) NOT NULL, greptime_value DOUBLE NULL, namespace STRING PRIMARY KEY, TIME INDEX (greptime_timestamp), ) PARTITION ON COLUMNS (namespace) ( namespace <'g', namespace >= 'g' AND namespace < 'n', namespace >= 'n' AND namespace < 't', namespace >= 't' ) ENGINE = metric with ( "physical_metric_table" = "", ); ``` Note that you won't have need add all possible *PRIMARY KEY* (label) here, metric engine will add them automatically. Only labels you use for partitioning are required to be defined ahead of time. ## Special labels for ingestion options :::warning Experimental Feature This experimental feature may contain unexpected behavior, have its functionality change in the future. ::: Normally, the complete dataset of a remote write request is ingested into the database under the same option, for example, a default physical table with metric engine enabled. All the logical tables (i.e, the metrics) is backed with the same physical table, even when the number of metrics grows. It's probably fine for data ingestion. However, this set-up might slow down the query speed if you just want to query for a small group of metrics, but the database have to scan the complete dataset because they are all in the same physical table. If you can foresee a large data volume and incremental queries upon a small group of metrics each time, then it might be useful to split the storage during the ingestion to reduce the query overhead later. This fine-grade level of control can be achieved using ingest options for each metric within a remote request. Starting from `v0.15`, GreptimeDB is adding support for special labels. There labels (along with there values) will turn into ingest options during the parsing phase, allowing individual metric within a request to be more precisely controlled. The labels are not mutually exclusive, so they can be combined together to produce more versatile controlling. Here is a representative diagram of special labels for a metric. Note this is not the actual data model of a metric. | `__name__` | `x_greptime_database` | `x_greptime_physical_table` | `pod_name_label` | `__normal_label_with_underscore_prefix__` | `timestamp` | `value` | |--------------------|-------------------------|-------------------------------|-----------------------|---------------------------------------------|---------------------------|-----------| | `some_metric_name` | `public` | `p_1` | `random_k8s_pod_name` | `true` | `2025-06-17 16:31:52.000` | `12.1` | The special labels you see above are just normal valid labels in Prometheus. GreptimeDB recognizes some of the label names and turns them into ingest options. It's much like the custom HTTP headers, where you just set a valid HTTP header and its value to indicate following operations, only the header pair means nothing outside your program. Here is a list of supported label names: - `x_greptime_database` - `x_greptime_physical_table` ### Setting labels How to set labels to the metrics is very dependent on the tools (or code) that collects the metrics and send them over to the database. If you're using Prometheus to scrape metrics from the source and send them to GreptimeDB using remote write, you can add `external_labels` in the global config. Refer to the [docs](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#configuration-file) here. It's the same for other collecting tools. You may have to find the relevant configuration for your tool of choice. ### `x_greptime_database` This option decides which database the metric goes into. Note, the database should be created in advance(for instance, using `create database xxx` SQL). Metrics from the same tech stack can have same metric names. For example, if you have two Kubernetes clusters with very different content, and you deploy a single collector on both clusters, they will generate metrics with same names but with different labels or values. If the metrics are collected and ingested into the same database, then on a Grafana dashboard you will have to manually set every label selection on every diagram to view the two clusters' metrics separately. This can be very tedious and painful. In this case, you might want to store the metrics on different databases during ingestion and use two dashboards to view the metrics separately. ### `x_greptime_physical_table` If the metric is storing using the metric engine, then there is a physical table behind each metric's logical table. By default, all metrics using the same physical table. With the number of the metrics growing, this physical table becomes a super wide table. If the metric frequency is different, then the table will be sparse. Finding a certain metric or a certain label in the complete metrics dataset would be very time-consuming since the database have to scan all the 'irrelevant' data. In this case, you might want to split the metrics into different physical tables to ease the pressure on a single physical table. It can also be helpful to group metrics by their frequency. Note, each metric's logical table is bound to a physical table upon creation. So setting different physical table for the same metric within the same database won't work. ## Using pipeline in remote write :::warning Experimental Feature This experimental feature may contain unexpected behavior, have its functionality change in the future. ::: Starting from `v0.15`, GreptimeDB supports using pipeline to process Prometheus remote write requests. You can simply set the HTTP header `x-greptime-pipeline-name` to the target pipeline name to enable pipeline processing. Here is a very simple pipeline configuration, using `vrl` processor to add a `source` label to each metric: ```YAML version: 2 processors: - vrl: source: | .source = "local_laptop" . transform: - field: greptime_timestamp type: time, ms index: timestamp ``` The result looks something like this ``` mysql> select * from `go_memstats_mcache_inuse_bytes`; +----------------------------+----------------+--------------------+---------------+--------------+ | greptime_timestamp | greptime_value | instance | job | source | +----------------------------+----------------+--------------------+---------------+--------------+ | 2025-07-11 07:42:03.064000 | 1200 | node_exporter:9100 | node-exporter | local_laptop | | 2025-07-11 07:42:18.069000 | 1200 | node_exporter:9100 | node-exporter | local_laptop | +----------------------------+----------------+--------------------+---------------+--------------+ 2 rows in set (0.01 sec) ``` You can refer to the [pipeline's documentation](/user-guide/logs/use-custom-pipelines.md) for more details. ## Performance tuning By default, the metric engine will automatically create a physical table named `greptime_physical_table` if it does not already exist. For performance optimization, you may choose to create a physical table with customized configurations. ### Enable skipping index By default, the metric engine won't create indexes for columns. You can enable it by setting the `index.type` to `skipping`. Create a physical table with a skipping index; all automatically added columns will have this index applied. ```sql CREATE TABLE greptime_physical_table ( greptime_timestamp TIMESTAMP(3) NOT NULL, greptime_value DOUBLE NULL, TIME INDEX (greptime_timestamp), ) engine = metric with ( "physical_metric_table" = "", "index.type" = "skipping" ); ``` For more configurations, please refer to the [create table](/reference/sql/create.md#create-table) section. ## VictoriaMetrics remote write VictoriaMetrics slightly modified Prometheus remote write protocol for better compression. The protocol is automatically enabled when you are using `vmagent` to send data to a compatible backend. GreptimeDB has this variant supported, too. Just configure GreptimeDB's remote write url for `vmagent`. For example, if you have GreptimeDB installed locally: ```shell vmagent -remoteWrite.url=http://localhost:4000/v1/prometheus/write ``` --- ## Vector :::tip NOTE This document is based on Vector v0.49.0. All example configurations below are based on this version. Please adjust the host and port configurations for each sink according to your actual GreptimeDB instance. All port values below are defaults. ::: Vector is a high-performance observability data pipeline. It natively supports GreptimeDB as a metrics data receiver. Through Vector, you can receive metrics data from various sources including Prometheus, OpenTelemetry, StatsD, etc. GreptimeDB can serve as a sink component for Vector to receive metrics data. ## Writing Metrics Data GreptimeDB supports multiple ways to write metrics data: - Using [`greptimedb_metrics` sink](https://vector.dev/docs/reference/configuration/sinks/greptimedb_metrics/) - Using InfluxDB line protocol format - Using Prometheus Remote Write protocol ### Using `greptimedb_metrics` sink #### Example Below is an example configuration using `greptimedb_metrics` sink to write host metrics: ```toml # sample.toml [sources.in] type = "host_metrics" [sinks.my_sink_id] inputs = ["in"] type = "greptimedb_metrics" endpoint = ":4001" dbname = "" username = "" password = "" new_naming = true ``` Vector uses gRPC to communicate with GreptimeDB, so the default port for Vector sink is `4001`. If you changed the default gRPC port when starting GreptimeDB with [custom configuration](/user-guide/deployments-administration/configuration.md#configuration-file), please use your own port. For more requirements, please visit [Vector GreptimeDB Configuration](https://vector.dev/docs/reference/configuration/sinks/greptimedb_metrics/) to view more configuration options. ### Data Model The following rules are used when storing Vector metrics into GreptimeDB: - Use `_` as the table name in GreptimeDB, for example, `host_cpu_seconds_total`; - Use the timestamp of the metric as the time index of GreptimeDB, the column name is `ts`; - Use the tags of the metric as GreptimeDB tags; - For Vector metrics which have multiple subtypes: - For Counter and Gauge metrics, the values are stored in the `val` column; - For Set metrics, the number of data points are stored in the `val` column; - For Distribution metrics, the values of each percentile are stored in the `pxx` column, where xx is the percentile, and the `min/max/avg/sum/count` columns are also stored; - For AggregatedHistogram metrics, the values of each bucket are stored in the `bxx` column, where xx is the upper limit of the bucket, and the `sum/count` columns are also stored; - For AggregatedSummary metrics, the values of each percentile are stored in the `pxx` column, where xx is the percentile, and the `sum/count` columns are also stored; - For Sketch metrics, the values of each percentile are stored in the `pxx` column, where xx is the percentile, and the `min/max/avg/sum` columns are also stored; ### Using InfluxDB Line Protocol Format You can use the `influx` sink to write metrics data. We recommend using v2 version of InfluxDB line protocol format. Below is an example configuration using `influx` sink to write host metrics: ```toml # sample.toml [sources.my_source_id] type = "internal_metrics" [sinks.my_sink_id] type = "influxdb_metrics" inputs = [ "my_source_id" ] bucket = "public" endpoint = "http://:4000/v1/influxdb" org = "" token = "" ``` The above configuration uses v2 version of InfluxDB line protocol. Vector determines the InfluxDB protocol version based on fields in the TOML configuration, so please ensure the configuration contains `bucket`, `org`, and `token` fields. Specific field explanations: - `type`: Value for InfluxDB line protocol is `influxdb_metrics`. - `bucket`: Database name in GreptimeDB. - `org`: Organization name in GreptimeDB (needs to be empty). - `token`: Token for authentication (needs to be empty). Since Influx line protocol token has special format and must start with `Token `, this differs from GreptimeDB's authentication method and is currently not compatible. If using GreptimeDB instance with authentication, please use `greptimedb_metrics`. For more details, please refer to [InfluxDB Line Protocol documentation](../for-iot/influxdb-line-protocol.md) to learn how to write data to GreptimeDB using InfluxDB Line Protocol. ### Using Prometheus Remote Write Protocol Below is an example configuration using Prometheus Remote Write protocol to write host metrics: ```toml # sample.toml [sources.my_source_id] type = "internal_metrics" [sinks.prometheus_remote_write] type = "prometheus_remote_write" inputs = [ "my_source_id" ] endpoint = "http://:4000/v1/prometheus/write?db=" compression = "snappy" auth = { strategy = "basic", username = "", password = "" } ``` ## Writing Logs Data GreptimeDB supports multiple ways to write logs data: - Using [`greptimedb_logs` sink](https://vector.dev/docs/reference/configuration/sinks/greptimedb_logs/) to write logs data to GreptimeDB. - Using Loki protocol to write logs data to GreptimeDB. We strongly recommend all users to use `greptimedb_logs` sink to write logs data, as it is optimized for GreptimeDB and better supports GreptimeDB features. We also recommend enabling compression for various protocols to improve data transmission efficiency. ### Using `greptimedb_logs` sink (recommended) ```toml # sample.toml [sources.my_source_id] type = "demo_logs" count = 10 format = "apache_common" interval = 1 [sinks.my_sink_id] type = "greptimedb_logs" inputs = [ "my_source_id" ] compression = "gzip" dbname = "public" endpoint = "http://:4000" extra_headers = { "skip_error" = "true" } pipeline_name = "greptime_identity" table = "" username = "" password = "" [sinks.my_sink_id.extra_params] source = "vector" x-greptime-pipeline-params = "max_nested_levels=10" ``` This example demonstrates how to use `greptimedb_logs` sink to write generated demo logs data to GreptimeDB. For more information, please refer to [Vector greptimedb_logs sink](https://vector.dev/docs/reference/configuration/sinks/greptimedb_logs/) documentation. ### Using Loki Protocol #### Example ```toml [sources.generate_syslog] type = "demo_logs" format = "syslog" count = 100 interval = 1 [transforms.remap_syslog] inputs = ["generate_syslog"] type = "remap" source = """ .labels = { "host": .host, "service": .service, } .structured_metadata = { "source_type": .source_type } """ [sinks.my_sink_id] type = "loki" inputs = ["remap_syslog"] compression = "snappy" endpoint = "http://:4000" out_of_order_action = "accept" path = "/v1/loki/api/v1/push" encoding = { codec = "raw_message" } labels = { "*" = "{{labels}}" } structured_metadata = { "*" = "{{structured_metadata}}" } auth = {strategy = "basic", user = "", password = ""} ``` The above configuration writes logs data to GreptimeDB using Loki protocol. Specific configuration item explanations: - `compression`: Sets compression algorithm for data transmission, using `snappy` here. - `endpoint`: Specifies Loki's receiving address. - `out_of_order_action`: Sets how to handle out-of-order logs, choosing `accept` here to accept out-of-order logs. GreptimeDB supports writing out-of-order logs. - `path`: Specifies Loki's API path. - `encoding`: Sets data encoding method, using `raw_message` here. - `labels`: Specifies log labels, mapping `labels` content to `{{labels}}` here. That is the `labels` field in remap_syslog. - `structured_metadata`: Specifies structured metadata, mapping `structured_metadata` content to `{{structured_metadata}}` here. That is the `structured_metadata` field in remap_syslog. For meanings of `labels` and `structured_metadata`, please refer to [Loki documentation](https://grafana.com/docs/loki/latest/get-started/labels/bp-labels/). For Loki protocol, `labels` will use Tag type in time series scenarios by default, please avoid using high-cardinality fields for these fields. `structured_metadata` will be stored as a complete JSON field. Note that since Vector's configuration doesn't allow setting headers, you cannot specify pipeline. If you need to use pipeline functionality, please consider using `greptimedb_logs` sink. --- ## Ingest Data GreptimeDB supports automatic schema generation and flexible data ingestion methods, enabling you to easily write data tailored to your specific scenarios. ## Automatic Schema Generation GreptimeDB supports schemaless writing, automatically creating tables and adding necessary columns as data is ingested. This capability ensures that you do not need to manually define schemas beforehand, making it easier to manage and integrate diverse data sources seamlessly. This feature is supported for all protocols and integrations, except [SQL](./for-iot/sql.md). ## Recommended Data Ingestion Methods GreptimeDB supports various data ingestion methods for specific scenarios, ensuring optimal performance and integration flexibility. - [For Observability Scenarios](./for-observability/overview.md): Suitable for real-time monitoring and alerting. - [For IoT Scenarios](./for-iot/overview.md): Suitable for real-time data and complex IoT infrastructures. ## Next Steps - [Query Data](/user-guide/query-data/overview.md): Learn how to explore your data by querying your GreptimeDB database. - [Manage Data](/user-guide/manage-data/overview.md): Learn how to update and delete data, etc., to ensure data integrity and efficient data management. --- ## Grafana Alloy(Integrations) GreptimeDB can be set up as a data sink for Grafana Alloy. For more information, please refer to the [Ingest Data through Grafana Alloy](/user-guide/ingest-data/for-observability/alloy.md) guide. --- ## Coroot Coroot is an open-source APM & Observability tool, a DataDog and NewRelic alternative. Metrics, logs, traces, continuous profiling, and SLO-based alerting, supercharged with predefined dashboards and inspections. GreptimeDB can be configured as a Prometheus data sink for Coroot. To integrate GreptimeDB with Coroot, navigate to `Settings` in the Coroot Dashboard, select the `Prometheus` configuration, and enter the following information: - Prometheus URL: `http{s}:///v1/prometheus` - If you have [enabled authentication](/user-guide/deployments-administration/authentication/static.md) on GreptimeDB, check the HTTP basic auth option and enter GreptimeDB username and password. Otherwise, leave it unchecked. - Remote Write URL: `http{s}:///v1/prometheus/write?db=` ## Example Configuration If your GreptimeDB host is `localhost` with port `4000` for the HTTP service and authentication is enabled, and you want to use the default database `public`, use the following configuration: - Prometheus URL: `http://localhost:4000/v1/prometheus` - Enable the HTTP basic auth option and enter GreptimeDB username and password - Remote Write URL: `http://localhost:4000/v1/prometheus/write?db=public` The image below shows the Coroot configuration example: Once the configuration is saved successfully, you can begin using Coroot to monitor your instances. The image below shows an example of a Coroot dashboard using GreptimeDB as a data source: ![coroot-cpu](/coroot-cpu.png) --- ## DBeaver [DBeaver](https://dbeaver.io/) is a free, open-source, and cross-platform database tool that supports all popular databases. It is a popular choice among developers and database administrators for its ease of use and extensive feature set. You can use DBeaver to connect to GreptimeDB via MySQL database drivers. Click the "New Database Connection" button in the DBeaver toolbar to create a new connection to GreptimeDB. Select MySQL and click "Next" to configure the connection settings. Install the MySQL driver if you haven't already. Input the following connection details: - Connect by Host - Host: `localhost` if GreptimeDB is running on your local machine - Port: `4002` if you use the default GreptimeDB configuration - Database: `public`, you can use any other database name you have created - Enter the username and password if authentication is enabled on GreptimeDB; otherwise, leave them blank. Click "Test Connection" to verify the connection settings and click "Finish" to save the connection. For more information on interacting with GreptimeDB using MySQL, refer to the [MySQL protocol documentation](/user-guide/protocols/mysql.md). --- ## EMQX(Integrations) GreptimeDB can be used as a data system for EMQX. For more information, please refer to the [Ingest Data through EMQX](/user-guide/ingest-data/for-iot/emqx.md) guide. --- ## Fluent Bit(Integrations) You can set GreptimeDB as a Output for Fluent Bit. For more information, please refer to the [Writing Data with Fluent Bit](../ingest-data/for-observability/fluent-bit.md) guide. --- ## Grafana GreptimeDB can be configured as a [Grafana data source](https://grafana.com/docs/grafana/latest/datasources/add-a-data-source/). You have the option to connect GreptimeDB with Grafana using one of three data sources: [GreptimeDB](#greptimedb-data-source-plugin), [Prometheus](#prometheus-data-source), or [MySQL](#mysql-data-source). ## GreptimeDB data source plugin The [GreptimeDB data source plugin](https://github.com/GreptimeTeam/greptimedb-grafana-datasource) is based on the ClickHouse data source and adds GreptimeDB-specific features. The plugin adapts perfectly to the GreptimeDB data model, thus providing a better user experience. In addition, it also solves some compatibility issues compared to using the Prometheus data source directly. ### Installation The GreptimeDB Data source plugin can currently only be installed on a local Grafana instance. Make sure Grafana is installed and running before installing the plugin. You can choose one of the following installation methods: - Download the installation package and unzip it to the relevant directory: Grab the latest release from [release page](https://github.com/GreptimeTeam/greptimedb-grafana-datasource/releases/latest/), Unzip the file to your [grafana plugin directory](https://grafana.com/docs/grafana/latest/setup-grafana/configure-grafana/#plugins). - Use grafana cli to download and install: ```shell grafana cli --pluginUrl https://github.com/GreptimeTeam/greptimedb-grafana-datasource/releases/latest/download/info8fcc-greptimedb-datasource.zip plugins install info8fcc ``` - Use our [prebuilt Grafana docker image](https://hub.docker.com/r/greptime/grafana-greptimedb), which ships the plugin by default: `docker run -p 3000:3000 greptime/grafana-greptimedb:latest` Note that you may need to restart your grafana server after installing the plugin. ### Connection settings Click the Add data source button and select GreptimeDB as the type. ![grafana-add-greptimedb-data-source](/grafana-add-greptimedb-data-source.png) Fill in the following URL in the GreptimeDB server URL: ```txt http://:4000 ``` In the Auth section, click basic auth, and fill in the username and password for GreptimeDB in the Basic Auth Details section (not set by default, no need to fill in). - User: `` - Password: `` Then click the Save & Test button to test the connection. ### General Query Settings Before selecting any query type, you first need to configure the **Database** and **Table** to query from. | Setting | Description | | :-------- | :---------------------------------------- | | **Database** | Select the database you want to query. | | **Table** | Select the table you want to query from. | ![DB Table Config](/grafana/dbtable.png) --- ### Table Query Choose the `Table` query type when your query results **do not include a time column**. This is suitable for displaying tabular data. | Setting | Description | | :-------- | :---------------------------------------------- | | **Columns** | Select the columns you want to retrieve. Multiple selections are allowed. | | **Filters** | Set conditions to filter your data. | ![Table Query](/grafana/table.png) --- ### Metrics Query Select the `Time Series` query type when your query results **include both a time column and a numerical value column**. This is ideal for visualizing metrics over time. | Main Setting | Description | | :----------- | :-------------------- | | **Time** | Select the time column. | | **Columns** | Select the numerical value column(s). | ![Time Series](/grafana/series1.png) --- ### Logs Query Choose the `Logs` query type when you want to query log data. You'll need to specify a **Time** column and a **Message** column. | Main Setting | Description | | :----------- | :---------------------------- | | **Time** | Select the timestamp column for your logs. | | **Message** | Select the column containing the log content. | | **Log Level**| (Optional) Select the column representing the log level. | ![Logs](/grafana/logs.png) #### logs Context Query Logs Context Query Performs an approximate time range query based on the value of context columns in a log row. * First, set the context column in Connection Page. ![Context Config](/grafana/context2.png) * Then, when making a query, include the context column in the query. ![Query Config](/grafana/context1.png) --- ### Traces Query Select the `Traces` query type when you want to query distributed tracing data. | Main Setting | Description | | :-------------------- | :------------------------------------------------------------------------------------------------------ | | **Trace Model** | Select `Trace Search` to query a list of traces. | | **Trace Id Column** | Default value: `trace_id` | | **Span Id Column** | Default value: `span_id` | | **Parent Span ID Column** | Default value: `parent_span_id` | | **Service Name Column** | Default value: `service_name` | | **Operation Name Column** | Default value: `span_name` | | **Start Time Column** | Default value: `timestamp` | | **Duration Time Column** | Default value: `duration_nano` | | **Duration Unit** | Default value: `nano_seconds` | | **Tags Column** | Multiple selections allowed. Corresponds to columns starting with `span_attributes` (e.g., `span_attributes.http.method`). | | **Service Tags Column** | Multiple selections allowed. Corresponds to columns starting with `resource_attributes` (e.g., `resource_attributes.host.name`). | ![Traces](/grafana/traceconfig.png) ## Prometheus data source Click the "Add data source" button and select Prometheus as the type. Fill in Prometheus server URL in HTTP: ```txt http://:4000/v1/prometheus ``` Click basic auth in the Auth section and fill in your GreptimeDB username and password in Basic Auth Details: - User: `` - Password: `` Click Custom HTTP Headers and add one header: - Header: `x-greptime-db-name` - Value: `` Then click "Save & Test" button to test the connection. For how to query data with PromQL, please refer to the [Prometheus Query Language](/user-guide/query-data/promql.md) document. ## MySQL data source Click the "Add data source" button and select MySQL as the type. Fill in the following information in MySQL Connection: - Host: `:4002` - Database: `` - User: `` - Password: `` - Session timezone: `UTC` Then click "Save & Test" button to test the connection. Note that you need to use raw SQL editor for panel creation. SQL Builder is not supported due to timestamp data type difference between GreptimeDB and vanilla MySQL. For how to query data with SQL, please refer to the [Query Data with SQL](/user-guide/query-data/sql.md) document. --- ## Kafka(Integrations) Vector can be used as a tool to transport data from Kafka to GreptimeDB. For more information, please refer to the [Ingest Data via Kafka](/user-guide/ingest-data/for-observability/kafka.md) guide. --- ## Model Context Protocol (MCP) :::warning Experimental Feature The GreptimeDB MCP Server is currently in experimental stage and under active development. APIs and features may change without notice. Please use with caution in production environments. ::: The [GreptimeDB MCP Server](https://github.com/GreptimeTeam/greptimedb-mcp-server) provides a Model Context Protocol implementation that enables AI assistants like Claude to securely explore and analyze your GreptimeDB databases. Watch our [demo video on YouTube](https://www.youtube.com/watch?v=EBTc46yamFI) to see the MCP Server in action and get a better understanding of its capabilities. ## What is MCP? Model Context Protocol (MCP) is a standard protocol that allows AI assistants to interact with external data sources and tools. With the GreptimeDB MCP Server, you can enable AI assistants to: - List and explore database tables - Read table data and schemas - Execute SQL queries - Analyze time-series data through natural language ## Installation Install the GreptimeDB MCP Server using pip: ```bash pip install greptimedb-mcp-server ``` ## Configuration The MCP server can be configured through environment variables or command-line arguments. Key configuration options include: - Database connection settings (host, port, username, password) - Database name - Timezone settings ### Example: Claude Desktop Integration To integrate with Claude Desktop, add the following configuration to your `claude_desktop_config.json`: ```json { "mcpServers": { "greptimedb": { "command": "python", "args": ["-m", "greptimedb_mcp_server"], "env": { "GREPTIMEDB_HOST": "localhost", "GREPTIMEDB_PORT": "4002", "GREPTIMEDB_USERNAME": "your_username", "GREPTIMEDB_PASSWORD": "your_password", "GREPTIMEDB_DATABASE": "your_database" } } } } ``` ## Learn More For detailed configuration options, advanced usage, and troubleshooting, refer to the [GreptimeDB MCP Server documentation](https://github.com/GreptimeTeam/greptimedb-mcp-server). :::note The GreptimeDB MCP Server is an experimental project still under development. Exercise caution when using it with sensitive data. ::: --- ## Metabase [Metabase](https://github.com/metabase/metabase) is an open source BI tool that written in Clojure. You can configure GreptimeDB as a metabase data source from a community driver plugin. ## Installation Download the driver plugin file `greptimedb.metabase-driver.jar` from its [release page](https://github.com/greptimeteam/greptimedb-metabase-driver/releases/latest/). Copy the jar file to `plugins/` of metabase's working directory. It will be discovered by Metabase automatically. ## Add GreptimeDB as database To add GreptimeDB database, select *Settings* / *Admin Settings* / *Databases*, click *Add Database* button and select GreptimeDB from *Database type*. You will be asked to provide host, port, database name and authentication information. - Use Greptime's Postgres protocol port `4003` as port. If you changed the defaults, use you own settings. - Username and password are optional if you didn't enable [authentication](/user-guide/deployments-administration/authentication/overview.md). - Use `public` as default *Database name*. When using GreptimeCloud instance, use the database name from your instance. --- ## MindsDB [MindsDB](https://mindsdb.com/) is an open-source machine learning platform that enables developers to easily incorporate advanced machine learning capabilities with existing databases. Your GreptimeDB instance work out of box as using GreptimeDB extension with MindsDB. You can configure GreptimeDB as a data source in MindsDB using MySQL protocol: ```sql CREATE DATABASE greptime_datasource WITH ENGINE = 'greptimedb', PARAMETERS = { "host": "", "port": 4002, "database": "", "user": "", "password": "", "ssl": True }; ``` - `` is the hostname or IP address of your GreptimeDB instance. - `` is the name of the database you want to connect to. - `` and `` are your [GreptimeDB credentials](/user-guide/deployments-administration/authentication/static.md). MindsDB is a great gateway for many machine learning features, including time-series forecasting, for your time series data stored in our instance. See [MindsDB docs](https://docs.mindsdb.com/what-is-mindsdb) for more information. --- ## Integrations GreptimeDB can be seamlessly integrated with popular tools for data ingestion, querying, and visualization. The subsequent sections offer comprehensive guidance on integrating GreptimeDB with the following tools: --- ## Prometheus(Integrations) ## Remote Write GreptimeDB can be used as a remote storage backend for Prometheus. For detailed information, please refer to the [Ingest Data with Prometheus Remote Write](/user-guide/ingest-data/for-observability/prometheus.md) document. ## Prometheus Query Language (PromQL) GreptimeDB supports the Prometheus Query Language (PromQL) for querying metrics. For more information, please refer to the [Query Data with Prometheus Query Language](/user-guide/query-data/promql.md) document. --- ## Streamlit [Streamlit](https://streamlit.io/) is a faster way to build and share data apps. It's possible to build streamlit based data apps based on GreptimeDB. To use GreptimeDB data in your application, you will need to create a SQL connection. Thanks to GreptimeDB's [MySQL protocol compatibility](/user-guide/protocols/mysql.md), you can treat GreptimeDB as MySQL when connecting to it. Here is an example code snippet to connect to GreptimeDB from Streamlit: ```python st.title('GreptimeDB Streamlit Demo') conn = st.connection("greptimedb", type="sql", url="mysql://:@:4002/") df = conn.query("SELECT * FROM ...") ``` - The `` is the hostname or IP address of your GreptimeDB instance. - The `` is the name of the database you want to connect to. - The `` and `` are your [GreptimeDB credentials](/user-guide/deployments-administration/authentication/static.md). Once you have created the connection, you can run SQL query against your GreptimeDB instance. The resultset is automatically converted to Pandas dataframe just like normal data source in streamlit. --- ## Superset [Apache Superset](https://superset.apache.org) is an open source BI tool that written in Python. To configure GreptimeDB as a database in Superset, you can follow this guide. ## Installation ### Running Superset with Docker Compose [Docker compose](https://superset.apache.org/docs/installation/docker-compose) is the recommended way to run Superset. To add GreptimeDB extension, create a `requirements-local.txt` file in `docker/` of Superset codebase. Add GreptimeDB dependency in `requirements-local.txt`: ```txt greptimedb-sqlalchemy ``` Start Superset services: ```bash docker compose -f docker-compose-non-dev.yml up ``` ### Running Superset Locally If you are [running Superset from pypi](https://superset.apache.org/docs/installation/pypi), install our extension to the same environment. ```bash pip install greptimedb-sqlalchemy ``` ## Add GreptimeDB as database To add GreptimeDB database, select *Settings* / *Database Connections*. Add database and select *GreptimeDB* from list of supported databases. Follow the SQLAlchemy URI pattern to provide your connection information: ``` greptimedb://:@:/ ``` - Ignore `:@` if you don't have [authentication](/user-guide/deployments-administration/authentication/overview.md) enabled. - Use `4003` for default port (this extension uses Postgres protocol). - Use `public` as default `database`. When using GreptimeCloud instance, use the database name from your instance. --- ## Telegraf For instructions on how to write data to GreptimeDB using Telegraf, please refer to the [Telegraf section](/user-guide/ingest-data/for-iot/influxdb-line-protocol.md#telegraf) in the InfluxDB Line Protocol documentation. --- ## Vector(Integrations) Please refer to the [Ingest Data with Vector](/user-guide/ingest-data/for-observability/vector.md) document for instructions on how to sink data to GreptimeDB using Vector. --- ## Full-Text Search This document provides a guide on how to use GreptimeDB's query language for effective searching and analysis of log data. GreptimeDB allows for flexible querying of data using SQL statements. This section introduces specific search functions and query statements designed to enhance your log querying capabilities. ## Pattern Matching Using the `matches_term` Function In SQL statements, you can use the `matches_term` function to perform exact term/phrase matching, which is especially useful for log analysis. The `matches_term` function supports pattern matching on `String` type columns. You can also use the `@@` operator as a shorthand for `matches_term`. Here's an example of how it can be used: ```sql -- Using matches_term function SELECT * FROM logs WHERE matches_term(message, 'error') OR matches_term(message, 'fail'); -- Using @@ operator (shorthand for matches_term) SELECT * FROM logs WHERE message @@ 'error' OR message @@ 'fail'; ``` The `matches_term` function is designed for exact term/phrase matching and uses the following syntax: - `text`: The text column to search, which should contain textual data of type `String`. - `term`: The search term or phrase to match exactly, following these rules: - Case-sensitive matching - Matches must have non-alphanumeric boundaries (start/end of text or any non-alphanumeric character) - Supports whole-word matching and phrase matching ## Query Statements ### Simple Term Matching The `matches_term` function performs exact word matching, which means it will only match complete words that are properly bounded by non-alphanumeric characters or the start/end of the text. This is particularly useful for finding specific error messages, status codes, version numbers, or paths in logs. Error messages: ```sql -- Using matches_term function SELECT * FROM logs WHERE matches_term(message, 'error'); -- Using @@ operator SELECT * FROM logs WHERE message @@ 'error'; ``` Examples of matches and non-matches: - ✅ "An error occurred!" - matches because "error" is a complete word - ✅ "Critical error: system failure" - matches because "error" is bounded by space and colon - ✅ "error-prone" - matches because "error" is bounded by hyphen - ❌ "errors" - no match because "error" is part of a larger word - ❌ "error123" - no match because "error" is followed by numbers - ❌ "errorLogs" - no match because "error" is part of a camelCase word File paths and commands: ```sql -- Find specific command with path SELECT * FROM logs WHERE matches_term(message, '/start'); ``` Examples of matches and non-matches for '/start': - ✅ "GET /app/start" - matches because "/start" is a complete term - ✅ "Command: /start-process" - matches because "/start" is bounded by hyphen - ✅ "Command: /start" - matches because "/start" is at the end of the message - ❌ "start" - no match because it's missing the leading slash - ❌ "start/stop" - no match because "/start" is not a complete term ### Multiple Term Searches You can combine multiple `matches_term` conditions using the `OR` operator to search for logs containing any of several terms. This is useful when you want to find logs that might contain different variations of an error or different types of issues. ```sql -- Using matches_term function SELECT * FROM logs WHERE matches_term(message, 'critical') OR matches_term(message, 'error'); -- Using @@ operator SELECT * FROM logs WHERE message @@ 'critical' OR message @@ 'error'; ``` This query will find logs containing either "critical" or "error" as complete words. Each term is matched independently, and the results include logs that match either condition. Examples of matches and non-matches: - ✅ "critical error: system failure" - matches both terms - ✅ "An error occurred!" - matches "error" - ✅ "critical failure detected" - matches "critical" - ❌ "errors" - no match because "error" is part of a larger word - ❌ "critical_errors" - no match because terms are part of larger words ### Exclusion Searches You can use the `NOT` operator with `matches_term` to exclude certain terms from your search results. This is useful when you want to find logs containing one term but not another. ```sql -- Using matches_term function SELECT * FROM logs WHERE matches_term(message, 'error') AND NOT matches_term(message, 'critical'); -- Using @@ operator SELECT * FROM logs WHERE message @@ 'error' AND NOT message @@ 'critical'; ``` This query will find logs containing the word "error" but not containing the word "critical". This is particularly useful for filtering out certain types of errors or focusing on specific error categories. Examples of matches and non-matches: - ✅ "An error occurred!" - matches because it contains "error" but not "critical" - ❌ "critical error: system failure" - no match because it contains both terms - ❌ "critical failure detected" - no match because it contains "critical" ### Required Term Searches You can use the `AND` operator to require that multiple terms be present in the log message. This is useful for finding logs that contain specific combinations of terms. ```sql -- Using matches_term function SELECT * FROM logs WHERE matches_term(message, 'critical') AND matches_term(message, 'error'); -- Using @@ operator SELECT * FROM logs WHERE message @@ 'critical' AND message @@ 'error'; ``` This query will find logs containing both "critical" and "error" as complete words. Both conditions must be satisfied for a log to be included in the results. Examples of matches and non-matches: - ✅ "critical error: system failure" - matches because it contains both terms - ❌ "An error occurred!" - no match because it only contains "error" - ❌ "critical failure detected" - no match because it only contains "critical" ### Phrase Matching The `matches_term` function can also match exact phrases, including those with spaces. This is useful for finding specific error messages or status updates that contain multiple words. ```sql -- Using matches_term function SELECT * FROM logs WHERE matches_term(message, 'system failure'); -- Using @@ operator SELECT * FROM logs WHERE message @@ 'system failure'; ``` This query will find logs containing the exact phrase "system failure" with proper boundaries. The entire phrase must match exactly, including the space between words. Examples of matches and non-matches: - ✅ "Alert: system failure detected" - matches because the phrase is properly bounded - ✅ "system failure!" - matches because the phrase is properly bounded - ❌ "system-failure" - no match because the words are separated by a hyphen instead of a space - ❌ "system failure2023" - no match because the phrase is followed by numbers ### Case-Insensitive Matching While `matches_term` is case-sensitive by default, you can achieve case-insensitive matching by converting the text to lowercase before matching. ```sql -- Using matches_term function SELECT * FROM logs WHERE matches_term(lower(message), 'warning'); -- Using @@ operator SELECT * FROM logs WHERE lower(message) @@ 'warning'; ``` This query will find logs containing the word "warning" regardless of its case. The `lower()` function converts the entire message to lowercase before matching. Examples of matches and non-matches: - ✅ "Warning: high temperature" - matches after case conversion - ✅ "WARNING: system overload" - matches after case conversion - ❌ "warned" - no match because it's a different word - ❌ "warnings" - no match because it's a different word --- ## Manage Pipelines In GreptimeDB, each `pipeline` is a collection of data processing units used for parsing and transforming the ingested log content. This document provides guidance on creating and deleting pipelines to efficiently manage the processing flow of log data. For specific pipeline configurations, please refer to the [Pipeline Configuration](/reference/pipeline/pipeline-config.md) documentation. ## Authentication The HTTP API for managing pipelines requires authentication. For more information, see the [Authentication](/user-guide/protocols/http.md#authentication) documentation. ## Upload a Pipeline GreptimeDB provides a dedicated HTTP interface for creating pipelines. Assuming you have prepared a pipeline configuration file `pipeline.yaml`, use the following command to upload the configuration file, where `test` is the name you specify for the pipeline: ```shell ## Upload the pipeline file. 'test' is the name of the pipeline curl -X "POST" "http://localhost:4000/v1/pipelines/test" \ -H "Authorization: Basic {{authentication}}" \ -F "file=@pipeline.yaml" ``` The created Pipeline is shared for all databases. ## Pipeline Versions You can upload multiple versions of a pipeline with the same name. Each time you upload a pipeline with an existing name, a new version is created automatically. You can specify which version to use when [ingesting logs](/reference/pipeline/write-log-api.md#http-api), [querying](#query-pipelines), or [deleting](#delete-a-pipeline) a pipeline. The last uploaded version is used by default if no version is specified. After successfully uploading a pipeline, the response will include version information: ```json {"name":"nginx_pipeline","version":"2024-06-27 12:02:34.257312110Z"} ``` The version is a timestamp in UTC format that indicates when the pipeline was created. This timestamp serves as a unique identifier for each pipeline version. ## Delete a Pipeline You can use the following HTTP interface to delete a pipeline: ```shell ## 'test' is the name of the pipeline curl -X "DELETE" "http://localhost:4000/v1/pipelines/test?version=2024-06-27%2012%3A02%3A34.257312110Z" \ -H "Authorization: Basic {{authentication}}" ``` In the above example, we deleted a pipeline named `test`. The `version` parameter is required to specify the version of the pipeline to be deleted. ## Query Pipelines Querying a pipeline with a name through HTTP interface as follow: ```shell ## 'test' is the name of the pipeline, it will return a pipeline with latest version if the pipeline named `test` exists. curl "http://localhost:4000/v1/pipelines/test" \ -H "Authorization: Basic {{authentication}}" ``` ```shell ## with the version parameter, it will return the specify version pipeline. curl "http://localhost:4000/v1/pipelines/test?version=2025-04-01%2006%3A58%3A31.335251882%2B0000" \ -H "Authorization: Basic {{authentication}}" ``` If the pipeline exists, the output should be: ```json { "pipelines": [ { "name": "test", "version": "2025-04-01 06:58:31.335251882", "pipeline": "version: 2\nprocessors:\n - dissect:\n fields:\n - message\n patterns:\n - '%{ip_address} - - [%{timestamp}] \"%{http_method} %{request_line}\" %{status_code} %{response_size} \"-\" \"%{user_agent}\"'\n ignore_missing: true\n - date:\n fields:\n - timestamp\n formats:\n - \"%d/%b/%Y:%H:%M:%S %z\"\n - select:\n type: exclude\n fields:\n - message\n\ntransform:\n - fields:\n - ip_address\n type: string\n index: inverted\n tag: true\n - fields:\n - status_code\n type: int32\n index: inverted\n tag: true\n - fields:\n - request_line\n - user_agent\n type: string\n index: fulltext\n - fields:\n - response_size\n type: int32\n - fields:\n - timestamp\n type: time\n index: timestamp\n" } ], "execution_time_ms": 7 } ``` In the output above, the `pipeline` field is a YAML-formatted string. You can use [`jq -r`](https://jqlang.org/) to print it in a more human-readable way: ```shell curl "http://localhost:4000/v1/pipelines/test?version=2025-04-01%2006%3A58%3A31.335251882%2B0000" \ -H "Authorization: Basic {{authentication}}" \ | jq -r '.pipelines[0].pipeline' ``` ```yml version: 2 processors: - dissect: fields: - message patterns: - '%{ip_address} - - [%{timestamp}] "%{http_method} %{request_line}" %{status_code} %{response_size} "-" "%{user_agent}"' ignore_missing: true - date: fields: - timestamp formats: - "%d/%b/%Y:%H:%M:%S %z" - select: type: exclude fields: - message transform: - fields: - ip_address type: string index: inverted tag: true - fields: - status_code type: int32 index: inverted tag: true - fields: - request_line - user_agent type: string index: fulltext - fields: - response_size type: int32 - fields: - timestamp type: time index: timestamp ``` Or you can use SQL to query pipeline information. ```sql SELECT * FROM greptime_private.pipelines; ``` Please note that if you are using the MySQL or PostgreSQL protocol to connect to GreptimeDB, the precision of the pipeline time information may vary, and nanosecond-level precision may be lost. To address this issue, you can cast the `created_at` field to a timestamp to view the pipeline's creation time. For example, the following query displays `created_at` in `bigint` format: ```sql SELECT name, pipeline, created_at::bigint FROM greptime_private.pipelines; ``` The query result is as follows: ``` name | pipeline | greptime_private.pipelines.created_at ------+-----------------------------------+--------------------------------------- test | processors: +| 1719489754257312110 | - date: +| | field: time +| | formats: +| | - "%Y-%m-%d %H:%M:%S%.3f"+| | ignore_missing: true +| | +| | transform: +| | - fields: +| | - id1 +| | - id2 +| | type: int32 +| | - fields: +| | - type +| | - logger +| | type: string +| | index: inverted +| | - fields: +| | - log +| | type: string +| | index: fulltext +| | - field: time +| | type: time +| | index: timestamp +| | | (1 row) ``` Then, you can use a program to convert the bigint type timestamp from the SQL result into a time string. ```shell timestamp_ns="1719489754257312110"; readable_timestamp=$(TZ=UTC date -d @$((${timestamp_ns:0:10}+0)) +"%Y-%m-%d %H:%M:%S").${timestamp_ns:10}Z; echo "Readable timestamp (UTC): $readable_timestamp" ``` Output: ```shell Readable timestamp (UTC): 2024-06-27 12:02:34.257312110Z ``` The output `Readable timestamp (UTC)` represents the creation time of the pipeline and also serves as the version number. ## Debug First, please refer to the [Quick Start example](/user-guide/logs/quick-start.md#write-logs-by-pipeline) to see the correct execution of the Pipeline. ### Debug creating a Pipeline You may encounter errors when creating a Pipeline. For example, when creating a Pipeline using the following configuration: ```bash curl -X "POST" "http://localhost:4000/v1/pipelines/test" \ -H "Content-Type: application/x-yaml" \ -H "Authorization: Basic {{authentication}}" \ -d $'processors: - date: field: time formats: - "%Y-%m-%d %H:%M:%S%.3f" ignore_missing: true - gsub: fields: - message pattern: "\\\." replacement: - "-" ignore_missing: true transform: - fields: - message type: string - field: time type: time index: timestamp ' ``` The pipeline configuration contains an error. The `gsub` Processor expects the `replacement` field to be a string, but the current configuration provides an array. As a result, the pipeline creation fails with the following error message: ```json {"error":"Failed to parse pipeline: 'replacement' must be a string"} ``` Therefore, We need to modify the configuration of the `gsub` Processor and change the value of the `replacement` field to a string type. ```bash curl -X "POST" "http://localhost:4000/v1/pipelines/test" \ -H "Content-Type: application/x-yaml" \ -H "Authorization: Basic {{authentication}}" \ -d $'processors: - date: field: time formats: - "%Y-%m-%d %H:%M:%S%.3f" ignore_missing: true - gsub: fields: - message pattern: "\\\." replacement: "-" ignore_missing: true transform: - fields: - message type: string - field: time type: time index: timestamp ' ``` Now that the Pipeline has been created successfully, you can test the Pipeline using the `dryrun` interface. ### Debug writing logs We can test the Pipeline using the `dryrun` interface. We will test it with erroneous log data where the value of the message field is in numeric format, causing the pipeline to fail during processing. **This API is only used to test the results of the Pipeline and does not write logs to GreptimeDB.** ```bash curl -X "POST" "http://localhost:4000/v1/pipelines/_dryrun?pipeline_name=test" \ -H "Content-Type: application/json" \ -H "Authorization: Basic {{authentication}}" \ -d $'{"message": 1998.08,"time":"2024-05-25 20:16:37.217"}' ``` Output: ```json {"error":"Processor gsub: expect string value, but got Float(1998.08)"} ``` The output indicates that the pipeline processing failed because the `gsub` Processor expects a string type rather than a floating-point number type. We need to adjust the format of the log data to ensure the pipeline can process it correctly. Let's change the value of the message field to a string type and test the pipeline again. ```bash curl -X "POST" "http://localhost:4000/v1/pipelines/_dryrun?pipeline_name=test" \ -H "Content-Type: application/json" \ -H "Authorization: Basic {{authentication}}" \ -d $'{"message": "1998.08","time":"2024-05-25 20:16:37.217"}' ``` At this point, the Pipeline processing is successful, and the output is as follows: ```json [ { "rows": [ [ { "data_type": "STRING", "key": "message", "semantic_type": "FIELD", "value": "1998-08" }, { "data_type": "TIMESTAMP_NANOSECOND", "key": "time", "semantic_type": "TIMESTAMP", "value": 1716668197217000000 } ] ], "schema": [ { "column_type": "FIELD", "data_type": "STRING", "fulltext": false, "name": "message" }, { "column_type": "TIMESTAMP", "data_type": "TIMESTAMP_NANOSECOND", "fulltext": false, "name": "time" } ], "table_name": "dry_run" } ] ``` It can be seen that the `.` in the string `1998.08` has been replaced with `-`, indicating a successful processing of the Pipeline. ## Get Table DDL from a Pipeline Configuration When using pipelines, GreptimeDB automatically creates target tables upon first data ingestion by default. However, you may want to manually create tables beforehand to add custom table options, such as partition rules for better performance. While the auto-created table schema is deterministic for a given pipeline configuration, manually writing the table DDL (Data Definition Language) according to the configuration can be tedious. The `/ddl` API endpoint simplifies this process. For an existing pipeline, you can use the `/v1/pipelines/{pipeline_name}/ddl` endpoint to generate the `CREATE TABLE` SQL. This API examines the transform definition in the pipeline configuration and infers the appropriate table schema. You can use this API to generate the basic table DDL, fine-tune table options and manually create the table before ingesting data. Some common cases would be: - Add [partition rules](/user-guide/deployments-administration/manage-data/table-sharding.md) - Modify [index options](/user-guide/manage-data/data-index.md) - Add other [table options](/reference/sql/create.md#table-options) Here is an example demonstrating how to use this API. Consider the following pipeline configuration: ```YAML # pipeline.yaml processors: - dissect: fields: - message patterns: - '%{ip_address} - %{username} [%{timestamp}] "%{http_method} %{request_line} %{protocol}" %{status_code} %{response_size}' ignore_missing: true - date: fields: - timestamp formats: - "%d/%b/%Y:%H:%M:%S %z" transform: - fields: - timestamp type: time index: timestamp - fields: - ip_address type: string index: skipping - fields: - username type: string tag: true - fields: - http_method type: string index: inverted - fields: - request_line type: string index: fulltext - fields: - protocol type: string - fields: - status_code type: int32 index: inverted tag: true - fields: - response_size type: int64 on_failure: default default: 0 - fields: - message type: string ``` First, upload the pipeline to the database using the following command: ```bash curl -X "POST" "http://localhost:4000/v1/pipelines/pp" -F "file=@pipeline.yaml" ``` Then, query the table DDL using the following command: ```bash curl -X "GET" "http://localhost:4000/v1/pipelines/pp/ddl?table=test_table" ``` The API returns the following output in JSON format: ```JSON { "sql": { "sql": "CREATE TABLE IF NOT EXISTS `test_table` (\n `timestamp` TIMESTAMP(9) NOT NULL,\n `ip_address` STRING NULL SKIPPING INDEX WITH(false_positive_rate = '0.01', granularity = '10240', type = 'BLOOM'),\n `username` STRING NULL,\n `http_method` STRING NULL INVERTED INDEX,\n `request_line` STRING NULL FULLTEXT INDEX WITH(analyzer = 'English', backend = 'bloom', case_sensitive = 'false', false_positive_rate = '0.01', granularity = '10240'),\n `protocol` STRING NULL,\n `status_code` INT NULL INVERTED INDEX,\n `response_size` BIGINT NULL,\n `message` STRING NULL,\n TIME INDEX (`timestamp`),\n PRIMARY KEY (`username`, `status_code`)\n)\nENGINE=mito\nWITH(\n append_mode = 'true'\n)" }, "execution_time_ms": 3 } ``` After formatting the `sql` field in the response, you can see the inferred table schema: ```SQL CREATE TABLE IF NOT EXISTS `test_table` ( `timestamp` TIMESTAMP(9) NOT NULL, `ip_address` STRING NULL SKIPPING INDEX WITH(false_positive_rate = '0.01', granularity = '10240', type = 'BLOOM'), `username` STRING NULL, `http_method` STRING NULL INVERTED INDEX, `request_line` STRING NULL FULLTEXT INDEX WITH(analyzer = 'English', backend = 'bloom', case_sensitive = 'false', false_positive_rate = '0.01', granularity = '10240'), `protocol` STRING NULL, `status_code` INT NULL INVERTED INDEX, `response_size` BIGINT NULL, `message` STRING NULL, TIME INDEX (`timestamp`), PRIMARY KEY (`username`, `status_code`) ) ENGINE=mito WITH( append_mode = 'true' ) ``` You can use the inferred table DDL as a starting point. After customizing the DDL to meet your requirements, execute it manually before ingesting data through the pipeline. **Notes:** 1. The API only infers the table schema from the pipeline configuration; it doesn't check if the table already exists. 2. The API doesn't account for table suffixes. If you're using `dispatcher`, `table_suffix`, or table suffix hints in your pipeline configuration, you'll need to adjust the table name manually. --- ## Logs GreptimeDB provides a comprehensive log management solution designed for modern observability needs. It offers seamless integration with popular log collectors, flexible pipeline processing, and powerful querying capabilities, including full-text search. Key features include: - **Unified Storage**: Store logs alongside metrics and traces in a single database - **Pipeline Processing**: Transform and enrich raw logs with customizable pipelines, supporting various log collectors and formats - **Advanced Querying**: SQL-based analysis with full-text search capabilities - **Real-time Processing**: Process and query logs in real-time for monitoring and alerting ## Log Collection Flow ![log-collection-flow](/log-collection-flow.drawio.svg) The diagram above illustrates the comprehensive log collection architecture, which follows a structured four-stage process: Log Sources, Log Collectors, Pipeline Processing, and Storage in GreptimeDB. ### Log Sources Log sources represent the foundational layer where log data originates within your infrastructure. GreptimeDB supports ingestion from diverse source types to accommodate comprehensive observability requirements: - **Applications**: Application-level logs from microservices architectures, web applications, mobile applications, and custom software components - **IoT Devices**: Device logs, sensor event logs, and operational status logs from Internet of Things ecosystems - **Infrastructure**: Cloud platform logs, container orchestration logs (Kubernetes, Docker), load balancer logs, and network infrastructure component logs - **System Components**: Operating system logs, kernel events, system daemon logs, and hardware monitoring logs - **Custom Sources**: Any other log sources specific to your environment or applications ### Log Collectors Log collectors are responsible for efficiently gathering log data from diverse sources and reliably forwarding it to the storage backend. GreptimeDB seamlessly integrates with industry-standard log collectors, including Vector, Fluent Bit, Apache Kafka, OpenTelemetry Collector and more. GreptimeDB functions as a powerful sink backend for these collectors, providing robust data ingestion capabilities. During the ingestion process, GreptimeDB's pipeline system enables real-time transformation and enrichment of log data, ensuring optimal structure and quality before storage. ### Pipeline Processing GreptimeDB's pipeline mechanism transforms raw logs into structured, queryable data: - **Parse**: Extract structured data from unstructured log messages - **Transform**: Enrich logs with additional context and metadata - **Index**: Configure indexes to optimize query performance and enable efficient searching, including full-text indexes, time indexes, and more ### Storage in GreptimeDB After processing through the pipeline, the logs are stored in GreptimeDB enabling flexible analysis and visualization: - **SQL Querying**: Use familiar SQL syntax to analyze log data - **Time-based Analysis**: Leverage time-series capabilities for temporal analysis - **Full-text Search**: Perform advanced text searches across log messages - **Real-time Analytics**: Query logs in real-time for monitoring and alerting ## Quick Start You can quickly get started by using the built-in `greptime_identity` pipeline for log ingestion. For more information, please refer to the [Quick Start](./quick-start.md) guide. ## Integrate with Log Collectors GreptimeDB integrates seamlessly with various log collectors to provide a comprehensive logging solution. The integration process follows these key steps: 1. **Select Appropriate Log Collectors**: Choose collectors based on your infrastructure requirements, data sources, and performance needs 2. **Analyze Output Format**: Understand the log format and structure produced by your chosen collector 3. **Configure Pipeline**: Create and configure pipelines in GreptimeDB to parse, transform, and enrich the incoming log data 4. **Store and Query**: Efficiently store processed logs in GreptimeDB for real-time analysis and monitoring To successfully integrate your log collector with GreptimeDB, you'll need to: - First understand how pipelines work in GreptimeDB - Then configure the sink settings in your log collector to send data to GreptimeDB Please refer to the following guides for detailed instructions on integrating GreptimeDB with log collectors: - [Vector](/user-guide/ingest-data/for-observability/vector.md#using-greptimedb_logs-sink-recommended) - [Kafka](/user-guide/ingest-data/for-observability/kafka.md#logs) - [Fluent Bit](/user-guide/ingest-data/for-observability/fluent-bit.md#http) - [OpenTelemetry Collector](/user-guide/ingest-data/for-observability/otel-collector.md) - [Loki](/user-guide/ingest-data/for-observability/loki.md#using-pipeline-with-loki-push-api) ## Learn More About Pipelines - [Using Custom Pipelines](./use-custom-pipelines.md): Explains how to create and use custom pipelines for log ingestion. - [Managing Pipelines](./manage-pipelines.md): Explains how to create and delete pipelines. ## Query Logs - [Full-Text Search](./fulltext-search.md): Guide on using GreptimeDB's query language for effective searching and analysis of log data. ## Reference - [Built-in Pipelines](/reference/pipeline/built-in-pipelines.md): Lists and describes the details of the built-in pipelines provided by GreptimeDB for log ingestion. - [APIs for Writing Logs](/reference/pipeline/write-log-api.md): Describes the HTTP API for writing logs to GreptimeDB. - [Pipeline Configuration](/reference/pipeline/pipeline-config.md): Provides in-depth information on each specific configuration of pipelines in GreptimeDB. --- ## GreptimeDB Logs Quick Start # Quick Start This guide will walk you through the essential steps to get started with GreptimeDB's log service. You'll learn how to ingest logs using the built-in `greptime_identity` pipeline and integrate with log collectors. GreptimeDB provides a powerful pipeline-based log ingestion system. For quick setup with JSON-formatted logs, you can use the built-in `greptime_identity` pipeline, which: - Automatically handles field mapping from JSON to table columns - Creates tables automatically if they don't exist - Supports flexible schemas for varying log structures - Requires minimal configuration to get started ## Direct HTTP Ingestion The simplest way to ingest logs into GreptimeDB is through a direct HTTP request using the `greptime_identity` pipeline. For example, you can use `curl` to send a POST request with JSON log data: ```shell curl -X POST \ "http://localhost:4000/v1/ingest?db=public&table=demo_logs&pipeline_name=greptime_identity" \ -H "Content-Type: application/json" \ -H "Authorization: Basic {{authentication}}" \ -d '[ { "timestamp": "2024-01-15T10:30:00Z", "level": "INFO", "service": "web-server", "message": "User login successful", "user_id": 12345, "ip_address": "192.168.1.100" }, { "timestamp": "2024-01-15T10:31:00Z", "level": "ERROR", "service": "database", "message": "Connection timeout occurred", "error_code": 500, "retry_count": 3 } ]' ``` The key parameters are: - `db=public`: Target database name (use your database name) - `table=demo_logs`: Target table name (created automatically if it doesn't exist) - `pipeline_name=greptime_identity`: Uses `greptime_identity` identity pipeline for JSON processing - `Authorization` header: Basic authentication with base64-encoded `username:password`, see the [HTTP Authentication Guide](/user-guide/protocols/http.md#authentication) A successful request returns: ```json { "output": [{"affectedrows": 2}], "execution_time_ms": 15 } ``` After successful ingestion, the corresponding table `demo_logs` is automatically created with columns based on the JSON fields. The schema is as follows: ```sql +--------------------+---------------------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +--------------------+---------------------+------+------+---------+---------------+ | greptime_timestamp | TimestampNanosecond | PRI | NO | | TIMESTAMP | | ip_address | String | | YES | | FIELD | | level | String | | YES | | FIELD | | message | String | | YES | | FIELD | | service | String | | YES | | FIELD | | timestamp | String | | YES | | FIELD | | user_id | Int64 | | YES | | FIELD | | error_code | Int64 | | YES | | FIELD | | retry_count | Int64 | | YES | | FIELD | +--------------------+---------------------+------+------+---------+---------------+ ``` ## Integration with Log Collectors For production environments, you'll typically use log collectors to automatically forward logs to GreptimeDB. Here is an example about how to configure Vector to send logs to GreptimeDB using the `greptime_identity` pipeline: ```toml [sinks.my_sink_id] type = "greptimedb_logs" dbname = "public" endpoint = "http://:4000" pipeline_name = "greptime_identity" table = "" username = "" password = "" # Additional configurations as needed ``` The key configuration parameters are: - `type = "greptimedb_logs"`: Specifies the GreptimeDB logs sink - `dbname`: Target database name - `endpoint`: GreptimeDB HTTP endpoint - `pipeline_name`: Uses `greptime_identity` pipeline for JSON processing - `table`: Target table name (created automatically if it doesn't exist) - `username` and `password`: Credentials for HTTP Basic Authentication For details about the Vector configuration and options, refer to the [Vector Integration Guide](/user-guide/ingest-data/for-observability/vector.md#using-greptimedb_logs-sink-recommended). ## Next Steps You've successfully ingested your first logs, here are the recommended next steps: - **Learn more about the behaviours of built-in Pipelines**: Refer to the [Built-in Pipelines](/reference/pipeline/built-in-pipelines.md) guide for detailed information on available built-in pipelines and their configurations. - **Integrate with Popular Log Collectors**: For detailed instructions on integrating GreptimeDB with various log collectors like Fluent Bit, Fluentd, and others, refer to the [Integrate with Popular Log Collectors](./overview.md#integrate-with-log-collectors) section in the [Logs Overview](./overview.md) guide. - **Using Custom Pipelines**: To learn more about creating custom pipelines for advanced log processing and transformation, refer to the [Using Custom Pipelines](./use-custom-pipelines.md) guide. --- ## Using Custom Pipelines GreptimeDB automatically parses and transforms logs into structured, multi-column data based on your pipeline configuration. When built-in pipelines cannot handle your specific log format, you can create custom pipelines to define exactly how your log data should be parsed and transformed. ## Identify Your Original Log Format Before creating a custom pipeline, it's essential to understand the format of original log data. If you're using log collectors and aren't sure about the log format, there are two ways to examine your logs: 1. **Read the collector official documentation**: Configure your collector to output data to console or file to inspect the log format. 2. **Use the `greptime_identity` pipeline**: Ingest sample logs directly into GreptimeDB using the built-in `greptime_identity` pipeline. The `greptime_identity` pipeline treats the entire text log as a single `message` field, which makes it very convenient to see the raw log content directly. Once understand the log format you want to process, you can create a custom pipeline. This document uses the following Nginx access log entry as an example: ```txt 127.0.0.1 - - [25/May/2024:20:16:37 +0000] "GET /index.html HTTP/1.1" 200 612 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36" ``` ## Create a Custom Pipeline GreptimeDB provides an HTTP interface for creating pipelines. Here's how to create one. First, create an example pipeline configuration file to process Nginx access logs, naming it `pipeline.yaml`: ```yaml version: 2 processors: - dissect: fields: - message patterns: - '%{ip_address} - - [%{timestamp}] "%{http_method} %{request_line}" %{status_code} %{response_size} "-" "%{user_agent}"' ignore_missing: true - date: fields: - timestamp formats: - "%d/%b/%Y:%H:%M:%S %z" - select: type: exclude fields: - message - vrl: source: | .greptime_ttl = "7d" . transform: - fields: - ip_address type: string index: inverted tag: true - fields: - status_code type: int32 index: inverted tag: true - fields: - request_line - user_agent type: string index: fulltext - fields: - response_size type: int32 - fields: - timestamp type: time index: timestamp ``` The pipeline configuration above uses the [version 2](/reference/pipeline/pipeline-config.md#transform-in-version-2) format, contains `processors` and `transform` sections that work together to structure your log data: **Processors**: Used to preprocess log data before transformation: - **Data Extraction**: The `dissect` processor uses pattern matching to parse the `message` field and extract structured data including `ip_address`, `timestamp`, `http_method`, `request_line`, `status_code`, `response_size`, and `user_agent`. - **Timestamp Processing**: The `date` processor parses the extracted `timestamp` field using the format `%d/%b/%Y:%H:%M:%S %z` and converts it to a proper timestamp data type. - **Field Selection**: The `select` processor excludes the original `message` field from the final output while retaining all other fields. - **Table Options**: The `vrl` processor sets the table options based on the extracted fields, such as adding a suffix to the table name and setting the TTL. The `greptime_ttl = "7d"` line configures the table data to have a time-to-live of 7 days. **Transform**: Defines how to convert and index the extracted fields: - **Field Transformation**: Each extracted field is converted to its appropriate data type with specific indexing configurations. Fields like `http_method` retain their default data types when no explicit configuration is provided. - **Indexing Strategy**: - `ip_address` and `status_code` use inverted indexing as tags for fast filtering - `request_line` and `user_agent` use full-text indexing for optimal text search capabilities - `timestamp` serves as the required time index column For detailed information about pipeline configuration options, please refer to the [Pipeline Configuration](/reference/pipeline/pipeline-config.md) documentation. ## Upload the Pipeline Execute the following command to upload the pipeline configuration: ```shell curl -X "POST" \ "http://localhost:4000/v1/pipelines/nginx_pipeline" \ -H 'Authorization: Basic {{authentication}}' \ -F "file=@pipeline.yaml" ``` After successful execution, a pipeline named `nginx_pipeline` will be created and return the following result: ```json {"name":"nginx_pipeline","version":"2024-06-27 12:02:34.257312110Z"}. ``` You can create multiple versions for the same pipeline name. All pipelines are stored in the `greptime_private.pipelines` table. Refer to [Query Pipelines](manage-pipelines.md#query-pipelines) to view pipeline data. ## Ingest Logs Using the Pipeline The following example writes logs to the `custom_pipeline_logs` table using the `nginx_pipeline` pipeline to format and transform the log messages: ```shell curl -X POST \ "http://localhost:4000/v1/ingest?db=public&table=custom_pipeline_logs&pipeline_name=nginx_pipeline" \ -H "Content-Type: application/json" \ -H "Authorization: Basic {{authentication}}" \ -d '[ { "message": "127.0.0.1 - - [25/May/2024:20:16:37 +0000] \"GET /index.html HTTP/1.1\" 200 612 \"-\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36\"" }, { "message": "192.168.1.1 - - [25/May/2024:20:17:37 +0000] \"POST /api/login HTTP/1.1\" 200 1784 \"-\" \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36\"" }, { "message": "10.0.0.1 - - [25/May/2024:20:18:37 +0000] \"GET /images/logo.png HTTP/1.1\" 304 0 \"-\" \"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0\"" }, { "message": "172.16.0.1 - - [25/May/2024:20:19:37 +0000] \"GET /contact HTTP/1.1\" 404 162 \"-\" \"Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1\"" } ]' ``` The command will return the following output upon success: ```json {"output":[{"affectedrows":4}],"execution_time_ms":79} ``` The `custom_pipeline_logs` table content is automatically created based on the pipeline configuration: ```sql +-------------+-------------+-------------+---------------------------+-----------------------------------------------------------------------------------------------------------------------------------------+---------------+---------------------+ | ip_address | http_method | status_code | request_line | user_agent | response_size | timestamp | +-------------+-------------+-------------+---------------------------+-----------------------------------------------------------------------------------------------------------------------------------------+---------------+---------------------+ | 10.0.0.1 | GET | 304 | /images/logo.png HTTP/1.1 | Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0 | 0 | 2024-05-25 20:18:37 | | 127.0.0.1 | GET | 200 | /index.html HTTP/1.1 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 | 612 | 2024-05-25 20:16:37 | | 172.16.0.1 | GET | 404 | /contact HTTP/1.1 | Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1 | 162 | 2024-05-25 20:19:37 | | 192.168.1.1 | POST | 200 | /api/login HTTP/1.1 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36 | 1784 | 2024-05-25 20:17:37 | +-------------+-------------+-------------+---------------------------+-----------------------------------------------------------------------------------------------------------------------------------------+---------------+---------------------+ ``` For more detailed information about the log ingestion API endpoint `/ingest`, including additional parameters and configuration options, please refer to the [APIs for Writing Logs](/reference/pipeline/write-log-api.md) documentation. ## Query Logs We use the `custom_pipeline_logs` table as an example to query logs. ### Query logs by tags With the multiple tag columns in `custom_pipeline_logs`, you can query data by tags flexibly. For example, query the logs with `status_code` 200 and `http_method` GET. ```sql SELECT * FROM custom_pipeline_logs WHERE status_code = 200 AND http_method = 'GET'; ``` ```sql +------------+-------------+----------------------+---------------------------------------------------------------------------------------------------------------------+---------------+---------------------+-------------+ | ip_address | status_code | request_line | user_agent | response_size | timestamp | http_method | +------------+-------------+----------------------+---------------------------------------------------------------------------------------------------------------------+---------------+---------------------+-------------+ | 127.0.0.1 | 200 | /index.html HTTP/1.1 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 | 612 | 2024-05-25 20:16:37 | GET | +------------+-------------+----------------------+---------------------------------------------------------------------------------------------------------------------+---------------+---------------------+-------------+ 1 row in set (0.02 sec) ``` ### Full‑Text Search For the text fields `request_line` and `user_agent`, you can use `matches_term` function to search logs. Remember, we created the full-text index for these two columns when [creating a pipeline](#create-a-pipeline). This allows for high-performance full-text searches. For example, query the logs with `request_line` containing `/index.html` or `/api/login`. ```sql SELECT * FROM custom_pipeline_logs WHERE matches_term(request_line, '/index.html') OR matches_term(request_line, '/api/login'); ``` ```sql +-------------+-------------+----------------------+--------------------------------------------------------------------------------------------------------------------------+---------------+---------------------+-------------+ | ip_address | status_code | request_line | user_agent | response_size | timestamp | http_method | +-------------+-------------+----------------------+--------------------------------------------------------------------------------------------------------------------------+---------------+---------------------+-------------+ | 127.0.0.1 | 200 | /index.html HTTP/1.1 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 | 612 | 2024-05-25 20:16:37 | GET | | 192.168.1.1 | 200 | /api/login HTTP/1.1 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36 | 1784 | 2024-05-25 20:17:37 | POST | +-------------+-------------+----------------------+--------------------------------------------------------------------------------------------------------------------------+---------------+---------------------+-------------+ 2 rows in set (0.00 sec) ``` You can refer to the [Full-Text Search](fulltext-search.md) document for detailed usage of the `matches_term` function. ## Benefits of Using Pipelines Using pipelines to process logs provides structured data and automatic field extraction, enabling more efficient querying and analysis. You can also write logs directly to the database without pipelines, but this approach limits high-performance analysis capabilities. ### Direct Log Insertion (Without Pipeline) For comparison, you can create a table to store original log messages: ```sql CREATE TABLE `origin_logs` ( `message` STRING FULLTEXT INDEX, `time` TIMESTAMP TIME INDEX ) WITH ( append_mode = 'true' ); ``` Use the `INSERT` statement to insert logs into the table. Note that you need to manually add a timestamp field for each log: ```sql INSERT INTO origin_logs (message, time) VALUES ('127.0.0.1 - - [25/May/2024:20:16:37 +0000] "GET /index.html HTTP/1.1" 200 612 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"', '2024-05-25 20:16:37.217'), ('192.168.1.1 - - [25/May/2024:20:17:37 +0000] "POST /api/login HTTP/1.1" 200 1784 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36"', '2024-05-25 20:17:37.217'), ('10.0.0.1 - - [25/May/2024:20:18:37 +0000] "GET /images/logo.png HTTP/1.1" 304 0 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0"', '2024-05-25 20:18:37.217'), ('172.16.0.1 - - [25/May/2024:20:19:37 +0000] "GET /contact HTTP/1.1" 404 162 "-" "Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1"', '2024-05-25 20:19:37.217'); ``` ### Schema Comparison: Pipeline vs Raw In the above examples, the table `custom_pipeline_logs` is automatically created by writing logs using pipeline, and the table `origin_logs` is created by writing logs directly. Let's explore the differences between these two tables. ```sql DESC custom_pipeline_logs; ``` ```sql +---------------+---------------------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +---------------+---------------------+------+------+---------+---------------+ | ip_address | String | PRI | YES | | TAG | | status_code | Int32 | PRI | YES | | TAG | | request_line | String | | YES | | FIELD | | user_agent | String | | YES | | FIELD | | response_size | Int32 | | YES | | FIELD | | timestamp | TimestampNanosecond | PRI | NO | | TIMESTAMP | | http_method | String | | YES | | FIELD | +---------------+---------------------+------+------+---------+---------------+ 7 rows in set (0.00 sec) ``` ```sql DESC origin_logs; ``` ```sql +---------+----------------------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +---------+----------------------+------+------+---------+---------------+ | message | String | | YES | | FIELD | | time | TimestampMillisecond | PRI | NO | | TIMESTAMP | +---------+----------------------+------+------+---------+---------------+ ``` Comparing the table structures shows the key differences: The `custom_pipeline_logs` table (created with pipeline) automatically structures log data into multiple columns: - `ip_address`, `status_code` as indexed tags for fast filtering - `request_line`, `user_agent` with full-text indexing for text search - `response_size`, `http_method` as regular fields - `timestamp` as the time index The `origin_logs` table (direct insertion) stores everything in a single `message` column. ### Why Use Pipelines? It is recommended to use the pipeline method to split the log message into multiple columns, which offers the advantage of explicitly querying specific values within certain columns. Column matching query proves superior to full-text searching for several key reasons: - **Performance**: Column-based queries are typically faster than full-text searches - **Storage Efficiency**: GreptimeDB's columnar storage compresses structured data better; inverted indexes for tags consume less storage than full-text indexes - **Query Simplicity**: Tag-based queries are easier to write, understand, and debug ## Next Steps - **Full-Text Search**: Explore the [Full-Text Search](fulltext-search.md) guide to learn advanced text search capabilities and query techniques in GreptimeDB - **Pipeline Configuration**: Explore the [Pipeline Configuration](/reference/pipeline/pipeline-config.md) documentation to learn more about creating and customizing pipelines for various log formats and processing needs --- ## Data Index GreptimeDB provides various indexing mechanisms to accelerate query performance. Indexes are essential database structures that help optimize data retrieval operations by creating efficient lookup paths to specific data. ## Overview Indexes in GreptimeDB are specified during table creation and are designed to improve query performance for different types of data and query patterns. The database currently supports these types of indexes: - Inverted Index - Skipping Index - Fulltext Index Notice that in this chapter we are narrowing the word "index" to those related to data value indexing. PRIMARY KEY and TIME INDEX can also be treated as index in some scenarios, but they are not covered here. ## Index Types ### Inverted Index An inverted index is particularly useful for tag columns. It creates a mapping between unique tag values and their corresponding rows, enabling fast lookups for specific tag values. The inverted index is not automatically applied to tag columns. You need to manually create an inverted index by considering the following typical use cases: - Querying data by tag values - Filtering operations on string columns - Point queries on tag columns Example: ```sql CREATE TABLE monitoring_data ( host STRING INVERTED INDEX, `region` STRING PRIMARY KEY INVERTED INDEX, cpu_usage DOUBLE, `timestamp` TIMESTAMP TIME INDEX, ); ``` However, when a column has very high cardinality, the inverted index may not be the best choice due to the overhead of maintaining the index. It may bring high memory consumption and large index size. In this case, you may consider using the skipping index. ### Skipping Index Skipping index suits for columnar data systems like GreptimeDB. It maintains metadata about value ranges within data blocks, allowing the query engine to skip irrelevant data blocks during range queries efficiently. This index also has smaller size compare to others. **Use Cases:** - When certain values are sparse, such as MAC address codes in logs. - Querying specific values that occur infrequently within large datasets Example: ```sql CREATE TABLE sensor_data ( `domain` STRING PRIMARY KEY, device_id STRING SKIPPING INDEX, temperature DOUBLE, `timestamp` TIMESTAMP TIME INDEX, ); ``` Skipping index supports options by `WITH`: * `type`: The index type, only supports `BLOOM` type right now. * `granularity`: (For `BLOOM` type) The size of data chunks covered by each filter. A smaller granularity improves filtering but increases index size. Default is `10240`. * `false_positive_rate`: (For `BLOOM` type) The probability of misidentifying a block. A lower rate improves accuracy (better filtering) but increases index size. Value is a float between `0` and `1`. Default is `0.01`. For example: ```sql CREATE TABLE sensor_data ( `domain` STRING PRIMARY KEY, device_id STRING SKIPPING INDEX WITH(type='BLOOM', granularity=1024, false_positive_rate=0.01), temperature DOUBLE, `timestamp` TIMESTAMP TIME INDEX, ); ``` Skipping index can't handle complex filter conditions, and usually has a lower filtering performance compared to inverted index or full-text index. ### Full-Text Index Full-text index is designed for text search operations on string columns. It enables efficient searching of text content using word-based matching and text search capabilities. You can query text data with flexible keywords, phrases, or pattern matching queries. **Use Cases:** - Text search operations - Pattern matching queries - Large text filtering Example: ```sql CREATE TABLE logs ( `message` STRING FULLTEXT INDEX, `level` STRING PRIMARY KEY, `timestamp` TIMESTAMP TIME INDEX, ); ``` #### Configuration Options When creating or modifying a full-text index, you can specify the following options using `FULLTEXT INDEX WITH`: - `analyzer`: Sets the language analyzer for the full-text index - Supported values: `English`, `Chinese` - Default: `English` - Note: The Chinese analyzer requires significantly more time to build the index due to the complexity of Chinese text segmentation. Consider using it only when Chinese text search is a primary requirement. - `case_sensitive`: Determines whether the full-text index is case-sensitive - Supported values: `true`, `false` - Default: `false` - Note: Setting to `true` may slightly improve performance for case-sensitive queries, but will degrade performance for case-insensitive queries. This setting does not affect the results of `matches_term` queries. - `backend`: Sets the backend for the full-text index - Supported values: `bloom`, `tantivy` - Default: `bloom` - `granularity`: (For `bloom` backend) The size of data chunks covered by each filter. A smaller granularity improves filtering but increases index size. - Supported values: positive integer - Default: `10240` - `false_positive_rate`: (For `bloom` backend) The probability of misidentifying a block. A lower rate improves accuracy (better filtering) but increases index size. - Supported values: float between `0` and `1` - Default: `0.01` #### Backend Selection GreptimeDB provides two full-text index backends for efficient log searching: 1. **Bloom Backend** - Best for: General-purpose log searching - Features: - Uses Bloom filter for efficient filtering - Lower storage overhead - Consistent performance across different query patterns - Limitations: - Slightly slower for high-selectivity queries - Storage Cost Example: - Original data: ~10GB - Bloom index: ~1GB 2. **Tantivy Backend** - Best for: High-selectivity queries (e.g., unique values like TraceID) - Features: - Uses inverted index for fast exact matching - Excellent performance for high-selectivity queries - Limitations: - Higher storage overhead (close to original data size) - Slower performance for low-selectivity queries - Storage Cost Example: - Original data: ~10GB - Tantivy index: ~10GB #### Performance Comparison The following table shows the performance comparison between different query methods (using Bloom as baseline): | Query Type | High Selectivity (e.g., TraceID) | Low Selectivity (e.g., "HTTP") | |------------|----------------------------------|--------------------------------| | LIKE | 50x slower | 1x | | Tantivy | 5x faster | 5x slower | | Bloom | 1x (baseline) | 1x (baseline) | Key observations: - For high-selectivity queries (e.g., unique values), Tantivy provides the best performance - For low-selectivity queries, Bloom offers more consistent performance - Bloom has significant storage advantage over Tantivy (1GB vs 10GB in test case) #### Examples **Creating a Table with Full-Text Index** ```sql -- Using Bloom backend (recommended for most cases) CREATE TABLE logs ( timestamp TIMESTAMP(9) TIME INDEX, `message` STRING FULLTEXT INDEX WITH ( backend = 'bloom', analyzer = 'English', case_sensitive = 'false' ) ); -- Using Tantivy backend (for high-selectivity queries) CREATE TABLE logs ( timestamp TIMESTAMP(9) TIME INDEX, `message` STRING FULLTEXT INDEX WITH ( backend = 'tantivy', analyzer = 'English', case_sensitive = 'false' ) ); ``` **Modifying an Existing Table** ```sql -- Enable full-text index on an existing column ALTER TABLE monitor MODIFY COLUMN load_15 SET FULLTEXT INDEX WITH ( analyzer = 'English', case_sensitive = 'false', backend = 'bloom' ); -- Change full-text index configuration ALTER TABLE logs MODIFY COLUMN message SET FULLTEXT INDEX WITH ( analyzer = 'English', case_sensitive = 'false', backend = 'tantivy' ); ``` Fulltext index usually comes with following drawbacks: - Higher storage overhead compared to regular indexes due to storing word tokens and positions - Increased flush and compaction latency as each text document needs to be tokenized and indexed - May not be optimal for simple prefix or suffix matching operations Consider using full-text index only when you need advanced text search capabilities and flexible query patterns. ## Modify indexes You can always change the index type of columns by the `ALTER TABLE` statement, read the [reference](/reference/sql/alter/#alter-table) for more info. ## Best Practices 1. Choose the appropriate index type based on your data type and query patterns 2. Index only the columns that are frequently used in WHERE clauses 3. Consider the trade-off between query performance, ingest performance and resource consumption 4. Monitor index usage and performance to optimize your indexing strategy continuously ## Performance Considerations While indexes can significantly improve query performance, they come with some overhead: - Additional storage space required for index structures - Impact on flush and compaction performance due to index maintenance - Memory usage for index caching Choose indexes carefully based on your specific use case and performance requirements. --- ## Manage Data(Manage-data) ## Update data ### Update data with same tags and time index Updates can be efficiently performed by inserting new data. If rows of data have the same tags and time index, the old data will be replaced with the new data. This means that you can only update columns with a field type. To update data, simply insert new data with the same tag and time index as the existing data. For more information about column types, please refer to the [Data Model](../concepts/data-model.md). :::warning Note Excessive updates may negatively impact query performance, even though the performance of updates is the same as insertion. ::: #### Update all fields in a table By default, when updating data, all fields will be overwritten with the new values, except for [InfluxDB line protocol](/user-guide/protocols/influxdb-line-protocol.md), which only [updates the specified fields](#overwrite-specific-fields-in-a-table). The following example using SQL demonstrates the behavior of overwriting all fields in a table. Assuming you have a table named `monitor` with the following schema. The `host` column represents the tag and the `ts` column represents the time index. ```sql CREATE TABLE monitor ( host STRING, ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP() TIME INDEX, cpu FLOAT64, memory FLOAT64, PRIMARY KEY(host) ); ``` Insert a new row into the `monitor` table: ```sql INSERT INTO monitor (host, ts, cpu, memory) VALUES ("127.0.0.1", "2024-07-11 20:00:00", 0.8, 0.1); ``` Check the data in the table: ```sql SELECT * FROM monitor; ``` ```sql +-----------+---------------------+------+--------+ | host | ts | cpu | memory | +-----------+---------------------+------+--------+ | 127.0.0.1 | 2024-07-11 20:00:00 | 0.8 | 0.1 | +-----------+---------------------+------+--------+ 1 row in set (0.00 sec) ``` To update the data, you can use the same `host` and `ts` values as the existing data and set the new `cpu` value to `0.5`: ```sql INSERT INTO monitor (host, ts, cpu, memory) -- The same tag `127.0.0.1` and the same time index 2024-07-11 20:00:00 VALUES ("127.0.0.1", "2024-07-11 20:00:00", 0.5, 0.1); ``` The new data will be: ```sql SELECT * FROM monitor; ``` ```sql +-----------+---------------------+------+--------+ | host | ts | cpu | memory | +-----------+---------------------+------+--------+ | 127.0.0.1 | 2024-07-11 20:00:00 | 0.5 | 0.1 | +-----------+---------------------+------+--------+ 1 row in set (0.01 sec) ``` With the default merge policy, if columns are omitted in the `INSERT INTO` statement, they will be overwritten with the default values. For example: ```sql INSERT INTO monitor (host, ts, cpu) VALUES ("127.0.0.1", "2024-07-11 20:00:00", 0.5); ``` The default value of the `memory` column in the `monitor` table is `NULL`. Therefore, the new data will be: ```sql SELECT * FROM monitor; ``` ```sql +-----------+---------------------+------+--------+ | host | ts | cpu | memory | +-----------+---------------------+------+--------+ | 127.0.0.1 | 2024-07-11 20:00:00 | 0.5 | NULL | +-----------+---------------------+------+--------+ 1 row in set (0.01 sec) ``` ### Update specific fields in a table This update policy is supported by default in the [InfluxDB line protocol](/user-guide/protocols/influxdb-line-protocol.md). You can also enable this behavior by specifying the `merge_mode` option as `last_non_null` when creating a table using SQL. Here's an example: ```sql CREATE TABLE monitor ( host STRING, ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP() TIME INDEX, cpu FLOAT64, memory FLOAT64, PRIMARY KEY(host) ) WITH ('merge_mode'='last_non_null'); ``` ```sql INSERT INTO monitor (host, ts, cpu, memory) VALUES ("127.0.0.1", "2024-07-11 20:00:00", 0.8, 0.1); ``` To update specific fields in the `monitor` table, you can insert new data with only the fields you want to update. For example: ```sql INSERT INTO monitor (host, ts, cpu) VALUES ("127.0.0.1", "2024-07-11 20:00:00", 0.5); ``` This will update the `cpu` field while leaving the `memory` field unchanged. The result will be: ```sql +-----------+---------------------+------+--------+ | host | ts | cpu | memory | +-----------+---------------------+------+--------+ | 127.0.0.1 | 2024-07-11 20:00:00 | 0.5 | 0.1 | +-----------+---------------------+------+--------+ ``` Notice that the `last_non_null` merge mode cannot update the old value to `NULL`. For example: ```sql INSERT INTO monitor (host, ts, cpu, memory) VALUES ("127.0.0.1", "2024-07-11 20:00:01", 0.8, 0.1); ``` ```sql INSERT INTO monitor (host, ts, cpu) VALUES ("127.0.0.1", "2024-07-11 20:00:01", NULL); ``` That will not update anything: ```sql +-----------+---------------------+------+--------+ | host | ts | cpu | memory | +-----------+---------------------+------+--------+ | 127.0.0.1 | 2024-07-11 20:00:01 | 0.8 | 0.1 | +-----------+---------------------+------+--------+ ``` For more information about the `merge_mode` option, please refer to the [CREATE TABLE](/reference/sql/create.md#create-a-table-with-merge-mode) statement. ### Avoid updating data by creating table with `append_mode` option GreptimeDB supports an `append_mode` option when creating a table, which always inserts new data to the table. This is especially useful when you want to keep all historical data, such as logs. You can only create a table with the `append_mode` option using SQL. After successfully creating the table, all protocols [ingest data](/user-guide/ingest-data/overview.md) to the table will always insert new data. For example, you can create an `app_logs` table with the `append_mode` option as follows. The `host` and `log_level` columns represent tags, and the `ts` column represents the time index. ```sql CREATE TABLE app_logs ( ts TIMESTAMP TIME INDEX, host STRING, api_path STRING FULLTEXT INDEX, log_level STRING, `log` STRING FULLTEXT INDEX, PRIMARY KEY (host, log_level) ) WITH ('append_mode'='true'); ``` Insert a new row into the `app_logs` table: ```sql INSERT INTO app_logs (ts, host, api_path, log_level, `log`) VALUES ('2024-07-11 20:00:10', 'host1', '/api/v1/resource', 'ERROR', 'Connection timeout'); ``` Check the data in the table: ```sql SELECT * FROM app_logs; ``` The output will be: ```sql +---------------------+-------+------------------+-----------+--------------------+ | ts | host | api_path | log_level | log | +---------------------+-------+------------------+-----------+--------------------+ | 2024-07-11 20:00:10 | host1 | /api/v1/resource | ERROR | Connection timeout | +---------------------+-------+------------------+-----------+--------------------+ 1 row in set (0.01 sec) ``` You can insert new data with the same tag and time index: ```sql INSERT INTO app_logs (ts, host, api_path, log_level, `log`) -- The same tag `host1` and `ERROR`, the same time index 2024-07-11 20:00:10 VALUES ('2024-07-11 20:00:10', 'host1', '/api/v1/resource', 'ERROR', 'Connection reset'); ``` Then you will find two rows in the table: ```sql SELECT * FROM app_logs; ``` ```sql +---------------------+-------+------------------+-----------+--------------------+ | ts | host | api_path | log_level | log | +---------------------+-------+------------------+-----------+--------------------+ | 2024-07-11 20:00:10 | host1 | /api/v1/resource | ERROR | Connection reset | | 2024-07-11 20:00:10 | host1 | /api/v1/resource | ERROR | Connection timeout | +---------------------+-------+------------------+-----------+--------------------+ 2 rows in set (0.01 sec) ``` ## Delete Data You can effectively delete data by specifying tags and time index. Deleting data without specifying the tag and time index columns is not efficient, as it requires two steps: querying the data and then deleting it by tag and time index. For more information about column types, please refer to the [Data Model](../concepts/data-model.md). :::warning Warning Excessive deletions can negatively impact query performance. ::: You can only delete data using SQL. For example, to delete a row from the `monitor` table with tag `host` and timestamp index `ts`: ```sql DELETE FROM monitor WHERE host='127.0.0.2' AND ts=1667446798450; ``` The output will be: ```sql Query OK, 1 row affected (0.00 sec) ``` For more information about the `DELETE` statement, please refer to the [SQL DELETE](/reference/sql/delete.md). ## Truncate Table To delete all data in a table, you can use the `TRUNCATE TABLE` statement in SQL. For example, to truncate the `monitor` table: ```sql TRUNCATE TABLE monitor; ``` For more information about the `TRUNCATE TABLE` statement, refer to the [SQL TRUNCATE TABLE](/reference/sql/truncate.md) documentation. ## Manage data retention with TTL policies You can use Time to Live (TTL) policies to automatically remove stale data from your databases. TTL allows you to set policies to periodically delete data from tables. Setting TTL policies has the following benefits: - Decrease storage costs by cleaning out obsolete data. - Reduce the number of rows the database has to scan for some queries, potentially increasing query performance. > Please note that the expired data due to TTL policy may not be deleted right after the expiration time. Instead, they are deleted during the compaction, which is a background job run asynchronously. > If you are testing the TTL policy, be sure to trigger data flush and compaction before querying the data. > You can use our "[ADMIN](/reference/sql/admin.md)" functions to manually run them. You can set TTL for every table when creating it. For example, the following SQL statement creates a table named `monitor` with a TTL policy of 7 days: ```sql CREATE TABLE monitor ( host STRING, ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP() TIME INDEX, cpu FLOAT64, memory FLOAT64, PRIMARY KEY(host) ) WITH ('ttl'='7d'); ``` You can also create a database-level TTL policy. For example, the following SQL statement creates a database named `test` with a TTL policy of 7 days: ```sql CREATE DATABASE test WITH ('ttl'='7d'); ``` You can set TTL policies at both the table level and the database level simultaneously. If a table has its own TTL policy, it will take precedence over the database TTL policy. Otherwise, the database TTL policy will be applied to the table. The value of `'ttl'` can be one of duration (like `1hour 12min 5s`), `instant` or `forever`. See details in [CREATE](/reference/sql/create.md#create-a-table-with-ttl) statement. Use [`ALTER`](/reference/sql/alter.md#alter-table-options) to modify the TTL of an existing table or database: ```sql -- for table ALTER TABLE monitor SET 'ttl'='1 month'; -- for database ALTER DATABASE test SET 'ttl'='1 month'; ``` If you want to remove the TTL policy, you can use the following SQL ```sql -- for table ALTER TABLE monitor UNSET 'ttl'; -- or for database ALTER DATABASE test UNSET 'ttl'; ``` For more information about TTL policies, please refer to the [CREATE](/reference/sql/create.md) statement. ## More data management operations For more advanced data management operations, such as basic table operations, table sharding and region migration, please refer to the [Data Management](/user-guide/deployments-administration/manage-data/overview.md) in the administration section. --- ## Migrate from ClickHouse This guide provides a detailed explanation on how to smoothly migrate your business from ClickHouse to GreptimeDB. It covers pre-migration preparation, data model adjustments, table structure reconstruction, dual-write assurance, and specific methods for data export and import, aiming to achieve a seamless system transition. ## Pre-Migration Notes - **Compatibility** Although GreptimeDB is SQL protocol compatible, the two databases have fundamental differences in data modeling, index design, and compression mechanisms. Be sure to refer to the [SQL compatibility](/reference/sql/compatibility.md) documentation and official [modeling guidelines](/user-guide/deployments-administration/performance-tuning/design-table.md) to refactor table structures and data flows during migration. - **Data Model Differences** ClickHouse is a general-purpose big data analytics engine, while GreptimeDB is optimized for time-series, metrics, and log observability scenarios. There are differences in their data models, index systems, and compression algorithms, so it’s important to take these differences and the actual business scenario into account during model design and compatibility considerations. --- ## Refactoring Data Model and Table Structure ### Time Index - ClickHouse tables do not always have a `time index` field. During migration, you need to clearly select the primary time field for your business to serve as the time index and specify it when creating the table in GreptimeDB. For example, typical log or trace print times. - The time precision (such as second, millisecond, microsecond, etc.) should be assessed based on real-world requirements and cannot be changed once set. ### Primary Key and Wide Table Recommendations - Primary Key: Just like the `order by` in ClickHouse without the timestamp column. It’s not recommended to include high-cardinality fields such as log IDs, user IDs or UUIDs to avoid primary key bloat, excessive write amplification, and inefficient queries. - Wide Table vs. Multiple Tables: For multiple metrics collected at the same observation point (such as on the same host), it’s better to use a wide table, which improves batch write efficiency and compression ratio. ### Index Planning - Inverted Index: Build indexes for low-cardinality columns to improve filter efficiency. - Skipping Index: Use as needed; Used when certain values are sparse or querying specific values that occur infrequently within large datasets. - Fulltext Index: Use as needed; Designed for text search operations on string columns; avoid building unnecessary indexes on high-cardinality or highly variable fields. - Read [Data Index](/user-guide/manage-data/data-index.md) for more info. ### Partitioning Table ClickHouse supports table partitioning via the `PARTITION BY` syntax. GreptimeDB provides a similar feature with a different syntax; see the [table sharding](/user-guide/deployments-administration/manage-data/table-sharding.md) documentation for details. ### TTL GreptimeDB supports TTL (Time-to-live) through the table option `ttl`. For more information, please refer to [Manage data retention with TTL policies](/user-guide/manage-data/overview.md#manage-data-retention-with-ttl-policies). ### Example Table Example ClickHouse table structure: ```sql CREATE TABLE example ( timestamp DateTime, host String, app String, metric String, value Float64 ) ENGINE = MergeTree() TTL timestamp + INTERVAL 30 DAY ORDER BY (timestamp, host, app, metric); ``` Recommended table structure after migrating to GreptimeDB: ```sql CREATE TABLE example ( `timestamp` TIMESTAMP NOT NULL, host STRING, app STRING INVERTED INDEX, metric STRING INVERTED INDEX, `value` DOUBLE, PRIMARY KEY (host, app, metric), TIME INDEX (`timestamp`) ) with(ttl='30d'); ``` > The choice of primary key and the granularity of the time index should be carefully planned based on your business's data volume and query scenarios. If the host cardinality is high (e.g., hundreds of thousands of monitored hosts), you should remove it from the primary key and consider creating a skipping index for it. --- ### Migrating Typical Log Tables > GreptimeDB already provides built-in modeling for otel log ingestion, so please refer to the [official documentation](/user-guide/ingest-data/for-observability/opentelemetry.md#logs). Common ClickHouse log table structure: ```sql CREATE TABLE logs ( timestamp DateTime, host String, service String, log_level String, log_message String, trace_id String, span_id String, INDEX inv_idx(log_message) TYPE ngrambf_v1(4, 1024, 1, 0) GRANULARITY 1 ) ENGINE = MergeTree ORDER BY (timestamp, host, service); ``` Recommended GreptimeDB table structure: - Time index: `timestamp` (precision set based on logging frequency) - Primary key: `host`, `service` (fields often used in queries/aggregations) - Field columns: `log_message`, `trace_id`, `span_id` (high-cardinality, unique identifiers, or raw content) ```sql CREATE TABLE logs ( `timestamp` TIMESTAMP NOT NULL, host STRING, service STRING, log_level STRING, log_message STRING FULLTEXT INDEX WITH ( backend = 'bloom', analyzer = 'English', case_sensitive = 'false' ), trace_id STRING SKIPPING INDEX, span_id STRING SKIPPING INDEX, PRIMARY KEY (host, service), TIME INDEX (`timestamp`) ); ``` **Notes:** - `host` and `service` serve as common query filters and are included in the primary key to optimize filtering. If there are very many hosts, you might not want to include `host` in the primary key but instead create a skip index. - `log_message` is treated as raw content with a full-text index created. If you want the full-text index to take effect during queries, you also need to adjust your SQL query syntax. Please refer to [the log query documentation](/user-guide/logs/fulltext-search.md) for details - Since `trace_id` and `span_id` are mostly high-cardinality fields, it is not recommended to use them in the primary key, but skip indexes have been added. --- ### Migrating Typical Traces Tables > GreptimeDB also provides built-in modeling for otel trace ingestion, please read the [official documentation](/user-guide/ingest-data/for-observability/opentelemetry.md#traces). Common ClickHouse trace table structure design: ```sql CREATE TABLE traces ( timestamp DateTime, trace_id String, span_id String, parent_span_id String, service String, operation String, duration UInt64, status String, tags Map(String, String) ) ENGINE = MergeTree() ORDER BY (timestamp, trace_id, span_id); ``` Recommended GreptimeDB table structure: - Time index: `timestamp` (e.g., collection/start time) - Primary key: `service`, `operation` (commonly filtered/aggregated properties) - Field columns: `trace_id`, `span_id`, `parent_span_id`, `duration`, `tags` (high-cardinality or Map type) ```sql CREATE TABLE traces ( `timestamp` TIMESTAMP NOT NULL, service STRING, operation STRING, `status` STRING, trace_id STRING SKIPPING INDEX, span_id STRING SKIPPING INDEX, parent_span_id STRING SKIPPING INDEX, duration DOUBLE, tags STRING, -- If this is structured JSON, either store it as-is or use the pipeline to parse fields PRIMARY KEY (service, operation), TIME INDEX (`timestamp`) ); ``` **Notes:** - `service` and `operation` serve as primary key, supporting trace scheduling and aggregate queries by service or operations. - `trace_id`, `span_id`, and `parent_span_id` use skip indexes but are not part of the primary key. - High-cardinality fields are set as fields for efficient writes. For complex properties like `tags`, [JSON storage](/reference/sql/data-types/#json-type-experimental) or string is recommended, and they can be expanded using GreptimeDB’s ETL - [Pipeline](/user-guide/logs/quick-start.md#write-logs-by-pipeline) if necessary. - Depending on overall business volume, consider whether to partition traces into multiple tables (such as in massive multi-service environments). --- ## Dual-write Strategy for Safe Migration During the migration process, to avoid data loss or inconsistent writes, adopt a dual-write approach: - The application should write to both ClickHouse and GreptimeDB simultaneously, running the two systems in parallel. - Validate and compare data using logs and checks to ensure data consistency. Once the data has been fully validated, you can switch fully over. --- ## Exporting and Importing Historical Data 1. **Enable dual-write before migration** The application should write to both ClickHouse and GreptimeDB. Check for data consistency to reduce the risk of missing data. 2. **Data export from ClickHouse** Use ClickHouse’s native command to export data as CSV, TSV, Parquet, or other formats. For example: ```sh clickhouse client --query="SELECT * FROM example INTO OUTFILE 'example.csv' FORMAT CSVWithNames" ``` The exported CSV will look like: ```csv "timestamp","host","app","metric","value" "2024-04-25 10:00:00","host01","nginx","cpu_usage",12.7 "2024-04-25 10:00:00","host02","redis","cpu_usage",8.4 "2024-04-25 10:00:00","host03","postgres","cpu_usage",15.3 "2024-04-25 10:01:00","host01","nginx","cpu_usage",12.5 "2024-04-25 10:01:00","host01","nginx","mem_usage",1034.5 "2024-04-25 10:01:00","host02","redis","mem_usage",876.2 "2024-04-25 10:01:00","host03","postgres","mem_usage",1145.2 "2024-04-25 10:02:00","host01","nginx","disk_io",120.3 "2024-04-25 10:02:00","host02","redis","disk_io",95.1 "2024-04-25 10:02:00","host03","postgres","disk_io",134.7 "2024-04-25 10:03:00","host02","redis","mem_usage",874 "2024-04-25 10:04:00","host03","postgres","cpu_usage",15.1 ``` 3. **Data import into GreptimeDB** > The table must be created in GreptimeDB before importing data. GreptimeDB currently supports batch data import via SQL commands or [REST API](/reference/http-endpoints.md#protocol-endpoints). For large datasets, import in batches. Use the [`COPY FROM` command](/reference/sql/copy.md#copy-from) to import: ```sql COPY example FROM "/path/to/example.csv" WITH (FORMAT = 'CSV'); ``` Alternatively, you can convert the CSV to standard INSERT statements for batch import. --- ## Validation and Cutover - Once the import is complete, use GreptimeDB’s query interface to compare data with ClickHouse for consistency. - After data verification and monitoring meet requirements, you can officially switch business writes to GreptimeDB and disable dual-write mode. --- ## Frequently Asked Questions and Optimization Tips ### What if SQL/types are incompatible? Before migration, audit all query SQL and rewrite or translate as necessary, referring to the [official documentation](/user-guide/query-data/sql.md) (especially for [log query](/user-guide/logs/fulltext-search.md)) for any incompatible syntax or data types. ### How do I efficiently import very large datasets in batches? For large tables or full historical data, export and import by partition or shard as appropriate. Monitor write speed and import progress closely. ### How should high-cardinality fields be handled? Avoid using high-cardinality fields as primary key. Store them as fields instead, and split into multiple tables if necessary. ### How should wide tables be planned? For each monitoring entity or collection endpoint, consolidate all metrics into a single table. For example, use a `host_metrics` table to store all server statistics. --- If you need a more detailed migration plan or example scripts, please provide the specific table structure and data volume. The [GreptimeDB official community](https://github.com/orgs/GreptimeTeam/discussions) will offer further support. Welcome to join the [Greptime Slack](http://greptime.com/slack). --- ## Migrate from InfluxDB ```shell curl -X POST 'http://{{host}}:4000/v1/influxdb/api/v2/write?db={{db-name}}' \ -H 'authorization: token {{greptime_user:greptimedb_password}}' \ -d 'census,location=klamath,scientist=anderson bees=23 1566086400000000000' ``` ```shell curl 'http://{{host}}:4000/v1/influxdb/write?db={{db-name}}&u={{greptime_user}}&p={{greptimedb_password}}' \ -d 'census,location=klamath,scientist=anderson bees=23 1566086400000000000' ``` For detailed configuration instructions, please refer to the [Ingest Data via Telegraf](/user-guide/ingest-data/for-iot/influxdb-line-protocol.md#telegraf) documentation. ```js [Node.js] 'use strict' /** @module write **/ /** Environment variables **/ const url = 'http://:4000/v1/influxdb' const token = ':' const org = '' const bucket = '' const influxDB = new InfluxDB({ url, token }) const writeApi = influxDB.getWriteApi(org, bucket) writeApi.useDefaultTags({ region: 'west' }) const point1 = new Point('temperature') .tag('sensor_id', 'TLM01') .floatField('value', 24.0) writeApi.writePoint(point1) ``` ```python from influxdb_client.client.write_api import SYNCHRONOUS bucket = "" org = "" token = ":" url="http://:4000/v1/influxdb" client = influxdb_client.InfluxDBClient( url=url, token=token, org=org ) # Write script write_api = client.write_api(write_options=SYNCHRONOUS) p = influxdb_client.Point("my_measurement").tag("location", "Prague").field("temperature", 25.3) write_api.write(bucket=bucket, org=org, record=p) ``` ```go bucket := "" org := "" token := ":" url := "http://:4000/v1/influxdb" client := influxdb2.NewClient(url, token) writeAPI := client.WriteAPIBlocking(org, bucket) p := influxdb2.NewPoint("stat", map[string]string{"unit": "temperature"}, map[string]interface{}{"avg": 24.5, "max": 45}, time.Now()) writeAPI.WritePoint(context.Background(), p) client.Close() ``` ```java private static String url = "http://:4000/v1/influxdb"; private static String org = ""; private static String bucket = ""; private static char[] token = ":".toCharArray(); public static void main(final String[] args) { InfluxDBClient influxDBClient = InfluxDBClientFactory.create(url, token, org, bucket); WriteApiBlocking writeApi = influxDBClient.getWriteApiBlocking(); Point point = Point.measurement("temperature") .addTag("location", "west") .addField("value", 55D) .time(Instant.now().toEpochMilli(), WritePrecision.MS); writeApi.writePoint(point); influxDBClient.close(); } ``` ```php $client = new Client([ "url" => "http://:4000/v1/influxdb", "token" => ":", "bucket" => "", "org" => "", "precision" => InfluxDB2\Model\WritePrecision::S ]); $writeApi = $client->createWriteApi(); $dateTimeNow = new DateTime('NOW'); $point = Point::measurement("weather") ->addTag("location", "Denver") ->addField("temperature", rand(0, 20)) ->time($dateTimeNow->getTimestamp()); $writeApi->write($point); ``` It is recommended using Grafana to visualize data in GreptimeDB. Please refer to the [Grafana documentation](/user-guide/integrations/grafana.md) for details on configuring GreptimeDB. ```shell for file in data.*; do curl -i --retry 3 \ -X POST "http://${GREPTIME_HOST}:4000/v1/influxdb/write?db=${GREPTIME_DB}&u=${GREPTIME_USERNAME}&p=${GREPTIME_PASSWORD}" \ --data-binary @${file} sleep 1 done ``` --- ## Migrate from MySQL This document will guide you through the migration process from MySQL to GreptimeDB. ## Before you start the migration Please be aware that though GreptimeDB supports the wire protocol of MySQL, it does not mean GreptimeDB implements all MySQL's features. You may refer to: * The [ANSI Compatibility](/reference/sql/compatibility.md) to see the constraints regarding using SQL in GreptimeDB. * The [Data Modeling Guide](/user-guide/deployments-administration/performance-tuning/design-table.md) to create proper table schemas. * The [Data Index Guide](/user-guide/manage-data/data-index.md) for index planning. ## Migration steps ### Create the databases and tables in GreptimeDB Before migrating the data from MySQL, you first need to create the corresponding databases and tables in GreptimeDB. GreptimeDB has its own SQL syntax for creating tables, so you cannot directly reuse the table creation SQLs that are produced by MySQL. When you write the table creation SQL for GreptimeDB, it's important to understand its "[data model](/user-guide/concepts/data-model.md)" first. Then, please take the following considerations in your create table SQL: 1. Since the time index column cannot be changed after the table is created, you need to choose the time index column carefully. The time index is best set to the natural timestamp when the data is generated, as it provides the most intuitive way to query the data, and the best query performance. For example, in the IOT scenes, you can use the collection time of sensor data as the time index; or the occurrence time of an event in the observability scenes. 2. In this migration process, it's not recommend to create another synthetic timestamp, such as a new column created with `DEFAULT current_timestamp()` as the time index column. It's not recommend to use the random timestamp as the time index either. 3. It's vital to set the most fit timestamp precision for your time index column, too. Like the chosen of time index column, the precision of it cannot be changed as well. Find the most fit timestamp type for your data set [here](/reference/sql/data-types#data-types-compatible-with-mysql-and-postgresql). 4. Choose a primary key only when it is truly needed. The primary key in GreptimeDB is different from that in MySQL. You should use a primary key only when: * Most queries can benefit from the ordering. * You need to deduplicate (including delete) rows by the primary key and time index. Otherwise, setting a primary key is optional and it may hurt performance. Read [Primary Key](/user-guide/deployments-administration/performance-tuning/design-table.md#primary-key) for details. Finally please refer to "[CREATE](/reference/sql/create.md)" SQL document for more details for choosing the right data types and "ttl" or "compaction" options, etc. 5. Choose proper indexes to speed up queries. * Inverted index: is ideal for filtering by low-cardinality columns and quickly finding rows with specific values. * Skipping index: works well with sparse data. * Fulltext index: enables efficient keyword and pattern search in large text columns. For details and best practices, refer to the [data index](user-guide/manage-data/data-index.md) documentation. ### Write data to both GreptimeDB and MySQL simultaneously Writing data to both GreptimeDB and MySQL simultaneously is a practical strategy to avoid data loss during migration. By utilizing MySQL's client libraries (JDBC + a MySQL driver), you can set up two client instances - one for GreptimeDB and another for MySQL. For guidance on writing data to GreptimeDB using SQL, please refer to the [Ingest Data](/user-guide/ingest-data/for-iot/sql.md) section. If retaining all historical data isn't necessary, you can simultaneously write data to both GreptimeDB and MySQL for a specific period to accumulate the required recent data. Subsequently, cease writing to MySQL and continue exclusively with GreptimeDB. If a complete migration of all historical data is needed, please proceed with the following steps. ### Export data from MySQL [mysqldump](https://dev.mysql.com/doc/refman/8.4/en/mysqldump.html) is a commonly used tool to export data from MySQL. Using it, we can export the data that can be later imported into GreptimeDB directly. For example, if we want to export two databases, `db1` and `db2` from MySQL, we can use the following command: ```bash mysqldump -h127.0.0.1 -P3306 -umysql_user -p --compact -cnt --skip-extended-insert --databases db1 db2 > /path/to/output.sql ``` Replace the `-h`, `-P` and `-u` flags with the appropriate values for your MySQL server. The `--databases` flag is used to specify the databases to be exported. The output will be written to the `/path/to/output.sql` file. The content in the `/path/to/output.sql` file should be like this: ```plaintext ~ ❯ cat /path/to/output.sql USE `db1`; INSERT INTO `foo` (`ts`, `a`, `b`) VALUES (1,'hello',1); INSERT INTO ... USE `db2`; INSERT INTO `foo` (`ts`, `a`, `b`) VALUES (2,'greptime',2); INSERT INTO ... ``` ### Import data into GreptimeDB The [MySQL Command-Line Client](https://dev.mysql.com/doc/refman/8.4/en/mysql.html) can be used to import data into GreptimeDB. Continuing the above example, say the data is exported to file `/path/to/output.sql`, then we can use the following command to import the data into GreptimeDB: ```bash mysql -h127.0.0.1 -P4002 -ugreptime_user -p -e "source /path/to/output.sql" ``` Replace the `-h`, `-P` and `-u` flags with the appropriate values for your GreptimeDB server. The `source` command is used to execute the SQL commands in the `/path/to/output.sql` file. Add `-vvv` to see the detailed execution results for debugging purpose. To summarize, data migration steps can be illustrate as follows: ![migrate mysql data steps](/migration-mysql.jpg) After the data migration is completed, you can stop writing data to MySQL and continue using GreptimeDB exclusively! If you need a more detailed migration plan or example scripts, please provide the specific table structure and data volume. The [GreptimeDB official community](https://github.com/orgs/GreptimeTeam/discussions) will offer further support. Welcome to join the [Greptime Slack](http://greptime.com/slack). --- ## Migrate from PostgreSQL This document will guide you through the migration process from PostgreSQL to GreptimeDB. ## Before you start the migration Please be aware that though GreptimeDB supports the wire protocol of PostgreSQL, it does not mean GreptimeDB implements all PostgreSQL's features. You may refer to: * The [ANSI Compatibility](/reference/sql/compatibility.md) to see the constraints regarding using SQL in GreptimeDB. * The [Data Modeling Guide](/user-guide/deployments-administration/performance-tuning/design-table.md) to create proper table schemas. * The [Data Index Guide](/user-guide/manage-data/data-index.md) for index planning. ## Migration steps ### Create the databases and tables in GreptimeDB Before migrating the data from PostgreSQL, you first need to create the corresponding databases and tables in GreptimeDB. GreptimeDB has its own SQL syntax for creating tables, so you cannot directly reuse the table creation SQLs that are produced by PostgreSQL. When you write the table creation SQL for GreptimeDB, it's important to understand its "[data model](/user-guide/concepts/data-model.md)" first. Then, please take the following considerations in your create table SQL: 1. Since the time index column cannot be changed after the table is created, you need to choose the time index column carefully. The time index is best set to the natural timestamp when the data is generated, as it provides the most intuitive way to query the data, and the best query performance. For example, in the IOT scenes, you can use the collection time of sensor data as the time index; or the occurrence time of an event in the observability scenes. 2. In this migration process, it's not recommend to create another synthetic timestamp, such as a new column created with `DEFAULT current_timestamp()` as the time index column. It's not recommend to use the random timestamp as the time index either. 3. It's vital to set the most fit timestamp precision for your time index column, too. Like the chosen of time index column, the precision of it cannot be changed as well. Find the most fit timestamp type for your data set [here](/reference/sql/data-types#data-types-compatible-with-mysql-and-postgresql). 4. Choose a primary key only when it is truly needed. The primary key in GreptimeDB is different from that in PostgreSQL. You should use a primary key only when: * Most queries can benefit from the ordering. * You need to deduplicate (including delete) rows by the primary key and time index. Otherwise, setting a primary key is optional and it may hurt performance. Read [Primary Key](/user-guide/deployments-administration/performance-tuning/design-table.md#primary-key) for details. Finally please refer to "[CREATE](/reference/sql/create.md)" SQL document for more details for choosing the right data types and "ttl" or "compaction" options, etc. 5. Choose proper indexes to speed up queries. * Inverted index: is ideal for filtering by low-cardinality columns and quickly finding rows with specific values. * Skipping index: works well with sparse data. * Fulltext index: enables efficient keyword and pattern search in large text columns. For details and best practices, refer to the [data index](user-guide/manage-data/data-index.md) documentation. ### Write data to both GreptimeDB and PostgreSQL simultaneously Writing data to both GreptimeDB and PostgreSQL simultaneously is a practical strategy to avoid data loss during migration. By utilizing PostgreSQL's client libraries (JDBC + a PostgreSQL driver), you can set up two client instances - one for GreptimeDB and another for PostgreSQL. For guidance on writing data to GreptimeDB using SQL, please refer to the [Ingest Data](/user-guide/ingest-data/for-iot/sql.md) section. If retaining all historical data isn't necessary, you can simultaneously write data to both GreptimeDB and PostgreSQL for a specific period to accumulate the required recent data. Subsequently, cease writing to PostgreSQL and continue exclusively with GreptimeDB. If a complete migration of all historical data is needed, please proceed with the following steps. ### Export data from PostgreSQL [pg_dump](https://www.postgresql.org/docs/current/app-pgdump.html) is a commonly used tool to export data from PostgreSQL. Using it, we can export the data that can be later imported into GreptimeDB directly. For example, if we want to export schemas whose names start with `db` in the database `postgres` from PostgreSQL, we can use the following command: ```bash pg_dump -h127.0.0.1 -p5432 -Upostgres -ax --column-inserts --no-comments -n 'db*' postgres | grep -v "^SE" > /path/to/output.sql ``` Replace the `-h`, `-p` and `-U` flags with the appropriate values for your PostgreSQL server. The `-n` flag is used to specify the schemas to be exported. And the database `postgres` is at the end of the `pg_dump` command line. Note that we pipe the `pg_dump` output through a special `grep`, to remove some unnecessary `SET` or `SELECT` lines. The final output will be written to the `/path/to/output.sql` file. The content in the `/path/to/output.sql` file should be like this: ```plaintext ~ ❯ cat /path/to/output.sql -- -- PostgreSQL database dump -- -- Dumped from database version 16.4 (Debian 16.4-1.pgdg120+1) -- Dumped by pg_dump version 16.4 -- -- Data for Name: foo; Type: TABLE DATA; Schema: db1; Owner: postgres -- INSERT INTO db1.foo (ts, a) VALUES ('2024-10-31 00:00:00', 1); INSERT INTO db1.foo (ts, a) VALUES ('2024-10-31 00:00:01', 2); INSERT INTO db1.foo (ts, a) VALUES ('2024-10-31 00:00:01', 3); INSERT INTO ... -- -- Data for Name: foo; Type: TABLE DATA; Schema: db2; Owner: postgres -- INSERT INTO db2.foo (ts, b) VALUES ('2024-10-31 00:00:00', '1'); INSERT INTO db2.foo (ts, b) VALUES ('2024-10-31 00:00:01', '2'); INSERT INTO db2.foo (ts, b) VALUES ('2024-10-31 00:00:01', '3'); INSERT INTO ... -- -- PostgreSQL database dump complete -- ``` ### Import data into GreptimeDB The [psql -- PostgreSQL interactive terminal](https://www.postgresql.org/docs/current/app-psql.html) can be used to we can use the following command to import the data into GreptimeDB: ```bash psql -h127.0.0.1 -p4003 -d public -f /path/to/output.sql ``` Replace the `-h` and `-p` flags with the appropriate values for your GreptimeDB server. The `-d` of the psql command is used to specify the database and cannot be omitted. The value `public` of `-d` is the default database used by GreptimeDB. You can also add `-a` to the end to see every executed line, or `-s` for entering the single-step mode. To summarize, data migration steps can be illustrate as follows: ![migrate postgresql data steps](/migration-postgresql.jpg) After the data migration is completed, you can stop writing data to PostgreSQL and continue using GreptimeDB exclusively! If you need a more detailed migration plan or example scripts, please provide the specific table structure and data volume. The [GreptimeDB official community](https://github.com/orgs/GreptimeTeam/discussions) will offer further support. Welcome to join the [Greptime Slack](http://greptime.com/slack). --- ## Migrate from Prometheus For information on configuring Prometheus to write data to GreptimeDB, please refer to the [remote write](/user-guide/ingest-data/for-observability/prometheus.md#remote-write-configuration) documentation. For detailed information on querying data in GreptimeDB using Prometheus query language, please refer to the [HTTP API](/user-guide/query-data/promql.md#prometheus-http-api) section in the PromQL documentation. To add GreptimeDB as a Prometheus data source in Grafana, please refer to the [Grafana](/user-guide/integrations/grafana.md#prometheus-data-source) documentation. --- ## Migrate to GreptimeDB You can migrate data from various databases to GreptimeDB, including InfluxDB, MySQL, PostgreSQL, Prometheus, and more. --- ## User Guide Welcome to the user guide for GreptimeDB. GreptimeDB is the unified observability database for metrics, logs, and traces, providing real-time insights from Edge to Cloud at any scale. ## Understanding GreptimeDB Concepts Before diving into GreptimeDB, it is recommended to familiarize yourself with its data model, key concepts, and features. For a comprehensive overview, refer to the [Concepts Documentation](./concepts/overview.md). ## Ingesting Data Based on Your Use Case GreptimeDB supports [multiple protocols](./protocols/overview.md) and [various integration tools](./integrations/overview.md) to simplify data ingestion tailored to your requirements. ### For Observability Scenarios If you plan to use GreptimeDB as metrics, logs and traces storage for observability purposes, see the [Observability Documentation](./ingest-data/for-observability/overview.md). It explains how to ingest data using tools like Otel-Collector, Vector, Kafka, Prometheus, and the InfluxDB line protocol. For a log storage solution, refer to the [Logs Documentation](./logs/overview.md). It details how to ingest pattern text logs using pipelines. For a trace storage solution, refer to the [Traces Documentation](./traces/overview.md). It explains how to ingest trace data using OpenTelemetry and query it with Jaeger. ### For IoT and Edge Computing Scenarios For IoT and Edge Computing scenarios, the [IoT Documentation](./ingest-data/for-iot/overview.md) provides comprehensive guidance on ingesting data from diverse sources. ## Querying Data for Insights GreptimeDB offers robust interfaces for [querying data](./query-data/overview.md). ### SQL Support You can use SQL for range queries, aggregations, and more. For detailed instructions, see the [SQL Query Documentation](./query-data/sql.md). ### Prometheus Query Language (PromQL) GreptimeDB supports PromQL for querying data. Refer to the [PromQL Documentation](./query-data/promql.md) for guidance. ### Flow Computation For real-time data processing and analysis, GreptimeDB provides [Flow Computation](./flow-computation/overview.md), enabling complex computations on data streams. ## Accelerating Queries with Indexes Indexes such as inverted indexes, skipping indexes, and full-text indexes can significantly enhance query performance. Learn more about effectively using these indexes in the [Data Index Documentation](./manage-data/data-index.md). ## Migrating to GreptimeDB from Other Databases Migrating data from other databases to GreptimeDB is straightforward. Follow the step-by-step instructions in the [Migration Documentation](./migrate-to-greptimedb/overview.md). ## Administering and Deploying GreptimeDB When you're ready to deploy GreptimeDB, consult the [Deployment & Administration Documentation](/user-guide/deployments-administration/overview.md) for detailed guidance on deployment and management. --- ## Elasticsearch(Protocols) Please refer to [Ingest Data with Elasticsearch](/user-guide/ingest-data/for-observability/elasticsearch.md) for detailed information. --- ## gRPC GreptimeDB offers [gRPC SDKs](/user-guide/ingest-data/for-iot/grpc-sdks/overview.md) for efficient and high-performance data ingestion. If there is no SDK available for your programming language, you have the option to [create your own SDK](/contributor-guide/how-to/how-to-write-sdk.md) by following the guidelines provided in the contributor guide. --- ## HTTP API GreptimeDB provides HTTP APIs for interacting with the database. For a complete list of available APIs, please refer to the [HTTP Endpoint](/reference/http-endpoints.md). ## Base URL The base URL of API is `http(s)://{{host}}:{{port}}/`. - For the GreptimeDB instance running on the local machine, with default port configuration `4000`, the base URL is `http://localhost:4000/`. You can change the server host and port in the [configuration](/user-guide/deployments-administration/configuration.md#protocol-options) file. - For GreptimeCloud, the base URL is `https://{{host}}/`. You can find the host in 'Connection Information' at the GreptimeCloud console. In the following sections, we use `http://{{API-host}}/` as the base URL to demonstrate the API usage. ## Common headers ### Authentication Assume that you have already configured the database [authentication](/user-guide/deployments-administration/authentication/overview.md) correctly, GreptimeDB supports the built-in `Basic` authentication scheme in the HTTP API. To set up authentication, follow these steps: 1. Encode your username and password using the `:` format and the `Base64` algorithm. 2. Attach your encoded credentials to the one of the following HTTP header: - `Authorization: Basic ` - `x-greptime-auth: Basic ` Here's an example. If you want to connect to GreptimeDB using the username `greptime_user` and password `greptime_pwd`, use the following command: ```shell curl -X POST \ -H 'Authorization: Basic Z3JlcHRpbWVfdXNlcjpncmVwdGltZV9wd2Q=' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'sql=show tables' \ http://localhost:4000/v1/sql ``` In this example, `Z3JlcHRpbWVfdXNlcjpncmVwdGltZV9wd2Q=` represents the Base64-encoded value of `greptime_user:greptime_pwd`. Make sure to replace it with your own configured username and password, and encode them using Base64. :::tip NOTE InfluxDB uses its own authentication format, see [InfluxDB](./influxdb-line-protocol.md) for details. ::: ### Timeout GreptimeDB supports the `X-Greptime-Timeout` header in HTTP requests. It is used to specify the timeout for the request running in the database server. For example, the following request set `120s` timeout for the request: ```bash curl -X POST \ -H 'Authorization: Basic {{authentication}}' \ -H 'X-Greptime-Timeout: 120s' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'sql=show tables' \ http://localhost:4000/v1/sql ``` ### Hints GreptimeDB supports the `x-greptime-hints` header in HTTP requests to pass hint key-value pairs that influence request behavior. These hints are primarily used to set table options when tables are [automatically created](/user-guide/ingest-data/overview.md#automatic-schema-generation) during data ingestion. The format is a comma-separated list of `key=value` pairs: ``` x-greptime-hints: key1=value1, key2=value2 ``` Supported hints: | Hint | Type | Default | Description | | --- | --- | --- | --- | | `auto_create_table` | Boolean | `true` | Whether to automatically create the table if it does not exist when inserting data. | | `ttl` | Duration string | None | Sets the [time-to-live](/user-guide/manage-data/overview.md#manage-data-retention-with-ttl-policies) for the table, e.g. `7d`, `24h`. Expired data will be automatically purged. | | `append_mode` | Boolean | `false` | Enables [append-only mode](/reference/sql/create.md#create-an-append-only-table) for the table, which disables deduplication by primary key and supports duplicate rows. | | `merge_mode` | String | None | Sets the [merge mode](/reference/sql/create.md#create-a-table-with-merge-mode) for the table, e.g. `last_non_null`, `last_row`. | | `physical_table` | String | None | Specifies the physical table name for the [metric engine](/contributor-guide/datanode/metric-engine.md). | | `skip_wal` | Boolean | `false` | Skips WAL (Write-Ahead Log) writes for the table. | | `sst_format` | String | None | Sets the SST (Sorted String Table) file format for the table. Valid values: `flat`, `primary_key`. | For example, the following request sets TTL and append mode for auto-created tables: ```bash curl -X POST \ -H 'Authorization: Basic {{authentication}}' \ -H 'x-greptime-hints: ttl=7d, append_mode=true' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'sql=INSERT INTO my_table VALUES (...)' \ http://localhost:4000/v1/sql ``` ## Admin APIs :::tip NOTE These endpoint cannot be used in GreptimeCloud. ::: Please refer to the [Admin APIs](/reference/http-endpoints.md#admin-apis) documentation for more information. ## POST SQL statements To submit a SQL query to the GreptimeDB server via HTTP API, use the following format: ```shell curl -X POST \ -H 'Authorization: Basic {{authentication}}' \ -H 'X-Greptime-Timeout: {{timeout}}' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'sql={{SQL-statement}}' \ http://{{API-host}}/v1/sql ``` ### Headers - [`Authorization`](#authentication) - [`X-Greptime-Timeout`](#timeout) - `Content-Type`: `application/x-www-form-urlencoded`. - `X-Greptime-Timezone`: The time zone for the current SQL query. Optional. Please refer to [time zone](#time-zone). ### Query string parameters - `db`: The database name. Optional. If not provided, the default database `public` will be used. - `format`: The output format. Optional. `greptimedb_v1` by default. In addition to the default JSON format, the HTTP API also allows you to customize output format by providing the `format` query parameter with following values: - `influxdb_v1`: [influxdb query API](https://docs.influxdata.com/influxdb/v1/tools/api/#query-http-endpoint) compatible format. Additional parameters: - `epoch`: `[ns,u,µ,ms,s,m,h]`, returns epoch timestamps with the specified precision - `csv`: outputs as comma-separated values - `csvWithNames`: outputs as comma-separated values with a column names header - `csvWithNamesAndTypes`: outputs as comma-separated values with column names and data types headers - `arrow`: [Arrow IPC format](https://arrow.apache.org/docs/python/feather.html). We use stream format for this API. Additional parameters: - `compression`: `zstd` or `lz4`, default: no compression - `table`: ASCII table format for console output - `null`: Concise text-only output of the row count and elapsed time, useful for evaluating query performance. ### Body - `sql`: The SQL statement. Required. ### Response The response is a JSON object containing the following fields: - `output`: The SQL executed result. Please refer to the examples below to see the details. - `execution_time_ms`: The execution time of the statement in milliseconds. ### Examples #### `INSERT` statement For example, to insert data into the `monitor` table of database `public`, use the following command: ```shell curl -X POST \ -H 'Authorization: Basic {{authorization if exists}}' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'sql=INSERT INTO monitor VALUES ("127.0.0.1", 1667446797450, 0.1, 0.4), ("127.0.0.2", 1667446798450, 0.2, 0.3), ("127.0.0.1", 1667446798450, 0.5, 0.2)' \ http://localhost:4000/v1/sql?db=public ``` The response will contain the number of affected rows: ```shell {"output":[{"affectedrows":3}],"execution_time_ms":11} ``` #### `SELECT` statement You can also use the HTTP API to execute other SQL statements. For example, to retrieve data from the `monitor` table: ```shell curl -X POST \ -H 'Authorization: Basic {{authorization if exists}}' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d "sql=SELECT * FROM monitor" \ http://localhost:4000/v1/sql?db=public ``` The response will contain the queried data in JSON format: ```json { "output": [ { "records": { "schema": { "column_schemas": [ { "name": "host", "data_type": "String" }, { "name": "ts", "data_type": "TimestampMillisecond" }, { "name": "cpu", "data_type": "Float64" }, { "name": "memory", "data_type": "Float64" } ] }, "rows": [ [ "127.0.0.1", 1720728000000, 0.5, 0.1 ] ], "total_rows": 1 } } ], "execution_time_ms": 7 } ``` The response contains the following fields: - `output`: The execution result. - `records`: The query result. - `schema`: The schema of the result, including the schema of each column. - `rows`: The rows of the query result, where each row is an array containing the corresponding values of the columns in the schema. - `execution_time_ms`: The execution time of the statement in milliseconds. #### Time zone GreptimeDB supports the `X-Greptime-Timezone` header in HTTP requests. It is used to specify the timezone for the current SQL query. For example, the following request uses the time zone `+1:00` for the query: ```bash curl -X POST \ -H 'Authorization: Basic {{authentication}}' \ -H 'X-Greptime-Timezone: +1:00' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'sql=SHOW VARIABLES time_zone;' \ http://localhost:4000/v1/sql ``` After the query, the result will be: ```json { "output": [ { "records": { "schema": { "column_schemas": [ { "name": "TIME_ZONE", "data_type": "String" } ] }, "rows": [ [ "+01:00" ] ] } } ], "execution_time_ms": 27 } ``` For information on how the time zone affects data inserts and queries, please refer to the SQL documents in the [Ingest Data](../ingest-data/for-iot/sql.md#time-zone) and [Query Data](../query-data/sql.md#time-zone) sections. #### Query data with `table` format output You can use the `table` format in the query string parameters to get the output in ASCII table format. ```shell curl -X POST \ -H 'Authorization: Basic {{authorization if exists}}' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d "sql=SELECT * FROM monitor" \ http://localhost:4000/v1/sql?db=public&format=table ``` Output ``` ┌─host────────┬─ts────────────┬─cpu─┬─memory─┐ │ "127.0.0.1" │ 1667446797450 │ 0.1 │ 0.4 │ │ "127.0.0.1" │ 1667446798450 │ 0.5 │ 0.2 │ │ "127.0.0.2" │ 1667446798450 │ 0.2 │ 0.3 │ └─────────────┴───────────────┴─────┴────────┘ ``` #### Query data with `csvWithNames` format output ```shell curl -X POST \ -H 'Authorization: Basic {{authorization if exists}}' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d "sql=SELECT * FROM monitor" \ http://localhost:4000/v1/sql?db=public&format=csvWithNames ``` Output: ```csv host,ts,cpu,memory 127.0.0.1,1667446797450,0.1,0.4 127.0.0.1,1667446798450,0.5,0.2 127.0.0.2,1667446798450,0.2,0.3 ``` Changes `format` to `csvWithNamesAndTypes`: ```shell curl -X POST \ -H 'Authorization: Basic {{authorization if exists}}' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d "sql=SELECT * FROM monitor" \ http://localhost:4000/v1/sql?db=public&format=csvWithNamesAndTypes ``` Output: ```csv host,ts,cpu,memory String,TimestampMillisecond,Float64,Float64 127.0.0.1,1667446797450,0.1,0.4 127.0.0.1,1667446798450,0.5,0.2 127.0.0.2,1667446798450,0.2,0.3 ``` #### Query data with `influxdb_v1` format output You can use the `influxdb_v1` format in the query string parameters to get the output in InfluxDB query API compatible format. ```shell curl -X POST \ -H 'Authorization: Basic {{authorization if exists}}' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d "sql=SELECT * FROM monitor" \ http://localhost:4000/v1/sql?db=public&format=influxdb_v1&epoch=ms ``` ```json { "results": [ { "statement_id": 0, "series": [ { "name": "", "columns": [ "host", "ts", "cpu", "memory" ], "values": [ ["127.0.0.1", 1667446797450, 0.1, 0.4], ["127.0.0.1", 1667446798450, 0.5, 0.2], ["127.0.0.2", 1667446798450, 0.2, 0.3] ] } ] } ], "execution_time_ms": 2 } ``` ### Parse SQL with GreptimeDB's SQL dialect To parse and understand queries written in GreptimeDB's SQL dialect for tools like dashboards, etc., you can use the `/v1/sql/parse` endpoint to obtain the structured result of an SQL query: ```shell curl -X POST \ -H 'Authorization: Basic {{authorization if exists}}' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d "sql=SELECT * FROM monitor" \ http://localhost:4000/v1/sql/parse ``` ```json [ { "Query": { "inner": { "with": null, "body": { "Select": { "select_token": { "token": { "Word": { "value": "SELECT", "quote_style": null, "keyword": "SELECT" } }, "span": { "start": { "line": 1, "column": 1 }, "end": { "line": 1, "column": 7 } } }, "optimizer_hint": null, "distinct": null, "select_modifiers": null, "top": null, "top_before_distinct": false, "projection": [ { "Wildcard": { "wildcard_token": { "token": "Mul", "span": { "start": { "line": 1, "column": 8 }, "end": { "line": 1, "column": 9 } } }, "opt_ilike": null, "opt_exclude": null, "opt_except": null, "opt_replace": null, "opt_rename": null } } ], "exclude": null, "into": null, "from": [ { "relation": { "Table": { "name": [ { "Identifier": { "value": "monitor", "quote_style": null, "span": { "start": { "line": 1, "column": 15 }, "end": { "line": 1, "column": 22 } } } } ], "alias": null, "args": null, "with_hints": [], "version": null, "with_ordinality": false, "partitions": [], "json_path": null, "sample": null, "index_hints": [] } }, "joins": [] } ], "lateral_views": [], "prewhere": null, "selection": null, "connect_by": [], "group_by": { "Expressions": [ [], [] ] }, "cluster_by": [], "distribute_by": [], "sort_by": [], "having": null, "named_window": [], "qualify": null, "window_before_qualify": false, "value_table_mode": null, "flavor": "Standard" } }, "order_by": null, "limit_clause": null, "fetch": null, "locks": [], "for_clause": null, "settings": null, "format_clause": null, "pipe_operators": [] }, "hybrid_cte": null } } ] ``` ## POST PromQL queries ### The API returns Prometheus query result format GreptimeDB compatible with Prometheus query language (PromQL) and can be used to query data in GreptimeDB. For all the compatible APIs, please refer to the [Prometheus Query Language](/user-guide/query-data/promql#prometheus-http-api) documentation. ### The API returns GreptimeDB JSON format GreptimeDB also exposes an custom HTTP API for querying with PromQL, and returning GreptimeDB's data frame output. You can find it on `/promql` path under the current stable API version `/v1`. The return value of this API is in GreptimeDB's JSON format, not Prometheus's format. For example: ```shell curl -X GET \ -H 'Authorization: Basic {{authorization if exists}}' \ -G \ --data-urlencode 'query=avg(system_metrics{idc="idc_a"})' \ --data-urlencode 'start=1667446797' \ --data-urlencode 'end=1667446799' \ --data-urlencode 'step=1s' \ 'http://localhost:4000/v1/promql?db=public' ``` The input parameters are similar to the [`range_query`](https://prometheus.io/docs/prometheus/latest/querying/api/#range-queries) in Prometheus' HTTP API: - `db=`: Required when using GreptimeDB with authorization, otherwise can be omitted if you are using the default `public` database. Note this parameter should be set in the query param, or using a HTTP header `--header 'x-greptime-db-name: '`. - `query=`: Required. Prometheus expression query string. - `start=`: Required. The start timestamp, which is inclusive. It is used to set the range of time in `TIME INDEX` column. - `end=`: Required. The end timestamp, which is inclusive. It is used to set the range of time in `TIME INDEX` column. - `step=`: Required. Query resolution step width in duration format or float number of seconds. - `format`: The output format. Optional. `greptimedb_v1` by default. In addition to the default JSON format, the HTTP API also allows you to customize output format by providing the `format` query parameter with following values: - `influxdb_v1`: [influxdb query API](https://docs.influxdata.com/influxdb/v1/tools/api/#query-http-endpoint) compatible format. Additional parameters: - `epoch`: `[ns,u,µ,ms,s,m,h]`, returns epoch timestamps with the specified precision - `csv`: outputs as comma-separated values - `csvWithNames`: outputs as comma-separated values with a column names header - `csvWithNamesAndTypes`: outputs as comma-separated values with column names and data types headers - `arrow`: [Arrow IPC format](https://arrow.apache.org/docs/python/feather.html). Additional parameters: - `compression`: `zstd` or `lz4`, default: no compression - `table`: ASCII table format for console output - `null`: Concise text-only output of the row count and elapsed time, useful for evaluating query performance. Here are some examples for each type of parameter: - rfc3339 - `2015-07-01T20:11:00Z` (default to seconds resolution) - `2015-07-01T20:11:00.781Z` (with milliseconds resolution) - `2015-07-02T04:11:00+08:00` (with timezone offset) - unix timestamp - `1435781460` (default to seconds resolution) - `1435781460.781` (with milliseconds resolution) - duration - `1h` (1 hour) - `5d1m` (5 days and 1 minute) - `2` (2 seconds) - `2s` (also 2 seconds) The result format is the same as `/sql` interface described in [Post SQL statements](#post-sql-statements) section. ```json { "output": [ { "records": { "schema": { "column_schemas": [ { "name": "ts", "data_type": "TimestampMillisecond" }, { "name": "AVG(system_metrics.cpu_util)", "data_type": "Float64" }, { "name": "AVG(system_metrics.memory_util)", "data_type": "Float64" }, { "name": "AVG(system_metrics.disk_util)", "data_type": "Float64" } ] }, "rows": [ [ 1667446798000, 80.1, 70.3, 90 ], [ 1667446799000, 80.1, 70.3, 90 ] ] } } ], "execution_time_ms": 5 } ``` ## Post Influxdb line protocol data ```shell curl -X POST \ -H 'Authorization: token {{username:password}}' \ -d '{{Influxdb-line-protocol-data}}' \ http://{{API-host}}/v1/influxdb/api/v2/write?precision={{time-precision}} ``` ```shell curl -X POST \ -d '{{Influxdb-line-protocol-data}}' \ http://{{API-host}}/v1/influxdb/write?u={{username}}&p={{password}}&precision={{time-precision}} ``` ### Headers - `Authorization`: **Unlike other APIs**, the InfluxDB line protocol APIs use the InfluxDB authentication format. For V2, it is `token {{username:password}}`. ### Query string parameters - `u`: The username. Optional. It is the authentication username for V1. - `p`: The password. Optional. It is the authentication password for V1. - `db`: The database name. Optional. The default value is `public`. - `precision`: Defines the precision of the timestamp provided in the request body. Please refer to [InfluxDB Line Protocol](/user-guide/ingest-data/for-iot/influxdb-line-protocol.md) in the user guide. ### Body The InfluxDB line protocol data points. Please refer to the [InfluxDB Line Protocol](https://docs.influxdata.com/influxdb/v1/write_protocols/line_protocol_tutorial/#syntax) document. ### Examples Please refer to [InfluxDB Line Protocol](/user-guide/ingest-data/for-iot/influxdb-line-protocol.md) in the user guide. ## API for managing Pipelines When writing logs to GreptimeDB, you can use HTTP APIs to manage the pipelines. For detailed information, please refer to the [Manage Pipelines](/user-guide/logs/manage-pipelines.md) documentation. --- ## InfluxDB Line Protocol(Protocols) ## Ingest data For how to ingest data to GreptimeDB using InfluxDB Line Protocol, please refer to the [Ingest Data](/user-guide/ingest-data/for-iot/influxdb-line-protocol.md) document. ## HTTP API Please refer to the [HTTP API](http.md#post-influxdb-line-protocol-data) document for details on the InfluxDB Line Protocol API. ## PING Additionally, GreptimeDB also provides support for the `ping` and `health` APIs of InfluxDB. Use `curl` to request `ping` API. ```shell curl -i "127.0.0.1:4000/v1/influxdb/ping" ``` ```shell HTTP/1.1 204 No Content date: Wed, 22 Feb 2023 02:29:44 GMT ``` Use `curl` to request `health` API. ```shell curl -i "127.0.0.1:4000/v1/influxdb/health" ``` ```shell HTTP/1.1 200 OK content-length: 0 date: Wed, 22 Feb 2023 02:30:46 GMT ``` --- ## Loki(Protocols) Please refer to [Ingest Data with Loki](/user-guide/ingest-data/for-observability/loki.md) for detailed information. --- ## MySQL ## Connect You can connect to GreptimeDB using MySQL via port `4002`. ```shell mysql -h -P 4002 -u -p ``` - For how to setup username and password for GreptimeDB, please refer to [Authentication](/user-guide/deployments-administration/authentication/overview.md). - If you want to use other ports for MySQL, please refer to [Protocol options](/user-guide/deployments-administration/configuration.md#protocol-options) in the configuration document. ## Table management Please refer to [Table Management](/user-guide/deployments-administration/manage-data/basic-table-operations.md). ## Ingest data Please refer to [SQL](/user-guide/ingest-data/for-iot/sql.md). ## Query data Please refer to [SQL](/user-guide/query-data/sql.md). ## Time zone GreptimeDB's MySQL protocol interface follows original MySQL on [how to deal with time zone](https://dev.mysql.com/doc/refman/8.0/en/time-zone-support.html). By default, MySQL uses its server time zone for timestamp. To override, you can set `time_zone` variable for current session using SQL statement `SET time_zone = '';`. The value of `time_zone` can be any of: - The server's time zone: `SYSTEM`. - Offset to UTC such as `+08:00`. - Any named time zone like `Europe/Berlin`. Some MySQL clients, such as Grafana MySQL data source, allow you to set the time zone for the current session. You can also use the above values when setting the time zone. You can use `SELECT` to check the current time zone settings. For example: ```sql SELECT @@system_time_zone, @@time_zone; ``` The result shows that both the system time zone and the session time zone are set to `UTC`: ```SQL +--------------------+-------------+ | @@system_time_zone | @@time_zone | +--------------------+-------------+ | UTC | UTC | +--------------------+-------------+ ``` Change the session time zone to `+1:00`: ```SQL SET time_zone = '+1:00' ``` Then you can see the difference between the system time zone and the session time zone: ```SQL SELECT @@system_time_zone, @@time_zone; +--------------------+-------------+ | @@system_time_zone | @@time_zone | +--------------------+-------------+ | UTC | +01:00 | +--------------------+-------------+ ``` For information on how the time zone affects data inserts and queries, please refer to the SQL documents in the [Ingest Data](/user-guide/ingest-data/for-iot/sql.md#time-zone) and [Query Data](/user-guide/query-data/sql.md#time-zone) sections. ## Query Timeout You can set the `max_execution_time` variable for the current session using SQL statement `SET max_execution_time = ` or `SET MAX_EXECUTION_TIME = `, which specifies the maximum time in milliseconds for a **read-only statement** to execute. The server will terminate the query if it exceeds the specified time. For example, to set the maximum query execution time to 10 seconds: ```SQL SET max_execution_time=10000; ``` --- ## OpenTelemetry (OTLP) GreptimeDB is an observability backend to consume OpenTelemetry Metrics natively via [OTLP/HTTP](https://opentelemetry.io/docs/specs/otlp/#otlphttp) protocol. Please refer to the [Ingest Data with OpenTelemetry](/user-guide/ingest-data/for-observability/opentelemetry.md) document for detailed information. --- ## OpenTSDB(Protocols) Please refer to [Ingest Data with OpenTSDB](/user-guide/ingest-data/for-iot/opentsdb.md) for detailed information. --- ## Protocols --- ## PostgreSQL ## Connect You can connect to GreptimeDB using PostgreSQL via port `4003`. Simply add the `-U` argument to your command, followed by your username and password. Here's an example: ```shell psql -h -p 4003 -U -d public ``` - For how to setup username and password for GreptimeDB, please refer to [Authentication](/user-guide/deployments-administration/authentication/overview.md). - If you want to use other ports for PostgreSQL, please refer to [Protocol options](/user-guide/deployments-administration/configuration.md#protocol-options) in the configuration document. ## Table management Please refer to [Table Management](/user-guide/deployments-administration/manage-data/basic-table-operations.md). ## Ingest data Please refer to [SQL](/user-guide/ingest-data/for-iot/sql.md). ## Query data Please refer to [SQL](/user-guide/query-data/sql.md). ## Time zone GreptimeDB's PostgreSQL protocol interface follows original PostgreSQL on [datatype-timezones](https://www.postgresql.org/docs/current/datatype-datetime.html#DATATYPE-TIMEZONES). By default, PostgreSQL uses its server time zone for timestamp. To override, you can set `time_zone` variable for current session using SQL statement `SET TIMEZONE TO '';`. The value of `time_zone` can be any of: - A full time zone name, for example `America/New_York`. - A time zone abbreviation, for example `PST`. - Offset to UTC such as `+08:00`. You can use `SHOW` to check the current time zone settings. For example: ```sql SHOW VARIABLES time_zone; ``` ```sql TIME_ZONE ----------- UTC ``` Change the session time zone to `+1:00`: ```SQL SET TIMEZONE TO '+1:00' ``` For information on how the time zone affects data inserts and queries, please refer to the SQL documents in the [Ingest Data](/user-guide/ingest-data/for-iot/sql.md#time-zone) and [Query Data](/user-guide/query-data/sql.md#time-zone) sections. ## Foreign Data Wrapper GreptimeDB can be configured as a foreign data server for Postgres' built-in [FDW extension](https://www.postgresql.org/docs/current/postgres-fdw.html). This allows user to query GreptimeDB tables seamlessly from Postgres server. It's also possible to join Postgres tables with GreptimeDB tables. For example, your IoT metadata, like device information, is stored in a relational data model in Postgres. It's possible to use filter queries to find out device IDs and join with time-series data from GreptimeDB. ### Setup To setup GreptimeDB for Postgres FDW, make sure you enabled postgres protocol support in GreptimeDB and it's accessible from your Postgres server. To create and configuration GreptimeDB in Postgres, first enable the `postgres_fdw` extension. ```sql CREATE EXTENSION postgres_fdw; ``` Add GreptimeDB instance as remote server. ```sql CREATE SERVER greptimedb FOREIGN DATA WRAPPER postgres_fdw OPTIONS (host 'greptimedb_host', dbname 'public', port '4003'); ``` Configure user mapping for Postgres user and GreptimeDB user. This step is required. But if you don't have authentication enabled in GreptimeDB OSS version, just fill the credential with random data. ```sql CREATE USER MAPPING FOR postgres SERVER greptimedb OPTIONS (user 'greptime', password '...'); ``` Create foreign table in Postgres to map GreptimeDB's schema. Note that you will need to use Postgres' corresponding data types for GreptimeDB's. For GreptimeDB's tables ```sql CREATE TABLE grpc_latencies ( ts TIMESTAMP TIME INDEX, host STRING, method_name STRING, latency DOUBLE, PRIMARY KEY (host, method_name) ) with('append_mode'='true'); CREATE TABLE app_logs ( ts TIMESTAMP TIME INDEX, host STRING, api_path STRING FULLTEXT INDEX, log_level STRING, log STRING FULLTEXT INDEX, PRIMARY KEY (host, log_level) ) with('append_mode'='true'); ``` The foreign table DDL is like this. You need to run them in Postgres to create these tables; ```sql CREATE FOREIGN TABLE ft_grpc_latencies ( ts TIMESTAMP, host VARCHAR, method_name VARCHAR, latency DOUBLE precision ) SERVER greptimedb OPTIONS (table_name 'grpc_latencies'); CREATE FOREIGN TABLE ft_app_logs ( ts TIMESTAMP, host VARCHAR, api_path VARCHAR, log_level VARCHAR, log VARCHAR ) SERVER greptimedb OPTIONS (table_name 'app_logs'); ``` To help you to generate statements in Postgres, we enhanced `SHOW CREATE TABLE` in GreptimeDB to dump the Postgres DDL for you. For example: ```sql SHOW CREATE TABLE grpc_latencies FOR postgres_foreign_table; ``` Note that you will need to replace server name `greptimedb` with the name you defined in `CREATE SERVER` statement. ### Run Queries You can now send query from Postgres. It's also possible to use functions that are available in both Postgres and GreptimeDB, like `date_trunc`. ```sql SELECT * FROM ft_app_logs ORDER BY ts DESC LIMIT 100; SELECT date_trunc('MINUTE', ts) as t, host, avg(latency), count(latency) FROM ft_grpc_latencies GROUP BY host, t; ``` ## Statement Timeout You can set the `statement_timeout` variable for the current session using SQL statement `SET statement_timeout = ` or `SET STATEMENT_TIMEOUT = `, which specifies the maximum time in milliseconds for a statement to execute. The server will terminate the statement if it exceeds the specified time. For example, to set the maximum execution time to 10 seconds: ```SQL SET statement_timeout=10000; ``` --- ## Common Table Expression (CTE) CTEs are similar to [Views](./view.md) in that they help you reduce the complexity of your queries, break down long and complex SQL statements, and improve readability and reusability. You already read a CTE in the [quickstart](/getting-started/quick-start.md#correlate-metrics-logs-and-traces) document. ## What is a Common Table Expression (CTE)? A Common Table Expression (CTE) is a temporary result set that you can reference within a `SELECT`, `INSERT`, `UPDATE`, or `DELETE` statement. CTEs help to break down complex queries into more readable parts and can be referenced multiple times within the same query. ## Basic syntax of CTE CTEs are typically defined using the `WITH` keyword. The basic syntax is as follows: ```sql WITH cte_name [(column1, column2, ...)] AS ( QUERY ) SELECT ... FROM cte_name; ``` ## Example explanation Next, we'll go through a complete example that demonstrates how to use CTEs, including data preparation, CTE creation, and usage. ### Step 1: Create example data Let's assume we have the following two tables: - `grpc_latencies`: Contains gRPC request latency data. - `app_logs`: Contains application log information. ```sql CREATE TABLE grpc_latencies ( ts TIMESTAMP TIME INDEX, host VARCHAR(255), latency FLOAT, PRIMARY KEY(host), ); INSERT INTO grpc_latencies VALUES ('2023-10-01 10:00:00', 'host1', 120), ('2023-10-01 10:00:00', 'host2', 150), ('2023-10-01 10:00:05', 'host1', 130); CREATE TABLE app_logs ( ts TIMESTAMP TIME INDEX, host VARCHAR(255), `log` TEXT, log_level VARCHAR(50), PRIMARY KEY(host, log_level), ); INSERT INTO app_logs VALUES ('2023-10-01 10:00:00', 'host1', 'Error on service', 'ERROR'), ('2023-10-01 10:00:00', 'host2', 'All services OK', 'INFO'), ('2023-10-01 10:00:05', 'host1', 'Error connecting to DB', 'ERROR'); ``` ### Step 2: Define and use CTEs We will create two CTEs to calculate the 95th percentile latency and the number of error logs, respectively. ```sql WITH metrics AS ( SELECT ts, host, approx_percentile_cont(0.95) WITHIN GROUP (ORDER BY latency) RANGE '5s' AS p95_latency FROM grpc_latencies ALIGN '5s' FILL PREV ), logs AS ( SELECT ts, host, COUNT(*) RANGE '5s' AS num_errors FROM app_logs WHERE log_level = 'ERROR' ALIGN '5s' BY (host) ) SELECT metrics.ts, metrics.host, metrics.p95_latency, COALESCE(logs.num_errors, 0) AS num_errors FROM metrics LEFT JOIN logs ON metrics.host = logs.host AND metrics.ts = logs.ts ORDER BY metrics.ts; ``` Output: ```sql +---------------------+-------+-------------+------------+ | ts | host | p95_latency | num_errors | +---------------------+-------+-------------+------------+ | 2023-10-01 10:00:00 | host2 | 150 | 0 | | 2023-10-01 10:00:00 | host1 | 120 | 1 | | 2023-10-01 10:00:05 | host1 | 130 | 1 | +---------------------+-------+-------------+------------+ ``` ## Detailed explanation 1. **Define CTEs**: - `metrics`: ```sql WITH metrics AS ( SELECT ts, host, approx_percentile_cont(0.95) WITHIN GROUP (ORDER BY latency) RANGE '5s' AS p95_latency FROM grpc_latencies ALIGN '5s' FILL PREV ), ``` Here we use a [range query](/user-guide/query-data/sql.md#aggregate-data-by-time-window) to calculate the 95th percentile latency for each `host` within every 5-second window. - `logs`: ```sql logs AS ( SELECT ts, host, COUNT(*) RANGE '5s' AS num_errors FROM app_logs WHERE log_level = 'ERROR' ALIGN '5s' BY (host) ) ``` Similarly, we calculate the number of error logs for each `host` within every 5-second window. 2. **Use CTEs**: The final query part: ```sql SELECT metrics.ts, metrics.host, metrics.p95_latency, COALESCE(logs.num_errors, 0) AS num_errors FROM metrics LEFT JOIN logs ON metrics.host = logs.host AND metrics.ts = logs.ts ORDER BY metrics.ts; ``` We perform a left join on the two CTE result sets to get a comprehensive analysis result. ## Using TQL in CTEs GreptimeDB supports using [TQL](/reference/sql/tql.md) (Telemetry Query Language) within CTEs, allowing you to combine PromQL's time-series computation with SQL's powerful post-processing capabilities like filtering, joining, and aggregation. ### Basic syntax ```sql WITH cte_name AS ( TQL EVAL (start, end, step) promql_expression AS value_alias ) SELECT * FROM cte_name; ``` ### Key points 1. **Column naming**: - The time index column name varies depending on your table schema (e.g., `ts` for custom tables, `greptime_timestamp` for Prometheus remote write) - The value column name depends on the PromQL expression and may be unpredictable, so it's better to use value aliasing with `AS` in TQL to ensure predictable column names: `TQL EVAL (...) expression AS my_value` - **Important**: In general, avoid using column aliases in CTE definitions (for example, `WITH cte_name (ts, val) AS (...)`) because TQL EVAL results can have variable column count and order, especially in Prometheus scenarios where tags can be dynamically added or removed. They are best reserved for cases where the result shape is stable, such as a simple `CREATE FLOW` TQL CTE. 2. **Supported commands**: Only `TQL EVAL` is supported within CTEs. `TQL ANALYZE` and `TQL EXPLAIN` cannot be used in CTEs. 3. **Lookback parameter**: The optional fourth parameter controls the lookback duration (default: 5 minutes). 4. **Using TQL CTEs in `CREATE FLOW`**: GreptimeDB supports `WITH ... AS (TQL EVAL ...)` in `CREATE FLOW`, but only in the simplest form: a single TQL CTE followed by `SELECT * FROM `. Extra SQL CTEs, filters, joins, or custom projections are not supported in flow definitions. ### Examples The following examples use Kubernetes monitoring metrics to demonstrate practical use cases. #### Filtering TQL results with SQL This example calculates CPU usage per pod using PromQL, then filters and sorts the results using SQL: ```sql WITH cpu_usage AS ( TQL EVAL (now() - interval '1' hour, now(), '5m') sum by (namespace, pod) (rate(container_cpu_usage_seconds_total{container!=""}[5m])) AS cpu_cores ) SELECT greptime_timestamp as ts, namespace, pod, cpu_cores FROM cpu_usage WHERE cpu_cores > 0.5 ORDER BY cpu_cores DESC; ``` #### Correlating multiple metrics This example demonstrates a capability that PromQL alone cannot achieve: joining different metrics for correlation analysis. It correlates CPU usage with request rates to analyze resource efficiency: ```sql WITH cpu_data AS ( TQL EVAL (now() - interval '1' hour, now(), '5m') sum by (pod) (rate(container_cpu_usage_seconds_total{container!=""}[5m])) AS cpu_cores ), request_data AS ( TQL EVAL (now() - interval '1' hour, now(), '5m') sum by (pod) (rate(http_requests_total[5m])) AS req_per_sec ) SELECT c.greptime_timestamp as ts, c.pod, c.cpu_cores, r.req_per_sec FROM cpu_data c JOIN request_data r ON c.greptime_timestamp = r.greptime_timestamp AND c.pod = r.pod WHERE r.req_per_sec > 1; ``` When joining multiple TQL CTEs, ensure: - The `by (...)` clauses contain matching dimensions - JOIN conditions include both timestamp and label columns ## Summary With CTEs, you can break down complex SQL queries into more manageable and understandable parts. In this example, we created two CTEs to calculate the 95th percentile latency and the number of error logs separately and then merged them into the final query for analysis. TQL support in CTEs extends this capability by allowing PromQL-style queries to be integrated seamlessly with SQL processing. Read more about [WITH](/reference/sql/with.md) and [TQL](/reference/sql/tql.md). For more TQL + CTE examples, see the blog post [When PromQL Meets SQL: Hybrid Queries for Kubernetes Monitoring](https://greptime.com/blogs/2026-01-08-tql-alias-k8s-monitoring). --- ## Jaeger (Experimental) :::warning The Jaeger query APIs are currently in the experimental stage and may be adjusted in future versions. ::: GreptimeDB currently supports the following [Jaeger](https://www.jaegertracing.io/) query interfaces: - `/api/services`: Get all services. - `/api/operations?service={service}`: Get all operations for a service. - `/api/services/{service}/operations`: Get all operations for a service. - `/api/traces`: Get traces by query parameters. You can use [Grafana's Jaeger plugin](https://grafana.com/docs/grafana/latest/datasources/jaeger/)(Recommended) or [Jaeger UI](https://github.com/jaegertracing/jaeger-ui) to query traces data in GreptimeDB. When using Jaeger UI, you can set the `proxyConfig` in `packages/jaeger-ui/vite.config.mts` to the GreptimeDB address, for example: ```ts const proxyConfig = { target: 'http://localhost:4000/v1/jaeger', secure: false, changeOrigin: true, ws: true, xfwd: true, }; ``` Currently, GreptimeDB exposes the Jaeger HTTP APIs under the `/v1/jaeger` endpoint. ## Quick Start We will use the Jaeger plugin in Grafana as an example to demonstrate how to query traces data in GreptimeDB. Before starting, please ensure that you have properly started GreptimeDB. ### Start an application to generate traces data and write it to GreptimeDB You can refer to the [OpenTelemetry official documentation](https://opentelemetry.io/docs/languages/) to choose any programming language you are familiar with to generate traces data. You can also refer to the [Configure OpenTelemetry Collector](/user-guide/traces/read-write.md#opentelemetry-collector) document. ### Configure the Grafana Jaeger plugin 1. Open Grafana and add a Jaeger data source: ![Add Jaeger data source](/add-jaeger-data-source.jpg) 2. Fill in the Jaeger address according to your actual situation, then **Save and Test**. For example: ``` http://localhost:4000/v1/jaeger ``` 3. Use Grafana's Jaeger Explore to view the data: ![Jaeger Explore](/jaeger-explore.png) ### Custom table By default, the jaeger compatible API will use the default table name `opentelemetry_traces` for its data. If you have multiple tables for trace data, you can update this behaviour with HTTP header `x-greptime-trace-table-name` and provide table name as the value. This can be configured via Grafana data source settings. --- ## Log Query (Experimental) :::warning The log query endpoint feature is currently experimental and may change in future releases. ::: GreptimeDB provides a dedicated HTTP endpoint to query log data. This feature allows you to search and process log entries using a simple query interface. This is an add-on feature to existing GreptimeDB capabilities like SQL queries and Flow computations. You can still use your existing tools and workflows to query log data like before. ## Endpoint ```http POST /v1/logs ``` ## Headers - [Authorization](/user-guide/protocols/http.md#authentication) - `Content-Type`: `application/json` ## Request Format The request body should be a JSON object (this is subject to change in patch version within the experimental phase). For the latest request format, please refer to the [implementation](https://github.com/GreptimeTeam/greptimedb/blob/main/src/log-query/src/log_query.rs): ## Response This endpoint has the same response format as the SQL query endpoint. Please refer to the [SQL query response](/user-guide/protocols/http/#response) for more details. ## Limitations - Maximum result limit: 1000 entries - Only supports tables with timestamp and string columns ## Example The following example demonstrates how to query log data using the log query endpoint (notice that in this experimental phase the following example might be outdated). ```shell curl -X "POST" "http://localhost:4000/v1/logs" \ -H "Authorization: Basic {{authentication}}" \ -H "Content-Type: application/json" \ -d $' { "table": { "catalog_name": "greptime", "schema_name": "public", "table_name": "my_logs" }, "time_filter": { "start": "2025-01-23" }, "limit": { "fetch": 1 }, "columns": [ "message" ], "filters": [ { "column_name": "message", "filters": [ { "Contains": "production" } ] } ], "context": "None", "exprs": [] } ' ``` In this query, we are searching for log entries in the `greptime.public.my_logs` table that contain the word `production` in `message` field. We also specify the time filter to fetch logs in `2025-01-23`, and limit the result to 1 entry. The response will be similar to the following: ```json { "output": [ { "records": { "schema": { "column_schemas": [ { "name": "message", "data_type": "String" } ] }, "rows": [ [ "Everything is in production" ] ], "total_rows": 1 } } ], "execution_time_ms": 30 } ``` --- ## Query Data ## Query languages - [PromQL](./promql.md) - [SQL](./sql.md) - [Log Query](./log-query.md) (Experimental) Since v0.9, GreptimeDB supports view and CTE just like other databases, used to simplify queries: * [View](./view.md) * [Common Table Expression (CTE)](./cte.md) ## Recommended libraries Since GreptimeDB uses SQL as its main query language and supports both [MySQL](/user-guide/protocols/mysql.md) and [PostgreSQL](/user-guide/protocols/postgresql.md) protocols, you can use mature SQL drivers that support MySQL or PostgreSQL to query data. For more information, please refer to the [SQL Tools](/reference/sql-tools.md) documentation. ## Query external data GreptimeDB has the capability to query external data files. For more information, please refer to the [Query External Data](./query-external-data.md) documentation. --- ## Prometheus Query Language GreptimeDB can be used as a drop-in replacement for Prometheus in Grafana, because GreptimeDB supports PromQL (Prometheus Query Language). GreptimeDB has reimplemented PromQL natively in Rust and exposes the ability to several interfaces, including the HTTP API of Prometheus, the HTTP API of GreptimeDB, and the SQL interface. ## Prometheus' HTTP API GreptimeDB has implemented a set of Prometheus compatible APIs under HTTP context `/v1/prometheus/`: - Instant queries `/api/v1/query` - Range queries `/api/v1/query_range` - Series `/api/v1/series` - Label names `/api/v1/labels` - Label values `/api/v1/label//values` It shares same input and output format with original Prometheus HTTP API. You can also use GreptimeDB as an in-place replacement of Prometheus. For example in Grafana Prometheus data source, set `http://localhost:4000/v1/prometheus/` as context root of Prometheus URL. Consult [Prometheus documents](https://prometheus.io/docs/prometheus/latest/querying/api) for usage of these API. You can use additional query parameter `db` to specify GreptimeDB database name. For example, the following query will return the CPU usage of the `process_cpu_seconds_total` metric in the `public` database: ```shell curl -X POST \ -H 'Authorization: Basic {{authorization if exists}}' \ --data-urlencode 'query=irate(process_cpu_seconds_total[1h])' \ --data-urlencode 'start=2024-11-24T00:00:00Z' \ --data-urlencode 'end=2024-11-25T00:00:00Z' \ --data-urlencode 'step=1h' \ 'http://localhost:4000/v1/prometheus/api/v1/query_range?db=public' ``` If authentication is enabled in GreptimeDB, the authentication header is required. Refer to the [authentication documentation](/user-guide/protocols/http.md#authentication) for more details. You need to either set it in the HTTP URL query param `db` like the example above, or set it using `--header 'x-greptime-db-name: '` as HTTP header. The query string parameters for the API are identical to those of the original [Prometheus API](https://prometheus.io/docs/prometheus/latest/querying/api/#range-queries), with the exception of the additional `db` parameter, which specifies the GreptimeDB database name. The output format is compatible with the Prometheus API: ```json { "status": "success", "data": { "resultType": "matrix", "result": [ { "metric": { "job": "node", "instance": "node_exporter:9100", "__name__": "process_cpu_seconds_total" }, "values": [ [ 1732618800, "0.0022222222222222734" ], [ 1732622400, "0.0009999999999999788" ], [ 1732626000, "0.0029999999999997585" ], [ 1732629600, "0.002222222222222175" ] ] } ] } } ``` ## SQL GreptimeDB also extends SQL grammar to support PromQL. You can start with the `TQL` (Time-series Query Language) keyword to write parameters and queries. The grammar looks like this: ```sql TQL [EVAL|EVALUATE] (, , ) ``` `` specifies the query start range and `` specifies the end time. `` identifies the query resolution step width. All of them can either be an unquoted number (represent UNIX timestamp for `` and ``, and duration in seconds for ``), or a quoted string (represent an RFC3339 timestamp for `` and ``, and duration in string format for ``). For example: ```sql TQL EVAL (1676738180, 1676738780, '10s') sum(some_metric) ``` You can write the above command in all places that support SQL, including the GreptimeDB HTTP API, SDK, PostgreSQL and MySQL client etc. ## GreptimeDB's extensions to PromQL ### Specifying value field Based on the table model, GreptimeDB supports multiple fields in a single table(or metric, in the context of Prometheus). Queries will run on every fields by default. Or you can use the special filter `__field__` to query a specific field(s): ```promql metric{__field__="field1"} ``` Exclude or regex are also supported: ```promql metric{__field__!="field1"} metric{__field__=~"field_1|field_2"} metric{__field__!~"field_1|field_2"} ``` ### Cross-database query Greptime has its own database concept. In order to run cross-database query, you can use `__database__` matcher to specify the database name. ```promql metric{__database__="mydatabase"} ``` Note that only `=` is supported for database matcher. ## Limitations Though GreptimeDB supports a rich set of data types, the PromQL implementation is still limited to the following types: - timestamp: `Timestamp` - tag: `String` - value: `Double` We have over 90% promql supported in GreptimeDB. Here attaches the compatibility list. You can also check our latest compliance report in this [tracking issue](https://github.com/GreptimeTeam/greptimedb/issues/1042). ### Literal Both string and float literals are supported, with the same [rule](https://prometheus.io/docs/prometheus/latest/querying/basics/#literals) as PromQL. ### Selector Both instant and range selector are supported. But notice that in both Prometheus and GreptimeDB, the label matching on metric name is an exception. Negative matching (e.g. `{__name__!="request_count}"`) is not allowed. Others like equal-matching or regex-matching are supported. Time duration and offset are supported, but `@` modifier is not supported yet. When selecting non-existent columns, they will be treated as columns filled with empty string values (`""`). This behavior aligns with both Prometheus and VictoriaMetrics. For selectors referencing non-existent columns, the behavior aligns with Prometheus: no error is raised, and the selector is silently ignored. However, for `__name__` selectors referencing non-existent metrics (or equivalent forms), GreptimeDB will report an error. ### Timestamp precision The timestamp precision in PromQL is limited by its query syntax, only supporting calculations up to millisecond precision. However, GreptimeDB supports storing high-precision timestamps, such as microseconds and nanoseconds. When using PromQL for calculations, these high-precision timestamps are implicitly converted to millisecond precision. ### Binary - Supported: | Operator | | :------- | | add | | sub | | mul | | div | | mod | | eqlc | | neq | | gtr | | lss | | gte | | lte | | power | | atan2 | | and | | or | | unless | - Unsupported: None ### Aggregators - Supported: | Aggregator | Example | | :----------- | :------------------------------------------- | | sum | `sum by (foo)(metric)` | | avg | `avg by (foo)(metric)` | | min | `min by (foo)(metric)` | | max | `max by (foo)(metric)` | | stddev | `stddev by (foo)(metric)` | | stdvar | `stdvar by (foo)(metric)` | | topk | `topk(3, rate(instance_cpu_time_ns[5m]))` | | bottomk | `bottomk(3, rate(instance_cpu_time_ns[5m]))` | | count_values | `count_values("version", build_version)` | | count | `count (metric)` | | quantile | `quantile(0.9, cpu_usage)` | - Unsupported: | Aggregator | Progress | | :--------- | :------- | | grouping | TBD | ### Instant Functions - Supported: | Function | Example | | :----------------- | :-------------------------------- | | abs | `abs(metric)` | | ceil | `ceil(metric)` | | exp | `exp(metric)` | | ln | `ln(metric)` | | log2 | `log2(metric)` | | log10 | `log10(metric)` | | sqrt | `sqrt(metric)` | | acos | `acos(metric)` | | asin | `asin(metric)` | | atan | `atan(metric)` | | sin | `sin(metric)` | | cos | `cos(metric)` | | tan | `tan(metric)` | | acosh | `acosh(metric)` | | asinh | `asinh(metric)` | | atanh | `atanh(metric)` | | sinh | `sinh(metric)` | | cosh | `cosh(metric)` | | scalar | `scalar(metric)` | | tanh | `tanh(metric)` | | timestamp | `timestamp()` | | sort | `sort(http_requests_total)` | | sort_desc | `sort_desc(http_requests_total)` | | histogram_quantile | `histogram_quantile(phi, metric)` | | predicate_linear | `predict_linear(metric, 120)` | | absent | `absent(nonexistent{job="myjob"})`| | sgn | `sgn(metric)` | | pi | `pi()` | | deg | `deg(metric)` | | rad | `rad(metric)` | | floor | `floor(metric)` | | clamp | `clamp(metric, 0, 12)` | | clamp_max | `clamp_max(metric, 12)` | | clamp_min | `clamp_min(metric, 0)` | - Unsupported: | Function | Progress / Example | | :------------------------- | :----------------- | | *other multiple input fns* | TBD | ### Range Functions - Supported: | Function | Example | | :----------------- | :----------------------------- | | idelta | `idelta(metric[5m])` | | \_over_time | `count_over_time(metric[5m])` | | stddev_over_time | `stddev_over_time(metric[5m])` | | stdvar_over_time | `stdvar_over_time(metric[5m])` | | changes | `changes(metric[5m])` | | delta | `delta(metric[5m])` | | rate | `rate(metric[5m])` | | deriv | `deriv(metric[5m])` | | increase | `increase(metric[5m])` | | irate | `irate(metric[5m])` | | reset | `reset(metric[5m])` | - Unsupported: None ### Label & Other Functions - Supported: | Function | Example | | :------------ | :------------------------------------------------------------------------------------------------ | | label_join | `label_join(up{job="api-server",src1="a",src2="b",src3="c"}, "foo", ",", "src1", "src2", "src3")` | | label_replace | `label_replace(up{job="api-server",service="a:c"}, "foo", "$1", "service", "(.*):.*")` | | sort_by_label | `sort_by_label(metric, "foo", "bar")` | | sort_by_label_desc | `sort_by_label_desc(metric, "foo", "bar")` | - Unsupported: None --- ## Query External Data ## Query on a file Currently, we support queries on `Parquet`, `CSV`, `ORC`, and `NDJson` format file(s). We use the [Taxi Zone Lookup Table](https://d37ci6vzurychx.cloudfront.net/misc/taxi+_zone_lookup.csv) data as an example. ```bash curl "https://d37ci6vzurychx.cloudfront.net/misc/taxi+_zone_lookup.csv" -o /tmp/taxi+_zone_lookup.csv ``` Create an external table: ```sql CREATE EXTERNAL TABLE taxi_zone_lookup with (location='/tmp/taxi+_zone_lookup.csv',format='csv'); ``` You can check the schema of the external table like follows: ```sql DESC TABLE taxi_zone_lookup; ``` ```sql +--------------------+----------------------+------+------+--------------------------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +--------------------+----------------------+------+------+--------------------------+---------------+ | LocationID | Int64 | | YES | | FIELD | | Borough | String | | YES | | FIELD | | Zone | String | | YES | | FIELD | | service_zone | String | | YES | | FIELD | | greptime_timestamp | TimestampMillisecond | PRI | NO | 1970-01-01 00:00:00+0000 | TIMESTAMP | +--------------------+----------------------+------+------+--------------------------+---------------+ 4 rows in set (0.00 sec) ``` :::tip Note Here, you may notice there is a `greptime_timestamp` column, which doesn't exist in the file. This is because when creating an external table, if we didn't specify a `TIME INDEX` column, the `greptime_timestamp` column is automatically added as the `TIME INDEX` column with a default value of `1970-01-01 00:00:00+0000`. You can find more details in the [create](/reference/sql/create.md#create-external-table) document. ::: Now you can query on the external table: ```sql SELECT `Zone`, `Borough` FROM taxi_zone_lookup LIMIT 5; ``` ```sql +-------------------------+---------------+ | Zone | Borough | +-------------------------+---------------+ | Newark Airport | EWR | | Jamaica Bay | Queens | | Allerton/Pelham Gardens | Bronx | | Alphabet City | Manhattan | | Arden Heights | Staten Island | +-------------------------+---------------+ ``` ## Query on a directory Let's download some data: ```bash mkdir /tmp/external curl "https://d37ci6vzurychx.cloudfront.net/trip-data/yellow_tripdata_2022-01.parquet" -o /tmp/external/yellow_tripdata_2022-01.parquet curl "https://d37ci6vzurychx.cloudfront.net/trip-data/yellow_tripdata_2022-02.parquet" -o /tmp/external/yellow_tripdata_2022-02.parquet ``` Verify the download: ```bash ls -l /tmp/external total 165368 -rw-r--r-- 1 wenyxu wheel 38139949 Apr 28 14:35 yellow_tripdata_2022-01.parquet -rw-r--r-- 1 wenyxu wheel 45616512 Apr 28 14:36 yellow_tripdata_2022-02.parquet ``` Create the external table: ```sql CREATE EXTERNAL TABLE yellow_tripdata with(location='/tmp/external/',format='parquet'); ``` Run queries: ```sql SELECT count(*) FROM yellow_tripdata; ``` ```sql +-----------------+ | COUNT(UInt8(1)) | +-----------------+ | 5443362 | +-----------------+ 1 row in set (0.48 sec) ``` ```sql SELECT * FROM yellow_tripdata LIMIT 5; ``` ```sql +----------+----------------------+-----------------------+-----------------+---------------+------------+--------------------+--------------+--------------+--------------+-------------+-------+---------+------------+--------------+-----------------------+--------------+----------------------+-------------+---------------------+ | VendorID | tpep_pickup_datetime | tpep_dropoff_datetime | passenger_count | trip_distance | RatecodeID | store_and_fwd_flag | PULocationID | DOLocationID | payment_type | fare_amount | extra | mta_tax | tip_amount | tolls_amount | improvement_surcharge | total_amount | congestion_surcharge | airport_fee | greptime_timestamp | +----------+----------------------+-----------------------+-----------------+---------------+------------+--------------------+--------------+--------------+--------------+-------------+-------+---------+------------+--------------+-----------------------+--------------+----------------------+-------------+---------------------+ | 1 | 2022-02-01 00:06:58 | 2022-02-01 00:19:24 | 1 | 5.4 | 1 | N | 138 | 252 | 1 | 17 | 1.75 | 0.5 | 3.9 | 0 | 0.3 | 23.45 | 0 | 1.25 | 1970-01-01 00:00:00 | | 1 | 2022-02-01 00:38:22 | 2022-02-01 00:55:55 | 1 | 6.4 | 1 | N | 138 | 41 | 2 | 21 | 1.75 | 0.5 | 0 | 6.55 | 0.3 | 30.1 | 0 | 1.25 | 1970-01-01 00:00:00 | | 1 | 2022-02-01 00:03:20 | 2022-02-01 00:26:59 | 1 | 12.5 | 1 | N | 138 | 200 | 2 | 35.5 | 1.75 | 0.5 | 0 | 6.55 | 0.3 | 44.6 | 0 | 1.25 | 1970-01-01 00:00:00 | | 2 | 2022-02-01 00:08:00 | 2022-02-01 00:28:05 | 1 | 9.88 | 1 | N | 239 | 200 | 2 | 28 | 0.5 | 0.5 | 0 | 3 | 0.3 | 34.8 | 2.5 | 0 | 1970-01-01 00:00:00 | | 2 | 2022-02-01 00:06:48 | 2022-02-01 00:33:07 | 1 | 12.16 | 1 | N | 138 | 125 | 1 | 35.5 | 0.5 | 0.5 | 8.11 | 0 | 0.3 | 48.66 | 2.5 | 1.25 | 1970-01-01 00:00:00 | +----------+----------------------+-----------------------+-----------------+---------------+------------+--------------------+--------------+--------------+--------------+-------------+-------+---------+------------+--------------+-----------------------+--------------+----------------------+-------------+---------------------+ 5 rows in set (0.11 sec) ``` :::tip Note The query result includes the value of the `greptime_timestamp` column, although it does not exist in the original file. All these column values are `1970-01-01 00:00:00+0000`, because when we create an external table, the `greptime_timestamp` column is automatically added with a default value of `1970-01-01 00:00:00+0000`. You can find more details in the [create](/reference/sql/create.md#create-external-table) document. ::: --- ## SQL(Query-data) GreptimeDB supports full SQL for querying data from a database. In this document, we will use the `monitor` table to demonstrate how to query data. For instructions on creating the `monitor` table and inserting data into it, Please refer to [table management](/user-guide/deployments-administration/manage-data/basic-table-operations.md#create-a-table) and [Ingest Data](/user-guide/ingest-data/for-iot/sql.md). ## Basic query The query is represented by the `SELECT` statement. For example, the following query selects all data from the `monitor` table: ```sql SELECT * FROM monitor; ``` The query result looks like the following: ```sql +-----------+---------------------+------+--------+ | host | ts | cpu | memory | +-----------+---------------------+------+--------+ | 127.0.0.1 | 2022-11-03 03:39:57 | 0.1 | 0.4 | | 127.0.0.1 | 2022-11-03 03:39:58 | 0.5 | 0.2 | | 127.0.0.2 | 2022-11-03 03:39:58 | 0.2 | 0.3 | +-----------+---------------------+------+--------+ 3 rows in set (0.00 sec) ``` Functions are also supported in the `SELECT` field list. For example, you can use the `count()` function to retrieve the total number of rows in the table: ```sql SELECT count(*) FROM monitor; ``` ```sql +-----------------+ | COUNT(UInt8(1)) | +-----------------+ | 3 | +-----------------+ ``` The `avg()` function returns the average value of a certain field: ```sql SELECT avg(cpu) FROM monitor; ``` ```sql +---------------------+ | AVG(monitor.cpu) | +---------------------+ | 0.26666666666666666 | +---------------------+ 1 row in set (0.00 sec) ``` You can also select only the result of a function. For example, you can extract the day of the year from a timestamp. The `DOY` in the SQL statement is the abbreviation of `day of the year`: ```sql SELECT date_part('DOY', '2021-07-01 00:00:00'); ``` Output: ```sql +----------------------------------------------------+ | date_part(Utf8("DOY"),Utf8("2021-07-01 00:00:00")) | +----------------------------------------------------+ | 182 | +----------------------------------------------------+ 1 row in set (0.003 sec) ``` The parameters and results of date functions align with the SQL client's time zone. For example, when the client's time zone is set to `+08:00`, the results of the two queries below are the same: ```sql select to_unixtime('2024-01-02 00:00:00'); select to_unixtime('2024-01-02 00:00:00+08:00'); ``` Please refer to [SELECT](/reference/sql/select.md) and [Functions](/reference/sql/functions/overview.md) for more information. ## Limit the number of rows returned Time series data is typically massive. To save bandwidth and improve query performance, you can use the `LIMIT` clause to restrict the number of rows returned by the `SELECT` statement. For example, the following query limits the number of rows returned to 10: ```sql SELECT * FROM monitor LIMIT 10; ``` ## Filter data You can use the `WHERE` clause to filter the rows returned by the `SELECT` statement. Filtering data by tags or time index is efficient and common in time series scenarios. For example, the following query filter data by tag `host`: ```sql SELECT * FROM monitor WHERE host='127.0.0.1'; ``` The following query filter data by time index `ts`, and returns the data after `2022-11-03 03:39:57`: ```sql SELECT * FROM monitor WHERE ts > '2022-11-03 03:39:57'; ``` You can also use the `AND` keyword to combine multiple constraints: ```sql SELECT * FROM monitor WHERE host='127.0.0.1' AND ts > '2022-11-03 03:39:57'; ``` ### Filter by time index Filtering data by the time index is a crucial feature in time series databases. When working with Unix time values, the database treats them based on the type of the column value. For instance, if the `ts` column in the `monitor` table has a value type of `TimestampMillisecond`, you can use the following query to filter the data: The Unix time value `1667446797000` corresponds to the `TimestampMillisecond` type。 ```sql SELECT * FROM monitor WHERE ts > 1667446797000; ``` When working with a Unix time value that doesn't have the precision of the column value, you need to use the `::` syntax to specify the type of the time value. This ensures that the database correctly identifies the type. For example, `1667446797` represents a timestamp in seconds, which is different from the default millisecond timestamp of the `ts` column. You need to specify its type as `TimestampSecond` using the `::TimestampSecond` syntax. This informs the database that the value `1667446797` should be treated as a timestamp in seconds. ```sql SELECT * FROM monitor WHERE ts > 1667446797::TimestampSecond; ``` For the supported time data types, please refer to [Data Types](/reference/sql/data-types.md#date-and-time-types). When using standard `RFC3339` or `ISO8601` string literals, you can directly use them in the filter condition since the precision is clear. ```sql SELECT * FROM monitor WHERE ts > '2022-07-25 10:32:16.408'; ``` Time and date functions are also supported in the filter condition. For example, use the `now()` function and the `INTERVAL` keyword to retrieve data from the last 5 minutes: ```sql SELECT * FROM monitor WHERE ts >= now() - '5 minutes'::INTERVAL; ``` For date and time functions, please refer to [Functions](/reference/sql/functions/overview.md) for more information. ### Time zone A string literal timestamp without time zone information will be interpreted based on the local time zone of the SQL client. For example, the following two queries are equivalent when the client time zone is `+08:00`: ```sql SELECT * FROM monitor WHERE ts > '2022-07-25 10:32:16.408'; SELECT * FROM monitor WHERE ts > '2022-07-25 10:32:16.408+08:00'; ``` All the timestamp column values in query results are formatted based on the client time zone. For example, the following code shows the same `ts` value formatted in the client time zones `UTC` and `+08:00` respectively. ```sql +-----------+---------------------+------+--------+ | host | ts | cpu | memory | +-----------+---------------------+------+--------+ | 127.0.0.1 | 2023-12-31 16:00:00 | 0.5 | 0.1 | +-----------+---------------------+------+--------+ ``` ```sql +-----------+---------------------+------+--------+ | host | ts | cpu | memory | +-----------+---------------------+------+--------+ | 127.0.0.1 | 2024-01-01 00:00:00 | 0.5 | 0.1 | +-----------+---------------------+------+--------+ ``` ### Functions GreptimeDB offers an extensive suite of built-in functions and aggregation capabilities tailored to meet the demands of data analytics. Its features include: - A comprehensive set of functions inherited from Apache Datafusion query engine, featuring a selection of date/time functions that adhere to Postgres naming conventions and behaviour. - Logical data type operations for JSON, Geolocation, and other specialized data types. - Advanced full-text matching capabilities. See [Functions reference](/reference/sql/functions/overview.md) for more details. ## Order By The order of the returned data is not guaranteed. You need to use the `ORDER BY` clause to sort the returned data. For example, in time series scenarios, it is common to use the time index column as the sorting key to arrange the data chronologically: ```sql -- ascending order by ts SELECT * FROM monitor ORDER BY ts ASC; ``` ```sql -- descending order by ts SELECT * FROM monitor ORDER BY ts DESC; ``` ## `CASE` Expression You can use the `CASE` statement to perform conditional logic within your queries. For example, the following query returns the status of the CPU based on the value of the `cpu` field: ```sql SELECT host, ts, CASE WHEN cpu > 0.5 THEN 'high' WHEN cpu > 0.3 THEN 'medium' ELSE 'low' END AS cpu_status FROM monitor; ``` The result is shown below: ```sql +-----------+---------------------+------------+ | host | ts | cpu_status | +-----------+---------------------+------------+ | 127.0.0.1 | 2022-11-03 03:39:57 | low | | 127.0.0.1 | 2022-11-03 03:39:58 | medium | | 127.0.0.2 | 2022-11-03 03:39:58 | low | +-----------+---------------------+------------+ 3 rows in set (0.01 sec) ``` For more information, please refer to [CASE](/reference/sql/case.md). ## Aggregate data by tag You can use the `GROUP BY` clause to group rows that have the same values into summary rows. The average memory usage grouped by idc: ```sql SELECT host, avg(cpu) FROM monitor GROUP BY host; ``` ```sql +-----------+------------------+ | host | AVG(monitor.cpu) | +-----------+------------------+ | 127.0.0.2 | 0.2 | | 127.0.0.1 | 0.3 | +-----------+------------------+ 2 rows in set (0.00 sec) ``` Please refer to [GROUP BY](/reference/sql/group_by.md) for more information. ### Find the latest data of time series To find the latest point of each time series, you can use `DISTINCT ON` together with `ORDER BY` like in [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/select/distinct). ```sql SELECT DISTINCT ON (host) * FROM monitor ORDER BY host, ts DESC; ``` ```sql +-----------+---------------------+------+--------+ | host | ts | cpu | memory | +-----------+---------------------+------+--------+ | 127.0.0.1 | 2022-11-03 03:39:58 | 0.5 | 0.2 | | 127.0.0.2 | 2022-11-03 03:39:58 | 0.2 | 0.3 | +-----------+---------------------+------+--------+ 2 rows in set (0.00 sec) ``` ## Aggregate data by time window GreptimeDB supports [Range Query](/reference/sql/range.md) to aggregate data by time window. Suppose we have the following data in the [`monitor` table](/user-guide/deployments-administration/manage-data/basic-table-operations.md#create-a-table): ```sql +-----------+---------------------+------+--------+ | host | ts | cpu | memory | +-----------+---------------------+------+--------+ | 127.0.0.1 | 2023-12-13 02:05:41 | 0.5 | 0.2 | | 127.0.0.1 | 2023-12-13 02:05:46 | NULL | NULL | | 127.0.0.1 | 2023-12-13 02:05:51 | 0.4 | 0.3 | | 127.0.0.2 | 2023-12-13 02:05:41 | 0.3 | 0.1 | | 127.0.0.2 | 2023-12-13 02:05:46 | NULL | NULL | | 127.0.0.2 | 2023-12-13 02:05:51 | 0.2 | 0.4 | +-----------+---------------------+------+--------+ ``` The following query returns the average CPU usage in a 10-second time range and calculates it every 5 seconds: ```sql SELECT ts, host, avg(cpu) RANGE '10s' FILL LINEAR FROM monitor ALIGN '5s' TO '2023-12-01T00:00:00' BY (host) ORDER BY ts ASC; ``` 1. `avg(cpu) RANGE '10s' FILL LINEAR` is a Range expression. `RANGE '10s'` specifies that the time range of the aggregation is 10s, and `FILL LINEAR` specifies that if there is no data within a certain aggregation time, use the `LINEAR` method to fill it. 2. `ALIGN '5s'` specifies the that data statistics should be performed in steps of 5s. 3. `TO '2023-12-01T00:00:00` specifies the origin alignment time. The default value is Unix time 0. 4. `BY (host)` specifies the aggregate key. If the `BY` keyword is omitted, the primary key of the data table is used as the aggregate key by default. 5. `ORDER BY ts ASC` specifies the sorting method of the result set. If you do not specify the sorting method, the order of the results is not guaranteed. The Response is shown below: ```sql +---------------------+-----------+----------------------------------------+ | ts | host | AVG(monitor.cpu) RANGE 10s FILL LINEAR | +---------------------+-----------+----------------------------------------+ | 2023-12-13 02:05:35 | 127.0.0.1 | 0.5 | | 2023-12-13 02:05:40 | 127.0.0.1 | 0.5 | | 2023-12-13 02:05:45 | 127.0.0.1 | 0.4 | | 2023-12-13 02:05:50 | 127.0.0.1 | 0.4 | | 2023-12-13 02:05:35 | 127.0.0.2 | 0.3 | | 2023-12-13 02:05:40 | 127.0.0.2 | 0.3 | | 2023-12-13 02:05:45 | 127.0.0.2 | 0.2 | | 2023-12-13 02:05:50 | 127.0.0.2 | 0.2 | +---------------------+-----------+----------------------------------------+ ``` ### Time range window The origin time range window steps forward and backward in the time series to generate all time range windows. In the example above, the origin alignment time is set to `2023-12-01T00:00:00`, which is also the end time of the origin time window. The `RANGE` option, along with the origin alignment time, defines the origin time range window that starts from `origin alignment timestamp` and ends at `origin alignment timestamp + range`. The `ALIGN` option defines the query resolution steps. It determines the calculation steps from the origin time window to other time windows. For example, with the origin alignment time `2023-12-01T00:00:00` and `ALIGN '5s'`, the alignment times are `2023-11-30T23:59:55`, `2023-12-01T00:00:00`, `2023-12-01T00:00:05`, `2023-12-01T00:00:10`, and so on. These time windows are left-closed and right-open intervals that satisfy the condition `[alignment timestamp, alignment timestamp + range)`. The following images can help you understand the time range window more visually: When the query resolution is greater than the time range window, the metrics data will be calculated for only one time range window. ![align > range](/align_greater_than_range.png) When the query resolution is less than the time range window, the metrics data will be calculated for multiple time range windows. ![align < range](/align_less_than_range.png) ### Align to specific timestamp The alignment times default based on the time zone of the current SQL client session. You can change the origin alignment time to any timestamp you want. For example, use `NOW` to align to the current time: ```sql SELECT ts, host, avg(cpu) RANGE '1w' FROM monitor ALIGN '1d' TO NOW BY (host); ``` Or use a `ISO 8601` timestamp to align to a specified time: ```sql SELECT ts, host, avg(cpu) RANGE '1w' FROM monitor ALIGN '1d' TO '2023-12-01T00:00:00+08:00' BY (host); ``` ### Fill null values The `FILL` option can be used to fill null values in the data. In the above example, the `LINEAR` method is used to fill null values. Other methods are also supported, such as `PREV` and a constant value `X`. For more information, please refer to the [FILL OPTION](/reference/sql/range.md#fill-option). ### Syntax Please refer to [Range Query](/reference/sql/range.md) for more information. ## Table name constraints If your table name contains special characters or uppercase letters, you must enclose the table name in backquotes. For examples, please refer to the [Table name constraints](/user-guide/deployments-administration/manage-data/basic-table-operations.md#table-name-constraints) section in the table creation documentation. ## HTTP API Use POST method to query data: ```shell curl -X POST \ -H 'authorization: Basic {{authorization if exists}}' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'sql=select * from monitor' \ http://localhost:4000/v1/sql?db=public ``` The result is shown below: ```json { "code": 0, "output": [ { "records": { "schema": { "column_schemas": [ { "name": "host", "data_type": "String" }, { "name": "ts", "data_type": "TimestampMillisecond" }, { "name": "cpu", "data_type": "Float64" }, { "name": "memory", "data_type": "Float64" } ] }, "rows": [ ["127.0.0.1", 1667446797450, 0.1, 0.4], ["127.0.0.1", 1667446798450, 0.5, 0.2], ["127.0.0.2", 1667446798450, 0.2, 0.3] ] } } ], "execution_time_ms": 0 } ``` For more information about SQL HTTP request, please refer to [API document](/user-guide/protocols/http.md#post-sql-statements). --- ## View In SQL, a view is a virtual table based on the result set of an SQL statement. It contains rows and columns just like a real table. The query of a view is run every time the view is referenced in a query. In the following situations, you can use views: * Simplifying complex queries, avoiding the need to repeatedly write and send complex statements for every query. * Granting read permissions to specific users while restricting access to certain columns and rows to ensure data security and isolation. A view is created with the `CREATE VIEW` statement. ## View examples ```sql CREATE VIEW cpu_monitor AS SELECT cpu, host, ts FROM monitor; ``` The view name is `cpu_monitor`, and the query statement after `AS` is the SQL statement to present the data. Query the view: ```sql SELECT * FROM cpu_monitor; ``` ```sql +------+-----------+---------------------+ | cpu | host | ts | +------+-----------+---------------------+ | 0.5 | 127.0.0.1 | 2023-12-13 02:05:41 | | 0.3 | 127.0.0.1 | 2023-12-13 02:05:46 | | 0.4 | 127.0.0.1 | 2023-12-13 02:05:51 | | 0.3 | 127.0.0.2 | 2023-12-13 02:05:41 | | 0.2 | 127.0.0.2 | 2023-12-13 02:05:46 | | 0.2 | 127.0.0.2 | 2023-12-13 02:05:51 | +------+-----------+---------------------+ ``` Query view by `WHERE`: ```sql SELECT * FROM cpu_monitor WHERE host = '127.0.0.2'; ``` ```sql +------+-----------+---------------------+ | cpu | host | ts | +------+-----------+---------------------+ | 0.3 | 127.0.0.2 | 2023-12-13 02:05:41 | | 0.2 | 127.0.0.2 | 2023-12-13 02:05:46 | | 0.2 | 127.0.0.2 | 2023-12-13 02:05:51 | +------+-----------+---------------------+ ``` Create a view that queries data from two tables: ```sql CREATE VIEW app_cpu_monitor AS SELECT cpu, latency, host, ts FROM monitor LEFT JOIN app_monitor ON monitor.host = app_monitor.host AND monitor.ts = app_monitor.ts ``` Then query the view as if the data were coming from one single table: ```sql SELECT * FROM app_cpu_monitor WHERE host = 'host1' ``` ## Update View `CREATE OR REPLACE VIEW` to update a view, if it doesn't exist, it will be created: ```sql CREATE OR REPLACE VIEW memory_monitor AS SELECT memory, host, ts FROM monitor; ``` ## Shows the view definition Shows the `CREATE VIEW` statement that creates the named view by `SHOW CREATE VIEW view_name`: ```sql SHOW CREATE VIEW cpu_monitor; ``` ```sql +-------------+--------------------------------------------------------------+ | View | Create View | +-------------+--------------------------------------------------------------+ | cpu_monitor | CREATE VIEW cpu_monitor AS SELECT cpu, host, ts FROM monitor | +-------------+--------------------------------------------------------------+ ``` ## List Views `SHOW VIEWS` statement to find all the views: ```sql > SHOW VIEWS; +----------------+ | Views | +----------------+ | cpu_monitor | | memory_monitor | +----------------+ ``` of course, just like `SHOW TABLES`, it supports `LIKE` and `WHERE`: ```sql > SHOW VIEWS like 'cpu%'; +-------------+ | Views | +-------------+ | cpu_monitor | +-------------+ 1 row in set (0.02 sec) > SHOW VIEWS WHERE Views = 'memory_monitor'; +----------------+ | Views | +----------------+ | memory_monitor | +----------------+ ``` ## Drop View Use `DROP VIEW` statement to drop a view: ```sql DROP VIEW cpu_monitor; ``` To be quiet if it does not exist: ```sql DROP VIEW IF EXISTS test; ``` --- ## Time Zone You can specify the time zone in the client session to manage time data conveniently. The specified time zone in the client session does not affect the time data stored in the GreptimeDB server, it only applies when the client sends a request to the server. GreptimeDB converts the time value from a string representation to a datetime according to the specified time zone during ingestion or querying, or converts it back. ## Specify time zone in clients By default, all clients use [the default time zone configuration](/user-guide/deployments-administration/configuration.md#default-time-zone-configuration), which is UTC. You can also specify a time zone in each client session, which will override the default time zone configuration. ### MySQL client - **Command Line**: For configuring the time zone via the MySQL command line client, please refer to the [time zone section](/user-guide/protocols/mysql.md#time-zone) in the MySQL protocol documentation. - **MySQL Driver**: If you are using MySQL Driver in Java or Go, see the [time zone section](/reference/sql-tools.md#time-zone) of the SQL tools documentation. ### PostgreSQL client To configure the time zone for the PostgreSQL client, please refer to the [time zone section](/user-guide/protocols/postgresql.md#time-zone) in the PostgreSQL protocol documentation. ### HTTP API When using the HTTP API, you can specify the time zone through the header parameter. For more information, please refer to the [HTTP API documentation](/user-guide/protocols/http.md#time-zone). ### Dashboard The dashboard will use the local timezone as the default timezone value. You can change it in the settings menu. ### Other clients For other clients, you can change [the default time zone configuration](/user-guide/deployments-administration/configuration.md#default-time-zone-configuration) of GreptimeDB. ## Impact of time zone on SQL statements The client's time zone setting influences both data ingestion and querying. ### Ingest data The time zone set in the client impacts the data during ingestion. For more information, please refer to the [ingest data section](/user-guide/ingest-data/for-iot/sql.md#time-zone). Additionally, the default timestamp values in the table schema are influenced by the client's time zone in the same manner as the ingested data. ### Query data The time zone setting also affects data during querying. For detailed information, please refer to the [query data section](/user-guide/query-data/sql.md#time-zone). --- ## Trace Data Modeling :::warning This section currently in the experimental stage and may be adjusted in future versions. ::: In this section, we will cover how trace data is modeled in GreptimeDB as tables. We reuse the concept of Pipeline for trace data modeling. However, note that at the moment, only built-in pipelines are supported. ## Data Model Versioning First, the data types and features in GreptimeDB are evolving. For forward-compatibility, we use the pipeline name for data model versioning. Currently we have following pipeline for trace: - `greptime_trace_v1` It is required for user to specify this on OpenTelemetry OTLP/HTTP headers via `x-greptime-pipeline-name: greptime_trace_v1`. We may introduce new data model by adding new available pipeline names. And we will keep previous pipeline supported. Note that new pipeline may not be compatible with previous ones so you are recommended to use it in new table. ## Data Model The `greptime_trace_v1` data model is pretty straight-forward. By default, trace data is stored in a table named `opentelemetry_traces`. You can customize the table name by specifying the `x-greptime-trace-table-name` header in your OTLP/HTTP requests. - It maps most common data fields from [OpenTelemetry Trace](https://opentelemetry.io/docs/concepts/signals/traces/) data model to GreptimeDB's table columns. - `service_name` is extracted from `resource_attributes["service.name"]` and used as a **Tag** (part of the **Primary Key**). - `timestamp` is the start time of the span and is used as the **Time Index**. - A new `duration_nano` column is generated using `end_time - start_time`. - All attributes fields are flattened into columns using the name pattern: `[span|resource|scope]_attributes.[attribute_key]`. - Note: `resource_attributes.service.name` is excluded from flattening as it is already stored in the `service_name` column. - If the attribute value is a compound type like `Array` or `Kvlist`, it is serialized to `JSON` type of GreptimeDB. - Compound fields, `span_links` and `span_events` are stored as `JSON` type. The table will be automatically generated when your first data item arrived. It also follows our schema-less principle to update the table schema automatically for new columns, for example, the new attribute fields. A typical table structure generated from OpenTelemetry django instrument is like: ``` timestamp | 2025-05-07 10:03:29.657544 timestamp_end | 2025-05-07 10:03:29.661714 duration_nano | 4169970 trace_id | fb60d19aa36fdcb7d14a71ca0b9b42ae span_id | 49806a2671f2ddcb span_kind | SPAN_KIND_SERVER span_name | POST todos/ span_status_code | STATUS_CODE_UNSET span_status_message | trace_state | scope_name | opentelemetry.instrumentation.django scope_version | 0.51b0 service_name | myproject span_attributes.http.request.method | POST span_attributes.url.full | span_attributes.server.address | django:8000 span_attributes.network.peer.address | span_attributes.server.port | 8000 span_attributes.network.peer.port | span_attributes.http.response.status_code | 201 span_attributes.network.protocol.version | 1.1 resource_attributes.telemetry.sdk.language | python resource_attributes.telemetry.sdk.name | opentelemetry resource_attributes.telemetry.sdk.version | 1.30.0 span_events | [] span_links | [] parent_span_id | eccc18b6fc210f31 span_attributes.db.system | span_attributes.db.name | span_attributes.db.statement | span_attributes.url.scheme | http span_attributes.url.path | /todos/ span_attributes.client.address | 10.89.0.5 span_attributes.client.port | 44302 span_attributes.user_agent.original | python-requests/2.32.3 span_attributes.http.route | todos/ ``` To check the table definition, you can use `show create table opentelemetry_traces` statement. An output like this is expected: ``` Table | opentelemetry_traces Create Table | CREATE TABLE IF NOT EXISTS "opentelemetry_traces" ( + | "timestamp" TIMESTAMP(9) NOT NULL, + | "timestamp_end" TIMESTAMP(9) NULL, + | "duration_nano" BIGINT UNSIGNED NULL, + | "trace_id" STRING NULL SKIPPING INDEX WITH(granularity = '10240', type = 'BLOOM'), + | "span_id" STRING NULL, + | "span_kind" STRING NULL, + | "span_name" STRING NULL, + | "span_status_code" STRING NULL, + | "span_status_message" STRING NULL, + | "trace_state" STRING NULL, + | "scope_name" STRING NULL, + | "scope_version" STRING NULL, + | "service_name" STRING NULL SKIPPING INDEX WITH(granularity = '10240', type = 'BLOOM'),+ | "span_attributes.http.request.method" STRING NULL, + | "span_attributes.url.full" STRING NULL, + | "span_attributes.server.address" STRING NULL, + | "span_attributes.network.peer.address" STRING NULL, + | "span_attributes.server.port" BIGINT NULL, + | "span_attributes.network.peer.port" BIGINT NULL, + | "span_attributes.http.response.status_code" BIGINT NULL, + | "span_attributes.network.protocol.version" STRING NULL, + | "resource_attributes.telemetry.sdk.language" STRING NULL, + | "resource_attributes.telemetry.sdk.name" STRING NULL, + | "resource_attributes.telemetry.sdk.version" STRING NULL, + | "span_events" JSON NULL, + | "span_links" JSON NULL, + | "parent_span_id" STRING NULL, + | "span_attributes.db.system" STRING NULL, + | "span_attributes.db.name" STRING NULL, + | "span_attributes.db.statement" STRING NULL, + | "span_attributes.url.scheme" STRING NULL, + | "span_attributes.url.path" STRING NULL, + | "span_attributes.client.address" STRING NULL, + | "span_attributes.client.port" BIGINT NULL, + | "span_attributes.user_agent.original" STRING NULL, + | "span_attributes.http.route" STRING NULL, + | TIME INDEX ("timestamp"), + | PRIMARY KEY ("service_name") + | ) + | PARTITION ON COLUMNS ("trace_id") ( + | trace_id < '1', + | trace_id >= 'f', + | trace_id >= '1' AND trace_id < '2', + | trace_id >= '2' AND trace_id < '3', + | trace_id >= '3' AND trace_id < '4', + | trace_id >= '4' AND trace_id < '5', + | trace_id >= '5' AND trace_id < '6', + | trace_id >= '6' AND trace_id < '7', + | trace_id >= '7' AND trace_id < '8', + | trace_id >= '8' AND trace_id < '9', + | trace_id >= '9' AND trace_id < 'a', + | trace_id >= 'a' AND trace_id < 'b', + | trace_id >= 'b' AND trace_id < 'c', + | trace_id >= 'c' AND trace_id < 'd', + | trace_id >= 'd' AND trace_id < 'e', + | trace_id >= 'e' AND trace_id < 'f' + | ) + | ENGINE=mito + | WITH( + | append_mode = 'true', + | table_data_model = 'greptime_trace_v1' + | ) ``` ### Partition Rules We included default [partition rules](/user-guide/deployments-administration/manage-data/table-sharding.md#partition) for trace table on the `trace_id` column based on the first character of it. This is optimised for retrieve trace spans by the trace id. The partition rule introduces 16 partitions for the table. It is suitable for a 3-5 datanode setup. To customize the partition rule, you can create a new table ahead-of-time by copying the DDL output by `show create table` on original table, update the `PARTITION ON` section to include your own rules. ### Index We include [skipping index](/user-guide/manage-data/data-index.md#skipping-index) on `service_name` and `trace_id` for most typical queries. In real-world, you may want to speed up queries on other fields like an attribute field. It's possible by apply additional index on these fields using [alter table](/reference/sql/alter.md#create-an-index-for-a-column) statement. Unlike partition rules, index can be created on existing table and be affective on new data. ### Append-only Mode By default, trace table created by OpenTelemetry API are in [append only mode](/user-guide/deployments-administration/performance-tuning/design-table.md#when-to-use-append-only-tables). ### TTL You can apply [TTL on trace table](/reference/sql/alter.md#alter-table-options). ## Auxiliary Tables When you ingest trace data, GreptimeDB automatically creates two auxiliary tables to facilitate searching for services and operations. These tables are named by appending `_services` and `_operations` to your main trace table name. By default, these are named `opentelemetry_traces_services` and `opentelemetry_traces_operations`. If you customize the main trace table name using the `x-greptime-trace-table-name` HTTP header, the auxiliary tables will be named accordingly (e.g., `_services` and `_operations`). ### Services Table (`opentelemetry_traces_services`) This table stores the list of unique service names found in the trace data. - **Columns**: - `timestamp`: A constant timestamp (2100-01-01 00:00:00) used for all entries. - `service_name`: The name of the service (Tag). ### Operations Table (`opentelemetry_traces_operations`) This table stores the list of unique operations (service, span name, and span kind) found in the trace data. - **Columns**: - `timestamp`: A constant timestamp (2100-01-01 00:00:00) used for all entries. - `service_name`: The name of the service (Tag). - `span_name`: The name of the span (Tag). - `span_kind`: The kind of the span (Tag). --- ## Extending Trace Data :::warning This section currently in the experimental stage and may be adjusted in future versions. ::: You can also generate derived data from trace. In this chapter, we will show you some examples. ## Generate Aggregated Metrics from Trace The span contains `duration_nano` field for span processing time. In this example, we will create [Flow](/user-guide/flow-computation/overview.md) task to generate latency metrics from trace data. We will use OpenTelemetry Django instruments for source data. But the source data doesn't really matter because fields used in this example are all generic ones. ### Create Sink Table First, we create a sink table which is a materialzed view in Flow. For latency quantiles, we will use [uddsketch](https://arxiv.org/abs/2004.08604) for a quick estimation of latency at given percentile. ```sql CREATE TABLE "django_http_request_latency" ( "span_name" STRING NULL, "latency_sketch" BINARY, "time_window" TIMESTAMP time index, PRIMARY KEY ("span_name") ); ``` This table contains 3 key columns: - `span_name`: the type or name of span - `latency_sketch`: the uddsketch data structure - `time_window`: indicate the time window of current record ### Create Flow Next we create a flow task to generate uddsketch data for every 30s time window. The example filters spans by the scope name, which is optional depends on your data. Note: In this example, we use the default table name `opentelemetry_traces` as the source trace table. You should replace it with your own trace table name if it's customized. ```sql CREATE FLOW django_http_request_latency_flow SINK TO django_http_request_latency EXPIRE AFTER '30m' COMMENT 'Aggregate latency using uddsketch' AS SELECT span_name, uddsketch_state(128, 0.01, "duration_nano") AS "latency_sketch", date_bin('30 seconds'::INTERVAL, "timestamp") as "time_window", FROM opentelemetry_traces WHERE scope_name = 'opentelemetry.instrumentation.django' GROUP BY span_name, time_window; ``` ### Query Metrics The sink table will be filled with aggregated data as trace data ingested. We can use following SQL to get p90 latency of the each span. ```sql SELECT span_name, time_window, uddsketch_calc(0.90, "latency_sketch") AS p90 FROM django_http_request_latency ORDER BY time_window DESC LIMIT 20; ``` The query will return results like: ``` span_name | time_window | p90 ---------------------+----------------------------+-------------------- GET todos/ | 2025-05-09 02:38:00.000000 | 4034758.586053441 POST todos/ | 2025-05-09 02:38:00.000000 | 22988738.680499777 PUT todos// | 2025-05-09 02:38:00.000000 | 5338559.200101535 GET todos/ | 2025-05-09 02:37:30.000000 | 4199425.807196321 POST todos/ | 2025-05-09 02:37:30.000000 | 15104466.164886404 PUT todos// | 2025-05-09 02:37:30.000000 | 16693072.385310777 GET todos/ | 2025-05-09 02:37:00.000000 | 4370813.453648573 POST todos/ | 2025-05-09 02:37:00.000000 | 30417369.407361753 PUT todos// | 2025-05-09 02:37:00.000000 | 14512192.224492861 GET todos/ | 2025-05-09 02:36:30.000000 | 3578495.53232116 POST todos/ | 2025-05-09 02:36:30.000000 | 15409606.895490168 PUT todos// | 2025-05-09 02:36:30.000000 | 15409606.895490168 GET todos/ | 2025-05-09 02:36:00.000000 | 3507634.2346514342 POST todos/ | 2025-05-09 02:36:00.000000 | 45377987.991290994 PUT todos// | 2025-05-09 02:36:00.000000 | 14512192.224492861 GET todos/ | 2025-05-09 02:35:30.000000 | 3237945.86410019 POST todos/ | 2025-05-09 02:35:30.000000 | 15409606.895490168 PUT todos// | 2025-05-09 02:35:30.000000 | 13131130.769316385 GET todos/ | 2025-05-09 02:35:00.000000 | 3173828.124217018 POST todos/ | 2025-05-09 02:35:00.000000 | 14512192.224492861 (20 rows) ``` --- ## Traces :::warning This section currently in the experimental stage and may be adjusted in future versions. ::: Native support for Trace data is introduced since GreptimeDB v0.14. In this section we will cover from basic ingestion and query steps, to advanced internals of data modeling. - [Ingestion and Query](./read-write.md) - [Trace Data Modeling in GreptimeDB](./data-model.md) - [Extending Trace Data](./extend-trace.md) --- ## Ingestion and Query :::warning This section currently in the experimental stage and may be adjusted in future versions. ::: In this section, we will get started with trace data in GreptimeDB from ingestion and query. GreptimeDB doesn't invent new protocols for trace, it follows existing standard and widely adopted protocols. ## Ingestion GreptimeDB uses OpenTelemetry OTLP/HTTP protocol as the primary trace data ingestion protocol. OpenTelemetry Trace is the most adopted subprotocol in OpenTelemetry family. ### OpenTelemetry SDK If OpenTelemetry SDK/API is used in your application, you can configure an OTLP/HTTP exporter to write trace data directly to GreptimeDB. We covered this part in our [OpenTelemetry protocol docs](/user-guide/ingest-data/for-observability/opentelemetry.md). You can follow the guide for endpoint and parameters. ### OpenTelemetry Collector [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/) is a vendor-neutral service for collecting and processing OpenTelemetry data. You can also configure it to send trace data to GreptimeDB using OTLP/HTTP. #### Start OpenTelemetry Collector You can use the following command to quickly start an OpenTelemetry Collector instance, which will listen on ports `4317` (gRPC) and `4318` (HTTP): ```shell docker run --rm \ --network host \ -p 4317:4317 \ -p 4318:4318 \ -v $(pwd)/config.yaml:/etc/otelcol-contrib/config.yaml \ otel/opentelemetry-collector-contrib:0.123.0 ``` The content of the `config.yaml` file is as follows: ```yaml receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 http: endpoint: 0.0.0.0:4318 exporters: otlphttp: endpoint: "http://greptimedb:4000/v1/otlp" # Replace greptimedb with your setup headers: x-greptime-pipeline-name: "greptime_trace_v1" #authorization: "Basic " tls: insecure: true service: pipelines: traces: receivers: [otlp] exporters: [otlphttp] ``` #### Write Trace Data to OpenTelemetry Collector You can configure the corresponding exporter to write traces data to the OpenTelemetry Collector. For example, you can use the environment variable `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` to configure the endpoint of the exporter: ```shell export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT="http://localhost:4318/v1/otlp/v1/traces" ``` For convenience, you can use the tool [`telemetrygen`](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/cmd/telemetrygen) to quickly generate traces data and write it to the OpenTelemetry Collector. For more details, please refer to the [OpenTelemetry Collector official documentation](https://opentelemetry.io/docs/collector/quick-start/). You can use the following command to install `telemetrygen` (please ensure you have installed Go): ```shell go install github.com/open-telemetry/opentelemetry-collector-contrib/cmd/telemetrygen@latest ``` Then you can use the following command to generate traces data and write it to the OpenTelemetry Collector: ```shell telemetrygen traces --otlp-insecure --traces 3 ``` The above command will generate 3 traces data and write it to the OpenTelemetry Collector via gRPC protocol, and eventually stored into GreptimeDB. ### Authorization The GreptimeDB OTEL endpoint supports Basic authentication. For details, please refer to the [authentication](/user-guide/protocols/http.md#authentication) documentation. ### GreptimeDB Pipeline The HTTP header `x-greptime-pipeline-name` is required for ingesting trace data. Here we reuse the Pipeline concept of GreptimeDB for data transformation. However, note that we only support built-in `greptime_trace_v1` as the pipeline for tracing. No custom pipeline is allowed for the moment. ### Append-only Mode By default, trace table created by OpenTelemetry API are in [append only mode](/user-guide/deployments-administration/performance-tuning/design-table.md#when-to-use-append-only-tables). ## Query To query the trace data, GreptimeDB has two types of API provided. The Jaeger compatible API and GreptimeDB's original SQL based query interfaces, which is available in HTTP, MySQL and Postgres protocols. ### Jaeger We build Jaeger compatibility layer into GreptimeDB so you can reuse your Jaeger frontend or any other integrations like Grafana's Jaeger data source. For detail of Jaeger's endpoint and parameters, check [our Jaeger protocol docs](/user-guide/query-data/jaeger.md). ### SQL All data in GreptimeDB is available for query using SQL, via MySQL and other transport protocol. By default, trace data is written into the table called `opentelemetry_traces`. The table name is customizable via header `x-greptime-trace-table-name`. You can run SQL queries against the table: ```sql SELECT * FROM public.opentelemetry_traces \G ``` An example output is like ``` *************************** 1. row *************************** timestamp: 2025-05-07 10:03:29.657544 timestamp_end: 2025-05-07 10:03:29.661714 duration_nano: 4169970 parent_span_id: eccc18b6fc210f31 trace_id: fb60d19aa36fdcb7d14a71ca0b9b42ae span_id: 49806a2671f2ddcb span_kind: SPAN_KIND_SERVER span_name: POST todos/ span_status_code: STATUS_CODE_UNSET span_status_message: trace_state: scope_name: opentelemetry.instrumentation.django scope_version: 0.51b0 service_name: myproject span_attributes.http.request.method: POST span_attributes.url.full: span_events: [] span_links: [] ... ``` We will cover more information about the table structure in [Data Model](./data-model.md) section. --- ## Vector Data Type ## Overview In the field of artificial intelligence, vectors are an important data type used to represent features or samples within a dataset. Vectors are utilized in various machine learning and deep learning algorithms, such as recommendation systems, natural language processing, and image recognition. By introducing the vector type, GreptimeDB enables more efficient support for these AI applications, offering robust vector storage and computation capabilities. ## Basic Introduction to Vector Type In GreptimeDB, a vector is represented as an array of Float32 (32-bit floating-point) with a fixed dimension. When creating a vector type column, the dimension must be specified and cannot be changed afterward. ## Defining a Vector Type Column In SQL, a table with a vector type column can be defined using the following syntax. Note that the dimension `` must be a positive integer that specifies the length of the vector. ```sql CREATE TABLE ( ... VECTOR() ); ``` For example, to define a table with a vector type column of dimension 3: ```sql CREATE TABLE vecs ( ts TIMESTAMP TIME INDEX, vec_col VECTOR(3) ); ``` ## Inserting Vector Data In GreptimeDB, you can insert vector data into the database in several ways. The simplest method is to use a string format and implicitly convert it to a vector. The string needs to be enclosed in square brackets `[]`. Below is an example of using implicit conversion in SQL: ```sql INSERT INTO () VALUES ('[, , ...]'), ('[, , ...]'), ... ('[, , ...]'); ``` For example, to insert three 3-dimensional vectors: ```sql INSERT INTO vecs (ts, vec_col) VALUES ('2024-11-18 00:00:01', '[1.0, 2.0, 3.0]'), ('2024-11-18 00:00:02', '[4.0, 5.0, 6.0]'), ('2024-11-18 00:00:03', '[7.0, 8.0, 9.0]'); ``` If you wish to have more explicit control over data conversion, you can use the `parse_vec` function to explicitly parse a string into a vector: ```sql INSERT INTO vecs (ts, vec_col) VALUES ('2024-11-18 00:00:01', parse_vec('[1.0, 2.0, 3.0]')), ('2024-11-18 00:00:02', parse_vec('[4.0, 5.0, 6.0]')), ('2024-11-18 00:00:03', parse_vec('[7.0, 8.0, 9.0]')); ``` ## Vector Calculations GreptimeDB supports various vector functions for calculating the similarity between vectors, including `vec_l2sq_distance`, `vec_cos_distance`, and `vec_dot_product`. These functions are used in AI applications to search for the most similar content. To perform vector calculations, use the following SQL format: ```sql SELECT (, ) FROM ; ``` For example, to find the vector with the smallest squared Euclidean distance to a given vector `[5.0, 5.0, 5.0]` and display the distance, you can use the following query: ```sql SELECT vec_to_string(vec_col), vec_l2sq_distance(vec_col, '[5.0, 5.0, 5.0]') AS distance FROM vecs ORDER BY distance; ``` Upon executing this query, you will get results similar to the following: ``` +-----------------------------+----------+ | vec_to_string(vecs.vec_col) | distance | +-----------------------------+----------+ | [4,5,6] | 2 | | [1,2,3] | 29 | | [7,8,9] | 29 | +-----------------------------+----------+ 3 rows in set (0.01 sec) ``` Through this approach, GreptimeDB enables you to quickly identify and locate similar data vectors, thus providing robust support for AI applications. For more information about vector functions, please refer to the [Vector Functions Reference](/reference/sql/functions/vector.md). --- ## Region Balancer This plugin balances the write load of regions across datanodes, using specified window sizes and load thresholds to prevent frequent region migrations. You can enable the Auto Rebalancer feature by adding the following configuration to Metasrv. ```toml [[plugins]] [plugins.region_balancer] window_size = "45s" window_stability_threshold = 2 min_load_threshold = "10MB" tick_interval = "45s" ``` ## Configuration Parameters - `window_size`: string - **Description**: Defines the time span for the sliding window used to calculate the short-term average load of a region. This window helps smooth out temporary spikes in load, reducing the chance of unnecessary rebalancing. - **Units**: Time (e.g., `"45s"` represents 45 seconds). - **Recommendation**: Adjust according to load volatility. Larger values smooth more effectively but may delay load balancing responses. - `window_stability_threshold`: integer - **Description**: Specifies the number of consecutive windows that must meet the load-balancing criteria before a region migration is triggered. This threshold helps prevent frequent balancing actions, ensuring region migration only occurs when imbalance is sustained. - **Recommendation**: Higher values delay rebalancing triggers and suit environments with volatile loads; a value of 2 means that at least two consecutive windows must meet the threshold before triggering. - `min_load_threshold`: string - **Description**: Minimum write load threshold (in bytes per second) to trigger region migration. Nodes with load below this value will not trigger rebalancing. - **Units**: Bytes (e.g., `"10MB"` represents 10 MiB). - **Recommendation**: Set an appropriate minimum to avoid triggering region migration with low load. Adjust based on typical traffic. - `tick_interval`: string - **Description**: Interval at which the balancer checks and potentially triggers a rebalancing task. - **Units**: Time (e.g., `"45s"` represents 45 seconds). - **Recommendation**: Set based on desired responsiveness and load volatility. Shorter intervals allow faster responses but may increase overhead. --- ## Management Console The GreptimeDB Enterprise Management Console is an enhanced version of the standard GreptimeDB dashboard, designed specifically for enterprise users who require advanced cluster observability and operational capabilities. It provides comprehensive monitoring, management, and operational tools that go beyond the standard dashboard functionality. ## Overview The **Overview** page displays the overall cluster status and resource usage. - **Service Overview**: CPU, memory, and storage usage; data ingestion rate; request rates by protocol. - **Storage Overview**: Number of databases, tables, and regions; sizes of Manifest, WAL, and Index files. - **Cluster**: Node types; node status and resource usage. ![Overview](/enterprise-console-overview.png) ## Region Management **Region Management** provides region-level operational capabilities for advanced cluster administration. - **Datanodes view**: View details of each datanode and its regions, including region ID, associated table, storage size, WAL/Manifest/Index usage, and row count. - **Tables view**: View region distribution by table with expandable region details for comprehensive analysis. - **Region maintenance**: Execute Flush and Compact operations to optimize storage and performance. - **Region migration**: Migrate regions between nodes with configurable timeout settings and real-time progress tracking. ![Region Management - Datanodes](/enterprise-console-region-datanodes.png) ![Region Management - Tables](/enterprise-console-region-tables.png) ## Data Management The **Data Management** page provides SQL/PromQL queries, data ingestion, logs queries, logs pipelines, traces queries, and Flow management. These features are consistent with the open-source Dashboard and Cloud Dashboard. ## Monitoring The **Monitoring** page provides comprehensive metrics and log monitoring capabilities for enterprise-grade observability. ### Metrics Provides multiple groups of monitoring panels including Overview, Ingestion, Queries, Resources, Frontend Requests, Frontend to Datanode, Mito Engine, OpenDAL, Metasrv, and Flownode. These panels cover essential cluster metrics such as operational status, request rates, latency, and resource utilization. ![Metrics](/enterprise-console-monitor-metrics.png) ### Instance Logs Enables advanced log filtering and analysis with support for filtering by role, instance, log level, time range, and keywords. Log results can be exported to JSON format for further analysis. ![Instance Logs](/enterprise-console-instance-logs.png) ### Slow Query Displays long-running SQL and PromQL queries with detailed execution time and query text information. Includes **Explain Query** functionality for execution plan analysis and query optimization. ![Slow Query](/enterprise-console-slow-query.png) --- ## LDAP Authentication In addition to the built-in [static user provider](/user-guide/deployments-administration/authentication/static.md) in GreptimeDB OSS, GreptimeDB Enterprise offers the capability to connect to an external LDAP server for authentication. ## Configuration Similar to [LDAP in PostgreSQL](https://www.postgresql.org/docs/current/auth-ldap.html), in GreptimeDB, LDAP authentication is operated in two modes: "simple bind" and "search bind", too. In the "simple bind" mode, GreptimeDB will bind to the "DN"(distinguished name) constructed as `{prefix}{username}{suffix}`. Typically, the `prefix` parameter is used to specify `cn=`, and the `suffix` is used to specify the remaining part of the DN. The `username`, of course, is provided by the client. Here's the configuration file example for the "simple bind" mode in GreptimeDB's LDAP user provider: ```toml # Name or IP address of the LDAP server to connect to. server = "127.0.0.1" # Port number on LDAP server to connect to. port = 636 # Set to "ldap" to use LDAP, "ldaps" to use LDAPS. # The connection between GreptimeDB and the LDAP server starts as an initially unencrypted one, # then upgrades to TLS as the first action against the server, per the LDAPv3 standard ("StartTLS"). scheme = "ldaps" # The authentication mode to the LDAP server, either `bind = "simple"` or `bind = "search"`. [auth_mode] # The following options are used in simple bind mode only: bind = "simple" # String to prepend to the username when forming the DN to bind as, when doing simple bind authentication. prefix = "cn=" # String to append to the username when forming the DN to bind as, when doing simple bind authentication. suffix = ",dc=example,dc=com" ``` In the "search bind" mode, GreptimeDB will first try to bind to the LDAP directory with a fixed username and password, which are set in the configuration file (`bind_dn` and `bind_passwd`), Then GreptimeDB performs a search for the user trying to log in to the database. The search will be performed over the subtree at `base_dn`, filtered by the `search_filter`, and will try to do an exact match of the attribute specified in `search_attribute`. Once the user has been found in this search, GreptimeDB re-binds to the directory as this user, using the password specified by the client, to verify that the login is correct. This method allows for significantly more flexibility in where the user objects are located in the directory, but will cause two additional requests to the LDAP server to be made. The following toml snippets show the configuration file example for the "search bind" mode in GreptimeDB's LDAP user provider. The common parts of `server`, `port`, and `scheme` as shown in the "simple bind" mode configuration file above are omitted: ```toml [auth_mode] # The following options are used in search bind mode only: bind = "search" # Root DN to begin the search for the user in, when doing search bind authentication. base_dn = "ou=people,dc=example,dc=com" # DN of user to bind to the directory with to perform the search when doing search bind authentication. bind_dn = "cn=admin,dc=example,dc=com" # Password for user to bind to the directory with to perform the search when doing search bind authentication. bind_passwd = "secret" # Attribute to match against the username in the search when doing search bind authentication. # If no attribute is specified, the uid attribute will be used. search_attribute = "cn" # The search filter to use when doing search bind authentication. # Occurrences of "$username" will be replaced with the username. # This allows for more flexible search filters than search_attribute. search_filter = "(cn=$username)" ``` ## Use LDAP user provider in GreptimeDB To use the LDAP user provider, first config your LDAP authentication mode like above, then start GreptimeDB with the `--user-provider` parameter set to `ldap_user_provider:`. For example, if you have a configuration file `/home/greptimedb/ldap.toml`, you can start a GreptimeDB standalone server with the following command: ```shell greptime standalone start --user-provider=ldap_user_provider:/home/greptimedb/ldap.toml ``` Now you can create a connection to GreptimeDB using your LDAP user accounts. :::tip NOTE If you are using the MySQL CLI to connect to GreptimeDB that is configured with LDAP user provider, you need to specify the `--enable-cleartext-plugin` in the MySQL CLI. ::: --- ## Backup ## Backup Metadata The metadata store of a GreptimeDB cluster can be stored in etcd or a relational database. For production clusters, it is recommended to use cloud provider managed relational database services (RDS) with periodic backup features enabled. Please refer to [Metadata Export & Import documentation](/user-guide/deployments-administration/disaster-recovery/back-up-&-restore-meta-data.md) for the details. ## Backup Database Since object storage typically maintains multiple replicas, if GreptimeDB data is stored on object storage, additional database backups are usually unnecessary. You may also consider enabling versioning features of object storage to prevent data loss from accidental operations. You can also use GreptimeDB's `COPY DATABASE` functionality to create backups. For more information, please refer to the [Data Export & Import documentation](/user-guide/deployments-administration/disaster-recovery/back-up-&-restore-data.md). --- ## Deploy a GreptimeDB Cluster with Datanode Groups In this guide, you will learn how to deploy a GreptimeDB cluster on Kubernetes with a datanode groups consisting of multiple datanode instances. :::tip NOTE This feature is for the Enterprise Edition only. Please do not use open-source image to enable this feature. Please [contact us](https://greptime.com/contactus) if you want to use it. ::: ## Prerequisites - [Docker](https://docs.docker.com/get-started/get-docker/) >= v23.0.0 - [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) >= v1.18.0 - [Helm](https://helm.sh/docs/intro/install/) >= v3.0.0 - [GreptimeDB Operator](https://github.com/GrepTimeTeam/greptimedb-operator) >= v0.3.0 ## Upgrade operator Install the GreptimeDB Operator, setting the image version to be greater than or equal to `v0.3.0`. For detailed instructions on upgrading the operator, please refer to the [GreptimeDB Operator Management](/user-guide/deployments-administration/deploy-on-kubernetes/greptimedb-operator-management.md#upgrade) guide. ## Datanode Groups Configuration In the enterprise edition, you can configure **datanode groups** to separate read and write workloads into different groups. The datanode accepts a `workload_types` field to distinguish its workload type. Supported types are **`hybrid`**, **`query`**, and **`ingest`**: * **`hybrid`** is the default and acts as a superset of `query` and `ingest`, allowing the datanode to handle both workloads. * **`query`** is optimized for read workloads, datanode only handle read workload. * **`ingest`** is optimized for write workloads, datanode only handle write workload. While `hybrid` is convenient, running both reads and writes on the same datanode may cause them to interfere with each other, for example, a large query may occupy too many resources, thus affecting the online ingestion. For best performance, it is recommended to separate read and write workloads into different datanode groups. When configuring datanode groups, ensure that each group includes a `name` field. The following `values.yaml` example demonstrates how to define separate datanode groups: ```yaml danodata: enabled: false datanodeGroups: - name: write replicas: 1 config: | workload_types = ["ingest"] template: main: resources: requests: cpu: '4' memory: 8Gi storage: fs: storageClassName: ${storageClassName} storageSize: 100Gi - name: read replicas: 1 config: | workload_types = ["query"] template: main: resources: limits: cpu: '8' memory: 16Gi meta: replicas: 1 backendStorage: etcd: endpoints: - "etcd.etcd-cluster.svc.cluster.local:2379" frontend: replicas: 1 ``` For guidance on configuring alternative metadata storage backends for Metasrv, refer to the [Metadata Storage Configuration](/user-guide/deployments-administration/manage-metadata/configuration.md) documentation. You can use the following command to apply the configuration: ``` helm upgrade --install ${release-name} greptime/greptimedb-cluster --namespace ${namespace} -f values.yaml ``` ## Verify the Installation Check the status of the pods: ```bash kubectl get pods -n ${namespace} NAME READY STATUS RESTARTS AGE ${release-name}-datanode-read-0 1/1 Running 0 30s ${release-name}-datanode-write-0 1/1 Running 0 30s ${release-name}-flownode-0 1/1 Running 0 60s ${release-name}-frontend-774c76cffc-znvrw 1/1 Running 0 30s ${release-name}-meta-58977b7897-8k2sf 1/1 Running 0 90s ``` ## Next steps - For best performance, it is recommended to [Configure frontend groups](/user-guide/deployments-administration/deploy-on-kubernetes/configure-frontend-groups.md), which ensures complete separation of read and write traffic, achieving maximum isolation. - Add Read Replica for your table, please refer to [Read Replica](/enterprise/read-replicas/overview.md). --- ## GreptimeDB Enterprise Deployment Guide ## Environment Requirements - [Docker](https://docs.docker.com/get-started/get-docker/) >= v23.0.0 - [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) >= v1.21.0 - [Helm](https://helm.sh/docs/intro/install/) >= v3.0.0 - [kubernetes](https://kubernetes.io/) >= 1.21 ## Overview The GreptimeDB Enterprise Edition deployment includes the following components: 1. GreptimeDB Operator: Used to interact with the Kubernetes cluster. 2. KV Store: Used to store database metadata (supports cloud services or self-hosted). It is recommended to use RDS from cloud services such as AWS RDS PostgreSQL. Optional storage facilities include: - PostgreSQL - MySQL - ETCD 3. GreptimeDB Database Cluster, including the following components: - Meta:Database cluster metadata management component - Datanode:Data node - Frontend:Entry point and protocol parsing node - Flownode(optional): Stream computing node - Vector Sidecar:Metrics collection agent - GreptimeDB Standalone: Cluster self-monitoring storage node 4. GreptimeDB Enterprise Dashboard 5. Kafka(optional): Provides Remote WAL for GreptimeDB 6. MinIO(optional): Provides object storage for GreptimeDB. It is recommended to use object storage from cloud services (e.g., AWS S3) Components marked with * are optional: | Pod Component Name | Replicas | CPU (Core) | Memory (GB) | Disk (Gi) | |----------------------------------|----------|------------|-------------|-----------| | ETCD`*` | 3 | 2 | 4 | 10 | | GreptimeDB Operator | 1 | 1 | 1 | | | Meta | | | | | | Datanode | | | | | | Frontend | | | | | | Flownode`*` | | | | | | Vector Sidecar | | | | | | GreptimeDB Standalone | 1 | 4 | 8 | | | GreptimeDB Enterprise Dashboard | 1 | | | | | Kafka`*` | 3 | | | | | MinIO`*` | 4 | | | | ## Deploy GreptimeDB Operator Refer to [GreptimeDB Operator Management Documentation](/user-guide/deployments-administration/deploy-on-kubernetes/greptimedb-operator-management.md) for detailed installation steps. ## Deploy ETCD (Option) Refer to [Manage ETCD](/user-guide/deployments-administration/manage-metadata/manage-etcd.md) for detailed installation steps. ## Deploy Kafka (Option) Refer to [Deploy Kafka Cluster](/user-guide/deployments-administration/deploy-on-kubernetes/deploy-kafka.md) for detailed installation steps. ## Deploy MinIO (Option) Refer to [Deploy MinIO Cluster](/user-guide/deployments-administration/deploy-on-kubernetes/deploy-minio.md) for detailed installation steps. ## Install GreptimeDB Infrastructure Test Refer to [Deploy GreptimeDB Infrastructure test](/user-guide/deployments-administration/deploy-on-kubernetes/deploy-greptimedb-infra-test.md) for detailed installation steps. Tell the test results to Greptimeteam. ## Install and Start GreptimeDB ### Obtain GreptimeDB Enterprise Edition Image GreptimeDB Enterprise Edition is distributed as a Docker image. We provide each customer with a dedicated private Docker repository hosted on Alibaba Cloud. You can pull it directly using the docker pull command or configure it in the Helm chart. You need to configure the image information in the Helm chart's `values.yaml` file to obtain your dedicated GreptimeDB Enterprise Edition, for example: ```yaml customImageRegistry: enabled: true # -- pull secret name, customizable, must match `image.pullSecrets` secretName: greptimedb-custom-image-pull-secret registry: username: password: image: registry: repository: tag: pullSecrets: - greptimedb-custom-image-pull-secret ``` In the above configuration: - `registry`, `username`, and `password` under `customImageRegistry` are used to create the Kubernetes pull secret - `registry`, `repository`, and `tag` under `image` are used to specify the GreptimeDB Enterprise Edition image - Therefore, `customImageRegistry.secretName` and `image.pullSecrets` must match to ensure correct authentication when pulling the image Please contact Greptime staff to obtain the specific values for the above configuration items. When Greptime staff first deliver the GreptimeDB Enterprise Edition to you, they will inform you of the image registry address, username, and password via email or other means. Please keep this information safe and do not share it with external parties! ### Configuration Management The following are tools and documentation that can help with configuration: - tool: https://greptimedb-enterprise-wizard.mrsatangel.workers.dev/ - documentation: [common-helm-chart-configurations](/user-guide/deployments-administration/deploy-on-kubernetes/common-helm-chart-configurations.md) Before installation, you need to create a file to configure the GreptimeDB cluster. Adjust it according to your Kubernetes environment. Below is a reference configuration for `greptimedb-cluster-values.yaml`: ```yaml customImageRegistry: enabled: true # -- pull secret name, customizable, must match `image.pullSecrets` secretName: greptimedb-custom-image-pull-secret registry: username: password: image: registry: repository: tag: pullSecrets: - greptimedb-custom-image-pull-secret additionalLabels: {} initializer: registry: docker.io repository: greptime/greptimedb-initializer tag: "v0.5.6" # -- Meta configuration meta: # -- Meta replicas replicas: 2 backendStorage: # Optional # KV storage configuration, this configuration connects to ETCD etcd: endpoints: ["etcd.etcd-cluster.svc.cluster.local:2379"] # Below is an example using PostgreSQL as the KV store: # postgresql: # host: "postgres.default.svc.cluster.local" # port: 5432 # database: "metasrv" # table: "greptime_metakv" # electionLockID: 1 # credentials: # secretName: "meta-postgresql-credentials" # username: "root" # password: "root" # Below is an example using MySQL as the KV store: # mysql: # host: "mysql.default.svc.cluster.local" # port: 3306 # database: "metasrv" # table: "greptime_metakv" # electionLockID: 1 # credentials: # secretName: "meta-mysql-credentials" # username: "root" # password: "root" podTemplate: main: # Meta resource configuration resources: requests: cpu: '2' memory: 4Gi limits: cpu: '2' memory: 4Gi affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - podAffinityTerm: labelSelector: matchLabels: app.greptime.io/component: greptimedb-meta topologyKey: kubernetes.io/hostname weight: 1 # -- Datanode configuration datanode: # -- Datanode replicas replicas: 3 # -- Datanode configuration configData: |- [[region_engine]] [region_engine.mito] write_cache_size = "20G" write_cache_ttl = "7d" podTemplate: main: # -- Datanode resource resources: requests: cpu: '8' memory: 16Gi limits: cpu: '8' memory: 16Gi affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - podAffinityTerm: labelSelector: matchLabels: app.greptime.io/component: greptimedb-datanode topologyKey: kubernetes.io/hostname weight: 1 # -- Datanode local disk configuration storage: storageClassName: null # -- Local disk size storageSize: 100Gi # -- Storage retain policy for datanode persistent volume storageRetainPolicy: Retain # -- Frontend configuration frontend: # -- Frontend replicas replicas: 3 podTemplate: main: # Frontend resource resources: requests: cpu: '8' memory: 16Gi limits: cpu: '8' memory: 16Gi affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - podAffinityTerm: labelSelector: matchLabels: app.greptime.io/component: greptimedb-frontend topologyKey: kubernetes.io/hostname weight: 1 # -- Flownode configuration flownode: # -- Whether to deploy flownode enabled: false # -- Flownode replicas replicas: 1 podTemplate: main: resources: requests: cpu: '8' memory: 16Gi limits: cpu: '8' memory: 16Gi # -- Database self-monitoring configuration monitoring: # -- Enable self-monitoring enabled: true standalone: base: imagePullSecrets: - name: "greptimedb-custom-image-pull-secret" main: # Self-monitoring resource configuration resources: requests: cpu: '4' memory: 8Gi limits: cpu: '4' memory: 8Gi # Self-monitoring standalone storage location, can be optionally configured for object storage # objectStorage: # s3: # secretName: "greptimedb-object-storage-secret" # bucket: "greptimedb-bucket" # region: "ap-southeast-1" # root: "greptimedb-monitor-data" # endpoint: "http://minio.minio:9000" # Self-monitoring local disk size datanodeStorage: fs: storageClassName: null storageSize: 100Gi # sidecar vector configuration vector: registry: docker.io repository: timberio/vector tag: 0.46.1-debian # sidecar vector resource configuration resources: requests: cpu: '1' memory: 1Gi limits: cpu: '1' memory: "1Gi" # Object storage related configuration, enable as needed # Using MinIO # objectStorage: # existingSecretName: "greptimedb-object-storage-secret" # cache: # cacheCapacity: "50GiB" # s3: # bucket: "greptimedb-bucket" # region: "ap-southeast-1" # root: "greptimedb-data" # endpoint: "http://minio.minio:9000" # Enable Enterprise Edition user and permission configuration auth: enabled: true useBuiltIn: true mountPath: "/etc/greptimedb/auth" fileName: "passwd" users: # Default admin username, modify as needed - username: "superuser" # Initial admin account password, modify as needed password: "1fa44bbc-5ded-42bd-a3f1-c3621affce63" permission: "admin" # Remote WAL related configuration, enable as needed # remoteWal: # enabled: true # kafka: # brokerEndpoints: # - "kafka-broker-0.kafka-broker-headless.kafka.svc.cluster.local:9092" # - "kafka-broker-1.kafka-broker-headless.kafka.svc.cluster.local:9092" # - "kafka-broker-2.kafka-broker-headless.kafka.svc.cluster.local:9092" ``` ### Start GreptimeDB Install the GreptimeDB cluster in the `greptimedb` namespace: ```bash helm upgrade --install greptimedb \ --create-namespace \ greptime/greptimedb-cluster \ -n greptimedb --values greptimedb-cluster-values.yaml ``` Verify the GreptimeDB installation: ```bash kubectl get pod -n greptimedb ```
Expected output ```bash NAME READY STATUS RESTARTS AGE greptimedb-datanode-0 2/2 Running 0 2m33s greptimedb-datanode-1 2/2 Running 0 2m33s greptimedb-datanode-2 2/2 Running 0 2m33s greptimedb-frontend-74999c79cc-pzj8w 2/2 Running 0 17s greptimedb-frontend-74999c79cc-rm2fb 2/2 Running 0 17s greptimedb-frontend-74999c79cc-zbtdg 2/2 Running 0 17s greptimedb-meta-56dc894867-jpt5c 2/2 Running 0 4m29s greptimedb-meta-56dc894867-tpw4c 2/2 Running 0 4m29s greptimedb-meta-56dc894867-wmh1t 2/2 Running 0 4m29s greptimedb-monitor-standalone-0 1/1 Running 0 4m42s ```
## Deploy Enterprise Dashboard ### Configuration Management Before installation, you need to create a file `dashboard-values.yaml` to configure the dashboard. Below is a configuration example: ```yaml replicaCount: 1 image: # Please contact Greptime staff for the value repository: tag: pullPolicy: IfNotPresent imagePullSecrets: - name: greptimedb-custom-image-pull-secret nameOverride: "" fullnameOverride: "" config: | servicePort: 19095 logLevel: info enableLicenseManager: true enableUserAuthentication: true backendStore: type: sqlite sqlite: dataDir: /data provisionedInstances: - name: greptimedb namespace: greptimedb type: cluster settings: basic: url: http://greptimedb-frontend.greptimedb.svc.cluster.local:4000 meta_url: http://greptimedb-meta.greptimedb.svc.cluster.local:4000 monitoring: greptimedb: url: http://greptimedb-monitor-standalone.greptimedb.svc.cluster.local:4000 license: secret_name: greptimedb-license secret_namespace: greptimedb servicePort: 19095 serviceAccount: create: true annotations: {} name: "" podAnnotations: {} podSecurityContext: {} # fsGroup: 2000 securityContext: {} service: type: ClusterIP port: 19095 annotations: {} resources: requests: cpu: '1' memory: 1Gi limits: cpu: '1' memory: 1Gi nodeSelector: {} tolerations: [] affinity: {} ``` ### Install ```bash helm upgrade --install greptimedb-enterprise-dashboard \ oci://greptime-registry.cn-hangzhou.cr.aliyuncs.com/charts/greptimedb-enterprise-dashboard \ -n greptimedb \ --values dashboard-values.yaml ``` Verify the Enterprise Dashboard installation: ```bash kubectl get pod -n greptimedb | grep enterprise-dashboard ```
Expected output ```bash greptimedb-enterprise-dashboard-67f498d6f9-n89z5 1/1 Running 0 27s ```
```bash kubectl get svc -n greptimedb | grep enterprise-dashboard ```
Expected output ```bash greptimedb-enterprise-dashboard ClusterIP 10.96.80.175 19095/TCP 89s ```
### Login Access port 19095 of the dashboard service to log in. ![Enterprise Dashboard Login](/enterprise-dashboard-login.png) Log in using the `auth.users[0].username` and `auth.users[0].password` from the database deployment configuration. For more console operation reference [documentation](/enterprise/console-ui.md). --- ## Deploy GreptimeDB on Kubernetes(Deploy-on-kubernetes) The deployment process for GreptimeDB Enterprise on Kubernetes is almost the same as the open-source version. This chapter focuses on the specific deployment configurations and features of the enterprise version. ## Installation To learn how to start GreptimeDB through Helm Chart, please see the [Install GreptimeDB](./installation.md) page. ## Upgrade Please visit the [Upgrade GreptimeDB](./upgrade.md) page to learn how to upgrade GreptimeDB enterprise. --- ## Upgrade(Deploy-on-kubernetes) ## Upgrade Cluster with GreptimeDB Operator Upgrading the GreptimeDB Enterprise Edition image is straightforward. Simply modify the `tag` in the Helm chart and restart. ## Upgrading Cluster Without GreptimeDB Operator When upgrading a cluster without the GreptimeDB Operator, you must manually enable Metasrv maintenance mode before operating on each component (e.g., rolling upgrade of Datanode nodes). After the upgrade is complete, wait for all components to return to a healthy state before disabling Metasrv maintenance mode. When Metasrv maintenance mode is enabled, the Auto Balancing (if enabled) and Region Failover (if enabled) mechanisms in the cluster will be suspended until maintenance mode is disabled. Please refer to [Managing Maintenance Mode](/user-guide/deployments-administration/maintenance/maintenance-mode.md#managing-maintenance-mode) for detailed instructions on how to enable and disable Metasrv maintenance mode. --- ## DR Solution Based on Active-Active Failover In GreptimeDB's "Active-Active Failover" architecture, two nodes are typically deployed (for example, node A and node B): - Both nodes provide full service capabilities to clients. - The two nodes are peers. Neither node is a long-term fixed single primary. - Writes use bidirectional asynchronous replication. A write accepted by either node is replicated to the peer node. - GreptimeDB's architecture prevents circular replication. - Queries are executed locally on each node. No cross-node query result merge is required. The goal of this model is to provide cross-node disaster recovery with relatively low architecture complexity, without introducing a third compute node or metadata node. ## Architecture and Read/Write Paths ### Write path 1. The client sends a write request to node A (or node B). 2. The receiving node persists the write locally, then returns success to the client. 3. The receiving node asynchronously replicates the write request to the peer node. - If too many write requests remain unreplicated (threshold is configurable), the node can pause client writes to help meet RPO and RTO targets. ### Query path - Queries run locally on the node that the client connects to. - The model does not depend on real-time query merge across two nodes. - As long as either node is available, the query path can continue serving traffic. - Due to the nature of async replication, we can achieve eventually consistency in this setup. ## RPO and RTO ### RPO Different configurations can achieve different RPO targets. The key configuration is the amount of reserved space for write requests pending replication. If this space is set to `0` (bytes), asynchronous replication effectively becomes synchronous replication, and RPO is `0`. For other values, RPO can be calculated dynamically based on write size and write throughput. ### RTO RTO depends on your node failover strategy. Different failover methods and configurations can achieve different RTO targets. See "Failover Implementation Methods" below. ## Failover Implementation Methods To retain the minimality of requirements of our active-active architecture, we don't have a third node or a third service to handle the failover of GreptimeDB. Generally speaking, there are several ways to handle the failover: - Through a LoadBalancer. If you can spare another node for deploying a LoadBalancer like the [HAProxy](https://www.haproxy.org/), or if you have your own LoadBalancer service can be used, we recommend this way. - By client SDK's failover mechanism. For example, if you are using MySQL Connector/j, you can configure the failover by setting multiple hosts and ports in the connection URL (see its document [here](https://dev.mysql.com/doc/connector-j/en/connector-j-config-failover.html)). PostgreSQL's driver [has the same mechanism](https://jdbc.postgresql.org/documentation/use/#connection-fail-over). This is the most easy way to handle the failover, but not every client SDK supports this failover mechanism. - Custom endpoint update mechanism. If you can detect the fall of nodes, you can retroactively update the GreptimeDB's endpoint set in your code. :::tip NOTE To compare the RPO and RTO across different disaster recovery solutions, please refer to "[Solution Comparison](/user-guide/deployments-administration/disaster-recovery/overview.md#solution-comparison)". ::: ## Summary The core of GreptimeDB's active-active failover DR solution is: - Two peer nodes with bidirectional asynchronous write replication. - Local query execution on each node. - Fast recovery from single-node failures through external failover mechanisms. Under this model, the architecture remains simple, and both RPO and RTO targets are explicit and configurable. This disaster recovery solution could be best suited for small-to-medium size business scenarios. --- ## Disaster Recovery(Disaster-recovery) As a distributed database, GreptimeDB provides different disaster recovery (DR) solutions. Please refer to the [Disaster Recovery Overview](/user-guide/deployments-administration/disaster-recovery/overview.md) in the GreptimeDB OSS documentation to learn about all the disaster recovery solutions provided by Greptime. This section only introduces the solutions provided in GreptimeDB Enterprise. - [DR Solution Based on Active-Active Failover](./dr-solution-based-on-active-active-failover.md) --- ## Audit Logging Database audit logging is the process of recording the actions performed on the database. The audit logs help monitor user activities, detect suspicious actions, and ensure compliance with regulations inside or outside of an organization. This document provides an overview of audit logging in GreptimeDB and how to configure it. ## Overview A statement (SQL or PromQL) that is executed on GreptimeDB is recorded in the audit log (if it is configured to be audited, of course). This is an example record in the audit log: ```json { "time": "2024-11-05T06:13:19.903713Z", "user": "greptime_user", "source": "Mysql", "class": "Ddl", "command": "Create", "object_type": "Database", "object_names": [ "audit_test" ], "statement": "CREATE DATABASE audit_test" } ``` As you can see, the record is formatted as a JSON string. It contains the following fields: - `time`: The time when the statement was executed. It's formatted as an ISO 8601 date and time string with UTC timezone. - `user`: The user who sends the request. - `source`: The protocol used to connect to GreptimeDB. - `class`: The class of the statement, like "Read", "Write" or "DDL" etc. - `command`: The command of the statement, like "Select", "Insert" or "Create" etc. - `object_type`: The type of the object that the statement operates on, like "Database", "Table" or "Flow" etc. - `object_names`: The names of the objects that the statement operates on. - `statement`: The statement itself. ## Configuration Audit logging is provided as a plugin in GreptimeDB. To enable and configure it, add the following TOML to your GreptimeDB config file: ```toml [[plugins]] # Add the audit log plugin to your GreptimeDB. [plugins.audit_log] # Whether to enable audit logging, defaults to true. enable = true # The directory to store the audit log files. Defaults to "./greptimedb_data/logs". dir = "./greptimedb_data/logs/" # The allowed auditing sources. This option works as a filter: # if a statement is not coming from one of these configured sources, it won't be recorded in the audit logs. # Multiple sources are separated by comma(","). # All sources are: "Http", "Mysql" and "Postgres". # A special "all" (which is the default value) means all the sources. sources = "all" # The allowed auditing classes. This option works as a filter: # if a statement's class do not match one of these configured values, it won't be recorded in the audit logs. # Multiple classes are separated by comma(","). # All classes are: "Read", "Write", "Admin", "DDL" and "Misc". # A special "all" means all the classes. # Defaults to "DDL" and "Admin". classes = "ddl,admin" # The allowed auditing commands. This option works as a filter: # if a statement's command do not match one of these configured values, they won't be recorded in the audit logs. # Multiple commands are separated by comma(","). # All commands are: "Promql", "Select", "Copy", "Insert", "Delete", "Create", "Alter", "Truncate", "Drop", "Admin" and "Misc". # A special "all" (which is the default value) means all the commands. commands = "all" # The allowed auditing object types. This option works as a filter: # if a statement's target object do not match one of these configured values, they won't be recorded in the audit logs. # Multiple object types are separated by comma(","). # All object types are: "Database", "Table", "View", "Flow", "Index", and "Misc". # A special "all" (which is the default value) means all the object types. object_types = "all" # The max retained audit log files. Defaults to 30. # A audit log is rotated daily. max_log_files = 30 ``` ## Caveats Audit logs can be huge if not properly configured. For example, in a busy loaded GreptimeDB, setting "`all`" to all the `sources`, `classes`, `commands` and `object_types` will record all the statements executed on GreptimeDB, resulting in a very large audit log file. That could easily explode the disk space. So, it's highly recommended to configure the audit log plugin properly to avoid such a situation. --- ## Check GreptimeDB Status(Monitoring) Please refer to the [OSS GreptimeDB documentation](/user-guide/deployments-administration/monitoring/check-db-status.md) for details on how to check the health status of GreptimeDB. --- ## Key Logs(Monitoring) During operation, GreptimeDB outputs key operations and unexpected error information to logs. You can use these logs to understand GreptimeDB's operational status and troubleshoot errors. ## GreptimeDB Operational Logs Refer to the [important logs](/user-guide/deployments-administration/monitoring/key-logs.md) outlined in the GreptimeDB OSS documentation for recommended monitoring practices. ## License Expiration Logs For the Enterprise Edition of GreptimeDB, it is crucial to monitor license expiration logs to ensure uninterrupted access to enterprise features. When the license expires, the metasrv component will generate the following warning log. Promptly contact GreptimeDB to renew your license: ```bash License is expired at xxx, please contact your GreptimeDB vendor to renew it ``` --- ## Key Metrics The key metrics for monitoring include CPU, memory, disk I/O, and network bandwidth usage. ## Alert Metrics Since each company typically has its own alerting system with potentially different configuration methods, this document does not provide specific alert configuration procedures. Instead, it lists key metrics that should be monitored. You can configure alerts based on whether these metrics remain at abnormal values for extended periods (several minutes). You should set alert thresholds according to your specific circumstances. | Metric | Description | Reference Rule | | --- | --- | --- | | `sum(process_resident_memory_bytes{}) by (instance, pod)` | Process memory usage | Usage rate continuously exceeds threshold | | `sum(rate(process_cpu_seconds_total{}[$__rate_interval]) * 1000) by (instance, pod)` | Process CPU usage, displayed in millicores | Utilization rate continuously exceeds threshold | | `sum by(instance, pod) (greptime_mito_write_stall_total{instance=~"$datanode"})` | Number of backlogged write requests on datanode | Remains greater than 0 for n minutes | | `sum(rate(greptime_table_operator_ingest_rows{instance=~"$frontend"}[$__rate_interval]))` | Current rows written per second | Drops to 0 (or below threshold) for n minutes | | `greptime_mito_compaction_failure_total` | Compaction failures | Recent increase greater than 0 | | `greptime_mito_flush_failure_total` | Flush failures | Recent increase greater than 0 | | `sum by(instance, pod, path, method, code) (rate(greptime_servers_http_requests_elapsed_count{path!~"/health\|/metrics"}[$__rate_interval]))` | HTTP request count and response codes | HTTP 200 request count below threshold for n minutes or non-200 response count above normal threshold for n minutes | | `sum by (instance, pod) (rate(greptime_mito_write_rows_total{instance=~"$datanode"}[$__rate_interval]))` | Storage engine write row count | Below normal threshold for n minutes | We also recommend configuring disk alerts at the Pod level to trigger when disk usage exceeds a certain threshold. Additionally, you can monitor the following events based on keywords from error logs listed in the operational [key logs](key-logs.md): - Region lease renewal failures - Region failover --- ## Monitoring(Monitoring) Effective database management relies heavily on monitoring. You can monitor GreptimeDB using the following methods: --- ## Deployments & Administration(Deployments-administration) Before reading this document, it is recommended to review the [Deployments & Administration documentation](/user-guide/deployments-administration/overview.md) of the GreptimeDB open-source database version, which covers all features that are also available in the enterprise edition. The following sections describe the enterprise-specific features and capabilities. ## Configuration and Deployment - [Deploy GreptimeDB Enterprise on Kubernetes](./deploy-on-kubernetes/overview.md): Learn how to obtain the dedicated GreptimeDB Enterprise image. - [LDAP Authentication](authentication.md): Enhanced authentication capabilities for GreptimeDB Enterprise. ## Monitoring The [monitoring](./monitoring/overview.md) section describes the enterprise version specific metrics and logs. ## Disaster Recovery The [disaster recovery](./disaster-recovery/overview.md) section provides strategies and best practices for ensuring data durability and availability in GreptimeDB Enterprise. --- ## Aggregation Queries ## Metric Aggregations In GreptimeDB, metric aggregations are used to perform statistical calculations on numeric fields, such as sum, average, maximum, minimum, etc. | Aggregation | Status | Description | | ----------- | ------ | ------------------------------------------------------------ | | sum | | Aggregates to calculate the sum of numeric fields. | | avg | | Aggregates to calculate the average of numeric fields. | | max | | Aggregates to calculate the maximum value of numeric fields. | | min | | Aggregates to calculate the minimum value of numeric fields. | | count | ✅ | Aggregates to calculate the number of documents. | ## Bucket Aggregations In GreptimeDB, bucket aggregations are used to group documents, such as bucketing by time, category, or other fields. | Aggregation | Status | Description | | -------------- | ------ | ------------------------------------------ | | date_histogram | ✅ | Aggregates to bucket by time fields. | | terms | | Aggregates to group by values of specified | --- ## GreptimeDB Elasticsearch Compatible Overview # Overview The Elasticsearch compatibility layer in GreptimeDB is designed to provide a certain degree of compatibility with Elasticsearch, allowing users to migrate existing Elasticsearch applications to GreptimeDB with relative ease. However, GreptimeDB does not fully support all features and functionalities of Elasticsearch. In some cases, users may need to adjust or modify their applications to achieve the same functionality in GreptimeDB. ## Principle Essentially, GreptimeDB receives Elasticsearch QueryDSL syntax, converts it to GreptimeDB's query syntax, and returns data in the Elasticsearch API format to achieve compatibility. ## Supported API List | API | Method | Description | | ------------------------------ | ------ | -------------------- | | /\{table_name\}/\_search | POST | Execute search query | | /\{table_name\}/\_async_search | POST | Execute search query | | /\_resolve/index/\{schema_name\} | POST | Index document | | /\{table_name\}/\_field_caps | GET | Get field info | ## Supported Query List | Query | Description | | ------------ | ----------------- | | match | Match query | | match_phrase | Phrase match | | match_all | Match all | | term | Exact match | | prefix | Prefix match | | range | Range query | | exists | Field existence | | bool | Compound query | | aggregation | Aggregation query | ## Supported Aggregation List | Aggregation | Status | Description | | -------------- | ------ | -------------- | | avg | | Average value | | sum | | Sum | | min | | Minimum value | | max | | Maximum value | | count | ✅ | Count | | date_histogram | ✅ | Date histogram | | histogram | | Histogram | | terms | | Terms | ## Querying GreptimeDB with Kibana For more information, please contact us. --- ## Query Since GreptimeDB and Elasticsearch are designed for different purposes, many features are not compatible. We have provided corresponding alternatives as much as possible. For each specific interface, we will explain GreptimeDB's implementation and the differences from Elasticsearch. :::tip All features related to boost scores are not supported. The `_id` field is not automatically added or maintained. If you need to use it, please include this field in your original data. Using @timestamp as a time field is not supported. It is not allowed to include both query and aggregation in the same request. ::: ## Query Syntax ### match In GreptimeDB, the `match` query is used to match one or more terms in a text field. The following options are not supported: analyzer, auto_generate_synonyms_phrase_query, fuzziness, max_expansions, prefix_length, fuzzy_transpositions, fuzzy_rewrite, lenient, operator, minimum_should_match, zero_terms_query. ### match_phrase In GreptimeDB, the `match_phrase` query is used to match a phrase in a text field. Different queries are generated based on the data type. If the data type is text, it is converted to a LIKE query. For other data types, it is converted to an equivalent value query. The following options are not supported: analyzer, auto_generate_synonyms_phrase_query, fuzziness, max_expansions, prefix_length, fuzzy_transpositions, fuzzy_rewrite, lenient, operator, minimum_should_match, zero_terms_query. ### match_all In GreptimeDB, the `match_all` query is used to match all documents. ### term In GreptimeDB, the `term` query is used to match an exact value in a text field. The query is mainly converted to an equality query. Currently, case_insensitive is not supported. ### prefix In GreptimeDB, the `prefix` query is used to match a prefix in a text field. The query is mainly converted to a LIKE query. For example, if you query for text starting with `yi`, it will be converted to `LIKE 'yi%'`. The following options are not supported: rewrite, case_insensitive. ### range In GreptimeDB, the `range` query is used to match a range in a text field. The query is mainly converted to greater than or equal to and less than or equal to conditions. Currently, format, relation, time_zone, and boost are not supported. ### exists In GreptimeDB, the `exists` query is used to match values that exist in a text field. The query is mainly converted to an existence condition. ### bool In GreptimeDB, the `bool` query is used to match multiple query conditions. The query is mainly converted to a combination of AND and OR conditions. --- ## Enterprise GreptimeDB Enterprise is a powerful time-series database solution designed to meet the specific needs of enterprises. In addition to the features available in the open-source version of GreptimeDB, the Enterprise edition offers enhancements that help businesses optimize data efficiency and significantly reduce costs, enabling smarter and faster decision-making with time-series data. GreptimeDB Enterprise solutions include: - **Bring Your Own Cloud (BYOC)**: Leverage your own cloud infrastructure to host GreptimeDB, offering extensive customization and flexibility tailored to your business needs. This service includes comprehensive management of your cloud resources and robust security measures to protect your infrastructure. - **Fully Managed Dedicated Cloud**: GreptimeDB team offers a fully managed, dedicated cloud environment, ensuring peak performance, enhanced security, and exceptional reliability tailored to your enterprise needs. - **[Edge-Cloud Integrated Solution](https://greptime.com/product/carcloud)**: A comprehensive solution for managing time-series data from edge devices to the cloud, enabling real-time analytics and insights across your entire infrastructure. - Industry-specific solutions for the Internet of Things (IoT), observability, and more. ## Features GreptimeDB Enterprise supports all features available in the open-source version, which you can read about in the [User Guide](/user-guide/overview.md) documentation. To understand the differences between the open-source and enterprise versions, please visit our [Pricing Page](https://greptime.com/pricing) or [contact us](https://greptime.com/contactus). GreptimeDB Enterprise includes the following advanced features, which are described in detail in the documentation in this section: - [Active-Active Failover Disaster Recovery Solution](./deployments-administration/disaster-recovery/overview.md): Ensure uninterrupted service and data protection with advanced disaster recovery solution. - [LDAP Authentication](./deployments-administration/authentication.md): Secure your system with LDAP-based authentication for access management. - [Audit Logging](./deployments-administration/monitoring/audit-logging.md): Track and monitor user activity with detailed audit logs. - [Automatic region load balance](./autopilot/region-balancer.md): Auto balance datanodes workload by moving regions between them. - [Elasticsearch query compatibility](./elasticsearch-compatible/overview.md): Use GreptimeDB backed Kibana for your logs. - [Greptime Enterprise Management Console](./console-ui.md): An enhanced version of our dashboard UI, carries more cluster management and monitoring features. - [Read Replica](./read-replicas/overview.md): Read-only datanode instances for heavy query workloads such as analytical queries. - [Triggers](./trigger.md): Periodically evaluate your rules and trigger external webhook. Compatible with Prometheus AlterManager. - [Built-in User Management](./user.md): Built-in RBAC and fine-grained ACLs for data security and isolation. - Reliability features for Flow. ## Release Notes - [25.05](./release-notes/release-25_05.md) - [24.11](./release-notes/release-24_11.md) --- ## Manage Read Replicas This guide explains how to manage **Read Replicas (follower regions)** in GreptimeDB Enterprise, including how to add and remove read replicas at both the table and region levels, inspect the current regions distribution with the `SHOW REGION`, and apply placement constraints and recommended best practices for performance. :::warning Warning Read Replicas (Follower Regions) require [object storage](/user-guide/deployments-administration/configuration.md#storage-options) (e.g., AWS S3). Because Follower Regions may be scheduled onto different Datanodes, they must share access to Region data through object storage. Clusters using only local storage are not supported. Before allowing queries to read from Follower Regions, ensure that [GC](/user-guide/deployments-administration/manage-data/gc.md) is enabled on Metasrv and all Datanodes. Reading from Follower Regions is only supported when GC is enabled. ::: ## Adding Read Replicas to a Table Adding a Read Replica is as simple as executing one SQL command: ```sql ADMIN ADD_TABLE_FOLLOWER() ``` Read Replica peers for each region are allocated based on the workload types of the datanodes. **For optimal performance, it is strongly recommended to [configure Datanode groups](/enterprise/deployments-administration/deploy-on-kubernetes/configure-datanode-groups.md) to separate read and write workloads into different datanode groups.** This is the function in GreptimeDB for adding read replicas to. The parameters are: - `table_name`: The name of the table to add read replicas to. Next is an example to illustrate steps to add read replicas to a table. First start a GreptimeDB Enterprise Cluster with 3 Datanodes. Then create a table: ```sql CREATE TABLE foo ( ts TIMESTAMP TIME INDEX, i INT PRIMARY KEY, s STRING, ) PARTITION ON COLUMNS ('i') ( i <= 0, i > 0, ); ``` Using the `SHOW REGION`, we can find the regions distribution information: ```sql SHOW REGION FROM foo; +-------+---------------+------+--------+ | Table | Region | Peer | Leader | +-------+---------------+------+--------+ | foo | 4398046511104 | 0 | Yes | | foo | 4398046511105 | 1 | Yes | +-------+---------------+------+--------+ ``` This shows two write replicas (leader regions) on Datanodes `1` and `2`. Then to add read replicas (Follower regions): ```sql ADMIN ADD_TABLE_FOLLOWER('foo'); ``` After the read replicas are added, find the regions distribution information: ```sql SHOW REGION FROM foo; +-------+---------------+------------+--------+ | Table | Region | Peer | Leader | +-------+---------------+------------+--------+ | foo | 4398046511104 | 0 | Yes | | foo | 4398046511104 | 4294967296 | No | | foo | 4398046511105 | 1 | Yes | | foo | 4398046511105 | 4294967297 | No | +-------+---------------+------------+--------+ ``` Now, read replicas can be found on Datanode `4294967296` and `4294967297`. ## Removing Read Replicas from a Table Removing a Read Replica is as simple as executing one SQL command: ```sql ADMIN REMOVE_TABLE_FOLLOWER() ``` This is the function in GreptimeDB for removing read replicas from a table. The parameters are: - `table_name`: The name of the table to remove read replicas from. This command removes **the most recently added read replica' peers from each region**. For example, before running the command: ```sql SHOW REGION FROM foo; +-------+---------------+------------+--------+ | Table | Region | Peer | Leader | +-------+---------------+------------+--------+ | foo | 4398046511104 | 0 | Yes | | foo | 4398046511104 | 4294967296 | No | | foo | 4398046511104 | 4294967297 | No | | foo | 4398046511105 | 1 | Yes | | foo | 4398046511105 | 4294967296 | No | | foo | 4398046511105 | 4294967297 | No | +-------+---------------+------------+--------+ ``` Here, region `4398046511104` has two read replicas on peers (`4294967296`, `4294967297`), and region `4398046511105` also has two read replicas on peers (`4294967296`, `4294967297`). After executing: ```sql ADMIN REMOVE_TABLE_FOLLOWER('foo'); +------------------------------------+ | ADMIN REMOVE_TABLE_FOLLOWER('foo') | +------------------------------------+ | 0 | +------------------------------------+ ``` The most recently added read replicas' peers of each region are removed: * Region `4398046511104`: removed read replica on peer `4294967297`. * Region `4398046511105`: removed read replica on peer `4294967296`. Result: ```sql SHOW REGION FROM foo; +-------+---------------+------------+--------+ | Table | Region | Peer | Leader | +-------+---------------+------------+--------+ | foo | 4398046511104 | 0 | Yes | | foo | 4398046511104 | 4294967296 | No | | foo | 4398046511105 | 1 | Yes | | foo | 4398046511105 | 4294967297 | No | +-------+---------------+------------+--------+ ``` ## Adding Read Replica to a Region ```sql ADMIN ADD_REGION_FOLLOWER(, ) ``` This is the function in GreptimeDB for adding read replicas to a region. The parameters are: - `region_id`: The id of the region to add Read Replica to. - `datanode_id`: The id of the datanode to add Read Replica to. A read replica and a write replica cannot be placed on the same datanode. Additionally, each datanode can host only one read replica per region. Example: ```sql -- Add a read replica for region 4398046511104 on datanode 2 ADMIN ADD_REGION_FOLLOWER(4398046511104, 2); ``` If the specified datanode already hosts a read replica for that region, or is the write replica (leader) of that region, the command will be rejected. ## Removing Read Replica from a Region ```sql ADMIN REMOVE_REGION_FOLLOWER(, ) ``` This is the function in GreptimeDB for removing read replicas from a region. The parameters are: - `region_id`: The id of the region to remove read replica from. - `datanode_id`: The id of the datanode to remove read replica from. Example: ```sql -- Remove the read replica on datanode 2 for region 4398046511104 ADMIN REMOVE_REGION_FOLLOWER(4398046511104, 2); ``` ## Next steps * [Query Read Replicas](/enterprise/read-replicas/query-read-replicas.md) --- ## GreptimeDB Read Replicas Overview # Overview Read Replicas are a key feature in GreptimeDB's Enterprise Cluster Edition, designed to enhance the overall read-write performance and scalability of the database system. :::warning Warning Read Replicas (Follower Regions) require [object storage](/user-guide/deployments-administration/configuration.md#storage-options) (e.g., AWS S3). Because Follower Regions may be scheduled onto different Datanodes, they must share access to Region data through object storage. Clusters using only local storage are not supported. Before allowing queries to read from Follower Regions, ensure that [GC](/user-guide/deployments-administration/manage-data/gc.md) is enabled on Metasrv and all Datanodes. Reading from Follower Regions is only supported when GC is enabled. ::: In the Read Replica mechanism, clients write data to the **Leader Region (write replica)**, which then synchronizes the data to **Follower Regions (read replicas)**. Follower Regions serve as read-only replicas of the Leader Region. By [configuring Datanode groups](/enterprise/deployments-administration/deploy-on-kubernetes/configure-datanode-groups.md), Leader Regions and Follower Regions can be deployed on different Datanode nodes, read and write requests are effectively isolated, preventing resource contention and delivering a smoother experience: ## Principles GreptimeDB's Enterprise Cluster Edition leverages its architecture to enable near-zero-cost data synchronization between replicas. Additionally, Read Replicas can access newly written data with minimal latency. Below is a brief explanation of the data synchronization and read mechanisms. ### Data Synchronization In GreptimeDB, storage and compute resources are disaggregated. All data is stored in SST files on object storage. Thus, synchronizing data between Leader and Follower Regions does not require copying SST files -- only their metadata needs to be synced. Metadata is significantly smaller than SST files, making synchronization effortless. Once metadata is synced, the Read Replica "possesses" the same SST files and can access the data: ![read-replica-data-sync](/read-replica-data-sync.png) In practice, SST files metadata is persisted in a special manifest file, also stored in object storage. Each manifest file has a unique version number. Synchronizing metadata between Leader and Follower Regions essentially involves syncing this version number -- a simple integer, ensuring minimal overhead. After receiving the version number, the Follower Region fetches the manifest file from object storage, thereby obtaining the SST files metadata generated by the Leader Region. The manifest version number is synchronized via heartbeats between Regions and Metasrv. The Leader Region includes the version number in its heartbeat to Metasrv, which then forwards it to Follower Regions in their heartbeat responses: ![read-replica-heartbeat](/read-replica-heartbeat.png) It's easy to see, if there were only SST files synchronization mechanism in place, the delay for Read Replica to access written data would be the sum of the heartbeat intervals between Leader/Follower Regions and Metasrv. For example, with a default 3-second heartbeat interval, Read Replica would only see the data that are written to SST files and flushed to object store 3 to 6 seconds prior. While this suffices for clients with relaxed freshness requirements, additional mechanisms are needed for near-real-time reads. ### Data Read Newly written data are stored in the Leader Region’s memtable. To access the latest data, Follower Region needs to request the memtable data from the Leader Region. By combining this with SST files data (obtained via data sync above), the Follower Region provides clients with a complete dataset, including the most recent writes: Follower Region fetch memtable data from Leader Region via an internal gRPC interface. While this imposes some read load on the Leader Region, the impact is minimal since the memtable data resides in memory and is finite in size. ## Next steps * [Manage Read Replicas](/enterprise/read-replicas/manage-read-replicas.md) * [Query Read Replicas](/enterprise/read-replicas/query-read-replicas.md) --- ## Query Read Replicas GreptimeDB allows you to read from **Region Replicas (follower regions)** to reduce load on Write Replicas (Leader regions) and improve query scalability. You can control the read preference through both **SQL** and **HTTP** protocols. :::warning Warning Read Replicas (Follower Regions) require [object storage](/user-guide/deployments-administration/configuration.md#storage-options) (e.g., AWS S3). Because Follower Regions may be scheduled onto different Datanodes, they must share access to Region data through object storage. Clusters using only local storage are not supported. Before allowing queries to read from Follower Regions, ensure that [GC](/user-guide/deployments-administration/manage-data/gc.md) is enabled on Metasrv and all Datanodes. Reading from Follower Regions is only supported when GC is enabled. ::: ## Read Preference Options The `READ_PREFERENCE` setting accepts the following values: * **`leader`** Always read from write replicas. * **`follower`** Read only from read replicas The query will fail if no read replicas exist. * **`follower_preferred`** Prefer read replicas but fall back to write replicas if read replicas are unavailable. ## SQL Protocol You can set the read preference in a SQL session: ```sql SET READ_PREFERENCE = 'follower'; ``` --- ## HTTP Protocol For HTTP requests, specify the `X-Greptime-Read-Preference` header. Example: ```bash curl -X POST \ -H "Content-Type: application/x-www-form-urlencoded" \ -H "X-Greptime-Read-Preference: follower" \ -d "sql=select * from monitoring" \ http://localhost:4000/v1/sql ``` --- ## Example: Reading from Read Replicas Before reading from Read Replicas, you need to add Read Replicas to the table. See [Replica Management](/enterprise/read-replicas/manage-read-replicas.md) for more details. Insert some data into a table: ```sql INSERT INTO foo (ts, i, s) VALUES (1, -1, 's1'), (2, 0, 's2'), (3, 1, 's3'); ``` Set the read preference to read replicas: ```sql SET READ_PREFERENCE = 'follower'; ``` Query the data: ```sql SELECT * FROM foo ORDER BY ts; +----------------------------+------+------+ | ts | i | s | +----------------------------+------+------+ | 1970-01-01 00:00:00.001000 | -1 | s1 | | 1970-01-01 00:00:00.002000 | 0 | s2 | | 1970-01-01 00:00:00.003000 | 1 | s3 | +----------------------------+------+------+ ``` --- ## Verifying Follower Reads To confirm that queries are served by read replicas, use `EXPLAIN ANALYZE`: ```sql EXPLAIN ANALYZE SELECT * FROM foo ORDER BY ts; ``` * A **non-zero `other_ranges`** value indicates read replicas were involved. * With the `VERBOSE` option, you can see details like this: ```plaintext extension_ranges: [LeaderMemtableRange{leader: Peer { id: 1, addr: "192.168.50.189:14101" }, num_rows: 2, time_range: (1::Millisecond, 2::Millisecond) ... ``` If the query runs only on leaders, this `extension_ranges` section will not appear. --- ## Release 24.11 We are pleased to introduce the 24.11 release of GreptimeDB Enterprise. ## Feature Highlights ### Region Rebalance To enhance the overall resilience of GreptimeDB, region rebalancing enables flexible relocation of regions among data nodes, whether initiated manually or dynamically. This proactive approach facilitates several key benefits, including redistributing workload across nodes and efficiently migrating regions to ensure uninterrupted operation during planned maintenance activities. ### GreptimeDB Enterprise Management Console Introducing the Console UI for Managing GreptimeDB Enterprise This initial release provides a comprehensive set of features, including: * In-depth slow query analysis and troubleshooting * Detailed cluster topology information * Real-time cluster metrics and log viewer ### LDAP User Provider Bridging your own LDAP user database and authentication to GreptimeDB Enterprise. We implemented flexible configuration options for LDAP connections, supporting both simple and complex authentication mechanisms. ### Audit Logs We provided logs to track queries in the database, with information of: - Query type: read, write, DDL or others - Command: select, insert, etc. - Object type: target of the operation, for example, table, database, etc. ## Features From GreptimeDB OSS This release is based on GreptimeDB OSS v0.10. The OSS base introduces a few new features includes - Vector data type support for similarity search. - Secondary index update: user can now create secondary index on any columns. - Alter table options are added for updating table TTL, compaction parameters and full-text index settings. - JSON data type and functions support. - More geospatial UDF: spatial relation and measurement, S2 index and etc. - Initial release of Loki remote write support. See [this](https://docs.greptime.com/release-notes/release-0-10-0) for a complete changelog of 0.10 --- ## GreptimeDB Enterprise 25.05 We are pleased to introduce the 25.05 release of GreptimeDB Enterprise. ## Feature Highlights ### Elasticsearch Compatibility The compatibility layer in GreptimeDB Enterprise for Elasticsearch. This layer allows user to configure GreptimeDB Enterprise as the backend of Kibana UI, for log search, aggregation and dashboard. Queries supported in this release: - match - match_all - multi_match - term - terms - prefix - wildcard - regexp - range - exists - bool ### Read Replicas To serve analytical and other heavy queries better, we introduce dedicated query nodes in this release. These type of nodes are responsible for serve queries only, so we can push them to resource limit without affecting data ingestion. Thanks to our compute-storage disaggregated architecture, it's not a huge refactoring to add read replicas to current architecture. A new type of datanodes will play the role. It's dedicated to process query workloads. Because data are available on object storage, there will be no data replication between these types of datanodes and those original ones who take writes. User will be able to add hint to their queries to specify whether the query should run on read replicas. ### Triggers Trigger evaluate data with your predefined rules periodically and invoke webhooks if it matches. This is the initial version of triggers. Of course we designed it to work with Prometheus AlertManager. ```sql CREATE TRIGGER IF NOT EXISTS cpu_monitor ON (SELECT host AS host_label, cpu, memory FROM machine_monitor WHERE cpu > 1 and ts >= now() - '5 minutes'::INTERVAL) EVERY '5 minute'::INTERVAL LABELS (severity = 'warning') ANNOTATIONS (summary = 'CPU utilization is too high', link = 'http://...') NOTIFY( WEBHOOK alert_manager URL 'http://127.0.0.1:9093' WITH (timeout="1m") ); ``` ### Flow Reliability Reliability features are added to flow, our light-weighted streaming engine: - Task migration: move tasks between flow nodes for load balancing. ## Features From GreptimeDB OSS This release is based on GreptimeDB OSS v0.14. --- ## GreptimeDB Enterprise 25.11 We are pleased to introduce the 25.11 release of GreptimeDB Enterprise. ## Enterprise Features ### Initial release of bulk ingestion Bulk ingestion is an alternative ingestion approach introduced to overcome some limitation of our normal integration path in OSS. It's designed for high volume ingestion scenario. According to our test, an acceleration up to 5x can be achieved by bulk ingestion. In this release, we made bulk ingestion available for Prometheus remote write API. The support for other APIs are coming in our future dot releases of 25.11. There is no client API change required for adopting bulk ingestion. ### Feature completion of Triggers Trigger has seen massive improves for its feature set. Adding support for Prometheus equivalent for `for` and `keep_firing_for`, to bring in state management of trigger events. [Read more from trigger documentation](../trigger.md). ## Features From GreptimeDB OSS This release is based on GreptimeDB OSS v1.0.0. --- ## Trigger Trigger allows you to define evaluation rules with SQL. GreptimeDB evaluates these rules periodically; once the condition is met, a notification is sent out. ## Key Features - **SQL-native**: Define trigger rules in SQL, reusing GreptimeDB's built-in functions without a learning curve - **Multi-stage state management**: Built-in pending / firing / inactive state machine prevents flapping and duplicate notifications - **Rich context**: Custom labels and annotations with automatic injection of query result fields to pinpoint root causes - **Ecosystem-friendly**: Alert payload fully compatible with Prometheus Alertmanager—use its grouping, inhibition, silencing, and routing without adapters ## Quick Start Example This section walks through an end-to-end alerting scenario: monitor system load (`load1`) and fire alerts when load exceeds a threshold. In this quick start, you will: - Create a `load1` table to store host load metrics - Define a Trigger with conditions, labels, annotations, and notifications - Simulate data ingestion with normal and abnormal values - Watch alerts transition through pending → firing → inactive ### 1. Create the Data Table Connect to GreptimeDB with a MySQL client and create the `load1` table: ```sql CREATE TABLE `load1` ( host STRING, load1 FLOAT32, ts TIMESTAMP TIME INDEX ) WITH ('append_mode'='true'); ``` ### 2. Create Trigger Connect to GreptimeDB with MySQL client and create the `load1_monitor` trigger: ```sql CREATE TRIGGER IF NOT EXISTS `load1_monitor` ON ( SELECT host AS label_host, avg(load1) AS avg_load1, max(ts) AS ts FROM public.load1 WHERE ts >= NOW() - '1 minutes'::INTERVAL GROUP BY host HAVING avg(load1) > 10 ) EVERY '1 minutes'::INTERVAL FOR '3 minutes'::INTERVAL KEEP FIRING FOR '3 minutes'::INTERVAL LABELS (severity=warning) ANNOTATIONS (comment='Your computer is smoking, should take a break.') NOTIFY( WEBHOOK alert_manager URL 'http://localhost:9093' WITH (timeout='1m') ); ``` This Trigger runs every minute, computes average load per host over the last 60 seconds, and produces an alert instance for each host where `avg(load1) > 10`. Key parameters: - **FOR**: Specifies how long the condition must continuously hold before an alert instance enters firing state. - **KEEP FIRING FOR**: Specifies how long an alert instance stays in the firing state after the condition no longer holds. See the [trigger syntax](/reference/sql/trigger-syntax.md) for more detail. ### 3. Check Trigger Status #### List all Triggers ```sql SHOW TRIGGERS; ``` Output: ```text +---------------+ | Triggers | +---------------+ | load1_monitor | +---------------+ ``` #### View the creation statement ```sql SHOW CREATE TRIGGER `load1_monitor`\G ``` Output: ```text *************************** 1. row *************************** Trigger: load1_monitor Create Trigger: CREATE TRIGGER IF NOT EXISTS `load1_monitor` ON (SELECT host AS label_host, avg(load1) AS avg_load1 ...) EVERY '1 minutes'::INTERVAL FOR '3 minutes'::INTERVAL KEEP FIRING FOR '3 minutes'::INTERVAL LABELS (severity = 'warning') ANNOTATIONS (comment = 'Your computer is smoking, should take a break.') NOTIFY( WEBHOOK `alert_manager` URL `http://localhost:9093` WITH (timeout = '1m'), ) ``` #### View Trigger details ```sql SELECT * FROM information_schema.triggers\G ``` Output: ```text *************************** 1. row *************************** trigger_name: load1_monitor trigger_id: 1024 raw_sql: (SELECT host AS label_host, avg(load1) AS avg_load1, ...) interval: 60 labels: {"severity":"warning"} annotations: {"comment":"Your computer is smoking, should take a break."} for: 180 keep_firing_for: 180 channels: [{"channel_type":{"Webhook":{"opts":{"timeout":"1m"}, ...}] flownode_id: 0 ``` See the [Triggers](/reference/sql/information-schema/triggers) for more details. #### View alert instances ```sql SELECT * FROM information_schema.alerts; ``` With no data written yet, this returns an empty set. See the [Alerts](/reference/sql/information-schema/alerts) for more details. ### 4. Write Data and Observe Alert States This script simulates data ingestion: normal values for the first minute, high values for 6 minutes to trigger alerts, then back to normal. ```bash #!/usr/bin/env bash MYSQL="mysql -h 127.0.0.1 -P 4002" insert_normal() { $MYSQL -e "INSERT INTO load1 (host, load1, ts) VALUES ('newyork1', 1.2, now()), ('newyork2', 1.1, now()), ('newyork3', 1.3, now());" } insert_high() { $MYSQL -e "INSERT INTO load1 (host, load1, ts) VALUES ('newyork1', 1.2, now()), ('newyork2', 12.1, now()), ('newyork3', 11.5, now());" } # First minute: normal data for i in {1..4}; do insert_normal; sleep 15; done # Next 6 minutes: high values for i in {1..24}; do insert_high; sleep 15; done # After: back to normal while true; do insert_normal; sleep 15; done ``` #### State Transitions In another terminal, query alert status: **Phase 1: No alerts** ```sql SELECT * FROM information_schema.alerts\G ``` Output: ``` Empty set ``` **Phase 2: pending** (condition met, `FOR` duration not reached) ```sql SELECT trigger_id, labels, active_at, fired_at, resolved_at FROM information_schema.alerts; ``` ```text +------------+-----------------------------------------------------------------------+----------------------------+----------+-------------+ | trigger_id | labels | active_at | fired_at | resolved_at | +------------+-----------------------------------------------------------------------+----------------------------+----------+-------------+ | 1024 | {"alert_name":"load1_monitor","host":"newyork3","severity":"warning"} | 2025-12-29 11:58:20.992670 | NULL | NULL | | 1024 | {"alert_name":"load1_monitor","host":"newyork2","severity":"warning"} | 2025-12-29 11:58:20.992670 | NULL | NULL | +------------+-----------------------------------------------------------------------+----------------------------+----------+-------------+ ``` **Phase 3: firing** (`FOR` satisfied, notifications sent) ```sql SELECT trigger_id, labels, active_at, fired_at, resolved_at FROM information_schema.alerts; ``` ```text +------------+-----------------------------------------------------------------------+----------------------------+----------------------------+-------------+ | trigger_id | labels | active_at | fired_at | resolved_at | +------------+-----------------------------------------------------------------------+----------------------------+----------------------------+-------------+ | 1024 | {"alert_name":"load1_monitor","host":"newyork3","severity":"warning"} | 2025-12-29 11:58:20.992670 | 2025-12-29 12:02:20.991713 | NULL | | 1024 | {"alert_name":"load1_monitor","host":"newyork2","severity":"warning"} | 2025-12-29 11:58:20.992670 | 2025-12-29 12:02:20.991713 | NULL | +------------+-----------------------------------------------------------------------+----------------------------+----------------------------+-------------+ ``` **Phase 4: inactive** (condition cleared + `KEEP FIRING FOR` expired) ```sql SELECT trigger_id, labels, active_at, fired_at, resolved_at FROM information_schema.alerts; ``` ```text +------------+-----------------------------------------------------------------------+----------------------------+----------------------------+----------------------------+ | trigger_id | labels | active_at | fired_at | resolved_at | +------------+-----------------------------------------------------------------------+----------------------------+----------------------------+----------------------------+ | 1024 | {"alert_name":"load1_monitor","host":"newyork3","severity":"warning"} | 2025-12-29 11:58:20.992670 | 2025-12-29 12:02:20.991713 | 2025-12-29 12:05:20.991750 | | 1024 | {"alert_name":"load1_monitor","host":"newyork2","severity":"warning"} | 2025-12-29 11:58:20.992670 | 2025-12-29 12:02:20.991713 | 2025-12-29 12:05:20.991750 | +------------+-----------------------------------------------------------------------+----------------------------+----------------------------+----------------------------+ ``` ### 5. Alertmanager Integration (Optional) If you have Prometheus Alertmanager deployed, GreptimeDB automatically pushes firing and inactive alerts to it. After each evaluation, the Trigger injects fields from the query results into labels and annotations. In this example, `host` is included as a label and `avg_load1` is included as an annotation. These fields are propagated to Alertmanager and can be referenced in notification templates. Since the payload is Alertmanager-compatible, you can use grouping, inhibition, silencing, and routing without adapters. ## Reference - [Trigger Syntax](/reference/sql/trigger-syntax.md): The syntax for SQL statements related to `TRIGGER` - [INFORMATION_SCHEMA.TRIGGERS](/reference/sql/information-schema/triggers): View for trigger metadata - [INFORMATION_SCHEMA.ALERTS](/reference/sql/information-schema/alerts): View for alert instance metadata --- ## Built-in User Management GreptimeDB Enterprise provides a built-in user and permission system backed by the Metasrv. It supports Role-Based Access Control (RBAC) and fine-grained Access Control Lists (ACLs) to ensure data security and isolation. ## Key Features - **Built-in User Management**: User accounts and permissions are stored in the Metasrv, ensuring consistent management across the cluster. - **Role-Based Access Control (RBAC)**: Assign global privileges to users, controlling operations like `SELECT`, `INSERT`, `CREATE TABLE`, and more. - **Fine-grained ACLs**: Control table-level access within specific databases using exact matches or regular expressions. - **Dynamic Management**: Manage users dynamically via HTTP APIs without restarting the server. - **Initial Seeding**: Support for seeding initial accounts from a password file at startup. ## Configuration and Explanation This section walks through how to enable the enterprise user provider and perform basic user management. ### 1. Enable User Provider To use the enterprise user and permission system, enable the `greptime_ee_user_provider` in the component that receives client requests. Configure it on the standalone server in standalone mode, or on each frontend node in cluster mode. The user provider value is: ```text greptime_ee_user_provider: ``` The password file is optional and is used only for initial account seeding. To enable the provider without seeding users, use `greptime_ee_user_provider:`. The trailing colon `:` is required by the configuration parser. **Standalone command line:** ```shell ./greptime standalone start \ --user-provider=greptime_ee_user_provider:/path/to/passwords.txt ``` **Standalone configuration file:** ```toml user_provider = "greptime_ee_user_provider:/path/to/passwords.txt" ``` ```shell ./greptime standalone start \ -c /path/to/standalone.toml ``` **Frontend command line:** ```shell ./greptime frontend start \ --metasrv-addrs=127.0.0.1:3002 \ --user-provider=greptime_ee_user_provider:/path/to/passwords.txt ``` **Frontend configuration file:** ```toml user_provider = "greptime_ee_user_provider:/path/to/passwords.txt" [meta_client] metasrv_addrs = ["127.0.0.1:3002"] ``` Then start frontend with the configuration file: ```shell ./greptime frontend start \ -c /path/to/frontend.toml ``` ### 2. Initial Account Seeding (Optional) The password file uses the following format: `[:]=` Available roles: - `admin`: Full privileges, including user management. - `readonly` (or `ro`): Read-only access (`SqlSelect`). - `writeonly` (or `wo`): Write-only access (e.g., `SqlInsert`, `TableCreate`). - `readwrite` (or `rw`): Both read and write access (default). Example `passwords.txt`: ```text # username[:role]=password superuser:admin=strong_password alice:ro=alice_pwd bob:rw=bob_pwd ``` Seeded users are granted full access (`AclType::All`) to the `public` database by default. Seed accounts are created only once. If a seeded user already exists on later startups, it is skipped. You can modify seeded users later through the UI. ## Privileges and ACLs ### Global Privileges Privileges include the following operations: | Privilege | Description | | :--- | :--- | | `TableCreate` | Create new tables | | `TableAlter` | Alter existing tables | | `TableDrop` | Drop tables | | `SqlSelect` | Execute `SELECT` queries | | `SqlInsert` | Execute `INSERT` operations | | `SqlDelete` | Execute `DELETE` operations | | `FlowCreate` | Create flows | | `FlowDrop` | Drop flows | | `DatabaseCreate` | Create databases | | `DatabaseAlter` | Alter databases | | `DatabaseDrop` | Drop databases | | `Admin` | Full administrative privileges | | `TriggerCreate` | Create triggers | | `TriggerDrop` | Drop triggers | | `TriggerAlter` | Alter triggers | #### Predefined Role Privileges When using the password file for seeding, the predefined roles map to the following privilege combinations: | Role | Privileges | | :--- | :--- | | `admin` | All privileges | | `readonly` / `ro` | `SqlSelect` | | `writeonly` / `wo` | `SqlInsert`, `SqlDelete`, `TableCreate`, `TableAlter`, `TableDrop`, `FlowCreate`, `FlowDrop`, `TriggerCreate`, `TriggerDrop`, `TriggerAlter`, `DatabaseCreate`, `DatabaseAlter`, `DatabaseDrop` | | `readwrite` / `rw` | `readonly` + `writeonly` privileges | ### Access Control Lists (ACLs) ACLs provide table-level security within a database. Each ACL entry is scoped to a database and controls which tables in that database the user can access. The `all` ACL grants access to every table in the database. Use it when a user should be able to read or write all current and future tables in that database, subject to the user's global privileges. The `match` ACL grants access to one table by exact name. Use it when a user should only access a specific table and should not automatically gain access to other tables with similar names. The `regex` ACL grants access to tables whose names match a regular expression. Use it when tables follow a naming convention and should be managed as a group. For example, `mem_.*` matches table names that start with `mem_`, `.*_metrics` matches table names that end with `_metrics`, and `sensor_[0-9]+` matches names such as `sensor_1` and `sensor_2024`. Regex ACLs are evaluated against table names within the configured database, so use specific patterns when possible to avoid granting access to more tables than intended. ## Validation Rules ### Username Usernames must: - Start with a letter (`a-z` or `A-Z`) - Contain only letters, digits, and underscores - Match the pattern `[a-zA-Z][a-zA-Z0-9_]*` ### Password Password validation depends on how the user is created or updated: - Seeded account passwords must not be empty. - Passwords created or updated through the UI must be 6 to 64 characters long. ## User Management in the Enterprise Dashboard After you enable `greptime_ee_user_provider`, both GreptimeDB and the Enterprise Dashboard require users to log in with an account. The following screenshot shows the Enterprise Dashboard login page: You can log in with the automatically created admin account or with an account defined in the seeding file. Only accounts with the `Admin` privilege can see the database management menu. Non-admin accounts can only access the query page, similar to the open-source dashboard. After logging in as an admin user, click `User Management` in the lower-left corner to open the user management page: This page lists all current users. From here, you can: 1. Create users 2. Update existing users 3. Delete users The following screenshot shows the form for creating a user: In this form, you can configure: 1. The username 2. The password 3. Whether the account has the `Admin` privilege. Non-admin users are granted the `readwrite` privilege. 4. The account ACL list The ACL form has two tabs. You can select an exact table, select an entire database to grant full-database access, or use a regular expression to grant access to a range of tables. The following screenshot shows the regular expression form: ## Reference - **Admin Account**: On the system's first startup, GreptimeDB Enterprise automatically creates a default `admin` account if it doesn't already exist. - If the environment variable `GREPTIME_ENTERPRISE_ADMIN_PASSWORD` is set, it uses that value as the password. - If the environment variable is not set, it generates a random UUID as the password. - **Checking Auto-generated Password**: If a random password was generated, you can find it in the GreptimeDB log files. Search for a message like: ```text Created admin user with auto-generated password ``` - **Resetting the Admin Password**: You can reset the `admin` password using the CLI without manually editing the KV store. The command reads backend storage settings from a Metasrv config file and supports the standard `GREPTIMEDB_METASRV__...` environment variable overrides. ```shell ./greptime-ee cli user admin-password \ --new-password \ --config-file /path/to/metasrv.toml ``` This command must be invoked from a Metasrv instance. The `--config-file` should point to the same Metasrv config file used by your Metasrv (or standalone) deployment, so the CLI can locate the correct backend storage (etcd, MySQL, or PostgreSQL). - **Persistence**: User information is persisted in the Metasrv's KV store, making it available across all frontend nodes in a cluster. - **Admin Protection**: The built-in `admin` user cannot be deleted via the API. --- ## GreptimeDB Table Engines ## Overview GreptimeDB offers multiple specialized table engines, each designed to excel at specific workloads and use cases. This document provides a comprehensive introduction to these engines and guidance on when to use each one. ### Mito Engine Mito is the default `storage engine` of GreptimeDB, responsible for efficiently storing and managing database data. Built on the [LSMT][1] (Log-structured Merge-tree) architecture, Mito has been extensively optimized for time-series data workloads. The engine features a robust architecture including Write-Ahead Logging (WAL) for durability, a memory table system, and an efficient compaction strategy based on Time Window Compaction Strategy (TWCS). This design enables Mito to handle high-throughput write operations while maintaining excellent query performance. Mito seamlessly integrates with various object storage solutions including S3, GCS, and Azure Blob Storage, providing native support without additional plugins. It implements a tiered cache system on top of object storage, optimizing both storage costs and access speeds for time-series data at any scale. [1]: https://en.wikipedia.org/wiki/Log-structured_merge-tree ### Metric Engine As the name suggests, the Metric Engine is designed to process metrics data efficiently. It specializes in handling scenarios with a large number of small tables typical in observability and monitoring workloads. The key innovation of the Metric Engine is its use of synthetic wide physical tables to store data from numerous small tables. This approach enables efficient column and metadata reuse across tables, significantly reducing storage overhead while enhancing columnar compression efficiency. Under the Metric Engine, tables become lightweight logical constructs, making it ideal for cloud-native monitoring scenarios where thousands of small metric tables are common. The Metric Engine is built on top of the Mito Engine, meaning that its data is actually stored in the Mito Engine. This architecture leverages Mito's robust storage capabilities while adding specialized optimizations for metrics data management. ### File Engine The File Engine is a specialized storage engine in GreptimeDB designed for handling file-based data sources. It allows GreptimeDB to directly query and process data stored in external files without requiring data import or conversion. This engine supports various file formats commonly used in data analytics workflows, enabling seamless integration with existing data pipelines. By treating external files as virtual tables, the File Engine provides SQL query capabilities over file-based data while maintaining the performance optimizations of GreptimeDB's query engine. The File Engine is particularly useful for scenarios where data already exists in file formats, allowing users to analyze this data alongside time-series data stored in other GreptimeDB engines. This capability makes GreptimeDB more versatile as a unified analytics platform that can work with diverse data sources. ## Engine Selection Guide ### When to Use Each Engine - **Mito Engine**: As the default storage engine, Mito is suitable for most general time-series workloads. It's an excellent choice when you need a balance of write throughput, query performance, and storage efficiency. Use Mito for applications requiring durable storage with good all-around performance characteristics. - **Metric Engine**: Choose the Metric Engine when dealing with observability and monitoring scenarios that involve thousands of small tables with similar schemas. This engine excels at reducing storage overhead and improving query performance in cloud-native monitoring environments where metrics data is predominant. - **File Engine**: Opt for the File Engine when you need to query data that already exists in external files without importing it into the database. This is ideal for data exploration, one-time analysis tasks, or when integrating with existing file-based data pipelines. ### Specifying Engine Type in SQL When creating a table in GreptimeDB, you can specify which engine to use through the `ENGINE` clause in your CREATE TABLE statement. For more detailed information on syntax and options, please refer to the [CREATE TABLE](/reference/sql/create.md#create-table) documentation. --- ## About GreptimeDB Version Number GreptimeDB follows the [Semantic Versioning](https://semver.org/) scheme: 1.2.3 where: - 1 is the major release - 2 is the minor release - 3 is the revision number ## Major release(1) The major version indicates a significant milestone in the software’s lifecycle, often introducing extensive changes. - Characteristics: Includes major architectural updates, substantial new features, or system overhauls. - Impact: Typically not backward-compatible, requiring adjustments from users or developers. - Examples: Major API redesigns, foundational architectural shifts, or the introduction of new core modules. ## Minor release(2) The minor version focuses on feature enhancements and minor improvements, aiming to refine the existing system. - Characteristics: Adds new features, small updates, or interface improvements. - Impact: While it strives for backward compatibility within the same major version, minor breaking changes might occasionally occur. - Examples: Introducing optional functionality, updating user interfaces, or expanding configuration options with slight adjustments to existing behaviors. ## Revision number(3) The revision number is used for patches or minor refinements that address specific issues. - Characteristics: Focuses on bug fixes, security updates, or performance optimizations. - Impact: Does not introduce new features or change the overall behavior of the system. - Examples: Fixing known bugs, addressing security vulnerabilities, or improving system stability. --- ## Datanode The `greptime datanode` command provides subcommands for managing and benchmarking datanode instances. ## start Start the datanode service. ### Options You can list all the options from the following command: ``` greptime datanode start --help ``` | Option | Description | | ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `-c`/`--config-file` | The configuration file for datanode | | `--data-home` | Database storage root directory | | `--env-prefix ` | The prefix of environment variables, default is `GREPTIMEDB_DATANODE` | | `--http-addr ` | HTTP server address | | `--http-timeout ` | HTTP request timeout in seconds | | `--metasrv-addrs ` | Metasrv address list | | `--node-id ` | The datanode ID | | `--rpc-bind-addr ` | The address to bind the gRPC server | | `--rpc-server-addr ` | The address advertised to the metasrv, and used for connections from outside the host. If left empty or unset, the server will automatically use the IP address of the first network interface on the host, with the same port number as the one specified in `rpc_bind_addr` | | `--wal-dir ` | The directory of WAL | All the `addr` options are in the form of `ip:port`. ### Examples #### Start service with configurations Starts a datanode instance with customized configurations: ```sh greptime datanode start -c config/datanode.example.toml ``` Starts a datanode instance with command line arguments specifying the gRPC service address, the MySQL service address, the address of the metasrv, and the node id of the instance: ```sh greptime datanode start --rpc-bind-addr=0.0.0.0:4001 --mysql-addr=0.0.0.0:4002 --metasrv-addrs=0.0.0.0:3002 --node-id=1 ``` The `datanode.example.toml` configuration file comes from the `config` directory of the `[GreptimeDB](https://github.com/GreptimeTeam/greptimedb/)` repository. You can find more example configuration files there. The `-c` option specifies the configuration file, for more information check [Configuration](/user-guide/deployments-administration/configuration.md). ## objbench The `objbench` subcommand is a benchmarking tool for measuring read/write performance of specific files on object storage. This is useful for diagnosing performance issues and testing storage layer performance. ### Options | Option | Description | | --------------------- | ------------------------------------------------------------------------------------------------------------------ | | `--config ` | Path to the datanode configuration file (TOML format) | | `--source ` | Source SST file path in object storage (e.g., `data/greptime/public/1024/1024_0000000000/metadata/.parquet`) | | `-v`/`--verbose` | Enable verbose output | | `--pprof-file ` | Output file path for pprof flamegraph (enables profiling). Generates an SVG flamegraph file | ### Examples #### Basic benchmark Measure the read/write performance of a specific file: ```sh greptime datanode objbench --config ./datanode.toml --source data/greptime/public/1024/1024_0000000000/metadata/8fb41bc7-a106-4b9e-879b-392da799f958.parquet ``` #### Benchmark with profiling Measure performance and generate a flamegraph for performance analysis: ```sh greptime datanode objbench --config ./datanode.toml --source data/greptime/public/1024/1024_0000000000/metadata/8fb41bc7-a106-4b9e-879b-392da799f958.parquet --pprof-file=./flamegraph.svg ``` This will generate a flamegraph in SVG format that can be opened in a web browser for performance analysis. ## scanbench The `scanbench` subcommand benchmarks region scans directly from storage. ### Options | Option | Description | | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------ | | `--config ` | Path to the datanode/standalone configuration file (TOML format). | | `--region-id ` | Region ID in one of: `` (for example, `4398046511104`) or `:` (for example, `1024:0`). | | `--table-dir ` | Table directory used in open request (for example, `greptime/public/1024`). | | `--scanner ` | Scan strategy. Defaults to `seq`. | | `--scan-config ` | JSON file used to tune the scan request. | | `--parallelism ` | Simulated scan parallelism. Defaults to `1`. | | `--iterations ` | Benchmark iterations. Defaults to `1`. | | `--path-type ` | Region path type. Defaults to `bare`. | | `--enable-wal` | Enable WAL replay when opening the region. Disabled by default. | | `--pprof-file ` | Output file path for pprof flamegraph (Unix only). | | `--pprof-after-warmup` | Start pprof after the first iteration (use the first iteration as warmup). Requires `--pprof-file`. Disabled by default. | | `-v`/`--verbose` | Enable verbose output. | ### `scan-config` JSON ```json { "projection_names": ["host", "cpu"], "filters": ["host = 'web-1'", "cpu > 80"], "series_row_selector": "last_row" } ``` Notes: - All fields are optional. - Use either `projection` (indexes) or `projection_names` (column names), not both. - `projection_names` uses exact (case-sensitive) column name matching. - `filters` should be SQL expressions (not full SQL statements). - `series_row_selector` currently supports only `last_row`. ### Examples #### Default sequential scan ```sh greptime datanode scanbench --config ./datanode.toml --region-id 1024:0 --table-dir greptime/public/1024 ``` #### Unordered scan with parallelism ```sh greptime datanode scanbench --config ./datanode.toml --region-id 1024:0 --table-dir greptime/public/1024 --scanner unordered --parallelism 8 --iterations 5 ``` #### Series scan on metric engine data directory ```sh greptime datanode scanbench --config ./datanode.toml --region-id 1024:0 --table-dir data/greptime/public/1024 --parallelism 16 --scan-config ./scanconfig.json --scanner series --path-type data --iterations 10 ``` Example `scanconfig.json`: ```json { "projection_names": ["greptime_timestamp", "greptime_value", "az", "hostname", "region", "__tsid"], "filters": [ "mode = 'idle'", "region = 'us-west-2'", "greptime_timestamp >= 1742550540001", "greptime_timestamp <= 1742552400000", "__table_id = 1182" ] } ``` #### Profile after warmup iteration ```sh greptime datanode scanbench --config ./datanode.toml --region-id 1024:0 --table-dir greptime/public/1024 --iterations 5 --pprof-file ./scanbench.svg --pprof-after-warmup ``` --- ## Flownode ## Subcommand options You can list all the options from the following command: ``` greptime flownode start --help ``` | Option | Description | | ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `-c`/`--config-file` | The configuration file for flownode | | `--env-prefix ` | The prefix of environment variables, default is `GREPTIMEDB_FLOWNODE` | | `--metasrv-addrs ...` | Metasrv address list | | `--node-id ` | Flownode's id | | `--rpc-bind-addr ` | The address to bind the gRPC server | | `--rpc-server-addr ` | The address advertised to the metasrv, and used for connections from outside the host. If left empty or unset, the server will automatically use the IP address of the first network interface on the host, with the same port number as the one specified in `rpc_bind_addr` | ## Examples ### Start service with configurations Starts a flownode instance with customized configurations: ```sh greptime flownode start -c config/flownode.example.toml ``` Starts a flownode instance with command line arguments specifying the address of the metasrv: ```sh greptime flownode start --node-id=0 --rpc-bind-addr=127.0.0.1:6800 --metasrv-addrs=127.0.0.1:3002 ``` The `flownode.example.toml` configuration file comes from the `config` directory of the `[GreptimeDB](https://github.com/GreptimeTeam/greptimedb/)` repository. You can find more example configuration files there. The `-c` option specifies the configuration file, for more information check [Configuration](/user-guide/deployments-administration/configuration.md). --- ## Frontend ## Subcommand options You can list all the options from the following command: ``` greptime frontend start --help ``` | Option | Description | | ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `-c`/`--config-file` | The configuration file for frontend | | `--disable-dashboard` | Disable dashboard http service, default is `false` | | `--env-prefix ` | The prefix of environment variables, default is `GREPTIMEDB_FRONTEND` | | `--rpc-bind-addr ` | The address to bind the gRPC server | | `--rpc-server-addr ` | The address advertised to the metasrv, and used for connections from outside the host. If left empty or unset, the server will automatically use the IP address of the first network interface on the host, with the same port number as the one specified in `rpc_bind_addr` | | `--http-timeout ` | HTTP request timeout in seconds | | `--influxdb-enable` | Whether to enable InfluxDB protocol in HTTP API | | `--metasrv-addrs ` | Metasrv address list | | `--mysql-addr ` | MySQL server address | | `--postgres-addr ` | Postgres server address | | `--tls-cert-path ` | The TLS public key file path | | `--tls-key-path ` | The TLS private key file path | | `--tls-mode ` | TLS Mode | | `--user-provider ` | You can refer [authentication](/user-guide/deployments-administration/authentication/overview.md) | ## Examples ### Start service with configurations Starts a frontend instance with customized configurations: ```sh greptime frontend start -c config/frontend.example.toml ``` Starts a frontend instance with command line arguments specifying the address of the metasrv: ```sh greptime frontend start --metasrv-addrs=0.0.0.0:3002 ``` The `frontend.example.toml` configuration file comes from the `config` directory of the `[GreptimeDB](https://github.com/GreptimeTeam/greptimedb/)` repository. You can find more example configuration files there. The `-c` option specifies the configuration file, for more information check [Configuration](/user-guide/deployments-administration/configuration.md). --- ## Metasrv ## Subcommand options You can list all the options from the following command: ``` greptime metasrv start --help ``` | Option | Description | | ------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `-c`/`--config-file` | The configuration file for metasrv | | `--enable-region-failover` | Whether to enable region failover, default is `false`. Please refer to [Region Failover](/user-guide/deployments-administration/manage-data/region-failover.md) for the conditions to enable it. | | `--env-prefix ` | The prefix of environment variables, default is `GREPTIMEDB_METASRV` | | `--rpc-bind-addr ` | The address to bind the gRPC server | | `--rpc-server-addr ` | The communication server address for the other components(frontend, datanode, flownode, etc.) If left empty or unset, the server will automatically use the IP address of the first network interface on the host, with the same port number as the one specified in `rpc_bind_addr` | | `--http-addr ` | HTTP server address | | `--http-timeout ` | HTTP request timeout in seconds | | `--selector ` | You can refer [selector-type](/contributor-guide/metasrv/selector.md#selector-type) | | `--store-addrs ` | Comma or space separated key-value storage server (default is etcd) address, used for storing metadata | ## Examples ### Start service with configurations Starts a metasrv with customized configurations: ```sh greptime metasrv start -c config/metasrv.example.toml ``` The `metasrv.example.toml` configuration file comes from the `config` directory of the `[GreptimeDB](https://github.com/GreptimeTeam/greptimedb/)` repository. You can find more example configuration files there. The `-c` option specifies the configuration file, for more information check [Configuration](/user-guide/deployments-administration/configuration.md). --- ## GreptimeDB Command Line Overview # Overview The `greptime` command can start/stop GreptimeDB and pass configuration options. ## Install the Greptime CLI The Greptime CLI is bundled with the GreptimeDB binary. If you start GreptimeDB using the binary file as described in the [installing GreptimeDB](/getting-started/installation/overview.md) documentation, you can execute the `./greptime` command from within the GreptimeDB directory. For convenience, if you prefer to run commands using `greptime` instead of `./greptime`, consider moving the CLI binary to your system's `bin` directory or adding the binary's path to your `PATH` environment variable. If you deployed GreptimeDB in Kubernetes, you can access the greptime command line through the frontend pod. Use the following command to enter the pod: ```sh kubectl exec -it -n -- /bin/bash ``` Once inside the pod, you can run `greptime help` to see all available commands. ## CLI Options The `help` command lists all available commands and options of `greptime`. ```sh $ greptime help Usage: greptime [OPTIONS] Commands: datanode Start datanode service flownode Start flownode service frontend Start frontend service metasrv Start metasrv service standalone Run greptimedb as a standalone service cli Execute the cli tools for greptimedb help Print this message or the help of the given subcommand(s) Options: --log-dir --log-level -h, --help Print help -V, --version Print version ``` ### Global options | Option | Description | | ------------------------- | ---------------------------------------------------------- | | `-h`/`--help` | Print help information | | `-V`/`--version` | Print version information | | `--log-dir ` | The logging directory, default is `./greptimedb_data/logs` | | `--log-level ` | The logging level, default is `info` | ### Subcommands - [Metasrv](/reference/command-lines/metasrv.md) - [Datanode](/reference/command-lines/datanode.md) - [Flownode](/reference/command-lines/flownode.md) - [Frontend](/reference/command-lines/frontend.md) - [Standalone](/reference/command-lines/standalone.md) ### Upgrade GreptimeDB version Please refer to [the upgrade steps](/user-guide/deployments-administration/upgrade.md) --- ## Standalone ## Subcommand options You can list all the options from the following command: ``` greptime standalone start --help ``` | Option | Description | | --------------------------------- | ----------------------------------------------------------------------- | | `-c`/`--config-file` | The configuration file for frontend | | `--env-prefix ` | The prefix of environment variables, default is `GREPTIMEDB_STANDALONE` | | `--http-addr ` | HTTP server address | | `--influxdb-enable` | Whether to enable InfluxDB protocol in HTTP API | | `--mysql-addr ` | MySQL server address | | `--postgres-addr ` | Postgres server address | | `--rpc-bind-addr ` | The address to bind the gRPC server | ## Examples ### Start standalone with configurations Starts GreptimeDB in standalone mode with customized configurations: ```sh greptime --log-dir=greptimedb_data/logs --log-level=info standalone start -c config/standalone.example.toml ``` The `standalone.example.toml` configuration file comes from the `config` directory of the `[GreptimeDB](https://github.com/GreptimeTeam/greptimedb/)` repository. You can find more example configuration files there. The `-c` option specifies the configuration file, for more information check [Configuration](/user-guide/deployments-administration/configuration.md). --- ## Data Export & Import(Utilities) The Export and Import tools provide functionality for backing up and restoring GreptimeDB databases. These tools can handle both schema and data, allowing for complete or selective backup and restoration operations. ## Export Tool ### Command Syntax ```bash greptime cli data export [OPTIONS] ``` ### Options | Option | Required | Default | Description | | ------------------------- | -------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `--addr` | Yes | - | Server address to connect | | `--output-dir` | Yes | - | Directory to store exported data. **Important**: This path is on the **remote server's filesystem**, not your local machine. If you need files locally, configure remote storage (S3/OSS/GCS/Azure Blob) for data export and use `--ddl-local-dir` to save SQL files to your local filesystem. | | `--database` | No | all databases | Name of the database to export | | `--db-parallelism`, `-j` | No | 1 | Number of databases to export in parallel. For example, if there are 20 databases and `db-parallelism` is set to 4, then 4 databases will be exported concurrently. (alias: `--export-jobs`) | | `--table-parallelism` | No | 4 | Number of tables to export in parallel within a single database. For example, if a database contains 30 tables and `table-parallelism` is set to 8, then 8 tables will be exported concurrently. | | `--max-retry` | No | 3 | Maximum retry attempts per job | | `--target`, `-t` | No | all | Export target (schema/data/all) | | `--start-time` | No | - | Start of time range for data export | | `--end-time` | No | - | End of time range for data export | | `--auth-basic` | No | - | Use the `:` format | | `--timeout` | No | 0 | The timeout for a single call to the DB, default is 0 which means never timeout (e.g., `30s`, `10min 20s`) | | `--proxy ` | No | - | The proxy server address to connect, if set, will override the system proxy. The default behavior will use the system proxy if neither `proxy` nor `no_proxy` is set. | | `--no-proxy` | No | - | Disable proxy server, if set, will not use any proxy | | `--s3` | No | - | If export data to s3 | | `--ddl-local-dir` | No | - | If both `ddl_local_dir` and remote storage (S3/OSS/GCS/Azure Blob) are set, `ddl_local_dir` will be only used for exported SQL files, and the data will be exported to remote storage. Note that `ddl_local_dir` export sql files to **LOCAL** file system, this is useful if export client don't have direct access to remote storage. If remote storage is set but `ddl_local_dir` is not set, both SQL&data will be exported to remote storage. | | `--s3-bucket` | Yes* | - | The s3 bucket name if s3 is set, this is required | | `--s3-root` | Yes* | - | If s3 is set, this is required | | `--s3-endpoint` | No* | - | The s3 endpoint if s3 is set, this is required | | `--s3-access-key-id` | Yes* | - | The s3 access key ID if s3 is set, this is required | | `--s3-secret-access-key` | Yes* | - | The s3 secret access key if s3 is set, this is required | | `--s3-region` | Yes* | - | The s3 region if s3 is set, this is required | | `--oss` | No | - | If export data to oss | | `--oss-bucket` | Yes* | - | The oss bucket name if oss is set, this is required | | `--oss-endpoint` | No* | - | The oss endpoint if oss is set, this is required | | `--oss-access-key-id` | Yes* | - | The oss access key id if oss is set, this is required | | `--oss-access-key-secret` | Yes* | - | The oss access key secret if oss is set, this is required | | `--gcs` | No | - | If export data to Google Cloud Storage (GCS) | | `--gcs-bucket` | Yes* | - | The GCS bucket name if gcs is set, this is required | | `--gcs-root` | Yes* | - | If gcs is set, this is required | | `--gcs-scope` | No | - | GCS service scope | | `--gcs-credential` | No | - | GCS credential content | | `--gcs-endpoint` | No | - | GCS endpoint URL | | `--azblob` | No | - | If export data to Azure Blob Storage | | `--azblob-container` | Yes* | - | The Azure Blob container name if azblob is set, this is required | | `--azblob-root` | Yes* | - | If azblob is set, this is required | | `--azblob-account-name` | Yes* | - | The Azure Blob account name if azblob is set, this is required | | `--azblob-account-key` | No | - | Azure Blob account key | | `--azblob-endpoint` | No | - | Azure Blob endpoint URL | | `--azblob-sas-token` | No | - | Azure Blob SAS token | ### Export Targets - `schema`: Exports table schemas only (`SHOW CREATE TABLE`) - `data`: Exports table data only (`COPY DATABASE TO`) - `all`: Exports both schemas and data (default) ## Import Tool ### Command Syntax ```bash greptime cli data import [OPTIONS] ``` ### Options | Option | Required | Default | Description | | ------------------------ | -------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `--addr` | Yes | - | Server address to connect | | `--input-dir` | Yes | - | Directory containing backup data | | `--database` | No | all databases | Name of the database to import | | `--db-parallelism`, `-j` | No | 1 | Number of databases to import in parallel. For example, if there are 20 databases and `db-parallelism` is set to 4, then 4 databases will be imported concurrently. (alias: `--import-jobs`) | | `--max-retry` | No | 3 | Maximum retry attempts per job | | `--target, -t` | No | all | Import target (schema/data/all) | | `--auth-basic` | No | - | Use the `:` format | ### Import Targets - `schema`: Imports table schemas only - `data`: Imports table data only - `all`: Imports both schemas and data (default) --- ## Metadata Interaction The `greptime cli meta` command can be used to interact with the metadata of GreptimeDB cluster. ## Common options | Option | Description | Default | Values | | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------- | ----------------------------------------------------- | | `--store-addrs ...` | The endpoint of store. One of etcd, postgres or mysql. For postgres store, the format is: `"password=password dbname=postgres user=postgres host=localhost port=5432"`. For etcd store, the format is: `"127.0.0.1:2379"`. For mysql store, the format is: `"mysql://user:password@ip:port/dbname"` | - | - | | `--max-txn-ops ` | The maximum number of operations in a transaction. Only used when using [etcd-store] | 128 | - | | `--backend ` | The metadata store backend | etcd-store | etcd-store, memory-store, postgres-store, mysql-store | | `--store-key-prefix ` | The key prefix of the metadata store | - | - | | `--meta-table-name ` | The table name in RDS to store metadata. Only used when using [postgres-store] or [mysql-store] | greptime_metakv | - | ## Get key-value pair ### Command syntax ```bash greptime cli meta get key [OPTIONS] [KEY] ``` ### Options | Option | Description | Default | | ----------------- | ------------------------------------------------------------------------------------------------------------------ | ------- | | `--prefix` | Whether to perform a prefix query. If true, returns all key-value pairs where the key starts with the given prefix | false | | `--limit ` | The maximum number of key-value pairs to return. If 0, returns all key-value pairs | 0 | ## Get table metadata ### Command syntax ```bash greptime cli meta get table [OPTIONS] ``` ### Options | Option | Description | Default | | ------------------------------- | -------------------------------- | -------- | | `--table-id ` | Get table metadata by table id | - | | `--table-name ` | Get table metadata by table name | - | | `--schema-name ` | The schema name of the table | public | | `--catalog-name ` | The catalog name of the table | greptime | | `--pretty` | Pretty print the output | - | ## Put key-value pair ### Command syntax ```bash greptime cli meta put key [OPTIONS] [KEY] ``` ### Options | Option | Description | Default | | --------------- | ---------------------------------------- | ------- | | `--value-stdin` | Read the value from standard input | - | | `--no-validate` | Skip metadata validation before writing | false | :::note `--value-stdin` is required. ::: ## Put table metadata ### Put table info #### Command syntax ```bash greptime cli meta put table info [OPTIONS] ``` #### Options | Option | Description | Default | | ------------------------------- | ---------------------------------------------------------------------- | -------- | | `--table-id ` | Select table by table id | - | | `--table-name ` | Select table by table name | - | | `--schema-name ` | The schema name of the table | public | | `--catalog-name ` | The catalog name of the table | greptime | | `--value-stdin` | Read the JSON-encoded `TableInfoValue` from standard input (required) | - | ### Put table route #### Command syntax ```bash greptime cli meta put table route [OPTIONS] ``` #### Options | Option | Description | Default | | ------------------------------- | ----------------------------------------------------------------------- | -------- | | `--table-id ` | Select table by table id | - | | `--table-name ` | Select table by table name | - | | `--schema-name ` | The schema name of the table | public | | `--catalog-name ` | The catalog name of the table | greptime | | `--value-stdin` | Read the JSON-encoded `TableRouteValue` from standard input (required) | - | ## Delete key-value pair ### Command syntax ```bash greptime cli meta del key [OPTIONS] [KEY] ``` ### Options | Option | Description | Default | | ---------- | --------------------------------------------- | ------- | | `--prefix` | Delete key-value pairs with the given prefix. | false | ## Delete table metadata ### Command syntax ```bash greptime cli meta del table [OPTIONS] ``` #### Options | Option | Description | Default | | ------------------------------- | -------------------------------- | -------- | | `--table-id ` | Get table metadata by table id | - | | `--table-name ` | Get table metadata by table name | - | | `--schema-name ` | The schema name of the table | public | | `--catalog-name ` | The catalog name of the table | greptime | ## Examples ### Get single key-value pair ```bash greptime cli meta get key --store-addrs=$ENDPOINT \ --backend=postgres-store \ __table_name/greptime/public/metric_table_2 ``` Output: ```json __table_name/greptime/public/metric_table_2 {"table_id":1059} ``` ### Get all key-value pairs with the prefix Output: ```bash greptime cli meta get key --prefix \ --store-addrs=$ENDPOINT \ --backend=postgres-store \ __table_name/greptime/public ``` ```json __table_name/greptime/public/greptime_physical_table {"table_id":1057} __table_name/greptime/public/metric_table_1 {"table_id":1058} __table_name/greptime/public/metric_table_2 {"table_id":1059} ``` ### Get table metadata by table id ```bash greptime cli meta get table --table-id=1059 \ --store-addrs=$ENDPOINT \ --backend=postgres-store \ --pretty ``` Output: ```json __table_info/1059 { "table_info": { "ident": { "table_id": 1059, "version": 0 }, "name": "metric_table_2", "desc": null, "catalog_name": "greptime", "schema_name": "public", "meta": { "schema": { "column_schemas": [ { "name": "app", "data_type": { "String": null }, "is_nullable": true, "is_time_index": false, "default_constraint": null, "metadata": {} }, ... ], "timestamp_index": 2, "version": 0 }, "primary_key_indices": [ 0, ... ], "value_indices": [ 3 ], "engine": "metric", "next_column_id": 8, "region_numbers": [ 0, ... ], "options": { "write_buffer_size": null, "ttl": null, "skip_wal": false, "extra_options": { "on_physical_table": "greptime_physical_table" } }, "created_on": "2025-06-17T14:53:14.639207075Z", "partition_key_indices": [] }, "table_type": "Base" }, "version": 0 } __table_route/1059 { "type": "logical", "physical_table_id": 1057, "region_ids": [ 4548370366464, 4548370366465, ... ] } ``` ### Get table metadata by table name ```bash greptime cli meta get table --table-name=metric_table_2 \ --schema-name=public \ --store-addrs=$ENDPOINT \ --backend=postgres-store ``` Output: same as the output of the command above. ### Put table info ```bash cat table_info.json | greptime cli meta put table info \ --table-id=1059 \ --store-addrs=$ENDPOINT \ --backend=postgres-store \ --value-stdin ``` Output: ```bash Table(1059) info updated ``` ### Put table route ```bash cat table_route.json | greptime cli meta put table route \ --table-id=1059 \ --store-addrs=$ENDPOINT \ --backend=postgres-store \ --value-stdin ``` Output: ```bash Table(1059) route updated ``` ## Delete non-existent key-value pair ```bash greptime cli meta del key --store-addrs=$ENDPOINT \ --backend=postgres-store \ non_existent_key ``` Output(Return deleted key-value pairs count): ```bash 0 ``` ## Delete a key-value pair ```bash greptime cli meta del key --store-addrs=$ENDPOINT \ --backend=postgres-store \ __table_name/greptime/public/metric_table_3 ``` Output(Return deleted key-value pairs count): ```bash 1 ``` ## Delete a table metadata ```bash greptime cli meta del table --table-id=1059 \ --store-addrs=$ENDPOINT \ --backend=postgres-store ``` Output: ```bash Table(1059) deleted ``` --- ## Metadata Export & Import(Utilities) The Export and Import tools provide functionality for backing up and restoring GreptimeDB metadata. These tools allow for metadata backup and restoration operations. ## Export Tool ### Command Syntax ```bash greptime cli meta snapshot save [OPTIONS] ``` ### Options #### Storage Backend Options | Option | Required | Default | Description | | ------------------ | -------- | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | | --store-addrs | Yes | - | Metadata storage service addresses to connect to (supports etcd, MySQL, PostgreSQL, and RaftEngine). Format consistent with store-addrs in metasrv configuration. For RaftEngine, use `raftengine:///path/to/metadata` | | --backend | Yes | - | Type of metadata storage backend, one of `etcd-store`, `postgres-store`, `mysql-store`, `raft-engine-store` | | --store-key-prefix | No | "" | Unified prefix for data in metasrv, refer to metasrv configuration | | --meta-table-name | No | greptime_metakv | When backend is one of `postgres-store`, `mysql-store`, the table name storing metadata | | --max-txn-ops | No | 128 | Maximum number of txn operations | #### File Options | Option | Required | Default | Description | | ------------ | -------- | ----------------- | --------------------------------------------------------------------------- | | --file-name | No | metadata_snapshot | File name for metadata export, will automatically add `.metadata.fb` suffix | | --dir | No | "" | Directory to store exported data | #### Object Storage Options To use object storage for storing exported metadata, enable one of the following providers and configure its connection parameters: ##### S3 | Option | Required | Default | Description | | ---------------------------- | -------- | ------- | ---------------------------------------------------------------- | | --s3 | No | false | Whether to use S3 as storage medium for exported data | | --s3-bucket | No | - | S3 bucket name | | --s3-root | No | - | Root path in S3 bucket | | --s3-access-key-id | No | - | S3 access key ID | | --s3-secret-access-key | No | - | S3 secret access key | | --s3-region | No | - | S3 region name | | --s3-endpoint | No | - | S3 endpoint URL (optional, defaults based on bucket region) | | --s3-enable-virtual-host-style | No | false | Enable virtual host style for S3 API requests | ##### OSS (Alibaba Cloud) | Option | Required | Default | Description | | ----------------------- | -------- | ------- | -------------------------------------- | | --oss | No | false | Whether to use OSS for exported data | | --oss-bucket | No | - | OSS bucket name | | --oss-root | No | - | Root path in OSS bucket | | --oss-access-key-id | No | - | OSS access key ID | | --oss-access-key-secret | No | - | OSS access key secret | | --oss-endpoint | No | - | OSS endpoint URL | ##### GCS (Google Cloud Storage) | Option | Required | Default | Description | | --------------------- | -------- | ------- | ------------------------------------- | | --gcs | No | false | Whether to use GCS for exported data | | --gcs-bucket | No | - | GCS bucket name | | --gcs-root | No | - | Root path in GCS bucket | | --gcs-scope | No | - | GCS service scope | | --gcs-credential | No | - | GCS credential content | | --gcs-endpoint | No | - | GCS endpoint URL | ##### Azure Blob Storage | Option | Required | Default | Description | | --------------------- | -------- | ------- | ------------------------------------------- | | --azblob | No | false | Whether to use Azure Blob for exported data | | --azblob-container | No | - | Azure Blob container name | | --azblob-root | No | - | Root path in container | | --azblob-account-name | No | - | Azure Blob account name | | --azblob-account-key | No | - | Azure Blob account key | | --azblob-endpoint | No | - | Azure Blob endpoint URL | | --azblob-sas-token | No | - | Azure Blob SAS token | ## Import Tool ### Command Syntax ```bash greptime cli meta snapshot restore [OPTIONS] ``` ### Options #### Storage Backend Options | Option | Required | Default | Description | | ------------------ | -------- | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | --store-addrs | Yes | - | Metadata storage service addresses to connect to (supports etcd, MySQL, PostgreSQL, and RaftEngine). Format consistent with store-addrs in metasrv configuration. For RaftEngine, use `raftengine:///path/to/metadata` | | --backend | Yes | - | Type of metadata storage backend, one of `etcd-store`, `postgres-store`, `mysql-store`, `raft-engine-store` | | --store-key-prefix | No | "" | Unified prefix for data in metasrv, refer to metasrv configuration | | --meta-table-name | No | greptime_metakv | When backend is `postgres-store`, `mysql-store`, the table name storing metadata | | --max-txn-ops | No | 128 | Maximum number of txn operations | #### File Options | Option | Required | Default | Description | | ----------- | -------- | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | --file-name | No | metadata_snapshot.metadata.fb | File name of metadata export to import | | --dir | No | "." | Directory storing exported data | | --force | No | false | Whether to force import, when target backend is detected to not be in a clean state, import is disabled by default, enable this flag to force import | #### Object Storage Options To use object storage for importing metadata, enable one of the following providers and configure its connection parameters: ##### S3 | Option | Required | Default | Description | | ---------------------------- | -------- | ------- | ---------------------------------------------------------------- | | --s3 | No | false | Whether to use S3 as storage medium for exported data | | --s3-bucket | No | - | S3 bucket name | | --s3-root | No | - | Root path in S3 bucket | | --s3-access-key-id | No | - | S3 access key ID | | --s3-secret-access-key | No | - | S3 secret access key | | --s3-region | No | - | S3 region name | | --s3-endpoint | No | - | S3 endpoint URL (optional, defaults based on bucket region) | | --s3-enable-virtual-host-style | No | false | Enable virtual host style for S3 API requests | ##### OSS (Alibaba Cloud) | Option | Required | Default | Description | | ----------------------- | -------- | ------- | -------------------------------------- | | --oss | No | false | Whether to use OSS for exported data | | --oss-bucket | No | - | OSS bucket name | | --oss-root | No | - | Root path in OSS bucket | | --oss-access-key-id | No | - | OSS access key ID | | --oss-access-key-secret | No | - | OSS access key secret | | --oss-endpoint | No | - | OSS endpoint URL | ##### GCS (Google Cloud Storage) | Option | Required | Default | Description | | --------------------- | -------- | ------- | ------------------------------------- | | --gcs | No | false | Whether to use GCS for exported data | | --gcs-bucket | No | - | GCS bucket name | | --gcs-root | No | - | Root path in GCS bucket | | --gcs-scope | No | - | GCS service scope | | --gcs-credential | No | - | GCS credential content | | --gcs-endpoint | No | - | GCS endpoint URL | ##### Azure Blob Storage | Option | Required | Default | Description | | --------------------- | -------- | ------- | ------------------------------------------- | | --azblob | No | false | Whether to use Azure Blob for exported data | | --azblob-container | No | - | Azure Blob container name | | --azblob-root | No | - | Root path in container | | --azblob-account-name | No | - | Azure Blob account name | | --azblob-account-key | No | - | Azure Blob account key | | --azblob-endpoint | No | - | Azure Blob endpoint URL | | --azblob-sas-token | No | - | Azure Blob SAS token | ## Info Tool The Info tool allows you to view the contents of a metadata snapshot without restoring it. ### Command Syntax ```bash greptime cli meta snapshot info [OPTIONS] ``` ### Options #### File Options | Option | Required | Default | Description | | ------------ | -------- | ----------------- | ------------------------------------------- | | --file-name | No | metadata_snapshot | File name of the metadata snapshot to view | | --dir | No | "." | Directory where the snapshot file is stored | | --inspect-key| No | "*" | Query pattern to filter metadata keys | | --limit | No | - | Maximum number of entries to display | #### Object Storage Options To inspect snapshots stored in object storage, enable one of the following providers and configure its connection parameters: ##### S3 | Option | Required | Default | Description | | ---------------------------- | -------- | ------- | ---------------------------------------------------------------- | | --s3 | No | false | Whether to use S3 as storage medium for the snapshot | | --s3-bucket | No | - | S3 bucket name | | --s3-root | No | - | Root path in S3 bucket | | --s3-access-key-id | No | - | S3 access key ID | | --s3-secret-access-key | No | - | S3 secret access key | | --s3-region | No | - | S3 region name | | --s3-endpoint | No | - | S3 endpoint URL (optional, defaults based on bucket region) | | --s3-enable-virtual-host-style | No | false | Enable virtual host style for S3 API requests | ##### OSS (Alibaba Cloud) | Option | Required | Default | Description | | ----------------------- | -------- | ------- | -------------------------------------- | | --oss | No | false | Whether to use OSS for the snapshot | | --oss-bucket | No | - | OSS bucket name | | --oss-root | No | - | Root path in OSS bucket | | --oss-access-key-id | No | - | OSS access key ID | | --oss-access-key-secret | No | - | OSS access key secret | | --oss-endpoint | No | - | OSS endpoint URL | ##### GCS (Google Cloud Storage) | Option | Required | Default | Description | | --------------------- | -------- | ------- | ------------------------------------- | | --gcs | No | false | Whether to use GCS for the snapshot | | --gcs-bucket | No | - | GCS bucket name | | --gcs-root | No | - | Root path in GCS bucket | | --gcs-scope | No | - | GCS service scope | | --gcs-credential | No | - | GCS credential content | | --gcs-endpoint | No | - | GCS endpoint URL | ##### Azure Blob Storage | Option | Required | Default | Description | | --------------------- | -------- | ------- | ------------------------------------------- | | --azblob | No | false | Whether to use Azure Blob for the snapshot | | --azblob-container | No | - | Azure Blob container name | | --azblob-root | No | - | Root path in container | | --azblob-account-name | No | - | Azure Blob account name | | --azblob-account-key | No | - | Azure Blob account key | | --azblob-endpoint | No | - | Azure Blob endpoint URL | | --azblob-sas-token | No | - | Azure Blob SAS token | --- ## Repair logical tables The `greptime cli meta repair logical-tables` command can be used to repair logical tables for GreptimeDB cluster. In some cases, the logical tables metadata may be inconsistent with metadata stored in the metadata store. This command can be used to repair the logical tables metadata. :::tip The tool needs to connect to both the metadata store and datanode. Ensure that the cluster is running and the tool can communicate with the datanode. ::: ## Command syntax ```bash greptime cli meta repair logical-tables [OPTIONS] ``` ## Options | Option | Description | Default | Values | | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------- | ----------------------------------------------------- | | `--store-addrs ...` | The endpoint of store. One of etcd, postgres or mysql. For postgres store, the format is: `"password=password dbname=postgres user=postgres host=localhost port=5432"`. For etcd store, the format is: `"127.0.0.1:2379"`. For mysql store, the format is: `"mysql://user:password@ip:port/dbname"` | - | - | | `--max-txn-ops ` | The maximum number of operations in a transaction. Only used when using [etcd-store] | 128 | - | | `--backend ` | The metadata store backend | etcd-store | etcd-store, memory-store, postgres-store, mysql-store | | `--store-key-prefix ` | The key prefix of the metadata store | - | - | | `--meta-table-name ` | The table name in RDS to store metadata. Only used when using [postgres-store] or [mysql-store] | greptime_metakv | - | | `--table-names ` | The names of the tables to repair, separated by comma | - | | `--table-ids ` | The id of the table to repair, separated by comma | - | | `--schema-name ` | The schema of the tables to repair | public | | `--catalog-name ` | The catalog of the tables to repair | greptime | | `--fail-fast` | Whether to fail fast if any repair operation fails | - | | `--client-timeout-secs ` | The timeout for the client to operate the datanode | 30 | | `--client-connect-timeout-secs ` | The timeout for the client to connect to the datanode | 3 | ## Examples ### Repair logical tables by table names ```bash greptime cli meta repair logical-tables --store-addrs=$ENDPOINT \ --backend=postgres-store \ --table-names=metric_table_1,metric_table_2 \ --schema-name=public \ --catalog-name=greptime ``` Output: ```bash 2025-06-20T08:31:43.904497Z INFO cli::metadata::repair: All alter table requests sent successfully for table: greptime.public.metric_table_1 2025-06-20T08:31:43.904499Z INFO cli::metadata::repair: All alter table requests sent successfully for table: greptime.public.metric_table_2 2025-06-20T08:31:43.904539Z INFO cli::metadata::repair: Repair logical tables result: 2 tables repaired, 0 tables skipped ``` --- ## Repair partition columns The `greptime cli meta repair partition-column` command can be used to repair partition columns for GreptimeDB cluster. ## When to use this tool Before the [PR-6494](https://github.com/GreptimeTeam/greptimedb/pull/6494), the columns for table partitioning could refer to invalid ones in the table metadata. For example, when a new column is added into the table before the partition columns. If you find that reads or writes fail because of incorrect partition columns, you can use this tool. This tool will scan all the tables' metadata and set the partition columns to the right ones. ## Command syntax ```bash greptime cli meta repair partition-column [OPTIONS] ``` ## Options | Option | Description | Default | Value | | - | - | - | - | | `--store-addrs ` | The endpoint of store. One of etcd, postgres or mysql. For postgres store, the format is: `"password=password dbname=postgres user=postgres host=localhost port=5432"`. For etcd store, the format is: `"127.0.0.1:2379"`. For mysql store, the format is: `"mysql://user:password@ip:port/dbname"` | | string | | `--backend ` | The metadata store backend | `etcd-store` | one of:`etcd-store``memory-store``postgres-store``mysql-store` | | `--max-txn-ops ` | The maximum number of operations in a transaction. Only used when using the `etcd-store`. | `128` | number | | `--store-key-prefix ` | The key prefix of the metadata store | "" | string | | `--meta-table-name ` | The table name in RDS to store metadata. Only used when using `postgres-store` or `mysql-store` | `greptime_metakv` | string | | `--dry-run ` | If set to `true`, the tool will do no alterations to the table metadata. Instead, it will only report (by printing some logs to the stdout) the invalid partition columns. We recommend setting this option to `true` the first time you run this tool, and manually verify the results. | `false` | one of:`true``false` | | `--update-limit ` | The maximum times this tool does the alterations to the table metadata. This option can be used to gradually update the table metadata | unlimited | number | ## Example ```bash greptime cli meta repair partition-column \ --store-addrs=$ENDPOINT \ --backend=postgres-store \ --dry-run true \ --update-limit 1 ``` --- ## GreptimeDB Glossary Welcome to the GreptimeDB Glossary! This resource provides clear definitions and explanations of key terms and concepts associated with GreptimeDB, a cloud-native, open-source time-series database designed for metrics, logs, and events. Explore the glossary to better understand the innovative features and technologies behind GreptimeDB. --- ## A ### Anomaly Detection The process of identifying data points, events, or observations that deviate significantly from the norm. In time-series data, anomaly detection helps in spotting unusual patterns that may indicate critical incidents. ### Append Only Table A table type in GreptimeDB optimized for write-heavy workloads where data is only inserted, never updated or deleted. This design significantly improves write and query performance, especially for log analytics and time-series data scenarios. --- ## C ### Cardinality A measure of the uniqueness of data elements in a database, such as the number of unique values in a column. High cardinality can increase the complexity and storage requirements of a database, especially in time-series data. ### Cloud-Native Design An architectural approach that utilizes cloud computing frameworks and services to build scalable and resilient applications. GreptimeDB's cloud-native design allows it to scale effortlessly from edge deployments to distributed clusters in the cloud. ### Columnar Storage A data storage format that stores data tables by columns rather than rows. This format enhances performance for read-heavy operations and is optimized for analytical queries, contributing to GreptimeDB's cost efficiency. --- ## D ### Decoupled Compute and Storage Architecture An architectural design where computing resources and storage are managed separately. This separation enables independent scaling and resource optimization, leading to improved performance and flexibility in managing workloads. --- ## E ### Edge Database A database deployed at the edge of a network, close to the data source or user, to minimize latency and optimize data processing in real-time. ### Edge Deployment The practice of deploying applications or services closer to the data source or end-user to reduce latency and bandwidth usage. GreptimeDB supports edge deployment, allowing for real-time data processing in resource-limited environments. ### Event Management The practice of collecting, organizing, and analyzing events—including metrics, logs, and traces—to monitor and optimize systems. Event management is a critical aspect of maintaining real-time systems and applications. --- ## D ### Datanode A core component in GreptimeDB's distributed architecture responsible for data storage and processing. Datanodes handle data ingestion, storage management, query execution on local data, and maintain regions containing actual table data. Multiple datanodes can be deployed across a cluster to provide horizontal scalability, fault tolerance, and distributed data processing capabilities. --- ## F ### Field A column type in GreptimeDB's data model that contains the actual measurement data or log contents being collected. Fields store the numerical values, text content, or other data indicators that represent the core information in time-series data, complementing Tag and Time Index columns to form the complete data model. ### Frontend The query processing layer in GreptimeDB's distributed architecture that serves as the entry point for client connections. Frontend nodes handle SQL parsing, query planning, distributed query coordination, and result aggregation. They route queries to appropriate datanodes, manage client sessions, and provide protocol compatibility for various database interfaces including MySQL, PostgreSQL, and GreptimeDB's native protocols. ### Flow Engine GreptimeDB's real-time stream processing system that enables continuous, incremental computation on streaming data. Flow Engine works like an intelligent materialized view that automatically updates result tables as new data arrives in source tables. It processes data at configurable intervals (default: one second) with minimal computational overhead, making it ideal for ETL processes, downsampling, real-time analytics, and continuous aggregation scenarios. --- ## G ### GreptimeCloud The fully managed cloud service offering of GreptimeDB that provides serverless, auto-scaling database-as-a-service (DBaaS) capabilities. GreptimeCloud eliminates operational overhead with features like automatic scaling, pay-as-you-go pricing, enterprise-grade security, and seamless cloud-to-edge deployment, making it ideal for organizations seeking a hassle-free observability database solution. --- ## I ### IoT Cloud A cloud computing platform specifically designed to support Internet of Things (IoT) applications by providing the necessary storage, processing power, and connectivity to manage IoT data at scale. ### IoT Database A database optimized for handling Internet of Things (IoT) data, which often involves time-series metrics from sensors and devices. GreptimeDB is suitable for IoT use cases, providing scalable and efficient storage and querying for high-frequency data generated by IoT devices. ### IoT Observability The ability to monitor, analyze, and gain insights into IoT devices and systems through metrics, logs, and events. IoT observability ensures that devices and applications perform reliably and efficiently. ### Interoperability The ability of different systems, applications, or products to connect and communicate in a coordinated way without effort from the end-user. GreptimeDB supports widely adopted database protocols and APIs, including SQL, InfluxDB, OpenTelemetry, Prometheus, Elasticsearch, and Loki, ensuring seamless integration. --- ## L ### Log Aggregation Perform calculations on a set of logs to generate a single summary statistic for analysis and troubleshooting. For example, SUM, COUNT, etc. ### Log Management The overall process of handling log data, including collection, storage, analysis, and visualization, to ensure system performance and security. --- ## M ### Memory Leak A type of software bug where a program fails to release unused memory, causing a gradual decrease in available memory and potential system instability over time. ### Metric Engine A specialized storage engine in GreptimeDB designed for efficient processing of metrics data, particularly scenarios with thousands of small tables common in observability workloads. The Metric Engine uses synthetic wide physical tables to store data from numerous logical tables, enabling efficient column and metadata reuse, reducing storage overhead, and enhancing columnar compression. Built on top of the Mito Engine for robust storage capabilities. ### Mito Engine The default storage engine in GreptimeDB based on Log-Structured Merge Tree (LSM-Tree) architecture, optimized for time-series workloads. Mito features Write-Ahead Logging (WAL), memory tables, and Time Window Compaction Strategy (TWCS) to handle high-throughput writes while maintaining excellent query performance. It integrates natively with object storage solutions (S3, GCS, Azure Blob) and implements tiered caching for optimal storage costs and access speeds. --- ## L ### LSM-Tree (Log-Structured Merge Tree) A data structure used by GreptimeDB's storage engine that optimizes write performance by initially writing data to a log and periodically merging these logs into sorted structures. This design is particularly effective for time-series workloads with high write throughput. --- ## M ### Metasrv The metadata management service in GreptimeDB's distributed architecture that maintains cluster state, table schemas, and region distribution information. Metasrv coordinates cluster operations, manages table creation and modifications, handles region assignments and migrations, and ensures metadata consistency across the cluster. It acts as the central control plane for cluster management and serves as the source of truth for all metadata operations. --- ## O ### Observability A measure of how well the internal states of a system can be inferred based on its external outputs. Observability tools, such as GreptimeDB, help engineers monitor, debug, and gain insights into system performance by analyzing metrics, logs, and events. ### OpenTelemetry An open-source observability framework for cloud-native software. OpenTelemetry provides APIs and SDKs for collecting, processing, and exporting telemetry data such as traces, metrics, and logs. GreptimeDB integrates with OpenTelemetry to enhance data observability. --- ## P ### PromQL (Prometheus Query Language) A powerful and flexible query language used to retrieve and manipulate time-series data stored in Prometheus. GreptimeDB supports PromQL with near 100% compatibility, enabling users to perform complex queries on their time-series data and use existing Prometheus dashboards and alerting rules. --- ## P ### Pipeline A powerful data parsing and transformation mechanism in GreptimeDB designed for processing incoming data in real-time. Pipeline consists of configurable processors that pre-process raw data, dispatchers that route data to different pipelines, and transform rules that convert data types and define table structures. It supports multiple input formats and data sources (including logs, Prometheus metrics, and other observability data) and provides extensive processing capabilities including timestamp parsing, regex matching, field extraction, and data type conversion, enabling structured storage and efficient querying of observability data. --- ## R ### Read Replica An enterprise feature in GreptimeDB that creates additional read-only instances of data to enhance query performance and scalability. Read replicas distribute read workloads across multiple instances, reducing load on primary databases while providing faster query responses. This feature supports geographic distribution of data access points, improves high availability for read operations, and enables efficient scaling of read-intensive workloads in enterprise environments. ### Region A fundamental unit of data distribution in GreptimeDB's architecture. Regions contain a subset of table data and can be distributed across different nodes in a cluster. Each region manages its own storage, indexing, and query processing, enabling horizontal scalability and fault tolerance. ### Repartition The process of adjusting table partition boundaries after creation by merging existing partitions and splitting them with new rules. Repartition is used to better match current data distribution, relieve hotspots, and reduce small cold regions. ### Rust A modern programming language known for its performance and safety features, particularly in system-level programming. GreptimeDB is built with Rust, contributing to its superior performance and reliability. --- ## S ### Scalability The capability of a database system to handle growing volumes of data and increasing query loads efficiently by scaling resources either vertically (adding more power to a single server) or horizontally (adding more servers to a cluster). Scalability ensures that the system can accommodate future growth without sacrificing performance or reliability, making it crucial for modern data-intensive applications. ### SQL (Structured Query Language) A standardized programming language used for managing and manipulating relational databases. GreptimeDB supports SQL, allowing users to query metrics, logs, and events efficiently. ### Stream Processing The continuous, real-time processing of data streams as they arrive. In GreptimeDB, stream processing is implemented through the Flow Engine, which performs incremental computation on streaming time-series data. This enables instant filtering, computing, and aggregation of metrics, logs, and events, providing actionable insights with minimal latency. --- ## T ### Tag A column type in GreptimeDB's data model that uniquely identifies time-series data. Rows with the same Tag values belong to the same time-series, making Tags essential for organizing and querying observability data. Tags are typically used to store metadata like host names, service names, or device IDs, and are specified as PRIMARY KEY columns in table schemas. ### Time Index A special timestamp column in GreptimeDB tables that serves as the primary time dimension for time-series data. Every GreptimeDB table requires exactly one Time Index column to organize data chronologically, enable time-based queries, and support efficient time-series operations like downsampling and time-window aggregations. ### Time Series Database A specialized database designed to handle time-series data, which consists of sequences of data points indexed by timestamps. GreptimeDB is a cloud-native time-series database optimized for analyzing and querying metrics, logs, and events. ### Table Sharding The technique of splitting a large table into multiple smaller partitions. In GreptimeDB, table sharding helps distribute load across regions and improve throughput for hot or large tables. --- ## T ### Trigger An enterprise-grade monitoring and alerting feature in GreptimeDB that enables automated evaluation of time-series data conditions. Triggers continuously monitor data in tables at specified intervals, execute SQL-based rules to check for predefined thresholds or conditions, and send notifications via webhooks when criteria are met. This feature integrates with alerting systems like Alertmanager and supports custom labels and annotations, making it ideal for real-time system monitoring, performance alerting, and automated incident response. --- ## U ### Unified Analysis The integration of various data types and sources into a single platform for analysis. GreptimeDB provides unified analysis by allowing users to query metrics, logs, and events using SQL and PromQL, simplifying data analytics workflows. ### Unified Observability A database architecture approach that consolidates metrics, logs, and traces into a single system, eliminating data silos and reducing operational complexity. GreptimeDB implements unified observability by treating all telemetry data types as wide events with timestamps, enabling cross-signal correlation, simplified data pipelines, and cost-effective observability infrastructure. --- ## W ### WAL (Write-Ahead Log) A logging mechanism used by GreptimeDB to ensure data durability and consistency. WAL records all data changes before they are applied to the main storage, enabling recovery in case of system failures. GreptimeDB supports flexible WAL options including local disk storage or distributed services like Kafka. ### Wide Events A foundational concept in Observability 2.0 that represents context-rich, high-dimensional telemetry data combining metrics, logs, and traces into single comprehensive events. Wide Events capture extensive contextual information per service interaction, including high-cardinality fields (user IDs, session IDs), business logic data, infrastructure details, and request metadata. GreptimeDB natively supports Wide Events as timestamped observability data, enabling complex multi-dimensional querying and solving "unknown unknowns" in system behavior analysis. --- ## V ### Vector Processing A high-performance data processing technique used by GreptimeDB's query engine that operates on data in batches (vectors) rather than individual values. Leverages SIMD instructions for acceleration, significantly improving query performance on large-scale time-series datasets. ### Vehicle Data Collection The process of gathering data generated by vehicles, such as sensor readings, GPS locations, and diagnostics, for analysis and insights. Vehicle data collection is a key component of modern IoT ecosystems. ### Vehicle-Cloud Integrated TSDB A time-series database designed to work seamlessly with vehicle data and cloud-based systems, enabling efficient data storage, querying, and real-time analysis for connected vehicle applications. --- *Note: This glossary is a work in progress and will be updated as new features and concepts emerge within the GreptimeDB ecosystem.* --- ## gtctl [gtctl][1], g-t-control, is a command-line tool for managing the GreptimeDB clusters. gtctl is the **All-in-One** binary that integrates with multiple operations of GreptimeDB clusters. ## Installation ### One-line Installation Download the binary using the following command: ```bash curl -fsSL https://raw.githubusercontent.com/greptimeteam/gtctl/develop/hack/install.sh | sh ``` After downloading, the gtctl will be in the current directory. You also can install gtctl from the AWS-CN S3 bucket: ```bash curl -fsSL https://downloads.greptime.cn/releases/scripts/gtctl/install.sh | sh -s -- -s aws ``` ### Homebrew On macOS, gtctl is available via Homebrew: ```bash brew tap greptimeteam/greptime brew install gtctl ``` ### From Source If you already have the [Go][2] installed, you can run the `make` command under this project to build gtctl: ```bash make gtctl ``` After building, the gtctl will be generated in `./bin/`. If you want to install gtctl, you can run the `install` command: ```bash # The built gtctl will be installed in /usr/local/bin. make install # The built gtctl will be installed in your customed path. make install INSTALL_DIR= ``` ## Enable gtctl Autocompletion (Optional) The gtctl supports autocompletion of several different shells. ### Bash The gtctl completion script for Bash can be generated with the command `gtctl completion bash`. Sourcing the completion script in your shell enables gtctl autocompletion. ```bash echo 'source <(gtctl completion bash)' >> ~/.bashrc ``` ### Zsh The gtctl completion script for Zsh can be generated with the command `gtctl completion zsh`. Sourcing the completion script in your shell enables gtctl autocompletion. ```bash mkdir -p $ZSH/completions && gtctl completion zsh > $ZSH/completions/_gtctl ``` ### Fish The gtctl completion script for Fish can be generated with the command `gtctl completion fish`. Sourcing the completion script in your shell enables gtctl autocompletion. ```bash gtctl completion fish | source ``` ## Quick Start The **fastest** way to experience the GreptimeDB cluster is to use the playground: ```bash gtctl playground ``` The `playground` will deploy the minimal GreptimeDB cluster on your environment in **bare-metal** mode. ## Deployments The gtctl supports two deployment mode: Kubernetes and Bare-Metal. ### Kubernetes #### Prerequisites * Kubernetes 1.18 or higher version is required. You can use the [kind][3] to create your own Kubernetes cluster: ```bash kind create cluster ``` #### Create Create your own GreptimeDB cluster and etcd cluster: ```bash gtctl cluster create mycluster -n default ``` If you want to use artifacts(charts and images) that are stored in the CN region, you can enable `--use-greptime-cn-artifacts`: ```bash gtctl cluster create mycluster -n default --use-greptime-cn-artifacts ``` After creating, the whole GreptimeDB cluster will start in the default namespace: ```bash # Get the cluster. gtctl cluster get mycluster -n default # List all clusters. gtctl cluster list ``` All the values used for cluster, etcd and operator which provided in [charts][4] are configurable, you can use `--set` to configure them. The gtctl also surface some commonly used configurations, you can use `gtctl cluster create --help` to browse them. ```bash # Configure cluster datanode replicas to 5 gtctl cluster create mycluster --set cluster.datanode.replicas=5 # Two same ways to configure etcd storage size to 15Gi gtctl cluster create mycluster --set etcd.storage.volumeSize=15Gi gtctl cluster create mycluster --etcd-storage-size 15Gi ``` #### Dry Run gtctl provides `--dry-run` option in cluster creation. If a user executes the command with `--dry-run`, gtctl will output the manifests content without applying them: ```bash gtctl cluster create mycluster -n default --dry-run ``` #### Connect You can use the kubectl `port-forward` command to forward frontend requests: ```bash kubectl port-forward svc/mycluster-frontend 4002:4002 > connections.out & ``` Use gtctl `connect` command or your `mysql` client to connect to your cluster: ```bash gtctl cluster connect mycluster -p mysql mysql -h 127.0.0.1 -P 4002 ``` #### Scale (Experimental) You can use the following commands to scale (or down-scale) your cluster: ```bash # Scale datanode to 3 replicas. gtctl cluster scale -n -c datanode --replicas 3 # Scale frontend to 5 replicas. gtctl cluster scale -n -c frontend --replicas 5 ``` #### Delete If you want to delete the cluster, you can: ```bash # Delete the cluster. gtctl cluster delete mycluster -n default # Delete the cluster, including etcd cluster. gtctl cluster delete mycluster -n default --tear-down-etcd ``` ### Bare-Metal #### Create You can deploy the GreptimeDB cluster on a bare-metal environment by the following simple command: ```bash gtctl cluster create mycluster --bare-metal ``` It will create all the necessary meta information on `${HOME}/.gtctl`. If you want to do more configurations, you can use the yaml format config file: ```bash gtctl cluster create mycluster --bare-metal --config ``` You can refer to the example config `cluster.yaml` and `cluster-with-local-artifacts.yaml` provided in [`examples/bare-metal`][5]. #### Delete Since the cluster in bare-metal mode runs in the foreground, any `SIGINT` and `SIGTERM` will delete the cluster. For example, the cluster will be deleted after pressing `Ctrl+C` on keyboard. The deletion will also delete the meta information of one cluster which located in `${HOME}/.gtctl`. The logs of cluster will remain if `--retain-logs` is enabled (enabled by default). ## Development There are many useful tools provided through Makefile, you can simply run make help to get more information: * Compile the project ```bash make ``` Then the gtctl will be generated in `./bin/`. * Run the unit test ```bash make test ``` * Run the e2e test ```bash make e2e ``` [1]: [2]: [3]: [4]: [5]: --- ## HTTP API Endpoint List Here is the full list for the various HTTP paths and their usage in GreptimeDB: ## Admin APIs Endpoints that is not versioned (under `/v1`). For admin usage like health check, status, metrics, etc. ### Health Check - **Path**: `/health` - **Methods**: `GET`, `POST` - **Description**: Provides a health check endpoint to verify that the server is running. - **Usage**: Access this endpoint to check the health status of the server. Please refer to the [check GreptimeDB health documentation](/enterprise/deployments-administration/monitoring/check-db-status.md#check-if-greptimedb-is-running-normally) for an example. ### Status - **Path**: `/status` - **Methods**: `GET` - **Description**: Retrieves the current status of the server. - **Usage**: Use this endpoint to obtain server status information. Please refer to the [Check GreptimeDB status documentation](/enterprise/deployments-administration/monitoring/check-db-status.md#check-greptimedb-status) for an example. ### Metrics - **Path**: `/metrics` - **Methods**: `GET` - **Description**: Exposes Prometheus metrics for monitoring purposes. - **Usage**: Prometheus can scrape this endpoint to collect metrics data. Example: ```bash curl -X GET http://127.0.0.1:4000/metrics ``` Output: ```text # HELP greptime_app_version app version # TYPE greptime_app_version gauge greptime_app_version{app="greptime-edge",short_version="main-b4bd34c5",version="0.12.0"} 1 # HELP greptime_catalog_catalog_count catalog catalog count # TYPE greptime_catalog_catalog_count gauge greptime_catalog_catalog_count 1 # HELP greptime_catalog_schema_count catalog schema count # TYPE greptime_catalog_schema_count gauge greptime_catalog_schema_count 3 # HELP greptime_flow_run_interval_ms flow run interval in ms # TYPE greptime_flow_run_interval_ms gauge greptime_flow_run_interval_ms 1000 # HELP greptime_meta_create_catalog meta create catalog # TYPE greptime_meta_create_catalog histogram greptime_meta_create_catalog_bucket{le="0.005"} 1 greptime_meta_create_catalog_bucket{le="0.01"} 1 greptime_meta_create_catalog_bucket{le="0.025"} 1 greptime_meta_create_catalog_bucket{le="0.05"} 1 greptime_meta_create_catalog_bucket{le="0.1"} 1 ... ``` ### Configuration - **Path**: `/config` - **Methods**: `GET` - **Description**: Retrieves the server's configuration options. - **Usage**: Access this endpoint to get configuration details. For example: ```shell curl http://localhost:4000/config ``` The output contains the configuration information of the GreptimeDB server. ```toml enable_telemetry = true user_provider = "static_user_provider:file:user" init_regions_in_background = false init_regions_parallelism = 16 [http] addr = "127.0.0.1:4000" timeout = "30s" body_limit = "64MiB" is_strict_mode = false # ... ``` ### Dashboard - **Paths**: `/dashboard` - **Methods**: `GET`, `POST` - **Description**: Provides access to the server's dashboard interface. - **Usage**: Access these endpoints to interact with the web-based dashboard. This dashboard is packaged with the GreptimeDB server and provides a user-friendly interface for interacting with the server. It requires corresponding compile flags to be enabled when building GreptimeDB. The original source code for the dashboard can be found at https://github.com/GreptimeTeam/dashboard ### Log Level - **Path**: `/debug/log_level` - **Methods**: `POST` - **Description**: Adjusts the server's log level dynamically. - **Usage**: Send a log level change request to this endpoint. For more information, refer to the [how-to documentation](https://github.com/GreptimeTeam/greptimedb/blob/main/docs/how-to/how-to-change-log-level-on-the-fly.md). ### Enable/Disable Trace - **Path**: `/debug/enable_trace` - **Methods**: `POST` - **Description**: Dynamically enables or disables distributed tracing at runtime. - **Usage**: Send `true` to enable tracing or `false` to disable tracing. Example to enable tracing: ```bash curl --data "true" http://127.0.0.1:4000/debug/enable_trace # Output: trace enabled ``` Example to disable tracing: ```bash curl --data "false" http://127.0.0.1:4000/debug/enable_trace # Output: trace disabled ``` For more information on tracing configuration, refer to the [tracing documentation](/user-guide/deployments-administration/monitoring/tracing.md). ### Profiling Tools - **Base Path**: `/debug/prof/` - **Endpoints**: - `cpu` - `mem` - **Methods**: `POST` for profiling the database node. - **Description**: Runtime profiling for CPU or Memory usage. - **Usage**: - Refer to [Profiling CPU](https://github.com/GreptimeTeam/greptimedb/blob/main/docs/how-to/how-to-profile-cpu.md) for detailed guide for CPU profiling. - Refer to [Profiling Memory](https://github.com/GreptimeTeam/greptimedb/blob/main/docs/how-to/how-to-profile-memory.md) for detailed guide for Memory profiling. ## Query Endpoints Various query APIs for sending query to GreptimeDB. ### SQL API - **Path**: `/v1/sql` - **Methods**: `GET`, `POST` - **Description**: Executes SQL queries against the server. - **Usage**: Send SQL queries in the request body. For more information on the SQL API, refer to the [HTTP API documentation](/user-guide/protocols/http.md#post-sql-statements) in the user guide. ### PromQL API - **Path**: `/v1/promql` - **Methods**: `GET`, `POST` - **Description**: Executes PromQL queries for Prometheus-compatible metrics, and returns data in GreptimeDB's JSON format. - **Usage**: Send PromQL queries in the request body. For more information on the PromQL API, refer to the [PromQL documentation](/user-guide/query-data/promql.md). ## Protocol Endpoints Endpoints for various protocols that are compatible with GreptimeDB. Like InfluxDB, Prometheus, OpenTelemetry, etc. ### InfluxDB Compatibility - **Paths**: - `/v1/influxdb/write` - `/v1/influxdb/api/v2/write` - `/v1/influxdb/ping` - `/v1/influxdb/health` - **Methods**: - `POST` for write endpoints. - `GET` for ping and health endpoints. - **Description**: Provides endpoints compatible with InfluxDB for data ingestion and health checks. - **Usage**: - Ingest data using InfluxDB line protocol. - Use ping and health endpoints to check server status. The detailed documentation for InfluxDB protocol can be found at [here](/user-guide/protocols/influxdb-line-protocol.md). ### Prometheus Remote Write/Read - **Paths**: - `/v1/prometheus/write` - `/v1/prometheus/read` - **Methods**: `POST` - **Description**: Supports Prometheus remote write and read APIs. - **Usage**: - Send metric data using Prometheus remote write protocol. - Read metric data using Prometheus remote read protocol. ### Prometheus HTTP API - **Base Path**: `/v1/prometheus/api/v1` - **Endpoints**: - `/format_query` - `/status/buildinfo` - `/query` - `/query_range` - `/labels` - `/series` - `/parse_query` - `/label/{label_name}/values` - **Methods**: `GET`, `POST` - **Description**: Provides Prometheus HTTP API endpoints for querying and retrieving metric data. - **Usage**: Use these endpoints to interact with metrics using standard Prometheus HTTP API. Refer to the original Prometheus documentation for more information on the [Prometheus HTTP API](https://prometheus.io/docs/prometheus/latest/querying/api/). ### OpenTelemetry Protocol (OTLP) - **Paths**: - `/v1/otlp/v1/metrics` - `/v1/otlp/v1/traces` - `/v1/otlp/v1/logs` - **Methods**: `POST` - **Description**: Supports OpenTelemetry protocol for ingesting metrics, traces, and logs. - **Usage**: Send OpenTelemetry formatted data to these endpoints. ### Loki Compatibility - **Path**: `/v1/loki/api/v1/push` - **Methods**: `POST` - **Description**: Compatible with Loki's API for log ingestion. - **Usage**: Send log data in Loki's format to this endpoint. ### OpenTSDB Protocol - **Path**: `/v1/opentsdb/api/put` - **Methods**: `POST` - **Description**: Supports data ingestion using the OpenTSDB protocol. - **Usage**: Ingest time series data using OpenTSDB's JSON format. ## Log Ingestion Endpoints - **Paths**: - `/v1/ingest` - `/v1/pipelines/{pipeline_name}` - `/v1/pipelines/_dryrun` - **Methods**: - `POST` for ingesting logs and adding pipelines. - `DELETE` for deleting pipelines. - **Description**: Provides endpoints for log ingestion and pipeline management. - **Usage**: - Ingest logs via the `/logs` endpoint. - Manage log pipelines using the `/pipelines` endpoints. For more information on log ingestion and pipeline management, refer to the [log overview](/user-guide/logs/overview.md). --- ## Built-in Pipelines GreptimeDB offers built-in pipelines for common log formats, allowing you to use them directly without creating new pipelines. Note that the built-in pipelines are not editable. Additionally, the "greptime_" prefix of the pipeline name is reserved. ## `greptime_identity` The `greptime_identity` pipeline is designed for writing JSON logs and automatically creates columns for each field in the JSON log. Nested JSON objects are automatically flattened into separate columns using dot notation. - Nested objects are automatically flattened (e.g., `{"a": {"b": 1}}` becomes column `a.b`) - Arrays are converted to JSON strings - An error is returned if the same field has different types - Fields with `null` values are ignored - If time index is not specified, an additional column, `greptime_timestamp`, is added to the table as the time index to indicate when the log was written ### Type conversion rules - `string` -> `string` - `number` -> `int64` or `float64` - `boolean` -> `bool` - `null` -> ignore - `array` -> `string` (JSON-stringified) - `object` -> automatically flattened into separate columns (see [Flatten JSON objects](#flatten-json-objects)) For example, if we have the following json data: ```json [ {"name": "Alice", "age": 20, "is_student": true, "score": 90.5,"object": {"a":1,"b":2}}, {"age": 21, "is_student": false, "score": 85.5, "company": "A" ,"whatever": null}, {"name": "Charlie", "age": 22, "is_student": true, "score": 95.5,"array":[1,2,3]} ] ``` We'll merge the schema for each row of this batch to get the final schema. Note that nested objects are automatically flattened into separate columns (e.g., `object.a`, `object.b`), and arrays are converted to JSON strings. The table schema will be: ```sql mysql> desc pipeline_logs; +--------------------+---------------------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +--------------------+---------------------+------+------+---------+---------------+ | age | Int64 | | YES | | FIELD | | is_student | Boolean | | YES | | FIELD | | name | String | | YES | | FIELD | | object.a | Int64 | | YES | | FIELD | | object.b | Int64 | | YES | | FIELD | | score | Float64 | | YES | | FIELD | | company | String | | YES | | FIELD | | array | String | | YES | | FIELD | | greptime_timestamp | TimestampNanosecond | PRI | NO | | TIMESTAMP | +--------------------+---------------------+------+------+---------+---------------+ 9 rows in set (0.00 sec) ``` The data will be stored in the table as follows: ```sql mysql> select * from pipeline_logs; +------+------------+---------+----------+----------+-------+---------+-----------+----------------------------+ | age | is_student | name | object.a | object.b | score | company | array | greptime_timestamp | +------+------------+---------+----------+----------+-------+---------+-----------+----------------------------+ | 22 | 1 | Charlie | NULL | NULL | 95.5 | NULL | [1,2,3] | 2024-10-18 09:35:48.333020 | | 21 | 0 | NULL | NULL | NULL | 85.5 | A | NULL | 2024-10-18 09:35:48.333020 | | 20 | 1 | Alice | 1 | 2 | 90.5 | NULL | NULL | 2024-10-18 09:35:48.333020 | +------+------------+---------+----------+----------+-------+---------+-----------+----------------------------+ 3 rows in set (0.01 sec) ``` ### Specify time index A time index is necessary in GreptimeDB. Since the `greptime_identity` pipeline does not require a YAML configuration, you must set the time index in the query parameters if you want to use the timestamp from the log data instead of the automatically generated timestamp when the data arrives. Example of Incoming Log Data: ```JSON [ {"action": "login", "ts": 1742814853} ] ``` To instruct the server to use ts as the time index, set the following query parameter in the HTTP header: ```shell curl -X "POST" "http://localhost:4000/v1/ingest?db=public&table=pipeline_logs&pipeline_name=greptime_identity&custom_time_index=ts;epoch;s" \ -H "Content-Type: application/json" \ -H "Authorization: Basic {{authentication}}" \ -d $'[{"action": "login", "ts": 1742814853}]' ``` The `custom_time_index` parameter accepts two formats, depending on the input data format: - Epoch number format: `;epoch;` - The field can be an integer or a string. - The resolution must be one of: `s`, `ms`, `us`, or `ns`. - Date string format: `;datestr;` - For example, if the input data contains a timestamp like `2025-03-24 19:31:37+08:00`, the corresponding format should be `%Y-%m-%d %H:%M:%S%:z`. With the configuration above, the resulting table will correctly use the specified log data field as the time index. ```sql DESC pipeline_logs; ``` ```sql +--------+-----------------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +--------+-----------------+------+------+---------+---------------+ | ts | TimestampSecond | PRI | NO | | TIMESTAMP | | action | String | | YES | | FIELD | +--------+-----------------+------+------+---------+---------------+ 2 rows in set (0.02 sec) ``` Here are some example of using `custom_time_index` assuming the time variable is named `input_ts`: - 1742814853: `custom_time_index=input_ts;epoch;s` - 1752749137000: `custom_time_index=input_ts;epoch;ms` - "2025-07-17T10:00:00+0800": `custom_time_index=input_ts;datestr;%Y-%m-%dT%H:%M:%S%z` - "2025-06-27T15:02:23.082253908Z": `custom_time_index=input_ts;datestr;%Y-%m-%dT%H:%M:%S%.9f%#z` ### Flatten JSON objects The `greptime_identity` pipeline **automatically flattens** nested JSON objects into a single-level structure. This behavior is always enabled and creates separate columns for each nested field using dot notation (e.g., `a.b.c`). #### Controlling flattening depth You can control how deeply nested objects are flattened using the `max_nested_levels` parameter in the `x-greptime-pipeline-params` header. The default value is 10 levels. Here is a sample request: ```shell curl -X "POST" "http://localhost:4000/v1/ingest?db=&table=&pipeline_name=greptime_identity&version=" \ -H "Content-Type: application/x-ndjson" \ -H "Authorization: Basic {{authentication}}" \ -H "x-greptime-pipeline-params: max_nested_levels=5" \ -d "$" ``` When the maximum nesting level is reached, any remaining nested structure is converted to a JSON string and stored in a single column. For example, with `max_nested_levels=3`: ```JSON { "a": { "b": { "c": { "d": [1, 2, 3] } } }, "e": [ "foo", "bar" ], "f": { "g": { "h": 123, "i": "hello", "j": { "k": true } } } } ``` Will be flattened to: ```json { "a.b.c": "{\"d\":[1,2,3]}", "e": "[\"foo\",\"bar\"]", "f.g.h": 123, "f.g.i": "hello", "f.g.j": "{\"k\":true}" } ``` Note that: - Arrays at any level are always converted to JSON strings (e.g., `"e"` becomes `"[\"foo\",\"bar\"]"`) - When the nesting level limit is reached (level 3 in this example), the remaining nested objects are converted to JSON strings (e.g., `"a.b.c"` and `"f.g.j"`) - Regular scalar values within the depth limit are stored as their native types (e.g., `"f.g.h"` as integer, `"f.g.i"` as string) --- ## Pipeline Configuration Pipeline is a mechanism in GreptimeDB for parsing and transforming log data. It consists of a unique name and a set of configuration rules that define how log data is formatted, split, and transformed. Currently, we support JSON (`application/json` or `application/x-ndjson`, the latter is preferred) and plain text (`text/plain`) formats as input for log data. These configurations are provided in YAML format, allowing the Pipeline to process data during the log writing process according to the defined rules and store the processed data in the database for subsequent structured queries. ## Input Formats In general, a pipeline receives a set of key-value pairs in the form of a map as its input. The following three formats can all be used as pipeline input: ### JSON Format When the request's Content-Type is `application/json`, the data format should be standard JSON. ```json [ {"message": "hello world", "time": "2024-07-12T16:18:53.048"}, {"message": "hello greptime", "time": "2024-07-12T16:18:53.048"} ] ``` ### NDJSON Format When the request's Content-Type is `application/x-ndjson`, each line is treated as a separate standard JSON object. ```json {"message": "hello world", "time": "2024-07-12T16:18:53.048"} {"message": "hello greptime", "time": "2024-07-12T16:18:53.048"} ``` ### Plain Text Format When the request's Content-Type is `text/plain`, each line is treated as a separate object. The entire line is treated as a string and stored in a map object containing only the `message` field. ``` hello world 2024-07-12T16:18:53.048 hello greptime 2024-07-12T16:18:53.048 ``` The above plain text data will be converted to the following equivalent form: ```json {"message": "hello world 2024-07-12T16:18:53.048"} {"message": "hello greptime 2024-07-12T16:18:53.048"} ``` In other words, when the input is in plain text format, you need to use `message` to refer to the content of each line when writing `Processor` and `Transform` configurations. ## Pipeline Configuration Structure Pipeline consists of four parts: Processors, Dispatcher, Transform, and Table suffix. Processors pre-process input log data. Dispatcher forwards pipeline execution context onto different subsequent pipeline. Transform decides the final datatype and table structure in the database. Table suffix allows storing the data into different tables. - Version is used to state the pipeline configuration format. Although it's optional, it's high recommended to start with version 2. See [here](#transform-in-version-2) for more details. - Processors are used for preprocessing log data, such as parsing time fields and replacing fields. - Dispatcher(optional) is used for forwarding the context into another pipeline, so that the same batch of input data can be divided and processed by different pipeline based on certain fields. - Transform(optional) is used for converting data formats, such as converting string types to numeric types, and specifying indexes. - Table suffix(optional) is used for storing data into different table for later convenience. Here is an example of a simple configuration that includes Processors and Transform: ```yaml version: 2 processors: - urlencoding: fields: - string_field_a - string_field_b method: decode ignore_missing: true dispatcher: field: type rules: - value: http table_suffix: _http pipeline: http - value: db table_suffix: _db transform: - fields: - string_field_a - string_field_b type: string # The written data must include the timestamp field - fields: - reqTimeSec, req_time_sec # epoch is a special field type and must specify precision type: epoch, ms index: timestamp table_suffix: _${string_field_a} ``` Starting from `v0.15`, the GreptimeDB introduce a version `2` format. The main change is the transform process. Refer to [the following documentation](#transform-in-version-2) for detailed changes. ## Processor The Processor is used for preprocessing log data, and its configuration is located under the `processors` section in the YAML file. The Pipeline processes data by applying multiple Processors in sequential order, where each Processor depends on the result of the previous Processor. A Processor consists of a name and multiple configurations, and different types of Processors have different fields in their configuration. We currently provide the following built-in Processors: - `date`: parses formatted time string fields, such as `2024-07-12T16:18:53.048`. - `epoch`: parses numeric timestamp fields, such as `1720772378893`. - `dissect`: splits log data fields. - `gsub`: replaces log data fields. - `join`: merges array-type fields in logs. - `letter`: converts log data fields to letters. - `regex`: performs regular expression matching on log data fields. - `urlencoding`: performs URL encoding/decoding on log data fields. - `csv`: parses CSV data fields in logs. - `json_path`: extracts fields from JSON data. (**deprecated**, please use `vrl` instead) - `json_parse`: parse a field into JSON object. - `simple_extract`: extracts fields from JSON data using simple key. - `digest`: extracts the template from a log message by removing variable content. - `select`: retain(include) or exclude fields from the pipeline context. - `vrl`: runs the [vrl](https://vector.dev/docs/reference/vrl/) script against the pipeline context. - `filter`: filter out lines if the condition check is meet. ### Input and output of Processors Most processors accept a `field` or `fields` parameter, which is a list of fields processed sequentially, as input data. Processors produce one or more output based on the input. For processors that produce a single output, the result will overwrite the original input key in the context. In the following example, after the `letter` processor, an upper-case version of the original string is saved back to the `message` field. ```yaml processors: - letter: fields: - message method: upper ``` We can save the output data to another field, leaving the original field unchanged. In the following example, we still use the `message` field as the input of the `letter` processor, but saving the output to a new field named `upper_message`. ```yaml processors: - letter: fields: - key: message rename_to: upper_message method: upper ``` This renaming syntax also has a shortcut form: simply separate the two field names with a `,`. Here is an example of this shortcut: ```yaml processors: - letter: fields: - message, upper_message method: upper ``` There are mainly two reasons why renaming is needed: 1. Leaving the original field unchanged, so it can be reused in more than one processors, or be saved into the database as well. 2. Unifying naming. For example rename camel-case names to snake-case names for consistency. ### `date` The `date` processor is used to parse time fields. Here's an example configuration: ```yaml processors: - date: fields: - time formats: - '%Y-%m-%d %H:%M:%S%.3f' ignore_missing: true timezone: 'Asia/Shanghai' ``` In the above example, the configuration of the `date` processor includes the following fields: - `fields`: A list of time field names to be parsed. - `formats`: Time format strings, supporting multiple format strings. Parsing is attempted in the order provided until successful. You can find reference [here](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) for formatting syntax. - `ignore_missing`: Ignores the case when the field is missing. Defaults to `false`. If the field is missing and this configuration is set to `false`, an exception will be thrown. - `timezone`: Time zone. Use the time zone identifiers from the [tz_database](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) to specify the time zone. Defaults to `UTC`. ### `epoch` The `epoch` processor is used to parse timestamp fields. Here's an example configuration: ```yaml processors: - epoch: fields: - reqTimeSec resolution: millisecond ignore_missing: true ``` In the above example, the configuration of the `epoch` processor includes the following fields: - `fields`: A list of timestamp field names to be parsed. - `resolution`: Timestamp precision, supports `s`, `sec`, `second`, `ms`, `millisecond`, `milli`, `us`, `microsecond`, `micro`, `ns`, `nanosecond`, `nano`. Defaults to `ms`. - `ignore_missing`: Ignores the case when the field is missing. Defaults to `false`. If the field is missing and this configuration is set to `false`, an exception will be thrown. ### `dissect` The `dissect` processor is used to split log data fields. Here's an example configuration: ```yaml processors: - dissect: fields: - message patterns: - '%{key1} %{key2}' ignore_missing: true append_separator: '-' ``` In the above example, the configuration of the `dissect` processor includes the following fields: - `fields`: A list of field names to be split, does not support field renaming. - `patterns`: The dissect pattern for splitting. - `ignore_missing`: Ignores the case when the field is missing. Defaults to `false`. If the field is missing and this configuration is set to `false`, an exception will be thrown. - `append_separator`: Specifies the separator for concatenating multiple fields with same field name together. Defaults to an empty string. See `+` modifier below. #### Dissect pattern Similar to Logstash's dissect pattern, the dissect pattern consists of `%{key}`, where `%{key}` is a field name. For example: ``` "%{key1} %{key2} %{+key3} %{+key4/2} %{key5->} %{?key6}" ``` #### Dissect modifiers The dissect pattern supports the following modifiers: | Modifier | Description | Example | | ------------ | ------------------------------------------------------ | --------------------- | | `+` | Concatenates two or more fields together | `%{+key} %{+key}` | | `+` and `/n` | Concatenates two or more fields in the specified order | `%{+key/2} %{+key/1}` | | `->` | Ignores any repeating characters on the right side | `%{key1->} %{key2->}` | | `?` | Ignores matching values | `%{?key}` | #### `dissect` examples For example, given the following log data: ``` "key1 key2 key3 key4 key5 key6" ``` Using the following Dissect pattern: ``` "%{key1} %{key2} %{+key3} %{+key3/2} %{key5->} %{?key6}" ``` The result will be: ``` { "key1": "key1", "key2": "key2", "key3": "key3 key4", "key5": "key5" } ``` ### `gsub` The `gsub` processor is used to replace values in log data fields. Here's an example configuration: ```yaml processors: - gsub: fields: - message pattern: 'old' replacement: 'new' ignore_missing: true ``` In the above example, the configuration of the `gsub` processor includes the following fields: - `fields`: A list of field names to be replaced. - `pattern`: The string to be replaced. Supports regular expressions. - `replacement`: The string to replace with. - `ignore_missing`: Ignores the case when the field is missing. Defaults to `false`. If the field is missing and this configuration is set to `false`, an exception will be thrown. ### `join` The `join` processor is used to merge Array-type fields in log data. Here's an example configuration: ```yaml processors: - join: fields: - message separator: ',' ignore_missing: true ``` In the above example, the configuration of the `join` processor includes the following fields: - `fields`: A list of field names to be merged. Note that all the fields mentioned are already of array type. Each field will have its own array merged separately. The content of multiple fields will not be combined. - `separator`: The separator for the merged result. - `ignore_missing`: Ignores the case when the field is missing. Defaults to `false`. If the field is missing and this configuration is set to `false`, an exception will be thrown. #### `join` example For example, given the following log data: ```json { "message": ["a", "b", "c"] } ``` Using the following configuration: ```yaml processors: - join: fields: - message separator: ',' ``` The result will be: ```json { "message": "a,b,c" } ``` ### `letter` The `letter` processor is used to convert the case of characters in log data fields. Here's an example configuration: ```yaml processors: - letter: fields: - message method: upper ignore_missing: true ``` In the above example, the configuration of the `letter` processor includes the following fields: - `fields`: A list of field names to be transformed. - `method`: The transformation method, supports `upper`, `lower`, `capital`. Defaults to `lower`. Note the `capital` only changes the first letter to uppercase. - `ignore_missing`: Ignores the case when the field is missing. Defaults to `false`. If the field is missing and this configuration is set to `false`, an exception will be thrown. ### `regex` The `regex` processor is used to perform regular expression matching on log data fields. Here's an example configuration: ```yaml processors: - regex: fields: - message patterns: - ':(?[0-9])' ignore_missing: true ``` In the above example, the configuration of the `regex` processor includes the following fields: - `fields`: A list of field names to be matched. If you rename the field, the renamed fields will be combined with the capture groups in `patterns` to generate the result name. - `pattern`: The regular expression pattern to match. Named capture groups are required to extract corresponding data from the respective field. - `ignore_missing`: Ignores the case when the field is missing. Defaults to `false`. If the field is missing and this configuration is set to `false`, an exception will be thrown. #### Rules for named capture groups in regex The `regex` processor supports the syntax `(?...)` to define named capture groups. The data will be processed into the following format: ```json { "_": "" } ``` For example, if the field name specified in the `regex` processor is `message`, and the corresponding content is `"[ERROR] error message"`, you can set the pattern as `\[(?[A-Z]+)\] (?.+)`, and the data will be processed as: ```json { "message_level": "ERROR", "message_content": "error message" } ``` ### `urlencoding` The `urlencoding` processor is used to perform URL encoding on log data fields. Here's an example configuration: ```yaml processors: - urlencoding: fields: - string_field_a - string_field_b method: decode ignore_missing: true ``` In the above example, the configuration of the `urlencoding` processor includes the following fields: - `fields`: A list of field names to be encoded. - `method`: The encoding method, supports `encode`, `decode`. Defaults to `encode`. - `ignore_missing`: Ignores the case when the field is missing. Defaults to `false`. If the field is missing and this configuration is set to `false`, an exception will be thrown. ### `csv` The `csv` processor is used to parse CSV-type fields in log data that do not have a header. Here's an example configuration: ```yaml processors: - csv: fields: - message separator: ',' quote: '"' trim: true ignore_missing: true ``` In the above example, the configuration of the `csv` processor includes the following fields: - `fields`: A list of field names to be parsed. - `separator`: The separator. - `quote`: The quotation mark. - `trim`: Whether to trim whitespace. Defaults to `false`. - `ignore_missing`: Ignores the case when the field is missing. Defaults to `false`. If the field is missing and this configuration is set to `false`, an exception will be thrown. ### `json_path` (deprecated) :::danger Deprecated Feature With the addition of the vrl processor, the use cases for the `json_path` processor have been greatly reduced. If you need to extract fields from JSON data, it is recommended to use the `vrl` processor for more flexible processing. We plan to deprecate the `json_path` processor in future versions. ::: The `json_path` processor is used to extract fields from JSON data. Here's an example configuration: ```yaml processors: - json_path: fields: - complex_object json_path: "$.shop.orders[?(@.active)].id" ignore_missing: true result_index: 1 ``` In the above example, the configuration of the `json_path` processor includes the following fields: - `fields`: A list of field names to be extracted. - `json_path`: The JSON path to extract. - `ignore_missing`: Ignores the case when the field is missing. Defaults to `false`. If the field is missing and this configuration is set to `false`, an exception will be thrown. - `result_index`: Specifies the index of the value in the extracted array to be used as the result value. By default, all values are included. The extracted value of the processor is an array containing all the values of the path. If an index is specified, the corresponding value in the extracted array will be used as the final result. #### JSON path syntax The JSON path syntax is based on the [jsonpath-rust](https://github.com/besok/jsonpath-rust) library. At this stage we only recommend using some simple field extraction operations to facilitate the extraction of nested fields to the top level. #### `json_path` example For example, given the following log data: ```json { "product_object": { "hello": "world" }, "product_array": [ "hello", "world" ], "complex_object": { "shop": { "orders": [ { "id": 1, "active": true }, { "id": 2 }, { "id": 3 }, { "id": 4, "active": true } ] } } } ``` Using the following configuration: ```yaml processors: - json_path: fields: - product_object, object_target json_path: "$.hello" result_index: 0 - json_path: fields: - product_array, array_target json_path: "$.[1]" result_index: 0 - json_path: fields: - complex_object, complex_target_1 json_path: "$.shop.orders[?(@.active)].id" - json_path: fields: - complex_target_1, complex_target_2 json_path: "$.[1]" result_index: 0 - json_path: fields: - complex_object, complex_target_3 json_path: "$.shop.orders[?(@.active)].id" result_index: 1 transform: - fields: - object_target - array_target type: string - fields: - complex_target_3 - complex_target_2 type: uint32 - fields: - complex_target_1 type: json ``` The result will be: ```json { "object_target": "world", "array_target": "world", "complex_target_3": 4, "complex_target_2": 4, "complex_target_1": [1, 4] } ``` ### `json_parse` `json_parse`, as its name suggests, parses a string field into a JSON object. Here's an example configuration: ```yaml processors: - json_parse: fields: - complex_object, target_field ignore_missing: true ``` In the above example, the configuration of the `json_parse` processor includes the following fields: - `fields`: For each field, the first key represents the entry string in the context, the second key represents the output key name. If the second key is not present, it uses the first key as the output key name too, which means in-place replacement of the original value. The example above means parsing `complex_object` and put the output into `target_field`. - `ignore_missing`: Ignores the case when the field is missing. Defaults to `false`. If the field is missing and this configuration is set to `false`, an exception will be thrown. #### `json_parse` example For example, given the following log data: ```json { "product_object": "{\"hello\":\"world\"}", } ``` Using the following configuration: ```yaml processors: - json_parse: fields: - product_object ``` The result will be: ```json { "product_object": { "hello": "world" } } ``` ### `simple_extract` While `json_path` processor is capable of extracting fields from JSON objects using complex expressions, it's relatively slow and costly. The `simple_extract` processor offers a simple way to extract fields by using just key names. Here's an example configuration: ```yaml processors: - simple_extract: fields: - complex_object, target_field key: "shop.name" ignore_missing: true ``` In the above example, the configuration of the `simple_extract` processor includes the following fields: - `fields`: For each field, the first key represents the entry JSON object in the context, the second key represents the output key name. The example above means extracting from `complex_object` and put the output into `target_field`. - `key`: The extracting key, using `x.x` format, each `.` represents a new nested layer. - `ignore_missing`: Ignores the case when the field is missing. Defaults to `false`. If the field is missing and this configuration is set to `false`, an exception will be thrown. #### `simple_extract` example For example, given the following log data: ```json { "product_object": { "hello": "world" }, "product_array": [ "hello", "world" ], "complex_object": { "shop": { "name": "some_shop_name" } } } ``` Using the following configuration: ```yaml processors: - simple_extract: fields: - complex_object, shop_name key: "shop.name" transform: - fields: - shop_name type: string ``` The result will be: ```json { "shop_name": "some_shop_name" } ``` ### `digest` The `digest` processor is used to extract the template from a log message by removing variable content, such as numbers, UUIDs, IP addresses, quoted strings, and bracketed text. The digested result can be useful for log template grouping and analysis. Here's an example configuration: ```yaml processors: - digest: fields: - message presets: - numbers - uuid - ip - quoted - bracketed regex: - "foobar" ignore_missing: true ``` In the above example, the configuration of the `digest` processor includes the following fields: - `fields`: A list of field names to be digested. The digested result will be stored in a new field with suffix `_digest`. - `presets`: A list of preset patterns to remove. The following patterns are supported: - `numbers`: Matches numeric sequences - `uuid`: Matches UUID strings like `123e4567-e89b-12d3-a456-426614174000` - `ip`: Matches IPv4/IPv6 addresses with optional port numbers - `quoted`: Matches text within single/double quotes (including various Unicode quotes) - `bracketed`: Matches text within various types of brackets (including various Unicode brackets) - `regex`: A list of custom regex patterns to remove - `ignore_missing`: Ignores the case when the field is missing. Defaults to `false`. If the field is missing and this configuration is set to `false`, an exception will be thrown. #### `digest` example For example, given the following log data: ```json { "message": "User 'john.doe' from [192.168.1.1] accessed resource 12345 with UUID 123e4567-e89b-12d3-a456-426614174000" } ``` Using the following configuration: ```yaml processors: - digest: fields: - message presets: - numbers - uuid - ip - quoted - bracketed ``` The result will be: ```json { "message": "User 'john.doe' from [192.168.1.1] accessed resource 12345 with UUID 123e4567-e89b-12d3-a456-426614174000", "message_digest": "User from accessed resource with UUID " } ``` The digested template can be used to group similar log messages together or analyze log patterns, even when the variable content differs. For example, all these log messages would generate the same template: - `User 'alice' from [10.0.0.1] accessed resource 54321 with UUID 987fbc97-4bed-5078-9141-2791ba07c9f3` - `User 'bob' from [2001:0db8::1] accessed resource 98765 with UUID 550e8400-e29b-41d4-a716-446655440000` ### `select` The `select` processor is used to retain or exclude fields from the pipeline execution context. Starting from `v0.15` release, we are introducing [`auto-transform`](#auto-transform) for simplicity. The `auto-transform` mode will try to preserve all fields from the pipeline execution context. The `select` processor can be used here to select fields to include or exclude, which will reflects the final table schema if `auto-transform` is used. The configuration options for `select` is simple: - `type`(optional) - `include`(default): only keeps the selected fields - `exclude`: removes the selected fields from the current context - `fields`: fields selected from the pipeline execution context Here is an example: ```YAML processors: - dissect: fields: - message patterns: - "%{+ts} %{+ts} %{http_status_code} %{content}" - date: fields: - ts formats: - "%Y-%m-%d %H:%M:%S%.3f" - select: fields: - http_status_code - ts ``` With `dissect` and `date` processor, there are four fields in the context: `ts`, `http_status_code`, `content` and the original `message`. Without the `select` processor, all four fields are preserved. The `select` processor here selects `http_status_code` and `ts` fields to include (by default), which effectively removes `content` and `message` in the pipeline execution context, resulting the `http_status_code` and `ts` to be preserved into the database. The above example can also be done in the following `select` processor's configuration: ```YAML - select: type: exclude fields: - content - message ``` ### `vrl` :::warning Experimental Feature This experimental feature may contain unexpected behavior, have its functionality change in the future. ::: The `vrl` processor run the vrl programming script against the pipeline context. It's more powerful than simple processors, for it allows you to write actual programming codes to manipulate the context; however, it also costs more resource to execute. Refer to the [official website](https://vector.dev/docs/reference/vrl/) for more language introduction and usage. The `vrl` processor only takes one configuration, that is the `source` field. Here's an example: ```YAML processors: - date: field: time formats: - "%Y-%m-%d %H:%M:%S%.3f" ignore_missing: true - vrl: source: | .from_source = "channel_2" cond, err = .id1 > .id2 if (cond) { .from_source = "channel_1" } del(.id1) del(.id2) . ``` The configuration uses a `|` to start a multi-line content in the YAML file. The whole script is then written below. Some notes regarding the `vrl` processor: 1. The script have to end with a newline of `.`, indicating returning the whole context as the returning value of the script. 2. The returning value of the vrl script should not contain any regex-type variables. They can be used in the script, but have to be `del`ed before returning. 3. Due to type conversion between pipeline's value type and vrl's, the value type that comes out of the vrl script will be the ones with max capacity, meaning `i64`, `f64`, and `Timestamp::nanoseconds`. You can use `vrl` processor to set [table options](./write-log-api.md#set-table-options) while writing logs. ### `filter` The `filter` processor can filter out unneeded lines when the condition is meet. Here is a simple example of the `filter` processor: ```YAML processors: - date: field: time formats: - "%Y-%m-%d %H:%M:%S%.3f" - filter: field: name mode: simple match_op: in case_insensitive: true targets: - John - Wick transform: - field: name type: string - field: time type: time index: timestamp ``` The `filter` processor is configured to check the `name` variable's value from the pipeline context. If the value of `name` is found within the target list `['John', 'Wick']`, the input line is considered a match and will be discarded, preventing it from being written to the database. The `filter` processor takes the following options: 1. `field`(or `fields`): the variable that is used for checking; it can be a list of variables, any match will do the filter. 2. `mode`(optional): default to `simple`, which means simple string matching. This field is here for future extension. 3. `match_op`(optional): if the mode is `simple`, this option can be `in` or `not_in`, which means if the target list contains the input value. Default to `in`. 4. `case_insensitive`(optional): default to `true`. 5. `targets`: the target string lists that are compared against the variable. ## Transform Transform is used to convert data formats and specify indexes upon columns. It is located under the `transform` section in the YAML file. Starting from `v0.15`, GreptimeDB is introducing version 2 format and auto-transform to largely simplify the configuration. See below for details. A Transform consists of one or more configurations, and each configuration contains the following fields: - `fields`: A list of field names to be transformed. - `type`: The target transformation type in the database. - `index`(optional): The index type. - `tag`(optional): Specify the field to be a tag field. - `on_failure`(optional): Handling method for transformation failures. - `default`(optional): Default value. ### Transform in version 2 Originally, you have to manually specify all the fields in the transform section for them to be persisted in the database. If a field is not specify in the transform, it will be discards. With the number of field growing, this can make the configuration both tedious and error-prone. Starting from `v0.15`, GreptimeDB introduces a new transform mode which make it easier to write pipeline configuration. You only set necessary fields in the transform section, specifying particular datatype and index for them; the rest of the fields from the pipeline context are set automatically by the pipeline engine. With the `select` processor, you can decide what field is wanted and what isn't in the final table. However, this is a breaking change to the existing pipeline configuration files. If you has already used pipeline with `dissect` or `regex` processors, after upgrading the database, the original message string, which is still in the pipeline context, gets immediately inserted into the database and there's no way to stop this behavior. Therefore, GreptimeDB introduces the concept of version to decide which transform mode you want to use, just like the version in a Docker Compose file. Here is an example: ```YAML version: 2 processors: - date: field: input_str formats: - "%Y-%m-%dT%H:%M:%S%.3fZ" transform: - field: input_str, ts type: time, ms index: timestamp ``` Simply add a `version: 2` line at the top of the config file, and the pipeline engine will run the transform in combined mode: 1. Process all written transform rules sequentially. 2. Write all fields of the pipeline context to the final table. Note: - The transform section **must contains one timestamp index field**. - The transform process in the version 2 will consume the original field in the pipeline context, so you can't transform the same field twice. ### Auto-transform The transform configuration in version 2 format is already a large simplification over the original transform. However, there are times when you might want to combine the power of processors with the ease of using `greptime_identity`, writing no transform code, letting the pipeline engine auto infer and persist the data. Now it is possible in custom pipelines. If no transform section is specified, the pipeline engine will attempt to infer the datatype of the fields from the pipeline context and preserve them into the database, much like what the `identity_pipeline` does. To create a table in GreptimeDB, a timestamp index column must be specified. In this case, the pipeline engine will try to find a field of type `timestamp` in the context and set it as the time index column. A `timestamp` field is produced by a `date` or `epoch` processor, so at least one `date` or `epoch` processor must be defined in the processor's section. Additionally, only one `timestamp` field is allowed, multiple `timestamp` fields would lead to an error due to ambiguity. For example, the following pipeline configuration is now valid. ```YAML version: 2 processors: - dissect: fields: - message patterns: - '%{ip_address} - %{username} [%{timestamp}] "%{http_method} %{request_line} %{protocol}" %{status_code} %{response_size}' ignore_missing: true - date: fields: - timestamp formats: - "%d/%b/%Y:%H:%M:%S %z" ``` And it result to the following table schema: ``` mysql> desc auto_trans; +---------------+---------------------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +---------------+---------------------+------+------+---------+---------------+ | timestamp | TimestampNanosecond | PRI | NO | | TIMESTAMP | | host | String | | YES | | FIELD | | http_method | String | | YES | | FIELD | | ip_address | String | | YES | | FIELD | | message | String | | YES | | FIELD | | protocol | String | | YES | | FIELD | | request_line | String | | YES | | FIELD | | response_size | String | | YES | | FIELD | | service | String | | YES | | FIELD | | source_type | String | | YES | | FIELD | | status_code | String | | YES | | FIELD | | username | String | | YES | | FIELD | +---------------+---------------------+------+------+---------+---------------+ 12 rows in set (0.03 sec) ``` We can see that all fields are preserved, including the original `message` field. Note that all fields are saved as `String` type, and the `timestamp` field is automatically set as the time index. ### The `fields` field Each field name is a string. `fields` in transform can also use renaming, refer to the docs [here](#input-and-output-of-processors). The final name of the field will be used as the column name in the database table. ### The `type` field GreptimeDB currently provides the following built-in transformation types: - `int8`, `int16`, `int32`, `int64`: Integer types. - `uint8`, `uint16`, `uint32`, `uint64`: Unsigned integer types. - `float32`, `float64`: Floating-point types. - `string`: String type. - `time`: Time type, which will be converted to GreptimeDB `timestamp(9)` type. - `epoch`: Timestamp type, which will be converted to GreptimeDB `timestamp(n)` type. The value of `n` depends on the precision of the epoch. When the precision is `s`, `n` is 0; when the precision is `ms`, `n` is 3; when the precision is `us`, `n` is 6; when the precision is `ns`, `n` is 9. If a field obtains an illegal value during the transformation process, the Pipeline will throw an exception. For example, when converting a string `abc` to an integer, an exception will be thrown because the string is not a valid integer. ### The `index` field The `Pipeline` will write the processed data to the automatically created table in GreptimeDB. To improve query efficiency, GreptimeDB creates indexes for certain columns in the table. The `index` field is used to specify which fields need to be indexed. For information about GreptimeDB index types, please refer to the [Data Index](/user-guide/manage-data/data-index.md) documentation. GreptimeDB supports the following four types of index for fields: - `timestamp`: Specifies a column as a timestamp index column. - `inverted`: Specifies a column to use the inverted index type. - `fulltext`: Specifies a column to use the fulltext index type. The column must be of string type. - `skipping`: Specifies a column to use the skipping index type. The column must be of string type. When `index` field is not provided, GreptimeDB doesn't create index on the column. In GreptimeDB, a table must include exact one column of type `timestamp` as the time index column. Therefore, a Pipeline can have only one time index column. #### The Timestamp column Specify which field is the timestamp index column using `index: timestamp`. Refer to the [Transform Example](#transform-example) below for syntax. #### The Inverted Index Specify which field uses the inverted index. Refer to the [Transform Example](#transform-example) below for syntax. #### The Fulltext Index Specify which field will be used for full-text search using `index: fulltext`. This index greatly improves the performance of [log search](/user-guide/logs/fulltext-search.md). Refer to the [Transform Example](#transform-example) below for syntax. #### The Skipping Index Specify which field uses the skipping index. This index speeds up the query on high cardinality fields but consumes far less storage for building index files. Refer to the [Transform Example](#transform-example) below for syntax. ### The `tag` field The `Pipeline` can also specify a tag field manually. For information about tag field, please refer to the [Data Model](/user-guide/concepts/data-model.md) documentation. Refer to the [Transform Example](#transform-example) below for syntax. ### The `on_failure` field The `on_failure` field is used to specify the handling method when a transformation fails. It supports the following methods: - `ignore`: Ignore the failed field and do not write it to the database. - `default`: Write the default value. The default value is specified by the `default` field. ### The `default` field The `default` field is used to specify the default value when a transformation fails. ### Transform Example For example, with the following log data: ```json { "num_field_a": "3", "string_field_a": "john", "string_field_b": "It was snowing when he was born.", "time_field_a": 1625760000 } ``` Using the following configuration: ```yaml transform: - fields: - string_field_a, name type: string index: skipping tag: true - fields: - num_field_a, age type: int32 index: inverted - fields: - string_field_b, description type: string index: fulltext - fields: - time_field_a, born_time type: epoch, s index: timestamp ``` The result will be: ``` { "name": "john", "age": 3, "description": "It was snowing when he was born.", "born_time": 2021-07-08 16:00:00 } ``` ## Dispatcher The pipeline dispatcher routes requests to other pipelines based on configured field values. It is useful when multiple log types share a single source and need to be stored in separate tables with different structures. A sample configuration is like: ```yaml dispatcher: field: type rules: - value: http table_suffix: _http pipeline: http - value: db table_suffix: _db ``` The dispatcher runs after processors and before transformations. It routes data to the next pipeline, where the defined processors will execute. You can specify a `field` and `rules` for routing. If the field value matches a rule's `value`, the data is routed to the specified `pipeline`. If no pipeline is defined, the current data structure is used as the table structure. In the example configuration above, if the `type` of input data is `http`, we will call `http` as next pipeline. And if `type` is `db`, we use current data structure to store the data. The target table name is determined by `table_suffix`, appended directly to the current `table`. If you want a separator such as an underscore `_`, include it in `table_suffix` explicitly. For example, if the table is `applogs` and it matches the `http` rule above, data is stored in `applogs_http`. If no rules match, data is transformed by the current pipeline's transformations. ## Table suffix :::warning Experimental Feature This experimental feature may contain unexpected behavior, have its functionality change in the future. ::: There are cases where you want to split and insert log data into different target table based on some certain values of input data. For example, if you want to divide and store the log data based on the application where the log is produced, thus adding an app name suffix to the target table. A sample configuration is like: ```yaml table_suffix: _${app_name} ``` The syntax is simple: use `${}` to include the variable in the pipeline execution context. The variable can be directly from the input data or a product of former process. After the table suffix is formatted, the whole string will be added to the input table name. Note: 1. The variable must be an integer number or a string type of data. 2. If any error occurs in runtime(e.g: the variable is missing or not a valid type), the input table name will be used. Here is an example of how it works. The input data is like following: ```JSON [ {"type": "db"}, {"type": "http"}, {"t": "test"} ] ``` The input table name is `persist_app`, and the pipeline config is like ```YAML table_suffix: _${type} ``` These three lines of input log will be inserted into three tables: 1. `persist_app_db` 2. `persist_app_http` 3. `persist_app`, for it doesn't have a `type` field, thus the default table name will be used. --- ## APIs for Writing Logs Before writing logs, please read the [Pipeline Configuration](/user-guide/logs/use-custom-pipelines.md#upload-pipeline) to complete the configuration setup and upload. ## HTTP API You can use the following command to write logs via the HTTP interface: ```shell curl -X "POST" "http://localhost:4000/v1/ingest?db=&table=&pipeline_name=&version=&skip_error=" \ -H "Content-Type: application/x-ndjson" \ -H "Authorization: Basic {{authentication}}" \ -d "$" ``` ### Request parameters This interface accepts the following parameters: - `db`: The name of the database. - `table`: The name of the table. - `pipeline_name`: The name of the [pipeline](./pipeline-config.md). - `version`: The version of the pipeline. Optional, default use the latest one. - `skip_error`: Whether to skip errors when writing logs. Optional, defaults to `false`. When set to `true`, GreptimeDB will skip individual log entries that encounter errors and continue processing the remaining logs. This prevents the entire request from failing due to a single problematic log entry. ### `Content-Type` and body format GreptimeDB uses `Content-Type` header to decide how to decode the payload body. Currently the following two format is supported: - `application/json`: this includes normal JSON format and NDJSON format. - `application/x-ndjson`: specifically uses NDJSON format, which will try to split lines and parse for more accurate error checking. - `text/plain`: multiple log lines separated by line breaks. #### `application/json` and `application/x-ndjson` format Here is an example of JSON format body payload ```JSON [ {"message":"127.0.0.1 - - [25/May/2024:20:16:37 +0000] \"GET /index.html HTTP/1.1\" 200 612 \"-\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36\""}, {"message":"192.168.1.1 - - [25/May/2024:20:17:37 +0000] \"POST /api/login HTTP/1.1\" 200 1784 \"-\" \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36\""}, {"message":"10.0.0.1 - - [25/May/2024:20:18:37 +0000] \"GET /images/logo.png HTTP/1.1\" 304 0 \"-\" \"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0\""}, {"message":"172.16.0.1 - - [25/May/2024:20:19:37 +0000] \"GET /contact HTTP/1.1\" 404 162 \"-\" \"Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1\""} ] ``` Note the whole JSON is an array (log lines). Each JSON object represents one line to be processed by Pipeline engine. The name of the key in JSON objects, which is `message` here, is used as field name in Pipeline processors. For example: ```yaml processors: - dissect: fields: # `message` is the key in JSON object - message patterns: - '%{ip_address} - - [%{timestamp}] "%{http_method} %{request_line}" %{status_code} %{response_size} "-" "%{user_agent}"' ignore_missing: true # rest of the file is ignored ``` We can also rewrite the payload into NDJSON format like following: ```JSON {"message":"127.0.0.1 - - [25/May/2024:20:16:37 +0000] \"GET /index.html HTTP/1.1\" 200 612 \"-\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36\""} {"message":"192.168.1.1 - - [25/May/2024:20:17:37 +0000] \"POST /api/login HTTP/1.1\" 200 1784 \"-\" \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36\""} {"message":"10.0.0.1 - - [25/May/2024:20:18:37 +0000] \"GET /images/logo.png HTTP/1.1\" 304 0 \"-\" \"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0\""} {"message":"172.16.0.1 - - [25/May/2024:20:19:37 +0000] \"GET /contact HTTP/1.1\" 404 162 \"-\" \"Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1\""} ``` Note the outer array is eliminated, and lines are separated by line breaks instead of `,`. #### `text/plain` format Log in plain text format is widely used throughout the ecosystem. GreptimeDB also supports `text/plain` format as log data input, enabling ingesting logs first hand from log producers. The equivalent body payload of previous example is like following: ```plain 127.0.0.1 - - [25/May/2024:20:16:37 +0000] "GET /index.html HTTP/1.1" 200 612 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36" 192.168.1.1 - - [25/May/2024:20:17:37 +0000] "POST /api/login HTTP/1.1" 200 1784 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36" 10.0.0.1 - - [25/May/2024:20:18:37 +0000] "GET /images/logo.png HTTP/1.1" 304 0 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0" 172.16.0.1 - - [25/May/2024:20:19:37 +0000] "GET /contact HTTP/1.1" 404 162 "-" "Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1" ``` Sending log ingestion request to GreptimeDB requires only modifying the `Content-Type` header to be `text/plain`, and you are good to go! Please note that, unlike JSON format, where the input data already have key names as field names to be used in Pipeline processors, `text/plain` format just gives the whole line as input to the Pipeline engine. In this case we use `message` as the field name to refer to the input line, for example: ```yaml processors: - dissect: fields: # use `message` as the field name - message patterns: - '%{ip_address} - - [%{timestamp}] "%{http_method} %{request_line}" %{status_code} %{response_size} "-" "%{user_agent}"' ignore_missing: true # rest of the file is ignored ``` It is recommended to use `dissect` or `regex` processor to split the input line into fields first and then process the fields accordingly. ## Set Table Options The table options need to be set in the pipeline configurations. Starting from `v0.15`, the pipeline engine recognizes certain variables, and can set corresponding table options based on the value of the variables. Combined with the `vrl` processor, it's now easy to create and set table options during the pipeline execution based on input data. Here is a list of supported common table option variables: - `greptime_auto_create_table` - `greptime_ttl` - `greptime_append_mode` - `greptime_merge_mode` - `greptime_physical_table` - `greptime_skip_wal` Please refer to [table options](/reference/sql/create.md#table-options) for the detailed explanation of each option. Here are some pipeline specific variables: - `greptime_table_suffix`: add suffix to the destined table name. Let's use the following pipeline file to demonstrate: ```YAML processors: - date: field: time formats: - "%Y-%m-%d %H:%M:%S%.3f" ignore_missing: true - vrl: source: | .greptime_table_suffix, err = "_" + .id .greptime_ttl = "1d" . ``` In the vrl script, we set the table suffix variable with the input field `.id`(leading with an underscore), and set the ttl to `1d`. Then we run the ingestion using the following JSON data. ```JSON { "id": "2436", "time": "2024-05-25 20:16:37.217" } ``` Assuming the given table name being `d_table`, the final table name would be `d_table_2436` as we would expected. The table is also set with a ttl of 1 day. ## Examples Please refer to the "Writing Logs" section in the [Quick Start](/user-guide/logs/quick-start.md#direct-http-ingestion) and [Using Custom Pipelines](/user-guide/logs/use-custom-pipelines.md#write-logs) guide for examples. --- ## ADMIN `ADMIN` is used to run administration functions. ```sql ADMIN function(arg1, arg2, ...) ``` ## Admin Functions GreptimeDB provides some administration functions to manage the database and data: * `flush_table(table_name)` to flush a table's memtables into SST file by table name. * `flush_region(region_id)` to flush a region's memtables into SST file by region id. Find the region id through [PARTITIONS](./information-schema/partitions.md) table. * `compact_table(table_name, [type], [options])` to schedule a compaction task for a table by table name, read [compaction](/user-guide/deployments-administration/manage-data/compaction.md#strict-window-compaction-strategy-swcs-and-manual-compaction) for more details. * `compact_region(region_id)` to schedule a compaction task for a region by region id. * `migrate_region(region_id, from_peer, to_peer, [timeout])` to migrate regions between datanodes, please read the [Region Migration](/user-guide/deployments-administration/manage-data/region-migration.md). * `procedure_state(procedure_id)` to query a procedure state by its id. * `flush_flow(flow_name)` to flush a flow's output into the sink table. * `reconcile_table(table_name)` to reconcile the metadata inconsistency of a table, read [table reconciliation](/user-guide/deployments-administration/maintenance/table-reconciliation.md) for more details. * `reconcile_database(database_name)` to reconcile the metadata inconsistency of all tables in a database, read [table reconciliation](/user-guide/deployments-administration/maintenance/table-reconciliation.md) for more details. * `reconcile_catalog()` to reconcile the metadata inconsistency of all tables in the entire cluster, read [table reconciliation](/user-guide/deployments-administration/maintenance/table-reconciliation.md) for more details. * `gc_table(table_name, [full_file_listing])` to garbage collect orphaned SST files in object storage for a dropped table. Returns the number of processed regions. The optional `full_file_listing` boolean (default `false`) enables a thorough scan of all files when set to `true`. * `gc_regions(region_id1, ..., region_idN, [full_file_listing])` to garbage collect orphaned SST files in object storage for one or more specific regions by their region ids. Returns the number of processed regions. The optional `full_file_listing` boolean (default `false`) enables a thorough scan of all files when set to `true`. For example: ```sql -- Flush the table test -- admin flush_table("test"); -- Schedule a compaction for table test with default parallelism (1) -- admin compact_table("test"); -- Schedule a regular compaction with parallelism set to 2 -- admin compact_table("test", "regular", "parallelism=2"); -- Schedule an SWCS compaction with default time window and parallelism set to 2 -- admin compact_table("test", "swcs", "parallelism=2"); -- Schedule an SWCS compaction with custom time window and parallelism -- admin compact_table("test", "swcs", "window=1800,parallelism=2"); -- Garbage collect orphaned SST files for a dropped table -- admin gc_table("test"); -- Garbage collect orphaned SST files for a dropped table with full file listing -- admin gc_table("test", true); -- Garbage collect orphaned SST files for specific regions -- admin gc_regions(1, 2, 3); -- Garbage collect orphaned SST files for specific regions with full file listing -- admin gc_regions(1, 2, 3, true); ``` --- ## ALTER `ALTER` can be used to modify any database options, table options or metadata of the table, including: - Modify database options - Add/Drop/Modify a column - Set/Drop column default values - Drop column default values - Rename a table - Modify table options ## ALTER DATABASE `ALTER DATABASE` statements can be used to modify the options of databases. ### Syntax ```sql ALTER DATABASE db [SET = [, ...] | UNSET [, ...] ] ``` Currently following options are supported: - `ttl`: Specifies the default retention time for data in the database. Data exceeding this retention period will be deleted asynchronously. - If `ttl` was not previously set, defining a new `ttl` using `ALTER` will result in the deletion of data that exceeds the specified retention time. - If `ttl` was already set, modifying it via `ALTER` will enforce the updated retention time immediately, removing data that exceeds the new retention threshold. - If `ttl` was previously set and is unset using `ALTER`, new data will no longer be deleted. However, data that was previously deleted due to the retention policy cannot be restored. - `compaction.twcs.time_window`: the time window parameter of TWCS compaction strategy. The value should be a [time duration string](/reference/time-durations.md). Changes to this option will immediately affect all tables that don't have their own explicit compaction settings. - `compaction.twcs.max_output_file_size`: the maximum allowed output file size of TWCS compaction strategy. Changes to this option will immediately affect all tables that don't have their own explicit compaction settings. - `compaction.twcs.trigger_file_num`: the number of files in a specific time window to trigger a compaction. Changes to this option will immediately affect all tables that don't have their own explicit compaction settings. ### Examples #### Modify default retention time of data in database Change the default retention time of data in the database to 1 day: ```sql ALTER DATABASE db SET 'ttl'='1d'; ``` Remove the default retention time of data in the database: ```sql ALTER DATABASE db UNSET 'ttl'; ``` #### Modify compaction options of database Database-level compaction options are dynamically resolved at compaction scheduling time. When you modify these options, the changes will immediately affect all tables in the database that don't have their own explicit compaction settings, similar to how TTL works. Change the compaction time window for the database: ```sql ALTER DATABASE db SET 'compaction.twcs.time_window'='2h'; ``` Change the maximum output file size for compaction: ```sql ALTER DATABASE db SET 'compaction.twcs.max_output_file_size'='500MB'; ``` Change the trigger file number for compaction: ```sql ALTER DATABASE db SET 'compaction.twcs.trigger_file_num'='8'; ``` Remove compaction options: ```sql ALTER DATABASE db UNSET 'compaction.twcs.time_window'; ``` ## ALTER TABLE ### Syntax ```sql ALTER TABLE [db.]table [ADD COLUMN name1 type1 [options], ADD COLUMN name2 type2 [options], ... | DROP COLUMN name | MODIFY COLUMN name type | MODIFY COLUMN name SET DEFAULT value | MODIFY COLUMN name DROP DEFAULT | MODIFY COLUMN name SET FULLTEXT INDEX [WITH ] | MODIFY COLUMN name UNSET FULLTEXT INDEX | SPLIT PARTITION () INTO () | MERGE PARTITION () | RENAME name | SET = [, ...] | UNSET [, ...] ] ``` ### Add column Adds a new column to the table: ```sql ALTER TABLE monitor ADD COLUMN load_15 double; ``` Definition of column is the same as in [CREATE](./create.md). Also, we can add multiple columns to the table at the same time: ```sql ALTER TABLE monitor ADD COLUMN disk_usage double, ADD COLUMN disk_free double; ``` We can set the new column's location. In first position for example: ```sql ALTER TABLE monitor ADD COLUMN load_15 double FIRST; ``` After an existing column: ```sql ALTER TABLE monitor ADD COLUMN load_15 double AFTER memory; ``` Adds a new column as a tag(primary key) with a default value: ```sql ALTER TABLE monitor ADD COLUMN app STRING DEFAULT 'shop' PRIMARY KEY; ``` ### Remove column Removes a column from the table: ```sql ALTER TABLE monitor DROP COLUMN load_15; ``` The removed column can't be retrieved immediately by all subsequent queries. ### Modify column type Modify the date type of a column ```sql ALTER TABLE monitor MODIFY COLUMN load_15 STRING; ``` The modified column cannot be a tag (primary key) or time index, and it must be nullable to ensure that the data can be safely converted (returns `NULL` on cast failures). ### Set column default value Set a default value for an existing column: ```sql ALTER TABLE monitor MODIFY COLUMN load_15 SET DEFAULT 0.0; ``` Set a string default value: ```sql ALTER TABLE monitor MODIFY COLUMN `status` SET DEFAULT 'active'; ``` The default value will be used for new rows when no explicit value is provided for the column during insertion. Remove the default value from a column: ```sql ALTER TABLE monitor MODIFY COLUMN load_15 DROP DEFAULT; ``` After dropping the default value, the column will use `NULL` as the default. The database only allow dropping defaults for nullable columns. ### Alter table options `ALTER TABLE` statements can also be used to change the options of tables. Currently following options are supported: - `ttl`: the retention time of data in table. - `append_mode`: whether the table is append-only. You can change it from `false` to `true`, but not from `true` to `false`. - `compaction.twcs.time_window`: the time window parameter of TWCS compaction strategy. The value should be a [time duration string](/reference/time-durations.md). - `compaction.twcs.max_output_file_size`: the maximum allowed output file size of TWCS compaction strategy. - `compaction.twcs.trigger_file_num`: the number of files in a specific time window to trigger a compaction. - `sst_format`: the SST format of the table. The value can be `flat` or `primary_key`. A table supports changing the format in both directions: `primary_key` to `flat` and `flat` to `primary_key`. ```sql ALTER TABLE monitor SET 'ttl'='1d'; ALTER TABLE monitor SET 'append_mode'='true'; ALTER TABLE monitor SET 'compaction.twcs.time_window'='2h'; ALTER TABLE monitor SET 'compaction.twcs.max_output_file_size'='500MB'; ALTER TABLE monitor SET 'compaction.twcs.trigger_file_num'='8'; ALTER TABLE monitor SET 'sst_format'='flat'; ALTER TABLE monitor SET 'sst_format'='primary_key'; ``` ### Unset table options ```sql ALTER TABLE monitor UNSET 'ttl'; ``` ### Split or merge partitions Use `SPLIT PARTITION` to split a partition into multiple partitions: ```sql ALTER TABLE sensor_readings SPLIT PARTITION ( device_id < 100 ) INTO ( device_id < 100 AND area < 'South', device_id < 100 AND area >= 'South' ); ``` Use `MERGE PARTITION` to merge multiple partitions into one. The following example merges two partitions into a single partition covering `device_id < 100`: ```sql ALTER TABLE sensor_readings MERGE PARTITION ( device_id < 100 AND area < 'South', device_id < 100 AND area >= 'South' ); ``` You can provide DDL options after the statement to control execution behavior: ```sql ALTER TABLE sensor_readings SPLIT PARTITION ( device_id < 100 ) INTO ( device_id < 100 AND area < 'South', device_id < 100 AND area >= 'South' ) WITH ( TIMEOUT = '5m', WAIT = false ); ``` When `WAIT = false`, the statement returns a `procedure_id`. You can check the status with `ADMIN procedure_state(procedure_id)` (see [ADMIN](/reference/sql/admin.md)). `TIMEOUT` controls the overall time limit for the operation, and it is enforced regardless of whether `WAIT` is `true` or `false`. :::caution Note Repartitioning operations are only supported in distributed clusters. You must enable shared object storage and GC, and ensure all datanodes can access the same object store before running these statements. ::: ### Create an index for a column Enable inverted index on a column: ```sql ALTER TABLE monitor MODIFY COLUMN host SET INVERTED INDEX; ``` Enable fulltext index on a column: ```sql ALTER TABLE monitor MODIFY COLUMN load_15 SET FULLTEXT INDEX WITH (analyzer = 'Chinese', case_sensitive = 'false', backend = 'bloom', granularity = 1024, false_positive_rate = 0.01); ``` You can specify the following options using `FULLTEXT INDEX WITH` when enabling fulltext options: - `analyzer`: Sets the language analyzer for the full-text index. Supported values are `English` and `Chinese`. Default is `English`. - `case_sensitive`: Determines whether the full-text index is case-sensitive. Supported values are `true` and `false`. Default is `false`. - `backend`: Sets the backend for the full-text index. Supported values are `bloom` and `tantivy`. Default is `bloom`. - `granularity`: (For `bloom` backend) The size of data chunks covered by each filter. A smaller granularity improves filtering but increases index size. Default is `10240`. - `false_positive_rate`: (For `bloom` backend) The probability of misidentifying a block. A lower rate improves accuracy (better filtering) but increases index size. Value is a float between `0` and `1`. Default is `0.01`. For more information on full-text index configuration and performance comparison, refer to the [Full-Text Index Configuration Guide](/user-guide/manage-data/data-index.md#fulltext-index). If `WITH ` is not specified, `FULLTEXT INDEX` will use the default values. Enable skipping index on a column: ```sql ALTER TABLE monitor MODIFY COLUMN host SET SKIPPING INDEX WITH(granularity = 1024, type = 'BLOOM', false_positive_rate = 0.01); ``` The valid options for the skipping index include: - `type`: The index type, only supports `BLOOM` type right now. - `granularity`: (For `BLOOM` type) The size of data chunks covered by each filter. A smaller granularity improves filtering but increases index size. Default is `10240`. - `false_positive_rate`: (For `BLOOM` type) The probability of misidentifying a block. A lower rate improves accuracy (better filtering) but increases index size. Value is a float between `0` and `1`. Default is `0.01`. ### Remove index on a column The syntax is: ```sql ALTER TABLE [table] MODIFY COLUMN [column] UNSET [INVERTED | SKIPPING | FULLTEXT] INDEX; ``` For example, remove the inverted index: ```sql ALTER TABLE monitor_pk MODIFY COLUMN host UNSET INVERTED INDEX; ``` Remove the skipping index: ```sql ALTER TABLE monitor_pk MODIFY COLUMN host UNSET SKIPPING INDEX; ``` Remove the fulltext index: ```sql ALTER TABLE monitor MODIFY COLUMN load_15 UNSET FULLTEXT INDEX; ``` The column must be a string type to alter the fulltext index. If the fulltext index has never been enabled, you can enable it and specify the `analyzer` and `case_sensitive` options. When the fulltext index is already enabled on a column, you can disable it but **cannot modify the options, and so does the skipping index**. ### Rename table Renames the table: ```sql ALTER TABLE monitor RENAME monitor_new; ``` This command only renames the table; it doesn't modify the data within the table. --- ## CASE The `CASE` statement allows you to perform conditional logic within your queries, similar to an IF-THEN-ELSE structure in programming languages. It enables you to return specific values based on evaluated conditions, making data retrieval and manipulation more dynamic. ## Syntax ```sql CASE WHEN condition1 THEN result1 WHEN condition2 THEN result2 ... ELSE result END ``` - `condition1`, `condition2`, ...: The conditions to evaluate against the expression. - `result1`, `result2`, ...: The values to return when the corresponding condition is met. - `result`: The value to return when none of the conditions are met (optional). ## Examples The `CASE` statement can be used in various clauses, such as `SELECT`, `WHERE`, `ORDER BY` and `GROUP BY`. ### Use `CASE` in `SELECT` In the `SELECT` clause, you can use the `CASE` statement to create new columns based on conditions. please see [the example](/user-guide/query-data/sql.md#case) in the query data guide. You can also use `CASE` with functions like `SUM` to conditionally aggregate data. for example, you can calculate the total number of logs with status 200 and 404: ```sql SELECT SUM(CASE WHEN status_code = '200' THEN 1 ELSE 0 END) AS status_200_count, SUM(CASE WHEN status_code = '404' THEN 1 ELSE 0 END) AS status_404_count FROM nginx_logs; ``` ### Use `CASE` in `WHERE` In the `WHERE` clause, you can filter rows based on conditions. For example, the following query retrieves data from the `monitor` table based on the `ts` condition: ```sql SELECT * FROM monitor WHERE host = CASE WHEN ts > '2023-12-13 02:05:46' THEN '127.0.0.1' ELSE '127.0.0.2' END; ``` ### Use `CASE` in `GROUP BY` The `CASE` statement can be utilized in the `GROUP BY` clause to categorize data based on specific conditions. For instance, the following query groups data by the `host` column and classifies the `cpu` column into three categories: 'high', 'medium', and 'low': ```sql SELECT host, COUNT(*) AS count, CASE WHEN cpu > 0.5 THEN 'high' WHEN cpu > 0.3 THEN 'medium' ELSE 'low' END AS cpu_status FROM monitor GROUP BY host, cpu_status; ``` ### Use `CASE` in `ORDER BY` According to GreptimeDB's [data model](/user-guide/concepts/data-model.md), the `Tag` columns are indexed and can be used in the `ORDER BY` clause to enhance query performance. For instance, if the `status_code` and `http_method` columns in the `nginx_logs` table are `Tag` columns storing string values, you can utilize the `CASE` statement to sort the data based on these columns as follows: ```sql SELECT * FROM nginx_logs ORDER BY CASE WHEN status_code IS NOT NULL THEN status_code ELSE http_method END; ``` --- ## CAST `CAST` is used to convert an expression of one data type to another. ## Syntax ```sql CAST (expression AS data_type) ``` ## Parameters - expression: the expression to be converted. - data_type: the data type to convert the expression to. # Examples Convert a string to an integer: ```sql SELECT CAST('123' AS INT) ; ``` ```sql +-------------+ | Utf8("123") | +-------------+ | 123 | +-------------+ ``` --- ## COMMENT The `COMMENT` statement is used to add or remove comments on tables, columns, and flows. Comments provide descriptions that can help document the purpose and usage of database objects. ## COMMENT ON TABLE `COMMENT ON TABLE` adds or removes a comment on a table. ### Syntax ```sql COMMENT ON TABLE table_name IS { 'comment' | NULL } ``` - `table_name`: The name of the table to comment on. - `'comment'`: A string literal containing the comment text. - `NULL`: Removes the existing comment from the table. ### Examples Add a comment to a table: ```sql COMMENT ON TABLE system_metrics IS 'System monitoring metrics collected every minute'; ``` Remove a comment from a table: ```sql COMMENT ON TABLE system_metrics IS NULL; ``` View the table comment using `SHOW CREATE TABLE`: ```sql SHOW CREATE TABLE system_metrics; ``` The comment can also be viewed through the `INFORMATION_SCHEMA.TABLES` table by querying the `table_comment` column. ## COMMENT ON COLUMN `COMMENT ON COLUMN` adds or removes a comment on a specific column of a table. ### Syntax ```sql COMMENT ON COLUMN table_name.column_name IS { 'comment' | NULL } ``` - `table_name`: The name of the table containing the column. - `column_name`: The name of the column to comment on. - `'comment'`: A string literal containing the comment text. - `NULL`: Removes the existing comment from the column. ### Examples Add a comment to a column: ```sql COMMENT ON COLUMN system_metrics.cpu_usage IS 'CPU usage percentage (0-100)'; ``` Add comments to multiple columns: ```sql COMMENT ON COLUMN system_metrics.memory_usage IS 'Memory usage in bytes'; COMMENT ON COLUMN system_metrics.disk_usage IS 'Disk usage percentage'; ``` Remove a comment from a column: ```sql COMMENT ON COLUMN system_metrics.cpu_usage IS NULL; ``` View column comments using `SHOW CREATE TABLE`: ```sql SHOW CREATE TABLE system_metrics; ``` Column comments can also be queried from the `INFORMATION_SCHEMA.COLUMNS` table by accessing the `column_comment` column. ## COMMENT ON FLOW `COMMENT ON FLOW` adds or removes a comment on a flow. ### Syntax ```sql COMMENT ON FLOW flow_name IS { 'comment' | NULL } ``` - `flow_name`: The name of the flow to comment on. - `'comment'`: A string literal containing the comment text. - `NULL`: Removes the existing comment from the flow. ### Examples Add a comment to a flow: ```sql COMMENT ON FLOW temperature_monitoring IS 'Monitors temperature sensors and alerts on high values'; ``` Remove a comment from a flow: ```sql COMMENT ON FLOW temperature_monitoring IS NULL; ``` View the flow comment using `SHOW CREATE FLOW`: ```sql SHOW CREATE FLOW temperature_monitoring; ``` Flow comments can also be queried from the `INFORMATION_SCHEMA.FLOWS` table by accessing the `comment` column. ## Notes - Comments are stored as metadata and do not affect the behavior or performance of tables, columns, or flows. - Comments can be updated by issuing a new `COMMENT ON` statement with a different comment text. - Setting a comment to `NULL` removes the existing comment but does not generate an error if no comment exists. - Comments are particularly useful for documenting the purpose of database objects, especially in collaborative environments. --- ## ANSI Compatibility GreptimeDB supports a subset of ANSI SQL and has some unique extensions. Some major incompatibilities and extensions are described below: 1. Create a table: * Supports the unique `TIME INDEX` constraint. Please refer to the [Data Model](/user-guide/concepts/data-model.md) and the [CREATE](./create.md) table creation syntax for details. * Currently only supports `PRIMARY KEY` constraints and does not support other types of constraints or foreign keys. * GreptimeDB is a native distributed database, so the table creation syntax for distributed tables supports partitioning rules. Please also refer to the [CREATE](./create.md). 2. Insert data: Consistent with ANSI SQL syntax, but requires the `TIME INDEX` column value (or default value) to be provided. 3. Update data: Does not support `UPDATE` syntax, but if the primary key and `TIME INDEX` corresponding column values are the same during `INSERT`, subsequent inserted rows will overwrite previously written rows, effectively achieving an update. * Since 0.8, GreptimeDB supports [append mode](/reference/sql/create.md#create-an-append-only-table) that creates an append-only table with `append_mode="true"` option which keeps duplicate rows. * GreptimeDB supports [merge mode](/reference/sql/create.md#create-an-append-only-table) that creates a table with `merge_mode="last_non_null"` option which allow updating a field partially. 4. Query data: Query syntax is compatible with ANSI SQL, with some functional differences and omissions. * Since v0.9.0, begins to support [VIEW](/user-guide/query-data/view.md). * TQL syntax extension: Supports executing PromQL in SQL via TQL subcommands. Please refer to the [TQL](./tql.md) section for details. * [Range Query](/reference/sql/range.md#range-query) to query and aggregate data within a range of time. 5. Delete data: Deletion syntax is basically consistent with ANSI SQL. 6. Others: * Identifiers such as table names and column names have constraints similar to ANSI SQL, are case sensitive, and require double quotes when encountering special characters or uppercase letters. * GreptimeDB has optimized identifier rules for different dialects. For example, when you connect with a MySQL or PostgreSQL client, you can use identifier rules specific to that SQL dialect, such as using backticks `` ` `` for MySQL and standard double quotes `"` for PostgreSQL. --- ## COPY ## COPY TABLE ### COPY TO `COPY TO` is used to export the contents of a table to a file. The syntax for using `COPY TO` is as follows: ```sql COPY tbl TO '/xxx/xxx/output.parquet' WITH (FORMAT = 'parquet'); ``` The command starts with the keyword `COPY`, followed by the name of the table you want to export data from (`tbl` in this case). `TO` specifies the file path and name to save the exported data (`/xxx/xxx/output.parquet` in this case). :::tip NOTE The output file is created on the GreptimeDB server node that executes the query, not on the client machine that issues the SQL. Make sure the path is accessible and writable on that server, or export to S3, GCS, Azure Blob Storage, or other supported cloud storage services via `CONNECTION`. ::: For example, to export data to CSV or JSON with custom timestamp and date formats: ```sql COPY tbl TO '/path/to/file.csv' WITH ( FORMAT = 'csv', TIMESTAMP_FORMAT = '%Y/%m/%d %H:%M:%S', DATE_FORMAT = '%Y-%m-%d' ); ``` ```sql COPY tbl TO '/path/to/file.json' WITH ( FORMAT = 'json', TIMESTAMP_FORMAT = '%Y/%m/%d %H:%M:%S', DATE_FORMAT = '%Y-%m-%d' ); ``` You can also export data to a compressed CSV or JSON file: ```sql COPY tbl TO '/path/to/file.csv.gz' WITH ( FORMAT = 'csv', compression_type = 'gzip' ); ``` :::tip NOTE When using compression, ensure the file extension matches the compression type: `.gz` for gzip, `.zst` for zstd, `.bz2` for bzip2, and `.xz` for xz. ::: #### `WITH` Option `WITH` adds options such as the file `FORMAT` which specifies the format of the exported file. In this example, the format is Parquet; it is a columnar storage format used for big data processing. Parquet efficiently compresses and encodes columnar data for big data analytics. | Option | Description | Required | |---|---|---| | `FORMAT` | Target file(s) format, e.g., JSON, CSV, Parquet | **Required** | | `START_TIME`/`END_TIME`| The time range within which data should be exported. `START_TIME` is inclusive and `END_TIME` is exclusive. | Optional | | `compression_type` | Compression algorithm for the exported file. Supported values: `gzip`, `zstd`, `bzip2`, `xz`. Only supported for CSV and JSON formats. | Optional | | `TIMESTAMP_FORMAT` | Custom format for timestamp columns when exporting to CSV or JSON format. Uses [strftime](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) format specifiers (e.g., `'%Y-%m-%d %H:%M:%S'`). Supported for CSV and JSON formats. | Optional | | `DATE_FORMAT` | Custom format for date columns when exporting to CSV or JSON format. Uses [strftime](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) format specifiers (e.g., `'%Y-%m-%d'`). Supported for CSV and JSON formats. | Optional | | `TIME_FORMAT` | Custom format for time columns when exporting to CSV or JSON format. Uses [strftime](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) format specifiers (e.g., `'%H:%M:%S'`). Supported for CSV and JSON formats. | Optional | #### `CONNECTION` Option `COPY TO` supports exporting data to cloud storage services. See [connect-to-s3](#connect-to-s3), [connect-to-gcs](#connect-to-gcs), or [connect-to-azure-blob-storage](#connect-to-azure-blob-storage) for more details. ### COPY FROM `COPY FROM` is used to import data from a file into a table. The syntax for using `COPY FROM` is as follows: ```sql COPY [.] FROM { '/[]' } [ [ WITH ] ( [ FORMAT = { 'CSV' | 'JSON' | 'PARQUET' | 'ORC' } ] [ PATTERN = '' ] ) ] [LIMIT NUM] ``` The command starts with the keyword `COPY`, followed by the name of the table you want to import data into. #### `WITH` Option `FORMAT` specifies the file format of the imported file. In this example, the format is Parquet. The option `PATTERN` allows the usage of wildcard characters like * to specify multiple input files that match a certain pattern. For example, you can use the following syntax to import all files in the directory(which must be an absolute path) "/path/to/folder" with the filename that contains `parquet`: ```sql COPY tbl FROM '/path/to/folder/' WITH (FORMAT = 'parquet', PATTERN = '.*parquet.*'); ``` Specifically, if you only have one file to import, you can use the following syntax: ```sql COPY tbl FROM '/path/to/folder/xxx.parquet' WITH (FORMAT = 'parquet'); ``` You can also import data from a compressed CSV or JSON file: ```sql COPY tbl FROM '/path/to/file.csv.gz' WITH ( FORMAT = 'csv', compression_type = 'gzip' ); ``` | Option | Description | Required | |---|---|---| | `FORMAT` | Target file(s) format, e.g., JSON, CSV, Parquet, ORC | **Required** | | `PATTERN` | Use regex to match files. e.g., `*_today.parquet` | Optional | | `compression_type` | Compression algorithm for the imported file. Supported values: `gzip`, `zstd`, `bzip2`, `xz`. Only supported for CSV and JSON formats. | Optional | :::tip NOTE The CSV file must have a header row to be imported correctly. The header row should contain the column names of the table. ::: #### `CONNECTION` Option `COPY FROM` also supports importing data from cloud storage services. See [connect-to-s3](#connect-to-s3), [connect-to-gcs](#connect-to-gcs), or [connect-to-azure-blob-storage](#connect-to-azure-blob-storage) for more details. ### Connect to S3 You can copy data from/to S3 ```sql -- COPY FROM COPY tbl FROM '' WITH (FORMAT = 'parquet') CONNECTION(REGION = 'us-west-2'); -- COPY TO COPY tbl TO '' WITH (FORMAT = 'parquet') CONNECTION(REGION = 'us-west-2'); ``` #### URL Notes: You should specify a file using `S3://bucket/key-name`. The following example shows the correct format. ``` s3://my-bucket/data.parquet ``` Another way is using Virtual-hosted–style(`ENABLE_VIRTUAL_HOST_STYLE` must be set to `true` to enable this). The following example shows the correct format. ``` s3://bucket-name.s3.region-code.amazonaws.com/key-name ``` :::tip NOTE You can use `Copy S3 URI` or `COPY URL` on S3 console to get S3 URI/HTTP URL prefix or full path. ::: #### Options You can set the following **CONNECTION** options: | Option | Description | Required | |---|---|---| | `REGION` | AWS region name. e.g., `us-west-2` | **Required** | | `ENDPOINT` | The bucket endpoint. e.g., `s3.us-west-2.amazonaws.com` | Optional | | `ACCESS_KEY_ID` | ACCESS_KEY_ID Your access key ID for connecting the AWS S3 compatible object storage. | Optional | | `SECRET_ACCESS_KEY` | Your secret access key for connecting the AWS S3 compatible object storage. | Optional | | `ENABLE_VIRTUAL_HOST_STYLE` | If you use virtual hosting to address the bucket, set it to "true".| Optional | | `SESSION_TOKEN` | Your temporary credential for connecting the AWS S3 service. | Optional | #### LIMIT You can use `LIMIT` to restrict maximum number of rows inserted at once. ### Connect to GCS You can copy data from/to Google Cloud Storage (GCS). ```sql -- COPY FROM COPY tbl FROM 'gcs:///' WITH (FORMAT = 'parquet') CONNECTION(SCOPE = 'https://www.googleapis.com/auth/devstorage.read_write'); -- COPY TO COPY tbl TO 'gcs:///' WITH (FORMAT = 'parquet') CONNECTION(SCOPE = 'https://www.googleapis.com/auth/devstorage.read_write'); ``` #### URL Specify the file or directory using `gcs://bucket/path`. For example: ``` gcs://my-bucket/data.parquet ``` #### Options | Option | Description | Required | |---|---|---| | `SCOPE` | The scope for GCS access, e.g., `https://www.googleapis.com/auth/devstorage.read_write` | Optional | | `CREDENTIAL` | The service account credential content in JSON format. | Optional | | `ENDPOINT` | The endpoint of the GCS service. | Optional | ### Connect to Azure Blob Storage You can copy data from/to Azure Blob Storage. ```sql -- COPY FROM COPY tbl FROM 'azblob:///' WITH (FORMAT = 'parquet') CONNECTION(ACCOUNT_NAME = 'my-account', ACCOUNT_KEY = 'my-key'); -- COPY TO COPY tbl TO 'azblob:///' WITH (FORMAT = 'parquet') CONNECTION(ACCOUNT_NAME = 'my-account', ACCOUNT_KEY = 'my-key'); ``` #### URL Specify the file or directory using `azblob://container/path`. For example: ``` azblob://my-container/data.parquet ``` #### Options | Option | Description | Required | |---|---|---| | `ACCOUNT_NAME` | Azure storage account name. | Optional | | `ACCOUNT_KEY` | Azure storage account key. | Optional | | `ENDPOINT` | The endpoint of the Azure Blob Storage service. | Optional | | `SAS_TOKEN` | Shared access signature (SAS) token for Azure Blob Storage. | Optional | ## COPY Query Results You can use the `COPY` statement to export the results of a query to a file. The syntax is as follows: ```sql COPY () TO '' WITH (FORMAT = { 'CSV' | 'JSON' | 'PARQUET' }); ``` | Option | Description | Required | |---|---|---| | `QUERY` | The SQL SELECT statement to execute | **Required** | | `PATH` | The file path where the output will be written | **Required** | | `FORMAT` | The output file format: 'CSV', 'JSON', or 'PARQUET' | **Required** | | `compression_type` | Compression algorithm for the exported file. Supported values: `gzip`, `zstd`, `bzip2`, `xz`. Only supported for CSV and JSON formats. | Optional | | `TIMESTAMP_FORMAT` | Custom format for timestamp columns when exporting to CSV or JSON format. Uses [strftime](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) format specifiers. Supported for CSV and JSON formats. | Optional | | `DATE_FORMAT` | Custom format for date columns when exporting to CSV or JSON format. Uses [strftime](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) format specifiers. Supported for CSV and JSON formats. | Optional | | `TIME_FORMAT` | Custom format for time columns when exporting to CSV or JSON format. Uses [strftime](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) format specifiers. Supported for CSV and JSON formats. | Optional | ### PostgreSQL `COPY ... TO STDOUT` When you connect through the PostgreSQL protocol, you can stream query results to the client with `COPY () TO STDOUT`. This is useful when you want the output to be handled by the PostgreSQL client, such as `psql`, instead of writing a file on the GreptimeDB server. PostgreSQL-compatible option syntax is supported in both forms: `WITH (...)` and bare `(...)`. ```sql COPY (SELECT * FROM tbl WHERE host = 'host1') TO STDOUT; COPY (SELECT * FROM tbl WHERE host = 'host1') TO STDOUT WITH (FORMAT csv); COPY (SELECT * FROM tbl WHERE host = 'host1') TO STDOUT (FORMAT binary); ``` - `FORMAT` supports PostgreSQL text output (default when omitted), `csv`, and `binary`. - `COPY ... TO STDOUT` is only supported for query results, that is, `COPY ()`, on the PostgreSQL protocol. For example, in `psql` you can use `\copy` to save the streamed result to a local file on the client machine: ```sql \copy (SELECT * FROM tbl WHERE host = 'host1') TO '/tmp/file.csv' WITH (FORMAT csv) ``` For example, the following statement exports query results to a CSV file: ```sql COPY (SELECT * FROM tbl WHERE host = 'host1') TO '/path/to/file.csv' WITH (FORMAT = 'csv'); ``` You can also export query results to a compressed file: ```sql COPY (SELECT * FROM tbl WHERE host = 'host1') TO '/path/to/file.json.gz' WITH ( FORMAT = 'json', compression_type = 'gzip' ); ``` You can also specify custom date and time formats when exporting to CSV or JSON: ```sql COPY (SELECT * FROM tbl WHERE host = 'host1') TO '/path/to/file.csv' WITH ( FORMAT = 'csv', TIMESTAMP_FORMAT = '%m-%d-%Y %H:%M:%S', DATE_FORMAT = '%Y/%m/%d' ); ``` ```sql COPY (SELECT * FROM tbl WHERE host = 'host1') TO '/path/to/file.json' WITH ( FORMAT = 'json', TIMESTAMP_FORMAT = '%m-%d-%Y %H:%M:%S', DATE_FORMAT = '%Y/%m/%d' ); ``` ## COPY DATABASE Beside copying specific table to/from some path, `COPY` statement can also be used to copy whole database to/from some path. The syntax for copying databases is: ```sql COPY DATABASE [TO | FROM] '' WITH ( FORMAT = { 'CSV' | 'JSON' | 'PARQUET' }, START_TIME = "", END_TIME = "", PARALLELISM = ) [CONNECTION( REGION = "", ENDPOINT = "", ACCESS_KEY_ID = "", SECRET_ACCESS_KEY = "", ENABLE_VIRTUAL_HOST_STYLE = "[true | false]", )] ``` | Option | Description | Required | |---|---|---| | `FORMAT` | Export file format, available options: JSON, CSV, Parquet | **Required** | | `START_TIME`/`END_TIME`| The time range within which data should be exported. `START_TIME` is inclusive and `END_TIME` is exclusive. | Optional | | `PARALLELISM` | Number of tables to process in parallel. For example, if a database contains 30 tables and `PARALLELISM` is set to 8, then 8 tables will be processed concurrently. Defaults to the total number of CPU cores, with a minimum value of 1. | Optional | > - When copying databases, `` must end with `/`. > - `CONNECTION` parameters can also be used to copying databases to/from object storage services like AWS S3, GCS, and Azure Blob Storage. ### Examples ```sql -- Export all tables' data to /tmp/export/ COPY DATABASE public TO '/tmp/export/' WITH (FORMAT='parquet'); -- Export all table data using 4 parallel operations COPY DATABASE public TO '/tmp/export/' WITH (FORMAT='parquet', PARALLELISM=4); -- Export all tables' data within time range 2022-04-11 08:00:00~2022-04-11 09:00:00 to /tmp/export/ COPY DATABASE public TO '/tmp/export/' WITH (FORMAT='parquet', START_TIME='2022-04-11 08:00:00', END_TIME='2022-04-11 09:00:00'); -- Import files under /tmp/export/ directory to database named public. COPY DATABASE public FROM '/tmp/export/' WITH (FORMAT='parquet'); -- Import files using 8 parallel operations COPY DATABASE public FROM '/tmp/export/' WITH (FORMAT='parquet', PARALLELISM=8); ``` ## Special reminder for Windows platforms Please notice that when executing `COPY`/`COPY DATABASE` statements on Windows platforms, backslashes (`\`) in paths should be replaced with `/` for compatibility. ```sql -- Won't work COPY tbl TO 'C:\xxx\xxx\output.parquet' WITH (FORMAT = 'parquet'); -- Correct path: COPY tbl TO 'C:/xxx/xxx/output.parquet' WITH (FORMAT = 'parquet'); ``` --- ## CREATE `CREATE` is used to create new databases or tables. ## CREATE DATABASE ### Syntax Creates a new database: ```sql CREATE DATABASE [IF NOT EXISTS] db_name [WITH ] ``` If the `db_name` database already exists, then GreptimeDB has the following behaviors: - Doesn't create a new database. - Doesn't return an error when the clause `IF NOT EXISTS` is presented. - Otherwise, returns an error. The database can also carry options similar to the `CREATE TABLE` statement by using the `WITH` keyword. The following options are available for databases: - `ttl` - Time-To-Live for data in all tables within the database (cannot be set to `instant`) - `memtable.type` - Type of memtable (`time_series`, `partition_tree`) - `append_mode` - Whether tables in the database should be append-only (`true`/`false`) - `merge_mode` - Strategy for merging duplicate rows (`last_row`, `last_non_null`) - `skip_wal` - Whether to disable Write-Ahead-Log for tables in the database (`'true'`/`'false'`) - `sst_format` - SST (Sorted String Table) file format for tables in the database (`flat`, `primary_key`) - `compaction.*` - Compaction-related settings (e.g., `compaction.type`, `compaction.twcs.time_window`) Read more about [table options](#table-options). :::note Important Behavior Differences Database options behave differently: - **TTL and Compaction options** (`ttl`, `compaction.*`): These options have ongoing effect. Tables without specified values will continuously inherit database-level values. Changing the database TTL or compaction options will immediately impact all tables that don't have their own settings. - **Other options** (`memtable.type`, `append_mode`, `merge_mode`, `skip_wal`, `sst_format`): These act as template variables that are only applied when creating new tables. Changing these database-level options will NOT affect existing tables - they only serve as defaults for newly created tables. ::: When creating a table, if the corresponding table options are not provided, the options configured at the database level will be applied. ### Examples Creates a `test` database: ```sql CREATE DATABASE test; ``` ```sql Query OK, 1 row affected (0.05 sec) ``` Creates it again with `IF NOT EXISTS`: ```sql CREATE DATABASE IF NOT EXISTS test; ``` Create a database with a `TTL` (Time-To-Live) of seven days, which means all the tables in this database will inherit this option if they don't have their own `TTL` setting: ```sql CREATE DATABASE test WITH (ttl='7d'); ``` Create a database with multiple options, including append mode and custom memtable type: ```sql CREATE DATABASE test WITH ( ttl='30d', 'memtable.type'='partition_tree', 'append_mode'='true' ); ``` Create a database with Write-Ahead-Log disabled and custom merge mode: ```sql CREATE DATABASE test WITH ( 'skip_wal'='true', 'merge_mode'='last_non_null' ); ``` Create a database with a specific SST file format: ```sql CREATE DATABASE test WITH ('sst_format'='flat'); ``` ## CREATE TABLE ### Syntax Creates a new table in the `db` database or the current database in use: ```sql CREATE TABLE [IF NOT EXISTS] [db.]table_name ( column1 type1 [NULL | NOT NULL] [DEFAULT expr1] [TIME INDEX] [PRIMARY KEY] [indexes] [COMMENT comment1], column2 type2 [NULL | NOT NULL] [DEFAULT expr2] [TIME INDEX] [PRIMARY KEY] [indexes] [COMMENT comment2], ... [TIME INDEX (column)], [PRIMARY KEY(column1, column2, ...)], ) [ PARTITION ON COLUMNS(column1, column2, ...) ( , ... ) ] ENGINE = engine WITH([TTL | storage | ...] = expr, ...) ``` The table schema is specified by the brackets before the `ENGINE`. The table schema is a list of column definitions and table constraints. For information on the `engine` option and table engine selection, please refer to the [Table Engines](/reference/about-greptimedb-engines.md) guide. A column definition includes the column `column_name`, `type`, and options such as nullable or default values, etc. Please see below. ### Table constraints The table constraints contain the following: - `TIME INDEX` specifies the time index column, which always has one and only one column. It indicates the `Timestamp` type in the [data model](/user-guide/concepts/data-model.md) of GreptimeDB. - `PRIMARY KEY` specifies the table's primary key column, which indicates the `Tag` type in the [data model](/user-guide/concepts/data-model.md) of GreptimeDB. It cannot include the time index column, but it always implicitly adds the time index column to the end of keys. - The Other columns are `Field` columns in the [data model](/user-guide/concepts/data-model.md) of GreptimeDB. :::tip NOTE The `PRIMARY KEY` specified in the `CREATE` statement is **not** the primary key in traditional relational databases. Actually, The `PRIMARY KEY` in traditional relational databases is equivalent to the combination of `PRIMARY KEY` and `TIME INDEX` in GreptimeDB. In other words, the `PRIMARY KEY` and `TIME INDEX` together constitute the unique identifier of a row in GreptimeDB. ::: The statement won't do anything if the table already exists and `IF NOT EXISTS` is presented; otherwise returns an error. #### Indexes GreptimeDB provides various type of indexes to accelerate query. Please refer to [Data Index](/user-guide/manage-data/data-index.md) for more details. ### Table options Users can add table options by using `WITH`. The valid options contain the following: | Option | Description | Value | | ------------------------------------------- | --------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `ttl` | The storage time of the table data | A time duration string such as `'60m'`, `'1h'` for one hour, `'14d'` for 14 days etc. Supported time units are: `s` / `m` / `h` / `d`. | | `storage` | The name of the table storage engine provider | String value, such as `S3`, `Gcs`, etc. It must be configured in `[[storage.providers]]`, see [configuration](/user-guide/deployments-administration/configuration.md#storage-engine-provider). | | `compaction.type` | Compaction strategy of the table | String value. Only `twcs` is allowed. | | `compaction.twcs.trigger_file_num` | Number of files in a specific time window to trigger a compaction | String value, such as '8'. Only available when `compaction.type` is `twcs`. You can refer to this [document](https://cassandra.apache.org/doc/latest/cassandra/managing/operating/compaction/twcs.html) to learn more about the `twcs` compaction strategy. | | `compaction.twcs.time_window` | Compaction time window | String value, such as '1d' for 1 day. The table usually partitions rows into different time windows by their timestamps. Only available when `compaction.type` is `twcs`. | | `compaction.twcs.max_output_file_size` | Maximum allowed output file size for TWCS compaction | String value, such as '1GB', '512MB'. Sets the maximum size for files produced by TWCS compaction. Only available when `compaction.type` is `twcs`. | | `memtable.type` | Type of the memtable. | String value, supports `time_series`, `partition_tree`. | | `append_mode` | Whether the table is append-only | String value. Default is 'false', which removes duplicate rows by primary keys and timestamps according to the `merge_mode`. Setting it to 'true' to enable append mode and create an append-only table which keeps duplicate rows. | | `merge_mode` | The strategy to merge duplicate rows | String value. Only available when `append_mode` is 'false'. Default is `last_row`, which keeps the last row for the same primary key and timestamp. Setting it to `last_non_null` to keep the last non-null field for the same primary key and timestamp. | | `sst_format` | The format of SST files | String value, supports `primary_key`, `flat`. Default is `flat`. `flat` is recommended for tables which have a large number of unique primary keys. | | `comment` | Table level comment | String value. | | `skip_wal` | Whether to disable Write-Ahead-Log for this table | String type. When set to `'true'`, the data written to the table will not be persisted to the write-ahead log, which can avoid storage wear and improve write throughput. However, when the process restarts, any unflushed data will be lost. Please use this feature only when the data source itself can ensure reliability. | | `index.type` | Index type | **Only for metric engine** String value, supports `none`, `skipping`. | #### Create a table with TTL For example, to create a table with the storage data TTL(Time-To-Live) is seven days: ```sql CREATE TABLE IF NOT EXISTS temperatures( ts TIMESTAMP TIME INDEX, temperature DOUBLE DEFAULT 10, ) with(ttl='7d'); ``` The `ttl` value can be one of the following: - A [duration](/reference/time-durations.md) like `1hour 12min 5s`. - `forever`, `NULL`, an empty string `''` and `0s` (or any zero length duration, like `0d`), means the data will never be deleted. - `instant`, note that database's TTL can't be set to `instant`. `instant` means the data will be deleted instantly when inserted, useful if you want to send input to a flow task without saving it, see more details in [flow management documents](/user-guide/flow-computation/manage-flow.md#manage-flows). - Unset, `ttl` can be unset by using `ALTER TABLE UNSET 'ttl'`, which means the table will inherit the database's ttl policy (if any). If a table has its own TTL policy, it will take precedence over the database TTL policy. Otherwise, the database TTL policy will be applied to the table. So if table's TTL is set to `forever`, no matter what the database's TTL is, the data will never be deleted. But if you unset table TTL using: ```sql ALTER TABLE UNSET 'ttl'; ``` Then the database's TTL will be applied to the table. Note that the default TTL setting for table and database is unset, which also means the data will never be deleted. #### Create a table with custom storage Create a table that stores the data in Google Cloud Storage: ```sql CREATE TABLE IF NOT EXISTS temperatures( ts TIMESTAMP TIME INDEX, temperature DOUBLE DEFAULT 10, ) with(ttl='7d', storage="Gcs"); ``` #### Create a table with custom compaction options Create a table with custom compaction options. The table will attempt to partition data into 1-day time window based on the timestamps of the data and merges files within each time window if they exceed 8 files. ```sql CREATE TABLE IF NOT EXISTS temperatures( ts TIMESTAMP TIME INDEX, temperature DOUBLE DEFAULT 10, ) with( 'compaction.type'='twcs', 'compaction.twcs.time_window'='1d', 'compaction.twcs.trigger_file_num'='8', 'compaction.twcs.max_output_file_size'='1GB' ); ``` #### Create an append-only table Create an append-only table which disables deduplication. ```sql CREATE TABLE IF NOT EXISTS temperatures( ts TIMESTAMP TIME INDEX, temperature DOUBLE DEFAULT 10, ) with('append_mode'='true'); ``` #### Create a table with merge mode Create a table with `last_row` merge mode, which is the default merge mode. ```sql create table if not exists metrics( host string, ts timestamp, cpu double, memory double, TIME INDEX (ts), PRIMARY KEY(host) ) with('merge_mode'='last_row'); ``` Under `last_row` mode, the table merges rows with the same primary key and timestamp by only keeping the latest row. ```sql INSERT INTO metrics VALUES ('host1', 0, 0, NULL), ('host2', 1, NULL, 1); INSERT INTO metrics VALUES ('host1', 0, NULL, 10), ('host2', 1, 11, NULL); SELECT * from metrics ORDER BY host, ts; +-------+-------------------------+------+--------+ | host | ts | cpu | memory | +-------+-------------------------+------+--------+ | host1 | 1970-01-01T00:00:00 | | 10.0 | | host2 | 1970-01-01T00:00:00.001 | 11.0 | | +-------+-------------------------+------+--------+ ``` Create a table with `last_non_null` merge mode. ```sql create table if not exists metrics( host string, ts timestamp, cpu double, memory double, TIME INDEX (ts), PRIMARY KEY(host) ) with('merge_mode'='last_non_null'); ``` Under `last_non_null` mode, the table merges rows with the same primary key and timestamp by keeping the latest non-null value of each field. ```sql INSERT INTO metrics VALUES ('host1', 0, 0, NULL), ('host2', 1, NULL, 1); INSERT INTO metrics VALUES ('host1', 0, NULL, 10), ('host2', 1, 11, NULL); SELECT * from metrics ORDER BY host, ts; +-------+-------------------------+------+--------+ | host | ts | cpu | memory | +-------+-------------------------+------+--------+ | host1 | 1970-01-01T00:00:00 | 0.0 | 10.0 | | host2 | 1970-01-01T00:00:00.001 | 11.0 | 1.0 | +-------+-------------------------+------+--------+ ``` #### Create a table with WAL disabled Create a table with WAL disabled. Please note that when WAL is disabled, unflushed data will be lost on process restart. ```sql CREATE TABLE IF NOT EXISTS temperatures( ts TIMESTAMP TIME INDEX, temperature DOUBLE DEFAULT 10 ) with('skip_wal'='true'); ``` #### Create a physical table with metric engine The metric engine use synthetic physical wide tables to store a large amount of small table data, achieving effects such as reuse of the same column and metadata. For details, please refer to the [metric engine document](/contributor-guide/datanode/metric-engine) and [Table Engines](/reference/about-greptimedb-engines.md) introduction. Create a physical table with the metric engine. ```sql CREATE TABLE greptime_physical_table ( greptime_timestamp TIMESTAMP(3) NOT NULL, greptime_value DOUBLE NULL, TIME INDEX (greptime_timestamp), ) engine = metric with ( "physical_metric_table" = "", ); ``` #### Create a physical table with enable skipping index for columns By default, the metric engine won't create indexes for columns. You can enable it by setting the `index.type` to `skipping`. Create a physical table with a skipping index; all automatically added columns will have this index applied. ```sql CREATE TABLE greptime_physical_table ( greptime_timestamp TIMESTAMP(3) NOT NULL, greptime_value DOUBLE NULL, TIME INDEX (greptime_timestamp), ) engine = metric with ( "physical_metric_table" = "", "index.type" = "skipping", ); ``` #### Create a table with SST format Create a table with `flat` SST format. ```sql CREATE TABLE IF NOT EXISTS metrics( host string, ts timestamp, cpu double, memory double, TIME INDEX (ts), PRIMARY KEY(host) ) with('sst_format'='flat'); ``` The `flat` format is optimized for high cardinality primary keys and is the default SST format for new tables. ### Column options GreptimeDB supports the following column options: | Option | Description | | ----------------- | ---------------------------------------------------------------------------------------------------------- | | NULL | The column value can be `null`. | | NOT NULL | The column value can't be `null`. | | DEFAULT `expr` | The column's default value is `expr`, which its result type must be the column's type | | COMMENT `comment` | The column comment. It must be a string value | | FULLTEXT INDEX | Creates a full-text index to speed up full-text search operations. Applicable only to string-type columns. | | SKIPPING INDEX | Creates a skipping index to speed up query on sparse data. | | INVERTED INDEX | Creates an inverted index to speed up query on dense data. | The table constraints `TIME INDEX` and `PRIMARY KEY` can also be set by column option, but they can only be specified once in column definitions. So you can't specify `PRIMARY KEY` for more than one column except by the table constraint `PRIMARY KEY` : ```sql CREATE TABLE system_metrics ( host STRING PRIMARY KEY, idc STRING PRIMARY KEY, cpu_util DOUBLE, memory_util DOUBLE, disk_util DOUBLE, ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP(), TIME INDEX(ts) ); ``` Goes wrong: ```sql Illegal primary keys definition: not allowed to inline multiple primary keys in columns options ``` ```sql CREATE TABLE system_metrics ( host STRING, idc STRING, cpu_util DOUBLE, memory_util DOUBLE, disk_util DOUBLE, ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP() TIME INDEX, PRIMARY KEY(host, idc), ); ``` ```sql Query OK, 0 rows affected (0.01 sec) ``` #### `INDEX` Column Option For more information on the `INDEX` column option, please refer to the [Data Index](/user-guide/manage-data/data-index.md) document. ### Region partition rules Please refer to [Partition](/contributor-guide/frontend/table-sharding.md#partition) for more details. ## CREATE EXTERNAL TABLE ### Syntax Creates a new file external table in the `db` database or the current database in use: ```sql CREATE EXTERNAL TABLE [IF NOT EXISTS] [db.]table_name [ ( column1 type1 [NULL | NOT NULL] [DEFAULT expr1] [TIME INDEX] [PRIMARY KEY] [COMMENT comment1], column2 type2 [NULL | NOT NULL] [DEFAULT expr2] [TIME INDEX] [PRIMARY KEY] [COMMENT comment2], ... [TIME INDEX (column)], [PRIMARY KEY(column1, column2, ...)] ) ] WITH ( LOCATION = url, FORMAT = { 'CSV' | 'JSON' | 'PARQUET' | 'ORC' } [,PATTERN = regex_pattern ] [,REGION = region ] [,ENDPOINT = uri ] [,ACCESS_KEY_ID = key_id ] [,SECRET_ACCESS_KEY = access_key ] [,ENABLE_VIRTUAL_HOST_STYLE = { TRUE | FALSE }] [,SESSION_TOKEN = token ] ... ) ``` ### Table options | Option | Description | Required | | ---------- | ------------------------------------------------------------------------------- | ------------ | | `LOCATION` | External files locations, e.g., `s3://[]`, `//[]` | **Required** | | `FORMAT` | Target file(s) format, e.g., JSON, CSV, Parquet, ORC | **Required** | | `PATTERN` | Use regex to match files. e.g., `*_today.parquet` | Optional | #### S3 | Option | Description | Required | | --------------------------- | ------------------------------------------------------------------------------------- | ------------ | | `REGION` | AWS region name. e.g., us-east-1. | **Required** | | `ENDPOINT` | The bucket endpoint | Optional | | `ACCESS_KEY_ID` | ACCESS_KEY_ID Your access key ID for connecting the AWS S3 compatible object storage. | Optional | | `SECRET_ACCESS_KEY` | Your secret access key for connecting the AWS S3 compatible object storage. | Optional | | `ENABLE_VIRTUAL_HOST_STYLE` | If you use virtual hosting to address the bucket, set it to "true". | Optional | | `SESSION_TOKEN` | Your temporary credential for connecting the AWS S3 service. | Optional | ### Time Index Column When creating an external table using the `CREATE EXTERNAL TABLE` statement, you are required to use the `TIME INDEX` constraint to specify a Time Index column. ### Examples You can create an external table without columns definitions, the column definitions will be automatically inferred: ```sql CREATE EXTERNAL TABLE IF NOT EXISTS city WITH (location='/var/data/city.csv',format='csv'); ``` In this example, we did not explicitly define the columns of the table. To satisfy the requirement that the external table must specify a **Time Index** column, the `CREATE EXTERNAL TABLE` statement will infer the Time Index column according to the following rules: 1. If the Time Index column can be inferred from the file metadata, then that column will be used as the Time Index column. 2. If there is a column named `greptime_timestamp` (the type of this column must be `TIMESTAMP`, otherwise, an error will be thrown), then this column will be used as the Time Index column. 3. Otherwise, a column named `greptime_timestamp` will be automatically created as the Time Index column, and a `DEFAULT '1970-01-01 00:00:00+0000'` constraint will be added. Or ```sql CREATE EXTERNAL TABLE city ( host string, ts timestamp, cpu float64 default 0, memory float64, TIME INDEX (ts), PRIMARY KEY(host) ) WITH (location='/var/data/city.csv', format='csv'); ``` In this example, we explicitly defined the `ts` column as the Time Index column. If there is no suitable Time Index column in the file, you can also create a placeholder column and add a `DEFAULT expr` constraint. ## CREATE FLOW ```sql CREATE [OR REPLACE] FLOW [ IF NOT EXISTS ] SINK TO [ EXPIRE AFTER ] [ COMMENT '' ] AS ; ``` For `CREATE FLOW`, the query after `AS` can be a regular flow query or a TQL query. GreptimeDB also supports a strict TQL CTE form for cleaner flow definitions: ```sql CREATE FLOW calc_rate_cte SINK TO rate_reqs EVAL INTERVAL '1m' AS WITH rate_data (ts, req_rate, host, job, instance) AS ( TQL EVAL (now() - '1m'::interval, now(), '30s') rate(http_requests_total{job="my_service"}[1m]) AS req_rate ) SELECT * FROM rate_data; ``` When using `WITH` in `CREATE FLOW`, the accepted shape is intentionally strict: - Only one CTE is allowed, and it must contain `TQL EVAL`. - The outer query must be exactly `SELECT * FROM `. - Additional projection, filtering, joins, ordering, or extra SQL CTEs are not supported. - If the CTE name is quoted, reference it with the same quoted name in the outer `SELECT`. For the statement to create or update a flow, please read the [flow management documents](/user-guide/flow-computation/manage-flow.md#create-a-flow). ## CREATE VIEW ```sql CREATE [OR REPLACE] VIEW [ IF NOT EXISTS ] AS select_statement ``` For the statement to create or update a view, please read the [view user guide](/user-guide/query-data/view.md#view). ## CREATE TRIGGER Please refer to the [CREATE TRIGGER](/reference/sql/trigger-syntax.md#create-trigger) documentation. --- ## Data Types SQL data types define the type of data that a column can store. When you run the `DESC TABLE` command, you can see the data type of each column. ## String and Binary Data Types | Type Name | Description | Size | | --------- | ---------------------------------------------------------------------- | -------------------------------- | | `String` | UTF-8 encoded strings. Holds up to 2,147,483,647 bytes of data | The length of the strings | | `Binary` | Variable-length binary values. Holds up to 2,147,483,647 bytes of data | The length of the data + 2 bytes | The maximum capacities of `String` and `Binary` are determined by their encodings and how the storage engine handles them. For example, `String` values are encoded into UTF-8. If all characters are 3 bytes in length, this field can store up to 715,827,882 characters. As for `Binary` types, they can store a maximum of 2,147,483,647 bytes. ## Numeric Data Types | Type Name | Description | Size | | --------- | ----------------------------------------------- | ------- | | `Int8` | -128 ~ 127 | 1 Byte | | `Int16` | -32768 ~ 32767 | 2 Bytes | | `Int32` | -2147483648 ~ 2147483647 | 4 Bytes | | `Int64` | -9223372036854775808 ~ 9223372036854775807 | 8 Bytes | | `UInt8` | 0 ~ 255 | 1 Byte | | `UInt16` | 0 ~ 65535 | 2 Bytes | | `UInt32` | 0 ~ 4294967295 | 4 Bytes | | `UInt64` | 0 ~ 18446744073709551615 | 8 Bytes | | `Float32` | 32-bit IEEE754 floating point values | 4 Bytes | | `Float64` | Double precision IEEE 754 floating point values | 8 Bytes | :::tip NOTE The descriptions here refer to **GreptimeDB native type information**, which are measured in **bits**. However, when using **SQL**, follow the conventions of **PostgreSQL** and **MySQL**, where types like `INT2`, `INT4`, `INT8`, `FLOAT4` and `FLOAT8` are defined in **bytes**. For example, in an SQL statement, `INT8` actually corresponds to **BigInt** (8 bytes, 64 bits). ::: ## Decimal Type GreptimeDB supports the `decimal` type, a fixed-point type represented as `decimal(precision, scale)`, where `precision` is the total number of digits, and `scale` is the number of digits in the fractional part. For example, `123.45` has a precision of 5 and a scale of 2. - `precision` can range from [1, 38]. - `scale` can range from [0, precision]. The default decimal is `decimal(38, 10)` if the precision and scale are not specified. ```sql CREATE TABLE decimals( d DECIMAL(3, 2), ts TIMESTAMP TIME INDEX, ); INSERT INTO decimals VALUES ('0.1',1000), ('0.2',2000); SELECT * FROM decimals; ``` Output: ```sql +------+---------------------+ | d | ts | +------+---------------------+ | 0.10 | 1970-01-01T00:00:01 | | 0.20 | 1970-01-01T00:00:02 | +------+---------------------+ ``` ## Date and Time Types | Type Name | Description | Size | | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | | `TimestampSecond` | 64-bit timestamp values with seconds precision, range: `[-262144-01-01 00:00:00, +262143-12-31 23:59:59]` | 8 Bytes | | `TimestampMillisecond` | 64-bit timestamp values with milliseconds precision, range: `[-262144-01-01 00:00:00.000, +262143-12-31 23:59:59.999]` | 8 Bytes | | `TimestampMicroSecond` | 64-bit timestamp values with microseconds precision, range: `[-262144-01-01 00:00:00.000000, +262143-12-31 23:59:59.999999]` | 8 Bytes | | `TimestampNanosecond` | 64-bit timestamp values with nanoseconds precision, range: `[1677-09-21 00:12:43.145225, 2262-04-11 23:47:16.854775807]` | 8 Bytes | | `Interval` | Time interval | 4 Bytes for `YearMonth`, 8 Bytes for `DayTime` and 16 Bytes for `MonthDayNano` | :::tip NOTE When inserting Timestamp string literals to GreptimeDB using MySQL/PostgreSQL protocol, the value range is limited to '0001-01-01 00:00:00' to '9999-12-31 23:59:59'. ::: ### Interval Type `Interval` type is used in scenarios where you need to track and manipulate time durations. It can be written using the following verbose syntax: ``` QUANTITY UNIT [QUANTITY UNIT...] ``` * `QUANTITY`: is a number (possibly signed), * `UNIT`: is `microsecond`, `millisecond`, `second`, `minute`, `hour`, `day`, `week`, `month`, `year`, `decade`, `century`, or abbreviations or plurals of these units; The amounts of the different units are combined, with each unit's sign determining if it adds or subtracts from the total interval. For example, '1 year -2 months' results in a net interval of ten months. Unfortunately, GreptimeDB doesn't support writing the interval in the format of [ISO 8601 time intervals](https://en.wikipedia.org/wiki/ISO_8601#Time_intervals) such as `P3Y3M700DT133H17M36.789S` etc. But it's output supports it. Let's take some examples: ```sql SELECT '2 years 15 months 100 weeks 99 hours 123456789 milliseconds'::INTERVAL; ``` ```sql +---------------------------------------------------------------------+ | Utf8("2 years 15 months 100 weeks 99 hours 123456789 milliseconds") | +---------------------------------------------------------------------+ | P3Y3M700DT133H17M36.789S | +---------------------------------------------------------------------+ ``` 55 minutes ago: ```sql SELECT '-1 hour 5 minute'::INTERVAL; ``` ```sql +--------------------------+ | Utf8("-1 hour 5 minute") | +--------------------------+ | P0Y0M0DT0H-55M0S | +--------------------------+ ``` 1 hour and 5 minutes ago: ```sql SELECT '-1 hour -5 minute'::INTERVAL; ``` ```sql +---------------------------+ | Utf8("-1 hour -5 minute") | +---------------------------+ | P0Y0M0DT-1H-5M0S | +---------------------------+ ``` And of course, you can manipulate time with intervals by arithmetics. Get the time of 5 minutes go: ```sql SELECT now() - '5 minute'::INTERVAL; ``` ```sql +----------------------------------------------+ | now() - IntervalMonthDayNano("300000000000") | +----------------------------------------------+ | 2024-06-24 21:24:05.012306 | +----------------------------------------------+ ``` GreptimeDB also supports shorthand forms without spaces, such as `3y2mon4h`: ```sql SELECT '3y2mon4h'::INTERVAL; ``` ``` +---------------------------------------------------------+ | IntervalMonthDayNano("3010670175542044842954670112768") | +---------------------------------------------------------+ | P3Y2M0DT4H0M0S | +---------------------------------------------------------+ ``` It also supports signed numbers: ```sql SELECT '-1h5m'::INTERVAL; ``` ``` +----------------------------------------------+ | IntervalMonthDayNano("18446740773709551616") | +----------------------------------------------+ | P0Y0M0DT0H-55M0S | +----------------------------------------------+ ``` Supported abbreviations include: | Abbreviation | Full name | | ------------ | ------------ | | y | years | | mon | months | | w | weeks | | d | days | | h | hours | | m | minutes | | s | seconds | | millis | milliseconds | | ms | milliseconds | | us | microseconds | | ns | nanoseconds | #### INTERVAL keyword In the examples above, we used the cast operation `'{quantity unit}'::INTERVAL` to demonstrate the interval type. In fact, the interval type can also be used with the syntax supported by the `INTERVAL` keyword, though the behavior varies between database dialects: 1. In MySQL, the syntax is `INTERVAL {quantity} {unit}`, where `quantity` can be a number or a string depending on the context. For example: ```sql mysql> SELECT INTERVAL 1 YEAR; +--------------------------------------------------------------------------------------+ | IntervalMonthDayNano("IntervalMonthDayNano { months: 12, days: 0, nanoseconds: 0 }") | +--------------------------------------------------------------------------------------+ | P1Y0M0DT0H0M0S | +--------------------------------------------------------------------------------------+ 1 row in set (0.01 sec) mysql> SELECT INTERVAL '1 YEAR 2' MONTH; +--------------------------------------------------------------------------------------+ | IntervalMonthDayNano("IntervalMonthDayNano { months: 14, days: 0, nanoseconds: 0 }") | +--------------------------------------------------------------------------------------+ | P1Y2M0DT0H0M0S | +--------------------------------------------------------------------------------------+ 1 row in set (0.00 sec) ``` 2. In PostgreSQL and the default GreptimeDB dialect, it is `INTERVAL '{quantity unit}'`, where the INTERVAL keyword is followed by the interval string: ```sql public=> SELECT INTERVAL '1 year'; IntervalMonthDayNano("IntervalMonthDayNano { months: 12, days: 0, nanoseconds: 0 }") -------------------------------------------------------------------------------------- 1 year (1 row) public=> SELECT INTERVAL '1 year 2 month'; IntervalMonthDayNano("IntervalMonthDayNano { months: 14, days: 0, nanoseconds: 0 }") -------------------------------------------------------------------------------------- 1 year 2 mons (1 row) ``` ## JSON Type (Experimental) :::warning The JSON feature is currently experimental and may change in future releases. ::: GreptimeDB supports the JSON type, allowing users to store and query JSON-formatted data. The JSON type is highly flexible and can store various forms of structured or unstructured data, making it suitable for use cases such as logging, analytics, and semi-structured data storage. ```sql CREATE TABLE json_data( my_json JSON, ts TIMESTAMP TIME INDEX ); INSERT INTO json_data VALUES ('{"key1": "value1", "key2": 10}', 1000), ('{"name": "GreptimeDB", "open_source": true}', 2000); SELECT * FROM json_data; ``` Output: ``` +------------------------------------------+---------------------+ | my_json | ts | +------------------------------------------+---------------------+ | {"key1":"value1","key2":10} | 1970-01-01 00:00:01 | | {"name":"GreptimeDB","open_source":true} | 1970-01-01 00:00:02 | +------------------------------------------+---------------------+ ``` ### Query JSON data You can query the JSON data directly or extract specific fields using [JSON functions](./functions/overview.md#json-functions) provided by GreptimeDB. Here's an example: ```sql SELECT json_get_string(my_json, '$.name') as name FROM json_data; ``` Output: ``` +---------------------------------------------------+ | name | +---------------------------------------------------+ | NULL | | GreptimeDB | +---------------------------------------------------+ ``` ## Boolean Type | Type Name | Description | Size | | --------- | ----------- | ------ | | `Boolean` | Bool values | 1 Byte | Use `TRUE` or `FALSE` to represent boolean values in SQL statements. For example: ```sql CREATE TABLE bools( b BOOLEAN, ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP() TIME INDEX, ); ``` ```sql INSERT INTO bools(b, ts) VALUES (TRUE, '2024-01-01 00:00:00'), (FALSE, '2024-01-01 00:00:01'); ``` ## Data types compatible with MySQL and PostgreSQL ### Type aliases For users migrating from MySQL or PostgreSQL to GreptimeDB, GreptimeDB supports the following alias types. | SQL Datatype Alias | Native Datatype | | --------------------------------------------------------------- | ---------------------- | | `Text`, `TinyText`, `MediumText`, `LongText`, `Varchar`, `Char` | `String` | | `Varbinary` | `Binary` | | `TinyInt` | `Int8` | | `SmallInt`, `Int2` | `Int16` | | `Int`, `Int4` | `Int32` | | `BigInt`, `Int8` | `Int64` | | `UnsignedTinyInt` | `UInt8` | | `UnsignedSmallInt` | `UInt16` | | `UnsignedInt` | `UInt32` | | `UnsignedBigInt` | `UInt64` | | `Float`, `Float4` | `Float32` | | `Double`, `Float8` | `Float64` | | `Timestamp_s`, `Timestamp_sec`, `Timestamp(0)` | `TimestampSecond` | | `Timestamp`, `Timestamp_ms`, `Timestamp(3)` | `TimestampMillisecond` | | `Timestamp_us`, `Timestamp(6)` | `TimestampMicroSecond` | | `Timestamp_ns`, `Timestamp(9)` | `TimestampNanosecond` | :::warning Note The type aliases `Int2`, `Int4`, `Int8`, `Float4`, and `Float8` follow the PostgreSQL and MySQL convention where these identifiers refer to the number of **bytes** (not bits) in the type. Specifically: - `Int2` = 2 bytes = `SmallInt` (16-bit) - `Int4` = 4 bytes = `Int` (32-bit) - `Int8` = 8 bytes = `BigInt` (64-bit) - `Float4` = 4 bytes = `Float` (32-bit) - `Float8` = 8 bytes = `Double` (64-bit) Note: GreptimeDB's native type names (like `UInt8`, `Int32`, `Int64`) refer to the number of **bits**, while the SQL aliases `Int2`, `Int4`, and `Int8` refer to the number of **bytes** following PostgreSQL/MySQL conventions. For example, the native type `Int8` is an 8-**bit** integer (`TinyInt`, 1 byte), while the SQL alias `INT8` maps to an 8-**byte** integer (`BigInt`, 64-bit). ::: You can use these alias types when creating tables. For example, use `Varchar` instead of `String`, `Double` instead of `Float64`, and `Timestamp(0)` instead of `TimestampSecond`. ```sql CREATE TABLE alias_types ( s TEXT, i DOUBLE, ts0 TIMESTAMP(0) DEFAULT CURRENT_TIMESTAMP() TIME INDEX, PRIMARY KEY(s) ); ``` ### Date and time types In addition to the `Timestamp` types used as the default time type in GreptimeDB, GreptimeDB also supports `Date` and `DateTime` types for compatibility with MySQL and PostgreSQL. | Type name | Description | Size | | ---------- | ----------------------------------------------------------------------------------------- | ------- | | `Date` | 32-bit date values represent the days since UNIX Epoch | 4 Bytes | | `DateTime` | 64-bit timestamp values with milliseconds precision, equivalent to `TimestampMicrosecond` | 8 Bytes | ## Examples ### Create Table ```sql CREATE TABLE data_types ( s STRING, vbi BINARY, b BOOLEAN, tint INT8, sint INT16, i INT32, bint INT64, utint UINT8, usint UINT16, ui UINT32, ubint UINT64, f FLOAT32, d FLOAT64, dm DECIMAL(3, 2), dt DATE, dtt DATETIME, ts0 TIMESTAMPSECOND, ts3 TIMESTAMPMILLISECOND, ts6 TIMESTAMPMICROSECOND, ts9 TIMESTAMPNANOSECOND DEFAULT CURRENT_TIMESTAMP() TIME INDEX, PRIMARY KEY(s)); ``` ### Describe Table ```sql DESC TABLE data_types; ``` ```sql +--------+----------------------+------+------+---------------------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +--------+----------------------+------+------+---------------------+---------------+ | s | String | PRI | YES | | TAG | | vbi | Binary | | YES | | FIELD | | b | Boolean | | YES | | FIELD | | tint | Int8 | | YES | | FIELD | | sint | Int16 | | YES | | FIELD | | i | Int32 | | YES | | FIELD | | bint | Int64 | | YES | | FIELD | | utint | UInt8 | | YES | | FIELD | | usint | UInt16 | | YES | | FIELD | | ui | UInt32 | | YES | | FIELD | | ubint | UInt64 | | YES | | FIELD | | f | Float32 | | YES | | FIELD | | d | Float64 | | YES | | FIELD | | dm | Decimal(3, 2) | | YES | | FIELD | | dt | Date | | YES | | FIELD | | dtt | TimestampMicrosecond | | YES | | FIELD | | ts0 | TimestampSecond | | YES | | FIELD | | ts3 | TimestampMillisecond | | YES | | FIELD | | ts6 | TimestampMicrosecond | | YES | | FIELD | | ts9 | TimestampNanosecond | PRI | NO | current_timestamp() | TIMESTAMP | +--------+----------------------+------+------+---------------------+---------------+ ``` --- ## DELETE `DELETE` is used to remove rows from a table. ## Syntax ```sql DELETE FROM [db.]table WHERE expr ``` It removes rows from the table `[db.]table` that satisfies the expression `expr` after `WHERE`. The removed rows are marked immediately and can't be retrieved by all subsequent queries. ## Example For example, there is a table with the primary key `host`: ```sql CREATE TABLE monitor ( host STRING, ts TIMESTAMP, cpu DOUBLE DEFAULT 0, memory DOUBLE, TIME INDEX (ts), PRIMARY KEY(host)) ; ``` To delete a row from it by primary key `host` and timestamp index `ts`: ```sql DELETE FROM monitor WHERE host = 'host1' and ts = 1655276557000; ``` --- ## DESCRIBE TABLE `DESCRIBE [TABLE] [db.]table` describes the table structure in the `db` or the current database in-use. ## Examples Describes the table `monitor`: ```sql DESCRIBE TABLE monitor; ``` or ```sql DESCRIBE monitor; ``` Output: ```sql +--------+----------------------+------+------+---------------------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +--------+----------------------+------+------+---------------------+---------------+ | host | String | PRI | YES | | TAG | | ts | TimestampMillisecond | PRI | NO | current_timestamp() | TIMESTAMP | | cpu | Float64 | | YES | 0 | FIELD | | memory | Float64 | | YES | | FIELD | +--------+----------------------+------+------+---------------------+---------------+ 4 rows in set (0.00 sec) ``` It produces the table structure: * `Column`: the column names * `Type`: the column data types * `Key`: `PRI` means the column is in the primary key constraint. * `Null`: `YES` means nullable, otherwise `NO` * `Default`: default value or expression of the column * `Semantic Type`: This column represents the semantic type, corresponding to `TAG`, `FIELD` or `TIMESTAMP` in the data model. --- ## DISTINCT `SELECT DISTINCT` is used to select unique values from a set of data. This keyword returns distinct values from the output of the query. The basic syntax for a `SELECT DISTINCT` statement is as followings: ```sql SELECT DISTINCT idc FROM system_metrics; ``` `SELECT DISTINCT` can be used in conjunction with filters. ```sql SELECT DISTINCT idc, host FROM system_metrics WHERE host != 'host2'; ``` `SELECT DISTINCT` is a simple but powerful command of GreptimeDB SQL that allows users to easily condense the data into a summary of unique values. It can be used on one column or multiple columns, making it very versatile for data analysis and reporting. Using "SELECT DISTINCT" is a great way to get an overview of the types of data stored in the tables. --- ## DROP ## DROP DATABASE `DROP DATABASE` drops a database. It removes the catalog entries for the database and deletes the directory containing the data. :::danger Danger `DROP DATABASE` cannot be undone. Use it with care! ::: ### Syntax ```sql DROP DATABASE [ IF EXISTS ] db_name ``` - `IF EXISTS`: Do not throw an error if the database does not exist. - `db_name`: The name of the database to remove. ### Examples To drop a database named `test`: ```sql DROP DATABASE test; ``` ## DROP TABLE `DROP TABLE` removes tables from the database. It will remove the table definition and all table data, indexes, rules, and constraints for that table. :::danger Danger `DROP TABLE` cannot be undone. Use it with care! ::: ### Syntax ```sql DROP TABLE [ IF EXISTS ] table_name ``` - `IF EXISTS`: Do not throw an error if the table does not exist. - `table_name`: The name of the table to remove. ### Examples Drop the table `monitor` in the current database: ```sql DROP TABLE monitor; ``` ## DROP FLOW ```sql DROP FLOW [ IF EXISTS ] flow_name; ``` - `IF EXISTS`: Do not throw an error if the flow does not exist. - `flow_name`: The name of the flow to destroy. ```sql DROP FLOW IF EXISTS test_flow; ``` ``` Query OK, 0 rows affected (0.00 sec) ``` ## DROP VIEW ```sql DROP VIEW [ IF EXISTS ] view_name; ``` - `IF EXISTS`: Do not throw an error if the view does not exist. - `view_name`: The name of the view to remove. ```sql DROP VIEW IF EXISTS test_view; ``` ``` Query OK, 0 rows affected (0.00 sec) ``` ## DROP TRIGGER Please refer to the [Trigger syntax](/reference/sql/trigger-syntax.md#drop-trigger) documentation. --- ## EXPLAIN `EXPLAIN` is used to provide the execution plan of a statement. ## Syntax ```sql EXPLAIN [ANALYZE] [VERBOSE] SELECT ... ``` The `ANALYZE` clause will execute the statement and measure time spent at each plan node and the total rows of the output etc. The `VERBOSE` clause will provide more detailed information about the execution plan. ## Examples Explains the following query: ```sql EXPLAIN SELECT * FROM monitor where host='host1'\G ``` Example: ```sql *************************** 1. row *************************** plan_type: logical_plan plan: MergeScan [is_placeholder=false] *************************** 2. row *************************** plan_type: physical_plan plan: MergeScanExec: peers=[4612794875904(1074, 0), ] ``` The column `plan_type` indicates whether it's a`logical_plan` or `physical_plan`. And the column `plan` explains the plan in detail. The `MergeScan` plan merges the results from multiple regions. The `peers` array in the `MergeScanExec` physical plan contains the IDs of the regions that the plan will scan. Explains the execution of the plan by `ANALYZE`: ```sql EXPLAIN ANALYZE SELECT * FROM monitor where host='host1'\G ``` Example: ```sql *************************** 1. row *************************** stage: 0 node: 0 plan: MergeScanExec: peers=[4612794875904(1074, 0), ] metrics=[output_rows: 0, greptime_exec_read_cost: 0, finish_time: 3301415, first_consume_time: 3299166, ready_time: 3104209, ] *************************** 2. row *************************** stage: 1 node: 0 plan: SeqScan: region=4612794875904(1074, 0), partition_count=0 (0 memtable ranges, 0 file 0 ranges) metrics=[output_rows: 0, mem_used: 0, build_parts_cost: 1, build_reader_cost: 1, elapsed_await: 1, elapsed_poll: 21250, scan_cost: 1, yield_cost: 1, ] *************************** 3. row *************************** stage: NULL node: NULL plan: Total rows: 0 ``` The `EXPLAIN ANALYZE` command provides metrics about the execution of each stage. The `SeqScan` plan scans the data from a single region. Explains the verbose information of the plan execution: ```sql EXPLAIN ANALYZE VERBOSE SELECT * FROM monitor where host='host1'; ``` Example: ```sql *************************** 1. row *************************** stage: 0 node: 0 plan: MergeScanExec: peers=[4612794875904(1074, 0), ] metrics=[output_rows: 0, greptime_exec_read_cost: 0, finish_time: 3479084, first_consume_time: 3476000, ready_time: 3209041, ] *************************** 2. row *************************** stage: 1 node: 0 plan: SeqScan: region=4612794875904(1074, 0), partition_count=0 (0 memtable ranges, 0 file 0 ranges), projection=["host", "ts", "cpu", "memory"], filters=[host = Utf8("host1")], metrics_per_partition: [[partition=0, {prepare_scan_cost=579.75µs, build_reader_cost=0ns, scan_cost=0ns, convert_cost=0ns, yield_cost=0ns, total_cost=789.708µs, num_rows=0, num_batches=0, num_mem_ranges=0, num_file_ranges=0, build_parts_cost=0ns, rg_total=0, rg_fulltext_filtered=0, rg_inverted_filtered=0, rg_minmax_filtered=0, rg_bloom_filtered=0, rows_before_filter=0, rows_fulltext_filtered=0, rows_inverted_filtered=0, rows_bloom_filtered=0, rows_precise_filtered=0, num_sst_record_batches=0, num_sst_batches=0, num_sst_rows=0, first_poll=785.041µs}]] metrics=[output_rows: 0, mem_used: 0, build_parts_cost: 1, build_reader_cost: 1, elapsed_await: 1, elapsed_poll: 17208, scan_cost: 1, yield_cost: 1, ] *************************** 3. row *************************** stage: NULL node: NULL plan: Total rows: 0 ``` The `EXPLAIN ANALYZE VERBOSE` command provides the detail metrics about the execution of scan plans. --- ## Anomaly Detection Functions GreptimeDB provides a set of statistical anomaly-scoring **window functions** that compute a numeric score reflecting how anomalous each row is relative to its window of values. All three functions must be used with an `OVER` clause (window function syntax). :::tip These functions return `NULL` when the window does not contain enough valid (non-NULL) data points. A score of `0.0` means the value is not anomalous; a larger value indicates a stronger anomaly. When the spread (stddev / MAD / IQR) is zero but the current value deviates from the window center, the returned score is `+inf`, meaning the deviation is infinitely anomalous. ::: ## `anomaly_score_zscore` Computes a Z-Score-based anomaly score for each row in a window. **Formula:** `|x − mean| / stddev` **Minimum valid samples:** 2 (uses population stddev, i.e. dividing by n) ```sql anomaly_score_zscore(value) OVER (window_spec) ``` **Arguments:** - **value**: A numeric column or expression to evaluate. **Return type:** `DOUBLE` **Degenerate cases:** | Condition | Result | |---|---| | Fewer than 2 valid points in window | `NULL` | | `stddev = 0` and `value = mean` | `0.0` | | `stddev = 0` and `value ≠ mean` | `+inf` | | Normal case | Finite positive `DOUBLE` | **Example:** ```sql SELECT ts, val, anomaly_score_zscore(val) OVER ( ORDER BY ts ROWS BETWEEN 4 PRECEDING AND CURRENT ROW ) AS zscore FROM metrics ORDER BY ts; ``` ## `anomaly_score_mad` Computes a Median Absolute Deviation (MAD)-based anomaly score for each row in a window. MAD is more robust than Z-Score because it is not influenced by extreme outliers. **Formula:** `|x − median| / (MAD × 1.4826)` The constant 1.4826 is a consistency factor that makes the MAD-based score asymptotically equivalent to the Z-Score for normally distributed data. **Minimum valid samples:** 3 (with ≤ 2 samples, MAD is almost always 0, which yields spurious `+inf` scores) ```sql anomaly_score_mad(value) OVER (window_spec) ``` **Arguments:** - **value**: A numeric column or expression to evaluate. **Return type:** `DOUBLE` **Degenerate cases:** | Condition | Result | |---|---| | Fewer than 3 valid points in window | `NULL` | | `MAD = 0` and `value = median` | `0.0` | | `MAD = 0` and `value ≠ median` | `+inf` | | Normal case | Finite positive `DOUBLE` | **Example:** ```sql SELECT ts, val, anomaly_score_mad(val) OVER ( PARTITION BY host ORDER BY ts ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS mad_score FROM metrics ORDER BY host, ts; ``` ## `anomaly_score_iqr` Computes an IQR (Interquartile Range / Tukey Fences)-based anomaly score for each row in a window. The score measures the distance of the value beyond the lower fence (`Q1 − k × IQR`) or upper fence (`Q3 + k × IQR`). Values within the fences receive a score of `0.0`. **Formula:** - If `value < Q1 − k × IQR`: score = `(Q1 − k × IQR − value) / IQR` - If `value > Q3 + k × IQR`: score = `(value − Q3 − k × IQR) / IQR` - Otherwise: score = `0.0` **Minimum valid samples:** 3 (linear-interpolated Q1 ≠ Q3 is only possible at n ≥ 3) ```sql anomaly_score_iqr(value, k) OVER (window_spec) ``` **Arguments:** - **value**: A numeric column or expression to evaluate. - **k**: A non-negative `DOUBLE` multiplier for the IQR fences (e.g., `1.5` for standard Tukey fences, `3.0` for far-out fences). Returns `NULL` if `k < 0`. **Return type:** `DOUBLE` **Degenerate cases:** | Condition | Result | |---|---| | Fewer than 3 valid points in window | `NULL` | | `IQR = 0` and value is within fences | `0.0` | | `IQR = 0` and value is outside fences | `+inf` | | Normal case | Finite non-negative `DOUBLE` | **Example:** ```sql SELECT ts, val, anomaly_score_iqr(val, 1.5) OVER ( PARTITION BY host ORDER BY ts ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS iqr_score FROM metrics ORDER BY host, ts; ``` ## Full Usage Example This example creates a sample table, inserts time-series data with an injected outlier, and then uses all three anomaly functions together. ```sql CREATE TABLE sensor_data ( host STRING, val DOUBLE, ts TIMESTAMP TIME INDEX, PRIMARY KEY (host) ); INSERT INTO sensor_data VALUES ('web-1', 10.0, '2025-01-01 00:00:00'), ('web-1', 11.0, '2025-01-01 00:01:00'), ('web-1', 10.5, '2025-01-01 00:02:00'), ('web-1', 10.8, '2025-01-01 00:03:00'), ('web-1', 80.0, '2025-01-01 00:04:00'), -- outlier ('web-1', 10.3, '2025-01-01 00:05:00'), ('web-1', 11.2, '2025-01-01 00:06:00'); ``` Use a shared named window and round results for readability: ```sql SELECT ts, val, ROUND(anomaly_score_zscore(val) OVER w, 2) AS zscore, ROUND(anomaly_score_mad(val) OVER w, 2) AS mad, ROUND(anomaly_score_iqr(val, 1.5) OVER w, 2) AS iqr FROM sensor_data WINDOW w AS ( PARTITION BY host ORDER BY ts ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) ORDER BY ts; ``` Expected output — the outlier row (`val = 80.0`) produces significantly higher scores across all three metrics: ``` +---------------------+------+--------+--------+-------+ | ts | val | zscore | mad | iqr | +---------------------+------+--------+--------+-------+ | 2025-01-01 00:00:00 | 10 | NULL | NULL | NULL | | 2025-01-01 00:01:00 | 11 | 1 | NULL | NULL | | 2025-01-01 00:02:00 | 10.5 | 0 | 0 | 0 | | 2025-01-01 00:03:00 | 10.8 | 0.6 | 0.4 | 0 | | 2025-01-01 00:04:00 | 80 | 2 | 155.58 | 136.5 | | 2025-01-01 00:05:00 | 10.3 | 0.46 | 0.67 | 0 | | 2025-01-01 00:06:00 | 11.2 | 0.38 | 0.67 | 0 | +---------------------+------+--------+--------+-------+ ``` ### Filter Anomalous Rows You can wrap the window query in a subquery to keep only rows whose score exceeds a threshold: ```sql SELECT * FROM ( SELECT host, ts, val, ROUND(anomaly_score_mad(val) OVER ( PARTITION BY host ORDER BY ts ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ), 2) AS mad FROM sensor_data ) WHERE mad > 3.0 ORDER BY host, ts; ``` Expected output: ``` +-------+---------------------+------+--------+ | host | ts | val | mad | +-------+---------------------+------+--------+ | web-1 | 2025-01-01 00:04:00 | 80 | 155.58 | +-------+---------------------+------+--------+ ``` --- ## Approximate Functions This page lists approximate functions in GreptimeDB, which are used for approximate data analysis. :::warning The following approximate functions is currently experimental and may change in future releases. ::: ## Approximate Count Distinct (HLL) The [HyperLogLog](https://algo.inria.fr/flajolet/Publications/FlFuGaMe07.pdf) (HLL) algorithm is used to calculate the approximate count distinct of a set of values. It provides efficient memory usage and speed for this purpose. Three functions are provided to work with the HLL algorithm, described in following chapters: :::warning Notice that due to the approximate nature of the algorithm, the results may not be exact but are usually very close to the actual count distinct. The relative standard error of the HyperLogLog algorithm is about 1.04/sqrt(m), where m is the number of registers used in the algorithm. GreptimeDB uses 16384 registers by default, which gives a relative standard error of about 0.008125(or 0.8125%). ::: ### `hll` `hll(value)` creates a HyperLogLog state in binary from a given column. The `value` can be any column that you want to calculate the approximate count distinct for. It returns a binary representation of the HLL state, which can be stored in a table or used in further calculations. See [Full Usage Example](#full-usage-example) for a full example of how to use this function in combination with other functions to calculate approximate count distinct. ### `hll_merge` `hll_merge(hll_state)` merges multiple HyperLogLog states into one. This is useful when you want to combine the results of multiple HLL calculations, such as when aggregating data from different time windows or sources. The `hll_state` parameter is the binary representation of the HLL state created by [`hll`](#hll). The merged state can then be used to calculate the approximate count distinct across all the merged states. See [Full Usage Example](#full-usage-example) for a full example of how to use this function in combination with other functions to calculate approximate count distinct. ### `hll_count` `hll_count(hll_state)` retrieves the approximate count distinct from a HyperLogLog state. This function takes the HLL state created by `hll` or merged by `hll_merge` and returns the approximate count of distinct values. See [Full Usage Example](#full-usage-example) for a full example of how to use this function in combination with other functions to calculate approximate count distinct. ### Full Usage Example This example demonstrates how to use these functions in combination to calculate the approximate count distinct user id. First create the base table `access_log` for storing user access logs, and the `access_log_10s` table for storing the HyperLogLog states within a 10-second time window. Notice the `state` column is of type `BINARY`, which will store the HyperLogLog state in binary format. ```sql CREATE TABLE access_log ( `url` STRING, user_id BIGINT, ts TIMESTAMP TIME INDEX, PRIMARY KEY (`url`, `user_id`) ); CREATE TABLE access_log_10s ( `url` STRING, time_window timestamp time INDEX, state BINARY, PRIMARY KEY (`url`) ); ``` Insert some sample data into access_log: ```sql INSERT INTO access_log VALUES ("/dashboard", 1, "2025-03-04 00:00:00"), ("/dashboard", 1, "2025-03-04 00:00:01"), ("/dashboard", 2, "2025-03-04 00:00:05"), ("/dashboard", 2, "2025-03-04 00:00:10"), ("/dashboard", 2, "2025-03-04 00:00:13"), ("/dashboard", 4, "2025-03-04 00:00:15"), ("/not_found", 1, "2025-03-04 00:00:10"), ("/not_found", 3, "2025-03-04 00:00:11"), ("/not_found", 4, "2025-03-04 00:00:12"); ``` Now we can use the `hll` function to create a HyperLogLog state for the `user_id` column with a 10-second time window. The output will be a binary representation of the HLL state, which contains the necessary information to calculate approximate count distinct later. The `date_bin` function is used to group the data into 10-second time windows. Hence this `INSERT INTO` statement will create a HyperLogLog state for each 10-second time window in the `access_log` table, and insert it into the `access_log_10s` table: ```sql -- Use a 10-second windowed query to calculate the HyperLogLog states INSERT INTO access_log_10s SELECT `url`, date_bin("10s" :: INTERVAL, ts) AS time_window, hll(`user_id`) AS state FROM access_log GROUP BY `url`, time_window; -- results will be similar to this: -- Query OK, 3 rows affected (0.05 sec) ``` Then we can use the `hll_count` function to retrieve the approximate count distinct from the HyperLogLog state(which is the `state` column). For example, to get the approximate count distinct of user visits for each 10-second time window, we can run the following query: ```sql -- use hll_count to query approximate data in access_log_10s, notice for small datasets, the results may not be very accurate. SELECT `url`, `time_window`, hll_count(state) FROM access_log_10s; -- results as follows: -- +------------+---------------------+---------------------------------+ -- | url | time_window | hll_count(access_log_10s.state) | -- +------------+---------------------+---------------------------------+ -- | /dashboard | 2025-03-04 00:00:00 | 2 | -- | /dashboard | 2025-03-04 00:00:10 | 2 | -- | /not_found | 2025-03-04 00:00:10 | 3 | -- +------------+---------------------+---------------------------------+ ``` In addition, we can aggregate the 10-second data to a 1-minute level by merging the HyperLogLog states using `hll_merge`. This allows us to calculate the approximate count distinct for a larger time window, which can be useful for analyzing trends over time. The following query demonstrates how to do this: ```sql -- aggregate the 10-second data to a 1-minute level by merging the HyperLogLog states using `hll_merge`. SELECT `url`, date_bin('1 minute' :: INTERVAL, `time_window`) AS time_window_1m, hll_count(hll_merge(state)) as uv_per_min FROM access_log_10s GROUP BY `url`, date_bin('1 minute' :: INTERVAL, `time_window`); -- results as follows: -- +------------+---------------------+------------+ -- | url | time_window_1m | uv_per_min | -- +------------+---------------------+------------+ -- | /dashboard | 2025-03-04 00:00:00 | 3 | -- | /not_found | 2025-03-04 00:00:00 | 3 | -- +------------+---------------------+------------+ ``` Note how the `hll_merge` function is used to merge the HyperLogLog states from the `access_log_10s` table, and then the `hll_count` function is used to calculate the approximate count distinct for each 1-minute time window. If only use `hll_merge` without `hll_count`, the result will just be a unreadable binary representation of the merged HyperLogLog state, which is not very useful for analysis. Hence we use `hll_count` to retrieve the approximate count distinct from the merged state. This following flowchart illustrates above usage of the HyperLogLog functions. First raw event data is first group by time window and url, then the `hll` function is used to create a HyperLogLog state for each time window and url, then the `hll_count` function is used to retrieve the approximate count distinct for each time window and url. Finally, the `hll_merge` function is used to merge the HyperLogLog states for each url, and then the `hll_count` function is used again to retrieve the approximate count distinct for the 1-minute time window. ![HLL Usage Flowchart](/hll.svg) ## Approximate Quantile (UDDSketch) Three functions are provided for approximate quantile calculation using the [UDDSketch](https://arxiv.org/abs/2004.08604) algorithm. :::warning Notice that the UDDSketch algorithm is designed to provide approximate quantiles with a tunable error rate, which allows for efficient memory usage and fast calculations. The results may not be exact but are usually very close to the actual quantiles. ::: ### `uddsketch_state` The `uddsketch_state` function is used to create a UDDSketch state in binary from a given column. It takes three parameters: - `bucket_num`, which is the number of buckets to use for the sketch, see [How to determine bucket number and error rate](#how-to-determine-bucket_num-and-error_rate) for how to decide the value. - `error_rate`, which is the desired error rate for the quantile calculation. - `value` parameter is the column from which the sketch will be created. for example, for a simple table `percentile_base` shown below, we can create a `uddsketch_state` for the `value` column with a bucket number of 128 and an error rate of 0.01 (1%). The output will be a binary representation of the UDDSketch state, which contains the necessary information to calculate approximate quantiles later. This output binary state can be think of as a histogram of the values in the `value` column, which can then be merged using `uddsketch_merge` or used to calculate quantiles using `uddsketch_calc` as shown later. See [UDDSketch Full Usage Example](#uddsketch-full-usage-example) for a full example of how to use these functions in combination to calculate approximate quantiles. ### `uddsketch_merge` The `uddsketch_merge` function is used to merge multiple UDDSketch states into one. It takes three parameters: - `bucket_num`, which is the number of buckets to use for the sketch, see [How to determine bucket number and error rate](#how-to-determine-bucket_num-and-error_rate) for how to decide the value. - `error_rate`, which is the desired error rate for the quantile calculation. - `udd_state`, which is the binary representation of the UDDSketch state created by `uddsketch_state`. This is useful when you want to combine results from different time windows or sources. Notice that the `bucket_num` and `error_rate` must match the original sketch where the state was created, or else the merge will fail. For example, if you have multiple UDDSketch states from different time windows, you can merge them into a single state to calculate the overall quantile across all the data.This output binary state can then be used to calculate quantiles using `uddsketch_calc`. See [UDDSketch Full Usage Example](#uddsketch-full-usage-example) for a full example of how to use these functions in combination to calculate approximate quantiles. ### `uddsketch_calc` The `uddsketch_calc` function is used to calculate the approximate quantile from a UDDSketch state. It takes two parameters: - `quantile`, which is a value between 0 and 1 representing the desired quantile to calculate, i.e., 0.99 for the 99th percentile. - `udd_state`, which is the binary representation of the UDDSketch state created by `uddsketch_state` or merged by `uddsketch_merge`. see [UDDSketch Full Usage Example](#uddsketch-full-usage-example) for a full example of how to use these functions in combination to calculate approximate quantiles. ### How to determine `bucket_num` and `error_rate` The `bucket_num` parameter sets the maximum number of internal containers the sketch can use, directly controlling its memory footprint. Think of it as the physical storage capacity for tracking different value ranges. A larger `bucket_num` allows the sketch to accurately represent a wider dynamic range of data (i.e. a larger ratio between the maximum and minimum values). If this limit is too small for your data, the sketch will be forced to merge very high or low values, which degrades its accuracy. A recommended value for `bucket_num` is 128, which provides a good balance between accuracy and memory usage for most use cases. The `error_rate` defines the desired precision for your quantile calculations. It guarantees that any computed quantile (e.g., p99) is within a certain *relative* percentage of the true value. For example, an `error_rate` of `0.01` ensures the result is within 1% of the actual value. A smaller `error_rate` provides higher accuracy, as it forces the sketch to use more granular buckets to distinguish between closer numbers. These two parameters create a direct trade-off. To achieve the high precision promised by a small `error_rate`, the sketch needs a sufficient `bucket_num`, especially for data that spans a wide range. `bucket_num` acts as the physical limit on accuracy. If your `bucket_num` is restricted by memory constraints, setting the `error_rate` to an extremely small value will not improve precision because the limit imposed by the available buckets. ### UDDSketch Full Usage Example This example demonstrates how to use three `uddsketch` functions describe above to calculate the approximate quantile of a set of values. First create the base table `percentile_base` for store the raw data, and the `percentile_5s` table for storing the UDDSketch states within a 5-second time window. notice the `percentile_state` column is of type `BINARY`, which will store the UDDSketch state in binary format. ```sql CREATE TABLE percentile_base ( `id` INT PRIMARY KEY, `value` DOUBLE, `ts` timestamp(0) time index ); CREATE TABLE percentile_5s ( `percentile_state` BINARY, `time_window` timestamp(0) time index ); ``` Insert some sample data into `percentile_base` : ```sql INSERT INTO percentile_base (`id`, `value`, `ts`) VALUES (1, 10.0, 1), (2, 20.0, 2), (3, 30.0, 3), (4, 40.0, 4), (5, 50.0, 5), (6, 60.0, 6), (7, 70.0, 7), (8, 80.0, 8), (9, 90.0, 9), (10, 100.0, 10); ``` Now we can use the `uddsketch_state` function to create a UDDSketch state for the `value` column with a bucket number of 128 and an error rate of 0.01 (1%). The output will be a binary representation of the UDDSketch state, which contains the necessary information to calculate approximate quantiles later, the `date_bin` function is used to group the data into 5-second time windows. Hence this `INSERT INTO` statement will create a UDDSketch state for each 5-second time window in the `percentile_base` table, and insert it into the `percentile_5s` table: ```sql INSERT INTO percentile_5s SELECT uddsketch_state(128, 0.01, `value`) AS percentile_state, date_bin('5 seconds' :: INTERVAL, `ts`) AS time_window FROM percentile_base GROUP BY time_window; -- results will be similar to this: -- Query OK, 3 rows affected (0.05 sec) ``` Now we can use the `uddsketch_calc` function to calculate the approximate quantile from the UDDSketch state. For example, to get the approximate 99th percentile (p99) for each 5-second time window, we can run the following query: ```sql -- query percentile_5s to get the approximate 99th percentile SELECT time_window, uddsketch_calc(0.99, `percentile_state`) AS p99 FROM percentile_5s; -- results as follows: -- +---------------------+--------------------+ -- | time_window | p99 | -- +---------------------+--------------------+ -- | 1970-01-01 00:00:00 | 40.04777053326359 | -- | 1970-01-01 00:00:05 | 89.13032933635911 | -- | 1970-01-01 00:00:10 | 100.49456770856492 | -- +---------------------+--------------------+ ``` Notice in above query the `percentile_state` column is the UDDSketch state created by `uddsketch_state`. In addition, we can aggregate the 5-second data to a 1-minute level by merging the UDDSketch states using `uddsketch_merge`. This allows us to calculate the approximate quantile for a larger time window, which can be useful for analyzing trends over time. The following query demonstrates how to do this: ```sql -- in addition, we can aggregate the 5-second data to a 1-minute level by merging the UDDSketch states using `uddsketch_merge`. SELECT date_bin('1 minute' :: INTERVAL, `time_window`) AS time_window_1m, uddsketch_calc(0.99, uddsketch_merge(128, 0.01, `percentile_state`)) AS p99 FROM percentile_5s GROUP BY time_window_1m; -- results as follows: -- +---------------------+--------------------+ -- | time_window_1m | p99 | -- +---------------------+--------------------+ -- | 1970-01-01 00:00:00 | 100.49456770856492 | -- +---------------------+--------------------+ ``` Notice how the `uddsketch_merge` function is used to merge the UDDSketch states from the `percentile_5s` table, and then the `uddsketch_calc` function is used to calculate the approximate 99th percentile (p99) for each 1-minute time window. This following flowchart illustrates above usage of the UDDSketch functions. First raw event data is first group by time window, then the `uddsketch_state` function is used to create a UDDSketch state for each time window, then the `uddsketch_calc` function is used to retrieve the approximate 99th quantile for each time window. Finally, the `uddsketch_merge` function is used to merge the UDDSketch states for each time window, and then the `uddsketch_calc` function is used again to retrieve the approximate 99th quantile for the 1-minute time window. ![UDDSketch Usage Flowchart](/udd.svg) --- ## DataFusion Functions This page is generated from the [Apache DataFusion](https://datafusion.apache.org/user-guide/sql/) project's documents: * [DataFusion Scalar Functions](#scalar-functions) * [DataFusion Aggregate Functions](#aggregate-functions) * [DataFusion Window Functions](#window-functions) * [DataFusion Special Functions](#special-functions) ## Scalar Functions ### Math Functions - [abs](#abs) - [acos](#acos) - [acosh](#acosh) - [asin](#asin) - [asinh](#asinh) - [atan](#atan) - [atan2](#atan2) - [atanh](#atanh) - [cbrt](#cbrt) - [ceil](#ceil) - [cos](#cos) - [cosh](#cosh) - [cot](#cot) - [degrees](#degrees) - [exp](#exp) - [factorial](#factorial) - [floor](#floor) - [gcd](#gcd) - [isnan](#isnan) - [iszero](#iszero) - [lcm](#lcm) - [ln](#ln) - [log](#log) - [log10](#log10) - [log2](#log2) - [nanvl](#nanvl) - [pi](#pi) - [pow](#pow) - [power](#power) - [radians](#radians) - [random](#random) - [round](#round) - [signum](#signum) - [sin](#sin) - [sinh](#sinh) - [sqrt](#sqrt) - [tan](#tan) - [tanh](#tanh) - [trunc](#trunc) ##### `abs` Returns the absolute value of a number. ```sql abs(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT abs(-5); +----------+ | abs(-5) | +----------+ | 5 | +----------+ ``` ##### `acos` Returns the arc cosine or inverse cosine of a number. ```sql acos(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT acos(1); +----------+ | acos(1) | +----------+ | 0.0 | +----------+ ``` ##### `acosh` Returns the area hyperbolic cosine or inverse hyperbolic cosine of a number. ```sql acosh(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT acosh(2); +------------+ | acosh(2) | +------------+ | 1.31696 | +------------+ ``` ##### `asin` Returns the arc sine or inverse sine of a number. ```sql asin(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT asin(0.5); +------------+ | asin(0.5) | +------------+ | 0.5235988 | +------------+ ``` ##### `asinh` Returns the area hyperbolic sine or inverse hyperbolic sine of a number. ```sql asinh(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT asinh(1); +------------+ | asinh(1) | +------------+ | 0.8813736 | +------------+ ``` ##### `atan` Returns the arc tangent or inverse tangent of a number. ```sql atan(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT atan(1); +-----------+ | atan(1) | +-----------+ | 0.7853982 | +-----------+ ``` ##### `atan2` Returns the arc tangent or inverse tangent of `expression_y / expression_x`. ```sql atan2(expression_y, expression_x) ``` ###### Arguments - **expression_y**: First numeric expression to operate on. Can be a constant, column, or function, and any combination of arithmetic operators. - **expression_x**: Second numeric expression to operate on. Can be a constant, column, or function, and any combination of arithmetic operators. ###### Example ```sql > SELECT atan2(1, 1); +------------+ | atan2(1,1) | +------------+ | 0.7853982 | +------------+ ``` ##### `atanh` Returns the area hyperbolic tangent or inverse hyperbolic tangent of a number. ```sql atanh(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT atanh(0.5); +-------------+ | atanh(0.5) | +-------------+ | 0.5493061 | +-------------+ ``` ##### `cbrt` Returns the cube root of a number. ```sql cbrt(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT cbrt(27); +-----------+ | cbrt(27) | +-----------+ | 3.0 | +-----------+ ``` ##### `ceil` Returns the nearest integer greater than or equal to a number. ```sql ceil(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT ceil(3.14); +------------+ | ceil(3.14) | +------------+ | 4.0 | +------------+ ``` ##### `cos` Returns the cosine of a number. ```sql cos(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT cos(0); +--------+ | cos(0) | +--------+ | 1.0 | +--------+ ``` ##### `cosh` Returns the hyperbolic cosine of a number. ```sql cosh(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT cosh(1); +-----------+ | cosh(1) | +-----------+ | 1.5430806 | +-----------+ ``` ##### `cot` Returns the cotangent of a number. ```sql cot(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT cot(1); +---------+ | cot(1) | +---------+ | 0.64209 | +---------+ ``` ##### `degrees` Converts radians to degrees. ```sql degrees(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT degrees(pi()); +------------+ | degrees(0) | +------------+ | 180.0 | +------------+ ``` ##### `exp` Returns the base-e exponential of a number. ```sql exp(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT exp(1); +---------+ | exp(1) | +---------+ | 2.71828 | +---------+ ``` ##### `factorial` Factorial. Returns 1 if value is less than 2. ```sql factorial(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT factorial(5); +---------------+ | factorial(5) | +---------------+ | 120 | +---------------+ ``` ##### `floor` Returns the nearest integer less than or equal to a number. ```sql floor(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT floor(3.14); +-------------+ | floor(3.14) | +-------------+ | 3.0 | +-------------+ ``` ##### `gcd` Returns the greatest common divisor of `expression_x` and `expression_y`. Returns 0 if both inputs are zero. ```sql gcd(expression_x, expression_y) ``` ###### Arguments - **expression_x**: First numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. - **expression_y**: Second numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT gcd(48, 18); +------------+ | gcd(48,18) | +------------+ | 6 | +------------+ ``` ##### `isnan` Returns true if a given number is +NaN or -NaN otherwise returns false. ```sql isnan(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT isnan(1); +----------+ | isnan(1) | +----------+ | false | +----------+ ``` ##### `iszero` Returns true if a given number is +0.0 or -0.0 otherwise returns false. ```sql iszero(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT iszero(0); +------------+ | iszero(0) | +------------+ | true | +------------+ ``` ##### `lcm` Returns the least common multiple of `expression_x` and `expression_y`. Returns 0 if either input is zero. ```sql lcm(expression_x, expression_y) ``` ###### Arguments - **expression_x**: First numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. - **expression_y**: Second numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT lcm(4, 5); +----------+ | lcm(4,5) | +----------+ | 20 | +----------+ ``` ##### `ln` Returns the natural logarithm of a number. ```sql ln(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT ln(2.71828); +-------------+ | ln(2.71828) | +-------------+ | 1.0 | +-------------+ ``` ##### `log` Returns the base-x logarithm of a number. Can either provide a specified base, or if omitted then takes the base-10 of a number. ```sql log(base, numeric_expression) log(numeric_expression) ``` ###### Arguments - **base**: Base numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT log(10); +---------+ | log(10) | +---------+ | 1.0 | +---------+ ``` ##### `log10` Returns the base-10 logarithm of a number. ```sql log10(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT log10(100); +-------------+ | log10(100) | +-------------+ | 2.0 | +-------------+ ``` ##### `log2` Returns the base-2 logarithm of a number. ```sql log2(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT log2(8); +-----------+ | log2(8) | +-----------+ | 3.0 | +-----------+ ``` ##### `nanvl` Returns the first argument if it's not _NaN_. Returns the second argument otherwise. ```sql nanvl(expression_x, expression_y) ``` ###### Arguments - **expression_x**: Numeric expression to return if it's not _NaN_. Can be a constant, column, or function, and any combination of arithmetic operators. - **expression_y**: Numeric expression to return if the first expression is _NaN_. Can be a constant, column, or function, and any combination of arithmetic operators. ###### Example ```sql > SELECT nanvl(0, 5); +------------+ | nanvl(0,5) | +------------+ | 0 | +------------+ ``` ##### `pi` Returns an approximate value of π. ```sql pi() ``` ##### `pow` _Alias of [power](#power)._ ##### `power` Returns a base expression raised to the power of an exponent. ```sql power(base, exponent) ``` ###### Arguments - **base**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. - **exponent**: Exponent numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT power(2, 3); +-------------+ | power(2,3) | +-------------+ | 8 | +-------------+ ``` ###### Aliases - pow ##### `radians` Converts degrees to radians. ```sql radians(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT radians(180); +----------------+ | radians(180) | +----------------+ | 3.14159265359 | +----------------+ ``` ##### `random` Returns a random float value in the range [0, 1). The random seed is unique to each row. ```sql random() ``` ###### Example ```sql > SELECT random(); +------------------+ | random() | +------------------+ | 0.7389238902938 | +------------------+ ``` ##### `round` Rounds a number to the nearest integer. ```sql round(numeric_expression[, decimal_places]) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. - **decimal_places**: Optional. The number of decimal places to round to. Defaults to 0. ###### Example ```sql > SELECT round(3.14159); +--------------+ | round(3.14159)| +--------------+ | 3.0 | +--------------+ ``` ##### `signum` Returns the sign of a number. Negative numbers return `-1`. Zero and positive numbers return `1`. ```sql signum(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT signum(-42); +-------------+ | signum(-42) | +-------------+ | -1 | +-------------+ ``` ##### `sin` Returns the sine of a number. ```sql sin(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT sin(0); +----------+ | sin(0) | +----------+ | 0.0 | +----------+ ``` ##### `sinh` Returns the hyperbolic sine of a number. ```sql sinh(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT sinh(1); +-----------+ | sinh(1) | +-----------+ | 1.1752012 | +-----------+ ``` ##### `sqrt` Returns the square root of a number. ```sql sqrt(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ##### `tan` Returns the tangent of a number. ```sql tan(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT tan(pi()/4); +--------------+ | tan(PI()/4) | +--------------+ | 1.0 | +--------------+ ``` ##### `tanh` Returns the hyperbolic tangent of a number. ```sql tanh(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT tanh(20); +----------+ | tanh(20) | +----------+ | 1.0 | +----------+ ``` ##### `trunc` Truncates a number to a whole number or truncated to the specified decimal places. ```sql trunc(numeric_expression[, decimal_places]) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. - **decimal_places**: Optional. The number of decimal places to truncate to. Defaults to 0 (truncate to a whole number). If `decimal_places` is a positive integer, truncates digits to the right of the decimal point. If `decimal_places` is a negative integer, replaces digits to the left of the decimal point with `0`. ###### Example ```sql > SELECT trunc(42.738); +----------------+ | trunc(42.738) | +----------------+ | 42 | +----------------+ ``` ### Conditional Functions - [coalesce](#coalesce) - [greatest](#greatest) - [ifnull](#ifnull) - [least](#least) - [nullif](#nullif) - [nvl](#nvl) - [nvl2](#nvl2) ##### `coalesce` Returns the first of its arguments that is not _null_. Returns _null_ if all arguments are _null_. This function is often used to substitute a default value for _null_ values. ```sql coalesce(expression1[, ..., expression_n]) ``` ###### Arguments - **expression1, expression_n**: Expression to use if previous expressions are _null_. Can be a constant, column, or function, and any combination of arithmetic operators. Pass as many expression arguments as necessary. ###### Example ```sql > select coalesce(null, null, 'datafusion'); +----------------------------------------+ | coalesce(NULL,NULL,Utf8("datafusion")) | +----------------------------------------+ | datafusion | +----------------------------------------+ ``` ##### `greatest` Returns the greatest value in a list of expressions. Returns _null_ if all expressions are _null_. ```sql greatest(expression1[, ..., expression_n]) ``` ###### Arguments - **expression1, expression_n**: Expressions to compare and return the greatest value.. Can be a constant, column, or function, and any combination of arithmetic operators. Pass as many expression arguments as necessary. ###### Example ```sql > select greatest(4, 7, 5); +---------------------------+ | greatest(4,7,5) | +---------------------------+ | 7 | +---------------------------+ ``` ##### `ifnull` _Alias of [nvl](#nvl)._ ##### `least` Returns the smallest value in a list of expressions. Returns _null_ if all expressions are _null_. ```sql least(expression1[, ..., expression_n]) ``` ###### Arguments - **expression1, expression_n**: Expressions to compare and return the smallest value. Can be a constant, column, or function, and any combination of arithmetic operators. Pass as many expression arguments as necessary. ###### Example ```sql > select least(4, 7, 5); +---------------------------+ | least(4,7,5) | +---------------------------+ | 4 | +---------------------------+ ``` ##### `nullif` Returns _null_ if _expression1_ equals _expression2_; otherwise it returns _expression1_. This can be used to perform the inverse operation of [`coalesce`](#coalesce). ```sql nullif(expression1, expression2) ``` ###### Arguments - **expression1**: Expression to compare and return if equal to expression2. Can be a constant, column, or function, and any combination of operators. - **expression2**: Expression to compare to expression1. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > select nullif('datafusion', 'data'); +-----------------------------------------+ | nullif(Utf8("datafusion"),Utf8("data")) | +-----------------------------------------+ | datafusion | +-----------------------------------------+ > select nullif('datafusion', 'datafusion'); +-----------------------------------------------+ | nullif(Utf8("datafusion"),Utf8("datafusion")) | +-----------------------------------------------+ | | +-----------------------------------------------+ ``` ##### `nvl` Returns _expression2_ if _expression1_ is NULL otherwise it returns _expression1_ and _expression2_ is not evaluated. This function can be used to substitute a default value for NULL values. ```sql nvl(expression1, expression2) ``` ###### Arguments - **expression1**: Expression to return if not null. Can be a constant, column, or function, and any combination of operators. - **expression2**: Expression to return if expr1 is null. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > select nvl(null, 'a'); +---------------------+ | nvl(NULL,Utf8("a")) | +---------------------+ | a | +---------------------+\ > select nvl('b', 'a'); +--------------------------+ | nvl(Utf8("b"),Utf8("a")) | +--------------------------+ | b | +--------------------------+ ``` ###### Aliases - ifnull ##### `nvl2` Returns _expression2_ if _expression1_ is not NULL; otherwise it returns _expression3_. ```sql nvl2(expression1, expression2, expression3) ``` ###### Arguments - **expression1**: Expression to test for null. Can be a constant, column, or function, and any combination of operators. - **expression2**: Expression to return if expr1 is not null. Can be a constant, column, or function, and any combination of operators. - **expression3**: Expression to return if expr1 is null. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > select nvl2(null, 'a', 'b'); +--------------------------------+ | nvl2(NULL,Utf8("a"),Utf8("b")) | +--------------------------------+ | b | +--------------------------------+ > select nvl2('data', 'a', 'b'); +----------------------------------------+ | nvl2(Utf8("data"),Utf8("a"),Utf8("b")) | +----------------------------------------+ | a | +----------------------------------------+ ``` ### String Functions - [ascii](#ascii) - [bit_length](#bit_length) - [btrim](#btrim) - [char_length](#char_length) - [character_length](#character_length) - [chr](#chr) - [concat](#concat) - [concat_ws](#concat_ws) - [contains](#contains) - [ends_with](#ends_with) - [find_in_set](#find_in_set) - [initcap](#initcap) - [instr](#instr) - [left](#left) - [length](#length) - [levenshtein](#levenshtein) - [lower](#lower) - [lpad](#lpad) - [ltrim](#ltrim) - [octet_length](#octet_length) - [overlay](#overlay) - [position](#position) - [repeat](#repeat) - [replace](#replace) - [reverse](#reverse) - [right](#right) - [rpad](#rpad) - [rtrim](#rtrim) - [split_part](#split_part) - [starts_with](#starts_with) - [strpos](#strpos) - [substr](#substr) - [substr_index](#substr_index) - [substring](#substring) - [substring_index](#substring_index) - [to_hex](#to_hex) - [translate](#translate) - [trim](#trim) - [upper](#upper) - [uuid](#uuid) ##### `ascii` Returns the first Unicode scalar value of a string. ```sql ascii(str) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > select ascii('abc'); +--------------------+ | ascii(Utf8("abc")) | +--------------------+ | 97 | +--------------------+ > select ascii('🚀'); +-------------------+ | ascii(Utf8("🚀")) | +-------------------+ | 128640 | +-------------------+ ``` **Related functions**: - [chr](#chr) ##### `bit_length` Returns the bit length of a string. ```sql bit_length(str) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > select bit_length('datafusion'); +--------------------------------+ | bit_length(Utf8("datafusion")) | +--------------------------------+ | 80 | +--------------------------------+ ``` **Related functions**: - [length](#length) - [octet_length](#octet_length) ##### `btrim` Trims the specified trim string from the start and end of a string. If no trim string is provided, all spaces are removed from the start and end of the input string. ```sql btrim(str[, trim_str]) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **trim_str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. _Default is a space._ ###### Example ```sql > select btrim('__datafusion____', '_'); +-------------------------------------------+ | btrim(Utf8("__datafusion____"),Utf8("_")) | +-------------------------------------------+ | datafusion | +-------------------------------------------+ ``` ###### Alternative Syntax ```sql trim(BOTH trim_str FROM str) ``` ```sql trim(trim_str FROM str) ``` ###### Aliases - trim **Related functions**: - [ltrim](#ltrim) - [rtrim](#rtrim) ##### `char_length` _Alias of [character_length](#character_length)._ ##### `character_length` Returns the number of characters in a string. ```sql character_length(str) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > select character_length('Ångström'); +------------------------------------+ | character_length(Utf8("Ångström")) | +------------------------------------+ | 8 | +------------------------------------+ ``` ###### Aliases - length - char_length **Related functions**: - [bit_length](#bit_length) - [octet_length](#octet_length) ##### `chr` Returns a string containing the character with the specified Unicode scalar value. ```sql chr(expression) ``` ###### Arguments - **expression**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > select chr(128640); +--------------------+ | chr(Int64(128640)) | +--------------------+ | 🚀 | +--------------------+ ``` **Related functions**: - [ascii](#ascii) ##### `concat` Concatenates multiple strings together. ```sql concat(str[, ..., str_n]) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **str_n**: Subsequent string expressions to concatenate. ###### Example ```sql > select concat('data', 'f', 'us', 'ion'); +-------------------------------------------------------+ | concat(Utf8("data"),Utf8("f"),Utf8("us"),Utf8("ion")) | +-------------------------------------------------------+ | datafusion | +-------------------------------------------------------+ ``` **Related functions**: - [concat_ws](#concat_ws) ##### `concat_ws` Concatenates multiple strings together with a specified separator. ```sql concat_ws(separator, str[, ..., str_n]) ``` ###### Arguments - **separator**: Separator to insert between concatenated strings. - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **str_n**: Subsequent string expressions to concatenate. ###### Example ```sql > select concat_ws('_', 'data', 'fusion'); +--------------------------------------------------+ | concat_ws(Utf8("_"),Utf8("data"),Utf8("fusion")) | +--------------------------------------------------+ | data_fusion | +--------------------------------------------------+ ``` **Related functions**: - [concat](#concat) ##### `contains` Return true if search_str is found within string (case-sensitive). ```sql contains(str, search_str) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **search_str**: The string to search for in str. ###### Example ```sql > select contains('the quick brown fox', 'row'); +---------------------------------------------------+ | contains(Utf8("the quick brown fox"),Utf8("row")) | +---------------------------------------------------+ | true | +---------------------------------------------------+ ``` ##### `ends_with` Tests if a string ends with a substring. ```sql ends_with(str, substr) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **substr**: Substring to test for. ###### Example ```sql > select ends_with('datafusion', 'soin'); +--------------------------------------------+ | ends_with(Utf8("datafusion"),Utf8("soin")) | +--------------------------------------------+ | false | +--------------------------------------------+ > select ends_with('datafusion', 'sion'); +--------------------------------------------+ | ends_with(Utf8("datafusion"),Utf8("sion")) | +--------------------------------------------+ | true | +--------------------------------------------+ ``` ##### `find_in_set` Returns a value in the range of 1 to N if the string str is in the string list strlist consisting of N substrings. ```sql find_in_set(str, strlist) ``` ###### Arguments - **str**: String expression to find in strlist. - **strlist**: A string list is a string composed of substrings separated by , characters. ###### Example ```sql > select find_in_set('b', 'a,b,c,d'); +----------------------------------------+ | find_in_set(Utf8("b"),Utf8("a,b,c,d")) | +----------------------------------------+ | 2 | +----------------------------------------+ ``` ##### `initcap` Capitalizes the first character in each word in the input string. Words are delimited by non-alphanumeric characters. ```sql initcap(str) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > select initcap('apache datafusion'); +------------------------------------+ | initcap(Utf8("apache datafusion")) | +------------------------------------+ | Apache Datafusion | +------------------------------------+ ``` **Related functions**: - [lower](#lower) - [upper](#upper) ##### `instr` _Alias of [strpos](#strpos)._ ##### `left` Returns a specified number of characters from the left side of a string. ```sql left(str, n) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **n**: Number of characters to return. ###### Example ```sql > select left('datafusion', 4); +-----------------------------------+ | left(Utf8("datafusion"),Int64(4)) | +-----------------------------------+ | data | +-----------------------------------+ ``` **Related functions**: - [right](#right) ##### `length` _Alias of [character_length](#character_length)._ ##### `levenshtein` Returns the [`Levenshtein distance`](https://en.wikipedia.org/wiki/Levenshtein_distance) between the two given strings. ```sql levenshtein(str1, str2) ``` ###### Arguments - **str1**: String expression to compute Levenshtein distance with str2. - **str2**: String expression to compute Levenshtein distance with str1. ###### Example ```sql > select levenshtein('kitten', 'sitting'); +---------------------------------------------+ | levenshtein(Utf8("kitten"),Utf8("sitting")) | +---------------------------------------------+ | 3 | +---------------------------------------------+ ``` ##### `lower` Converts a string to lower-case. ```sql lower(str) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > select lower('Ångström'); +-------------------------+ | lower(Utf8("Ångström")) | +-------------------------+ | ångström | +-------------------------+ ``` **Related functions**: - [initcap](#initcap) - [upper](#upper) ##### `lpad` Pads the left side of a string with another string to a specified string length. ```sql lpad(str, n[, padding_str]) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **n**: String length to pad to. If the input string is longer than this length, it is truncated (on the right). - **padding_str**: Optional string expression to pad with. Can be a constant, column, or function, and any combination of string operators. _Default is a space._ ###### Example ```sql > select lpad('Dolly', 10, 'hello'); +---------------------------------------------+ | lpad(Utf8("Dolly"),Int64(10),Utf8("hello")) | +---------------------------------------------+ | helloDolly | +---------------------------------------------+ ``` **Related functions**: - [rpad](#rpad) ##### `ltrim` Trims the specified trim string from the beginning of a string. If no trim string is provided, spaces are removed from the start of the input string. ```sql ltrim(str[, trim_str]) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **trim_str**: String expression to trim from the beginning of the input string. Can be a constant, column, or function, and any combination of arithmetic operators. _Default is a space._ ###### Example ```sql > select ltrim(' datafusion '); +-------------------------------+ | ltrim(Utf8(" datafusion ")) | +-------------------------------+ | datafusion | +-------------------------------+ > select ltrim('___datafusion___', '_'); +-------------------------------------------+ | ltrim(Utf8("___datafusion___"),Utf8("_")) | +-------------------------------------------+ | datafusion___ | +-------------------------------------------+ ``` ###### Alternative Syntax ```sql trim(LEADING trim_str FROM str) ``` **Related functions**: - [btrim](#btrim) - [rtrim](#rtrim) ##### `octet_length` Returns the length of a string in bytes. ```sql octet_length(str) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > select octet_length('Ångström'); +--------------------------------+ | octet_length(Utf8("Ångström")) | +--------------------------------+ | 10 | +--------------------------------+ ``` **Related functions**: - [bit_length](#bit_length) - [length](#length) ##### `overlay` Returns the string which is replaced by another string from the specified position and specified count length. ```sql overlay(str PLACING substr FROM pos [FOR count]) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **substr**: Substring to replace in str. - **pos**: The start position to start the replace in str. - **count**: The count of characters to be replaced from start position of str. If not specified, will use substr length instead. ###### Example ```sql > select overlay('Txxxxas' placing 'hom' from 2 for 4); +--------------------------------------------------------+ | overlay(Utf8("Txxxxas"),Utf8("hom"),Int64(2),Int64(4)) | +--------------------------------------------------------+ | Thomas | +--------------------------------------------------------+ ``` ##### `position` _Alias of [strpos](#strpos)._ ##### `repeat` Returns a string with an input string repeated a specified number. ```sql repeat(str, n) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **n**: Number of times to repeat the input string. ###### Example ```sql > select repeat('data', 3); +-------------------------------+ | repeat(Utf8("data"),Int64(3)) | +-------------------------------+ | datadatadata | +-------------------------------+ ``` ##### `replace` Replaces all occurrences of a specified substring in a string with a new substring. ```sql replace(str, substr, replacement) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **substr**: Substring expression to replace in the input string. Substring expression to operate on. Can be a constant, column, or function, and any combination of operators. - **replacement**: Replacement substring expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > select replace('ABabbaBA', 'ab', 'cd'); +-------------------------------------------------+ | replace(Utf8("ABabbaBA"),Utf8("ab"),Utf8("cd")) | +-------------------------------------------------+ | ABcdbaBA | +-------------------------------------------------+ ``` ##### `reverse` Reverses the character order of a string. ```sql reverse(str) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > select reverse('datafusion'); +-----------------------------+ | reverse(Utf8("datafusion")) | +-----------------------------+ | noisufatad | +-----------------------------+ ``` ##### `right` Returns a specified number of characters from the right side of a string. ```sql right(str, n) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **n**: Number of characters to return. ###### Example ```sql > select right('datafusion', 6); +------------------------------------+ | right(Utf8("datafusion"),Int64(6)) | +------------------------------------+ | fusion | +------------------------------------+ ``` **Related functions**: - [left](#left) ##### `rpad` Pads the right side of a string with another string to a specified string length. ```sql rpad(str, n[, padding_str]) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **n**: String length to pad to. If the input string is longer than this length, it is truncated. - **padding_str**: String expression to pad with. Can be a constant, column, or function, and any combination of string operators. _Default is a space._ ###### Example ```sql > select rpad('datafusion', 20, '_-'); +-----------------------------------------------+ | rpad(Utf8("datafusion"),Int64(20),Utf8("_-")) | +-----------------------------------------------+ | datafusion_-_-_-_-_- | +-----------------------------------------------+ ``` **Related functions**: - [lpad](#lpad) ##### `rtrim` Trims the specified trim string from the end of a string. If no trim string is provided, all spaces are removed from the end of the input string. ```sql rtrim(str[, trim_str]) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **trim_str**: String expression to trim from the end of the input string. Can be a constant, column, or function, and any combination of arithmetic operators. _Default is a space._ ###### Example ```sql > select rtrim(' datafusion '); +-------------------------------+ | rtrim(Utf8(" datafusion ")) | +-------------------------------+ | datafusion | +-------------------------------+ > select rtrim('___datafusion___', '_'); +-------------------------------------------+ | rtrim(Utf8("___datafusion___"),Utf8("_")) | +-------------------------------------------+ | ___datafusion | +-------------------------------------------+ ``` ###### Alternative Syntax ```sql trim(TRAILING trim_str FROM str) ``` **Related functions**: - [btrim](#btrim) - [ltrim](#ltrim) ##### `split_part` Splits a string based on a specified delimiter and returns the substring in the specified position. ```sql split_part(str, delimiter, pos) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **delimiter**: String or character to split on. - **pos**: Position of the part to return (counting from 1). Negative values count backward from the end of the string. ###### Example ```sql > select split_part('1.2.3.4.5', '.', 3); +--------------------------------------------------+ | split_part(Utf8("1.2.3.4.5"),Utf8("."),Int64(3)) | +--------------------------------------------------+ | 3 | +--------------------------------------------------+ ``` ##### `starts_with` Tests if a string starts with a substring. ```sql starts_with(str, substr) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **substr**: Substring to test for. ###### Example ```sql > select starts_with('datafusion','data'); +----------------------------------------------+ | starts_with(Utf8("datafusion"),Utf8("data")) | +----------------------------------------------+ | true | +----------------------------------------------+ ``` ##### `strpos` Returns the starting position of a specified substring in a string. Positions begin at 1. If the substring does not exist in the string, the function returns 0. ```sql strpos(str, substr) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **substr**: Substring expression to search for. ###### Example ```sql > select strpos('datafusion', 'fus'); +----------------------------------------+ | strpos(Utf8("datafusion"),Utf8("fus")) | +----------------------------------------+ | 5 | +----------------------------------------+ ``` ###### Alternative Syntax ```sql position(substr in origstr) ``` ###### Aliases - instr - position ##### `substr` Extracts a substring of a specified number of characters from a specific starting position in a string. ```sql substr(str, start_pos[, length]) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **start_pos**: Character position to start the substring at. The first character in the string has a position of 1. If the start position is less than 1, it is treated as if it is before the start of the string and the (absolute) number of characters before position 1 is subtracted from `length` (if given). For example, `substr('abc', -3, 6)` returns `'ab'`. - **length**: Number of characters to extract. If not specified, returns the rest of the string after the start position. ###### Example ```sql > select substr('datafusion', 5, 3); +----------------------------------------------+ | substr(Utf8("datafusion"),Int64(5),Int64(3)) | +----------------------------------------------+ | fus | +----------------------------------------------+ ``` ###### Alternative Syntax ```sql substring(str from start_pos for length) ``` ###### Aliases - substring ##### `substr_index` Returns the substring from str before count occurrences of the delimiter delim. If count is positive, everything to the left of the final delimiter (counting from the left) is returned. If count is negative, everything to the right of the final delimiter (counting from the right) is returned. ```sql substr_index(str, delim, count) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **delim**: The string to find in str to split str. - **count**: The number of times to search for the delimiter. Can be either a positive or negative number. ###### Example ```sql > select substr_index('www.apache.org', '.', 1); +---------------------------------------------------------+ | substr_index(Utf8("www.apache.org"),Utf8("."),Int64(1)) | +---------------------------------------------------------+ | www | +---------------------------------------------------------+ > select substr_index('www.apache.org', '.', -1); +----------------------------------------------------------+ | substr_index(Utf8("www.apache.org"),Utf8("."),Int64(-1)) | +----------------------------------------------------------+ | org | +----------------------------------------------------------+ ``` ###### Aliases - substring_index ##### `substring` _Alias of [substr](#substr)._ ##### `substring_index` _Alias of [substr_index](#substr_index)._ ##### `to_hex` Converts an integer to a hexadecimal string. ```sql to_hex(int) ``` ###### Arguments - **int**: Integer expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > select to_hex(12345689); +-------------------------+ | to_hex(Int64(12345689)) | +-------------------------+ | bc6159 | +-------------------------+ ``` ##### `translate` Performs character-wise substitution based on a mapping. ```sql translate(str, from, to) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **from**: The characters to be replaced. - **to**: The characters to replace them with. Each character in **from** that is found in **str** is replaced by the character at the same index in **to**. Any characters in **from** that don't have a corresponding character in **to** are removed. If a character appears more than once in **from**, the first occurrence determines the mapping. ###### Example ```sql > select translate('twice', 'wic', 'her'); +--------------------------------------------------+ | translate(Utf8("twice"),Utf8("wic"),Utf8("her")) | +--------------------------------------------------+ | there | +--------------------------------------------------+ ``` ##### `trim` _Alias of [btrim](#btrim)._ ##### `upper` Converts a string to upper-case. ```sql upper(str) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > select upper('dataFusion'); +---------------------------+ | upper(Utf8("dataFusion")) | +---------------------------+ | DATAFUSION | +---------------------------+ ``` **Related functions**: - [initcap](#initcap) - [lower](#lower) ##### `uuid` Returns [`UUID v4`](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_%28random%29) string value which is unique per row. ```sql uuid() ``` ###### Example ```sql > select uuid(); +--------------------------------------+ | uuid() | +--------------------------------------+ | 6ec17ef8-1934-41cc-8d59-d0c8f9eea1f0 | +--------------------------------------+ ``` ### Binary String Functions - [decode](#decode) - [encode](#encode) ##### `decode` Decode binary data from textual representation in string. ```sql decode(expression, format) ``` ###### Arguments - **expression**: Expression containing encoded string data - **format**: Same arguments as [encode](#encode) **Related functions**: - [encode](#encode) ##### `encode` Encode binary data into a textual representation. ```sql encode(expression, format) ``` ###### Arguments - **expression**: Expression containing string or binary data - **format**: Supported formats are: `base64`, `base64pad`, `hex` **Related functions**: - [decode](#decode) ### Regular Expression Functions Apache DataFusion uses a [PCRE-like](https://en.wikibooks.org/wiki/Regular_Expressions/Perl-Compatible_Regular_Expressions) regular expression [syntax](https://docs.rs/regex/latest/regex/#syntax) (minus support for several features including look-around and backreferences). The following regular expression functions are supported: - [regexp_count](#regexp_count) - [regexp_instr](#regexp_instr) - [regexp_like](#regexp_like) - [regexp_match](#regexp_match) - [regexp_replace](#regexp_replace) ##### `regexp_count` Returns the number of matches that a [regular expression](https://docs.rs/regex/latest/regex/#syntax) has in a string. ```sql regexp_count(str, regexp[, start, flags]) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **regexp**: Regular expression to operate on. Can be a constant, column, or function, and any combination of operators. - **start**: - **start**: Optional start position (the first position is 1) to search for the regular expression. Can be a constant, column, or function. - **flags**: Optional regular expression flags that control the behavior of the regular expression. The following flags are supported: - **i**: case-insensitive: letters match both upper and lower case - **m**: multi-line mode: ^ and $ match begin/end of line - **s**: allow . to match \n - **R**: enables CRLF mode: when multi-line mode is enabled, \r\n is used - **U**: swap the meaning of x* and x*? ###### Example ```sql > select regexp_count('abcAbAbc', 'abc', 2, 'i'); +---------------------------------------------------------------+ | regexp_count(Utf8("abcAbAbc"),Utf8("abc"),Int64(2),Utf8("i")) | +---------------------------------------------------------------+ | 1 | +---------------------------------------------------------------+ ``` ##### `regexp_instr` Returns the position in a string where the specified occurrence of a POSIX regular expression is located. ```sql regexp_instr(str, regexp[, start[, N[, flags[, subexpr]]]]) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **regexp**: Regular expression to operate on. Can be a constant, column, or function, and any combination of operators. - **start**: - **start**: Optional start position (the first position is 1) to search for the regular expression. Can be a constant, column, or function. Defaults to 1 - **N**: - **N**: Optional The N-th occurrence of pattern to find. Defaults to 1 (first match). Can be a constant, column, or function. - **flags**: Optional regular expression flags that control the behavior of the regular expression. The following flags are supported: - **i**: case-insensitive: letters match both upper and lower case - **m**: multi-line mode: ^ and $ match begin/end of line - **s**: allow . to match \n - **R**: enables CRLF mode: when multi-line mode is enabled, \r\n is used - **U**: swap the meaning of x* and x*? - **subexpr**: Optional Specifies which capture group (subexpression) to return the position for. Defaults to 0, which returns the position of the entire match. ###### Example ```sql > SELECT regexp_instr('ABCDEF', 'C(.)(..)'); +---------------------------------------------------------------+ | regexp_instr(Utf8("ABCDEF"),Utf8("C(.)(..)")) | +---------------------------------------------------------------+ | 3 | +---------------------------------------------------------------+ ``` ##### `regexp_like` Returns true if a [regular expression](https://docs.rs/regex/latest/regex/#syntax) has at least one match in a string, false otherwise. ```sql regexp_like(str, regexp[, flags]) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **regexp**: Regular expression to operate on. Can be a constant, column, or function, and any combination of operators. - **flags**: Optional regular expression flags that control the behavior of the regular expression. The following flags are supported: - **i**: case-insensitive: letters match both upper and lower case - **m**: multi-line mode: ^ and $ match begin/end of line - **s**: allow . to match \n - **R**: enables CRLF mode: when multi-line mode is enabled, \r\n is used - **U**: swap the meaning of x* and x*? ###### Example ```sql select regexp_like('Köln', '[a-zA-Z]ö[a-zA-Z]{2}'); +--------------------------------------------------------+ | regexp_like(Utf8("Köln"),Utf8("[a-zA-Z]ö[a-zA-Z]{2}")) | +--------------------------------------------------------+ | true | +--------------------------------------------------------+ SELECT regexp_like('aBc', '(b|d)', 'i'); +--------------------------------------------------+ | regexp_like(Utf8("aBc"),Utf8("(b|d)"),Utf8("i")) | +--------------------------------------------------+ | true | +--------------------------------------------------+ ``` Additional examples can be found [here](https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/builtin_functions/regexp.rs) ##### `regexp_match` Returns the first [regular expression](https://docs.rs/regex/latest/regex/#syntax) matches in a string. ```sql regexp_match(str, regexp[, flags]) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **regexp**: Regular expression to match against. Can be a constant, column, or function. - **flags**: Optional regular expression flags that control the behavior of the regular expression. The following flags are supported: - **i**: case-insensitive: letters match both upper and lower case - **m**: multi-line mode: ^ and $ match begin/end of line - **s**: allow . to match \n - **R**: enables CRLF mode: when multi-line mode is enabled, \r\n is used - **U**: swap the meaning of x* and x*? ###### Example ```sql > select regexp_match('Köln', '[a-zA-Z]ö[a-zA-Z]{2}'); +---------------------------------------------------------+ | regexp_match(Utf8("Köln"),Utf8("[a-zA-Z]ö[a-zA-Z]{2}")) | +---------------------------------------------------------+ | [Köln] | +---------------------------------------------------------+ SELECT regexp_match('aBc', '(b|d)', 'i'); +---------------------------------------------------+ | regexp_match(Utf8("aBc"),Utf8("(b|d)"),Utf8("i")) | +---------------------------------------------------+ | [B] | +---------------------------------------------------+ ``` Additional examples can be found [here](https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/builtin_functions/regexp.rs) ##### `regexp_replace` Replaces substrings in a string that match a [regular expression](https://docs.rs/regex/latest/regex/#syntax). ```sql regexp_replace(str, regexp, replacement[, flags]) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **regexp**: Regular expression to match against. Can be a constant, column, or function. - **replacement**: Replacement string expression to operate on. Can be a constant, column, or function, and any combination of operators. - **flags**: Optional regular expression flags that control the behavior of the regular expression. The following flags are supported: - **g**: (global) Search globally and don't return after the first match - **i**: case-insensitive: letters match both upper and lower case - **m**: multi-line mode: ^ and $ match begin/end of line - **s**: allow . to match \n - **R**: enables CRLF mode: when multi-line mode is enabled, \r\n is used - **U**: swap the meaning of x* and x*? ###### Example ```sql > select regexp_replace('foobarbaz', 'b(..)', 'X\\1Y', 'g'); +------------------------------------------------------------------------+ | regexp_replace(Utf8("foobarbaz"),Utf8("b(..)"),Utf8("X\1Y"),Utf8("g")) | +------------------------------------------------------------------------+ | fooXarYXazY | +------------------------------------------------------------------------+ SELECT regexp_replace('aBc', '(b|d)', 'Ab\\1a', 'i'); +-------------------------------------------------------------------+ | regexp_replace(Utf8("aBc"),Utf8("(b|d)"),Utf8("Ab\1a"),Utf8("i")) | +-------------------------------------------------------------------+ | aAbBac | +-------------------------------------------------------------------+ ``` Additional examples can be found [here](https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/builtin_functions/regexp.rs) ### Time and Date Functions - [current_date](#current_date) - [current_time](#current_time) - [current_timestamp](#current_timestamp) - [date_bin](#date_bin) - [date_format](#date_format) - [date_part](#date_part) - [date_trunc](#date_trunc) - [datepart](#datepart) - [datetrunc](#datetrunc) - [from_unixtime](#from_unixtime) - [make_date](#make_date) - [make_time](#make_time) - [now](#now) - [to_char](#to_char) - [to_date](#to_date) - [to_local_time](#to_local_time) - [to_time](#to_time) - [to_timestamp](#to_timestamp) - [to_timestamp_micros](#to_timestamp_micros) - [to_timestamp_millis](#to_timestamp_millis) - [to_timestamp_nanos](#to_timestamp_nanos) - [to_timestamp_seconds](#to_timestamp_seconds) - [to_unixtime](#to_unixtime) - [today](#today) ##### `current_date` Returns the current date in the session time zone. The `current_date()` return value is determined at query time and will return the same date, no matter when in the query plan the function executes. ```sql current_date() (optional) SET datafusion.execution.time_zone = '+00:00'; SELECT current_date(); ``` ###### Example ```sql > SELECT current_date(); +----------------+ | current_date() | +----------------+ | 2024-12-23 | +----------------+ -- The current date is based on the session time zone (UTC by default) > SET datafusion.execution.time_zone = 'Asia/Tokyo'; > SELECT current_date(); +----------------+ | current_date() | +----------------+ | 2024-12-24 | +----------------+ ``` ###### Aliases - today ##### `current_time` Returns the current time in the session time zone. The `current_time()` return value is determined at query time and will return the same time, no matter when in the query plan the function executes. The session time zone can be set using the statement 'SET datafusion.execution.time_zone = desired time zone'. The time zone can be a value like +00:00, 'Europe/London' etc. ```sql current_time() (optional) SET datafusion.execution.time_zone = '+00:00'; SELECT current_time(); ``` ###### Example ```sql > SELECT current_time(); +--------------------+ | current_time() | +--------------------+ | 06:30:00.123456789 | +--------------------+ -- The current time is based on the session time zone (UTC by default) > SET datafusion.execution.time_zone = 'Asia/Tokyo'; > SELECT current_time(); +--------------------+ | current_time() | +--------------------+ | 15:30:00.123456789 | +--------------------+ ``` ##### `current_timestamp` _Alias of [now](#now)._ ##### `date_bin` Calculates time intervals and returns the start of the interval nearest to the specified timestamp. Use `date_bin` to downsample time series data by grouping rows into time-based "bins" or "windows" and applying an aggregate or selector function to each window. For example, if you "bin" or "window" data into 15 minute intervals, an input timestamp of `2023-01-01T18:18:18Z` will be updated to the start time of the 15 minute bin it is in: `2023-01-01T18:15:00Z`. ```sql date_bin(interval, expression, origin-timestamp) ``` ###### Arguments - **interval**: Bin interval. - **expression**: Time expression to operate on. Can be a constant, column, or function. - **origin-timestamp**: Optional. Starting point used to determine bin boundaries. If not specified defaults 1970-01-01T00:00:00Z (the UNIX epoch in UTC). The following intervals are supported: - nanoseconds - microseconds - milliseconds - seconds - minutes - hours - days - weeks - months - years - century ###### Example ```sql -- Bin the timestamp into 1 day intervals > SELECT date_bin(interval '1 day', time) as bin FROM VALUES ('2023-01-01T18:18:18Z'), ('2023-01-03T19:00:03Z') t(time); +---------------------+ | bin | +---------------------+ | 2023-01-01T00:00:00 | | 2023-01-03T00:00:00 | +---------------------+ 2 row(s) fetched. -- Bin the timestamp into 1 day intervals starting at 3AM on 2023-01-01 > SELECT date_bin(interval '1 day', time, '2023-01-01T03:00:00') as bin FROM VALUES ('2023-01-01T18:18:18Z'), ('2023-01-03T19:00:03Z') t(time); +---------------------+ | bin | +---------------------+ | 2023-01-01T03:00:00 | | 2023-01-03T03:00:00 | +---------------------+ 2 row(s) fetched. -- Bin the time into 15 minute intervals starting at 1 min > SELECT date_bin(interval '15 minutes', time, TIME '00:01:00') as bin FROM VALUES (TIME '02:18:18'), (TIME '19:00:03') t(time); +----------+ | bin | +----------+ | 02:16:00 | | 18:46:00 | +----------+ 2 row(s) fetched. ``` ##### `date_format` _Alias of [to_char](#to_char)._ ##### `date_part` Returns the specified part of the date as an integer. ```sql date_part(part, expression) ``` ###### Arguments - **part**: Part of the date to return. The following date parts are supported: - year - isoyear (ISO 8601 week-numbering year) - quarter (emits value in inclusive range [1, 4] based on which quartile of the year the date is in) - month - week (week of the year) - day (day of the month) - hour - minute - second - millisecond - microsecond - nanosecond - dow (day of the week where Sunday is 0) - doy (day of the year) - epoch (seconds since Unix epoch for timestamps/dates, total seconds for intervals) - isodow (day of the week where Monday is 0) - **expression**: Time expression to operate on. Can be a constant, column, or function. ###### Example ```sql > SELECT date_part('year', '2024-05-01T00:00:00'); +-----------------------------------------------------+ | date_part(Utf8("year"),Utf8("2024-05-01T00:00:00")) | +-----------------------------------------------------+ | 2024 | +-----------------------------------------------------+ > SELECT extract(day FROM timestamp '2024-05-01T00:00:00'); +----------------------------------------------------+ | date_part(Utf8("DAY"),Utf8("2024-05-01T00:00:00")) | +----------------------------------------------------+ | 1 | +----------------------------------------------------+ ``` ###### Alternative Syntax ```sql extract(field FROM source) ``` ###### Aliases - datepart ##### `date_trunc` Truncates a timestamp or time value to a specified precision. ```sql date_trunc(precision, expression) ``` ###### Arguments - **precision**: Time precision to truncate to. The following precisions are supported: For Timestamp types: - year / YEAR - quarter / QUARTER - month / MONTH - week / WEEK - day / DAY - hour / HOUR - minute / MINUTE - second / SECOND - millisecond / MILLISECOND - microsecond / MICROSECOND For Time types (hour, minute, second, millisecond, microsecond only): - hour / HOUR - minute / MINUTE - second / SECOND - millisecond / MILLISECOND - microsecond / MICROSECOND - **expression**: Timestamp or time expression to operate on. Can be a constant, column, or function. ###### Example ```sql > SELECT date_trunc('month', '2024-05-15T10:30:00'); +-----------------------------------------------+ | date_trunc(Utf8("month"),Utf8("2024-05-15T10:30:00")) | +-----------------------------------------------+ | 2024-05-01T00:00:00 | +-----------------------------------------------+ > SELECT date_trunc('hour', '2024-05-15T10:30:00'); +----------------------------------------------+ | date_trunc(Utf8("hour"),Utf8("2024-05-15T10:30:00")) | +----------------------------------------------+ | 2024-05-15T10:00:00 | +----------------------------------------------+ ``` ###### Aliases - datetrunc ##### `datepart` _Alias of [date_part](#date_part)._ ##### `datetrunc` _Alias of [date_trunc](#date_trunc)._ ##### `from_unixtime` Converts an integer to RFC3339 timestamp format (`YYYY-MM-DDT00:00:00.000000000Z`). Integers and unsigned integers are interpreted as seconds since the unix epoch (`1970-01-01T00:00:00Z`) return the corresponding timestamp. ```sql from_unixtime(expression[, timezone]) ``` ###### Arguments - **expression**: The expression to operate on. Can be a constant, column, or function, and any combination of operators. - **timezone**: Optional timezone to use when converting the integer to a timestamp. If not provided, the default timezone is UTC. ###### Example ```sql > select from_unixtime(1599572549, 'America/New_York'); +-----------------------------------------------------------+ | from_unixtime(Int64(1599572549),Utf8("America/New_York")) | +-----------------------------------------------------------+ | 2020-09-08T09:42:29-04:00 | +-----------------------------------------------------------+ ``` ##### `make_date` Make a date from year/month/day component parts. ```sql make_date(year, month, day) ``` ###### Arguments - **year**: Year to use when making the date. Can be a constant, column or function, and any combination of arithmetic operators. - **month**: Month to use when making the date. Can be a constant, column or function, and any combination of arithmetic operators. - **day**: Day to use when making the date. Can be a constant, column or function, and any combination of arithmetic operators. ###### Example ```sql > select make_date(2023, 1, 31); +-------------------------------------------+ | make_date(Int64(2023),Int64(1),Int64(31)) | +-------------------------------------------+ | 2023-01-31 | +-------------------------------------------+ > select make_date('2023', '01', '31'); +-----------------------------------------------+ | make_date(Utf8("2023"),Utf8("01"),Utf8("31")) | +-----------------------------------------------+ | 2023-01-31 | +-----------------------------------------------+ ``` Additional examples can be found [here](https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/builtin_functions/date_time.rs) ##### `make_time` Make a time from hour/minute/second component parts. ```sql make_time(hour, minute, second) ``` ###### Arguments - **hour**: Hour to use when making the time. Can be a constant, column or function, and any combination of arithmetic operators. - **minute**: Minute to use when making the time. Can be a constant, column or function, and any combination of arithmetic operators. - **second**: Second to use when making the time. Can be a constant, column or function, and any combination of arithmetic operators. ###### Example ```sql > select make_time(13, 23, 1); +-------------------------------------------+ | make_time(Int64(13),Int64(23),Int64(1)) | +-------------------------------------------+ | 13:23:01 | +-------------------------------------------+ > select make_time('23', '01', '31'); +-----------------------------------------------+ | make_time(Utf8("23"),Utf8("01"),Utf8("31")) | +-----------------------------------------------+ | 23:01:31 | +-----------------------------------------------+ ``` Additional examples can be found [here](https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/builtin_functions/date_time.rs) ##### `now` Returns the current timestamp in the system configured timezone (None by default). The `now()` return value is determined at query time and will return the same timestamp, no matter when in the query plan the function executes. ```sql now() ``` ###### Example ```sql > SELECT now(); +----------------------------------+ | now() | +----------------------------------+ | 2024-12-23T06:30:00.123456789 | +----------------------------------+ -- The timezone of the returned timestamp depends on the session time zone > SET datafusion.execution.time_zone = 'America/New_York'; > SELECT now(); +--------------------------------------+ | now() | +--------------------------------------+ | 2024-12-23T01:30:00.123456789-05:00 | +--------------------------------------+ ``` ###### Aliases - current_timestamp ##### `to_char` Returns a string representation of a date, time, timestamp or duration based on a [Chrono format](https://docs.rs/chrono/latest/chrono/format/strftime/index.html). Unlike the PostgreSQL equivalent of this function numerical formatting is not supported. ```sql to_char(expression, format) ``` ###### Arguments - **expression**: Expression to operate on. Can be a constant, column, or function that results in a date, time, timestamp or duration. - **format**: A [Chrono format](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) string to use to convert the expression. - **day**: Day to use when making the date. Can be a constant, column or function, and any combination of arithmetic operators. ###### Example ```sql > select to_char('2023-03-01'::date, '%d-%m-%Y'); +----------------------------------------------+ | to_char(Utf8("2023-03-01"),Utf8("%d-%m-%Y")) | +----------------------------------------------+ | 01-03-2023 | +----------------------------------------------+ ``` Additional examples can be found [here](https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/builtin_functions/date_time.rs) ###### Aliases - date_format ##### `to_date` Converts a value to a date (`YYYY-MM-DD`). Supports strings, numeric and timestamp types as input. Strings are parsed as YYYY-MM-DD (e.g. '2023-07-20') if no [Chrono format](https://docs.rs/chrono/latest/chrono/format/strftime/index.html)s are provided. Integers and doubles are interpreted as days since the unix epoch (`1970-01-01T00:00:00Z`). Returns the corresponding date. Note: `to_date` returns Date32, which represents its values as the number of days since unix epoch(`1970-01-01`) stored as signed 32 bit value. The largest supported date value is `9999-12-31`. ```sql to_date('2017-05-31', '%Y-%m-%d') ``` ###### Arguments - **expression**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **format_n**: Optional [Chrono format](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) strings to use to parse the expression. Formats will be tried in the order they appear with the first successful one being returned. If none of the formats successfully parse the expression an error will be returned. ###### Example ```sql > select to_date('2023-01-31'); +-------------------------------+ | to_date(Utf8("2023-01-31")) | +-------------------------------+ | 2023-01-31 | +-------------------------------+ > select to_date('2023/01/31', '%Y-%m-%d', '%Y/%m/%d'); +---------------------------------------------------------------------+ | to_date(Utf8("2023/01/31"),Utf8("%Y-%m-%d"),Utf8("%Y/%m/%d")) | +---------------------------------------------------------------------+ | 2023-01-31 | +---------------------------------------------------------------------+ ``` Additional examples can be found [here](https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/builtin_functions/date_time.rs) ##### `to_local_time` Converts a timestamp with a timezone to a timestamp without a timezone (with no offset or timezone information). This function handles daylight saving time changes. ```sql to_local_time(expression) ``` ###### Arguments - **expression**: Time expression to operate on. Can be a constant, column, or function. ###### Example ```sql > SELECT to_local_time('2024-04-01T00:00:20Z'::timestamp); +---------------------------------------------+ | to_local_time(Utf8("2024-04-01T00:00:20Z")) | +---------------------------------------------+ | 2024-04-01T00:00:20 | +---------------------------------------------+ > SELECT to_local_time('2024-04-01T00:00:20Z'::timestamp AT TIME ZONE 'Europe/Brussels'); +---------------------------------------------+ | to_local_time(Utf8("2024-04-01T00:00:20Z")) | +---------------------------------------------+ | 2024-04-01T00:00:20 | +---------------------------------------------+ > SELECT time, arrow_typeof(time) as type, to_local_time(time) as to_local_time, arrow_typeof(to_local_time(time)) as to_local_time_type FROM ( SELECT '2024-04-01T00:00:20Z'::timestamp AT TIME ZONE 'Europe/Brussels' AS time ); +---------------------------+----------------------------------+---------------------+--------------------+ | time | type | to_local_time | to_local_time_type | +---------------------------+----------------------------------+---------------------+--------------------+ | 2024-04-01T00:00:20+02:00 | Timestamp(ns, "Europe/Brussels") | 2024-04-01T00:00:20 | Timestamp(ns) | +---------------------------+----------------------------------+---------------------+--------------------+ ## combine `to_local_time()` with `date_bin()` to bin on boundaries in the timezone rather ## than UTC boundaries > SELECT date_bin(interval '1 day', to_local_time('2024-04-01T00:00:20Z'::timestamp AT TIME ZONE 'Europe/Brussels')) AS date_bin; +---------------------+ | date_bin | +---------------------+ | 2024-04-01T00:00:00 | +---------------------+ > SELECT date_bin(interval '1 day', to_local_time('2024-04-01T00:00:20Z'::timestamp AT TIME ZONE 'Europe/Brussels')) AT TIME ZONE 'Europe/Brussels' AS date_bin_with_timezone; +---------------------------+ | date_bin_with_timezone | +---------------------------+ | 2024-04-01T00:00:00+02:00 | +---------------------------+ ``` ##### `to_time` Converts a value to a time (`HH:MM:SS.nnnnnnnnn`). Supports strings and timestamps as input. Strings are parsed as `HH:MM:SS`, `HH:MM:SS.nnnnnnnnn`, or `HH:MM` if no [Chrono format](https://docs.rs/chrono/latest/chrono/format/strftime/index.html)s are provided. Timestamps will have the time portion extracted. Returns the corresponding time. Note: `to_time` returns Time64(Nanosecond), which represents the time of day in nanoseconds since midnight. ```sql to_time('12:30:45', '%H:%M:%S') ``` ###### Arguments - **expression**: String or Timestamp expression to operate on. Can be a constant, column, or function, and any combination of operators. - **format_n**: Optional [Chrono format](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) strings to use to parse the expression. Formats will be tried in the order they appear with the first successful one being returned. If none of the formats successfully parse the expression an error will be returned. ###### Example ```sql > select to_time('12:30:45'); +---------------------------+ | to_time(Utf8("12:30:45")) | +---------------------------+ | 12:30:45 | +---------------------------+ > select to_time('12-30-45', '%H-%M-%S'); +--------------------------------------------+ | to_time(Utf8("12-30-45"),Utf8("%H-%M-%S")) | +--------------------------------------------+ | 12:30:45 | +--------------------------------------------+ > select to_time('2024-01-15 14:30:45'::timestamp); +--------------------------------------------------+ | to_time(Utf8("2024-01-15 14:30:45")) | +--------------------------------------------------+ | 14:30:45 | +--------------------------------------------------+ ``` Additional examples can be found [here](https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/builtin_functions/date_time.rs) ##### `to_timestamp` Converts a value to a timestamp (`YYYY-MM-DDT00:00:00.000000`) in the session time zone. Supports strings, integer, unsigned integer, and double types as input. Strings are parsed as RFC3339 (e.g. '2023-07-20T05:44:00') if no [Chrono formats](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) are provided. Strings that parse without a time zone are treated as if they are in the session time zone, or UTC if no session time zone is set. Integers, unsigned integers, and doubles are interpreted as seconds since the unix epoch (`1970-01-01T00:00:00Z`). Note: `to_timestamp` returns `Timestamp(ns, TimeZone)` where the time zone is the session time zone. The supported range for integer input is between`-9223372037` and `9223372036`. Supported range for string input is between `1677-09-21T00:12:44.0` and `2262-04-11T23:47:16.0`. Please use `to_timestamp_seconds` for the input outside of supported bounds. The session time zone can be set using the statement `SET TIMEZONE = 'desired time zone'`. The time zone can be a value like +00:00, 'Europe/London' etc. ```sql to_timestamp(expression[, ..., format_n]) ``` ###### Arguments - **expression**: Expression to operate on. Can be a constant, column, or function, and any combination of arithmetic operators. - **format_n**: Optional [Chrono format](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) strings to use to parse the expression. Formats will be tried in the order they appear with the first successful one being returned. If none of the formats successfully parse the expression an error will be returned. Note: parsing of named timezones (e.g. 'America/New_York') using %Z is only supported at the end of the string preceded by a space. ###### Example ```sql > select to_timestamp('2023-01-31T09:26:56.123456789-05:00'); +-----------------------------------------------------------+ | to_timestamp(Utf8("2023-01-31T09:26:56.123456789-05:00")) | +-----------------------------------------------------------+ | 2023-01-31T14:26:56.123456789 | +-----------------------------------------------------------+ > select to_timestamp('03:59:00.123456789 05-17-2023', '%c', '%+', '%H:%M:%S%.f %m-%d-%Y'); +--------------------------------------------------------------------------------------------------------+ | to_timestamp(Utf8("03:59:00.123456789 05-17-2023"),Utf8("%c"),Utf8("%+"),Utf8("%H:%M:%S%.f %m-%d-%Y")) | +--------------------------------------------------------------------------------------------------------+ | 2023-05-17T03:59:00.123456789 | +--------------------------------------------------------------------------------------------------------+ ``` Additional examples can be found [here](https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/builtin_functions/date_time.rs) ##### `to_timestamp_micros` Converts a value to a timestamp (`YYYY-MM-DDT00:00:00.000000`) in the session time zone. Supports strings, integer, unsigned integer, and double types as input. Strings are parsed as RFC3339 (e.g. '2023-07-20T05:44:00') if no [Chrono formats](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) are provided. Strings that parse without a time zone are treated as if they are in the session time zone, or UTC if no session time zone is set. Integers, unsigned integers, and doubles are interpreted as microseconds since the unix epoch (`1970-01-01T00:00:00Z`). The session time zone can be set using the statement `SET TIMEZONE = 'desired time zone'`. The time zone can be a value like +00:00, 'Europe/London' etc. ```sql to_timestamp_micros(expression[, ..., format_n]) ``` ###### Arguments - **expression**: Expression to operate on. Can be a constant, column, or function, and any combination of arithmetic operators. - **format_n**: Optional [Chrono format](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) strings to use to parse the expression. Formats will be tried in the order they appear with the first successful one being returned. If none of the formats successfully parse the expression an error will be returned. Note: parsing of named timezones (e.g. 'America/New_York') using %Z is only supported at the end of the string preceded by a space. ###### Example ```sql > select to_timestamp_micros('2023-01-31T09:26:56.123456789-05:00'); +------------------------------------------------------------------+ | to_timestamp_micros(Utf8("2023-01-31T09:26:56.123456789-05:00")) | +------------------------------------------------------------------+ | 2023-01-31T14:26:56.123456 | +------------------------------------------------------------------+ > select to_timestamp_micros('03:59:00.123456789 05-17-2023', '%c', '%+', '%H:%M:%S%.f %m-%d-%Y'); +---------------------------------------------------------------------------------------------------------------+ | to_timestamp_micros(Utf8("03:59:00.123456789 05-17-2023"),Utf8("%c"),Utf8("%+"),Utf8("%H:%M:%S%.f %m-%d-%Y")) | +---------------------------------------------------------------------------------------------------------------+ | 2023-05-17T03:59:00.123456 | +---------------------------------------------------------------------------------------------------------------+ ``` Additional examples can be found [here](https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/builtin_functions/date_time.rs) ##### `to_timestamp_millis` Converts a value to a timestamp (`YYYY-MM-DDT00:00:00.000`) in the session time zone. Supports strings, integer, unsigned integer, and double types as input. Strings are parsed as RFC3339 (e.g. '2023-07-20T05:44:00') if no [Chrono formats](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) are provided. Strings that parse without a time zone are treated as if they are in the session time zone, or UTC if no session time zone is set. Integers, unsigned integers, and doubles are interpreted as milliseconds since the unix epoch (`1970-01-01T00:00:00Z`). The session time zone can be set using the statement `SET TIMEZONE = 'desired time zone'`. The time zone can be a value like +00:00, 'Europe/London' etc. ```sql to_timestamp_millis(expression[, ..., format_n]) ``` ###### Arguments - **expression**: Expression to operate on. Can be a constant, column, or function, and any combination of arithmetic operators. - **format_n**: Optional [Chrono format](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) strings to use to parse the expression. Formats will be tried in the order they appear with the first successful one being returned. If none of the formats successfully parse the expression an error will be returned. Note: parsing of named timezones (e.g. 'America/New_York') using %Z is only supported at the end of the string preceded by a space. ###### Example ```sql > select to_timestamp_millis('2023-01-31T09:26:56.123456789-05:00'); +------------------------------------------------------------------+ | to_timestamp_millis(Utf8("2023-01-31T09:26:56.123456789-05:00")) | +------------------------------------------------------------------+ | 2023-01-31T14:26:56.123 | +------------------------------------------------------------------+ > select to_timestamp_millis('03:59:00.123456789 05-17-2023', '%c', '%+', '%H:%M:%S%.f %m-%d-%Y'); +---------------------------------------------------------------------------------------------------------------+ | to_timestamp_millis(Utf8("03:59:00.123456789 05-17-2023"),Utf8("%c"),Utf8("%+"),Utf8("%H:%M:%S%.f %m-%d-%Y")) | +---------------------------------------------------------------------------------------------------------------+ | 2023-05-17T03:59:00.123 | +---------------------------------------------------------------------------------------------------------------+ ``` Additional examples can be found [here](https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/builtin_functions/date_time.rs) ##### `to_timestamp_nanos` Converts a value to a timestamp (`YYYY-MM-DDT00:00:00.000000000`) in the session time zone. Supports strings, integer, unsigned integer, and double types as input. Strings are parsed as RFC3339 (e.g. '2023-07-20T05:44:00') if no [Chrono formats](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) are provided. Strings that parse without a time zone are treated as if they are in the session time zone. Integers, unsigned integers, and doubles are interpreted as nanoseconds since the unix epoch (`1970-01-01T00:00:00Z`). The session time zone can be set using the statement `SET TIMEZONE = 'desired time zone'`. The time zone can be a value like +00:00, 'Europe/London' etc. ```sql to_timestamp_nanos(expression[, ..., format_n]) ``` ###### Arguments - **expression**: Expression to operate on. Can be a constant, column, or function, and any combination of arithmetic operators. - **format_n**: Optional [Chrono format](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) strings to use to parse the expression. Formats will be tried in the order they appear with the first successful one being returned. If none of the formats successfully parse the expression an error will be returned. Note: parsing of named timezones (e.g. 'America/New_York') using %Z is only supported at the end of the string preceded by a space. ###### Example ```sql > select to_timestamp_nanos('2023-01-31T09:26:56.123456789-05:00'); +-----------------------------------------------------------------+ | to_timestamp_nanos(Utf8("2023-01-31T09:26:56.123456789-05:00")) | +-----------------------------------------------------------------+ | 2023-01-31T14:26:56.123456789 | +-----------------------------------------------------------------+ > select to_timestamp_nanos('03:59:00.123456789 05-17-2023', '%c', '%+', '%H:%M:%S%.f %m-%d-%Y'); +--------------------------------------------------------------------------------------------------------------+ | to_timestamp_nanos(Utf8("03:59:00.123456789 05-17-2023"),Utf8("%c"),Utf8("%+"),Utf8("%H:%M:%S%.f %m-%d-%Y")) | +--------------------------------------------------------------------------------------------------------------+ | 2023-05-17T03:59:00.123456789 | +---------------------------------------------------------------------------------------------------------------+ ``` Additional examples can be found [here](https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/builtin_functions/date_time.rs) ##### `to_timestamp_seconds` Converts a value to a timestamp (`YYYY-MM-DDT00:00:00`) in the session time zone. Supports strings, integer, unsigned integer, and double types as input. Strings are parsed as RFC3339 (e.g. '2023-07-20T05:44:00') if no [Chrono formats](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) are provided. Strings that parse without a time zone are treated as if they are in the session time zone, or UTC if no session time zone is set. Integers, unsigned integers, and doubles are interpreted as seconds since the unix epoch (`1970-01-01T00:00:00Z`). The session time zone can be set using the statement `SET TIMEZONE = 'desired time zone'`. The time zone can be a value like +00:00, 'Europe/London' etc. ```sql to_timestamp_seconds(expression[, ..., format_n]) ``` ###### Arguments - **expression**: Expression to operate on. Can be a constant, column, or function, and any combination of arithmetic operators. - **format_n**: Optional [Chrono format](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) strings to use to parse the expression. Formats will be tried in the order they appear with the first successful one being returned. If none of the formats successfully parse the expression an error will be returned. Note: parsing of named timezones (e.g. 'America/New_York') using %Z is only supported at the end of the string preceded by a space. ###### Example ```sql > select to_timestamp_seconds('2023-01-31T09:26:56.123456789-05:00'); +-------------------------------------------------------------------+ | to_timestamp_seconds(Utf8("2023-01-31T09:26:56.123456789-05:00")) | +-------------------------------------------------------------------+ | 2023-01-31T14:26:56 | +-------------------------------------------------------------------+ > select to_timestamp_seconds('03:59:00.123456789 05-17-2023', '%c', '%+', '%H:%M:%S%.f %m-%d-%Y'); +----------------------------------------------------------------------------------------------------------------+ | to_timestamp_seconds(Utf8("03:59:00.123456789 05-17-2023"),Utf8("%c"),Utf8("%+"),Utf8("%H:%M:%S%.f %m-%d-%Y")) | +----------------------------------------------------------------------------------------------------------------+ | 2023-05-17T03:59:00 | +----------------------------------------------------------------------------------------------------------------+ ``` Additional examples can be found [here](https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/builtin_functions/date_time.rs) ##### `to_unixtime` Converts a value to seconds since the unix epoch (`1970-01-01T00:00:00`). Supports strings, dates, timestamps, integer, unsigned integer, and float types as input. Strings are parsed as RFC3339 (e.g. '2023-07-20T05:44:00') if no [Chrono formats](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) are provided. Integers, unsigned integers, and floats are interpreted as seconds since the unix epoch (`1970-01-01T00:00:00`). ```sql to_unixtime(expression[, ..., format_n]) ``` ###### Arguments - **expression**: Expression to operate on. Can be a constant, column, or function, and any combination of arithmetic operators. - **format_n**: Optional [Chrono format](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) strings to use to parse the expression. Formats will be tried in the order they appear with the first successful one being returned. If none of the formats successfully parse the expression an error will be returned. ###### Example ```sql > select to_unixtime('2020-09-08T12:00:00+00:00'); +------------------------------------------------+ | to_unixtime(Utf8("2020-09-08T12:00:00+00:00")) | +------------------------------------------------+ | 1599566400 | +------------------------------------------------+ > select to_unixtime('01-14-2023 01:01:30+05:30', '%q', '%d-%m-%Y %H/%M/%S', '%+', '%m-%d-%Y %H:%M:%S%#z'); +-----------------------------------------------------------------------------------------------------------------------------+ | to_unixtime(Utf8("01-14-2023 01:01:30+05:30"),Utf8("%q"),Utf8("%d-%m-%Y %H/%M/%S"),Utf8("%+"),Utf8("%m-%d-%Y %H:%M:%S%#z")) | +-----------------------------------------------------------------------------------------------------------------------------+ | 1673638290 | +-----------------------------------------------------------------------------------------------------------------------------+ ``` ##### `today` _Alias of [current_date](#current_date)._ ### Array Functions - [array_any_value](#array_any_value) - [array_append](#array_append) - [array_cat](#array_cat) - [array_concat](#array_concat) - [array_contains](#array_contains) - [array_dims](#array_dims) - [array_distance](#array_distance) - [array_distinct](#array_distinct) - [array_element](#array_element) - [array_empty](#array_empty) - [array_except](#array_except) - [array_extract](#array_extract) - [array_has](#array_has) - [array_has_all](#array_has_all) - [array_has_any](#array_has_any) - [array_indexof](#array_indexof) - [array_intersect](#array_intersect) - [array_join](#array_join) - [array_length](#array_length) - [array_max](#array_max) - [array_min](#array_min) - [array_ndims](#array_ndims) - [array_pop_back](#array_pop_back) - [array_pop_front](#array_pop_front) - [array_position](#array_position) - [array_positions](#array_positions) - [array_prepend](#array_prepend) - [array_push_back](#array_push_back) - [array_push_front](#array_push_front) - [array_remove](#array_remove) - [array_remove_all](#array_remove_all) - [array_remove_n](#array_remove_n) - [array_repeat](#array_repeat) - [array_replace](#array_replace) - [array_replace_all](#array_replace_all) - [array_replace_n](#array_replace_n) - [array_resize](#array_resize) - [array_reverse](#array_reverse) - [array_slice](#array_slice) - [array_sort](#array_sort) - [array_to_string](#array_to_string) - [array_union](#array_union) - [arrays_overlap](#arrays_overlap) - [arrays_zip](#arrays_zip) - [cardinality](#cardinality) - [empty](#empty) - [flatten](#flatten) - [generate_series](#generate_series) - [list_any_value](#list_any_value) - [list_append](#list_append) - [list_cat](#list_cat) - [list_concat](#list_concat) - [list_contains](#list_contains) - [list_dims](#list_dims) - [list_distance](#list_distance) - [list_distinct](#list_distinct) - [list_element](#list_element) - [list_empty](#list_empty) - [list_except](#list_except) - [list_extract](#list_extract) - [list_has](#list_has) - [list_has_all](#list_has_all) - [list_has_any](#list_has_any) - [list_indexof](#list_indexof) - [list_intersect](#list_intersect) - [list_join](#list_join) - [list_length](#list_length) - [list_max](#list_max) - [list_ndims](#list_ndims) - [list_pop_back](#list_pop_back) - [list_pop_front](#list_pop_front) - [list_position](#list_position) - [list_positions](#list_positions) - [list_prepend](#list_prepend) - [list_push_back](#list_push_back) - [list_push_front](#list_push_front) - [list_remove](#list_remove) - [list_remove_all](#list_remove_all) - [list_remove_n](#list_remove_n) - [list_repeat](#list_repeat) - [list_replace](#list_replace) - [list_replace_all](#list_replace_all) - [list_replace_n](#list_replace_n) - [list_resize](#list_resize) - [list_reverse](#list_reverse) - [list_slice](#list_slice) - [list_sort](#list_sort) - [list_to_string](#list_to_string) - [list_union](#list_union) - [list_zip](#list_zip) - [make_array](#make_array) - [make_list](#make_list) - [range](#range) - [string_to_array](#string_to_array) - [string_to_list](#string_to_list) ##### `array_any_value` Returns the first non-null element in the array. ```sql array_any_value(array) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. ###### Example ```sql > select array_any_value([NULL, 1, 2, 3]); +-------------------------------+ | array_any_value(List([NULL,1,2,3])) | +-------------------------------------+ | 1 | +-------------------------------------+ ``` ###### Aliases - list_any_value ##### `array_append` Appends an element to the end of an array. ```sql array_append(array, element) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **element**: Element to append to the array. ###### Example ```sql > select array_append([1, 2, 3], 4); +--------------------------------------+ | array_append(List([1,2,3]),Int64(4)) | +--------------------------------------+ | [1, 2, 3, 4] | +--------------------------------------+ ``` ###### Aliases - list_append - array_push_back - list_push_back ##### `array_cat` _Alias of [array_concat](#array_concat)._ ##### `array_concat` Concatenates arrays. ```sql array_concat(array[, ..., array_n]) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **array_n**: Subsequent array column or literal array to concatenate. ###### Example ```sql > select array_concat([1, 2], [3, 4], [5, 6]); +---------------------------------------------------+ | array_concat(List([1,2]),List([3,4]),List([5,6])) | +---------------------------------------------------+ | [1, 2, 3, 4, 5, 6] | +---------------------------------------------------+ ``` ###### Aliases - array_cat - list_concat - list_cat ##### `array_contains` _Alias of [array_has](#array_has)._ ##### `array_dims` Returns an array of the array's dimensions. ```sql array_dims(array) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. ###### Example ```sql > select array_dims([[1, 2, 3], [4, 5, 6]]); +---------------------------------+ | array_dims(List([1,2,3,4,5,6])) | +---------------------------------+ | [2, 3] | +---------------------------------+ ``` ###### Aliases - list_dims ##### `array_distance` Returns the Euclidean distance between two input arrays of equal length. ```sql array_distance(array1, array2) ``` ###### Arguments - **array1**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **array2**: Array expression. Can be a constant, column, or function, and any combination of array operators. ###### Example ```sql > select array_distance([1, 2], [1, 4]); +------------------------------------+ | array_distance(List([1,2], [1,4])) | +------------------------------------+ | 2.0 | +------------------------------------+ ``` ###### Aliases - list_distance ##### `array_distinct` Returns distinct values from the array after removing duplicates. ```sql array_distinct(array) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. ###### Example ```sql > select array_distinct([1, 3, 2, 3, 1, 2, 4]); +---------------------------------+ | array_distinct(List([1,2,3,4])) | +---------------------------------+ | [1, 2, 3, 4] | +---------------------------------+ ``` ###### Aliases - list_distinct ##### `array_element` Extracts the element with the index n from the array. ```sql array_element(array, index) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **index**: Index to extract the element from the array. ###### Example ```sql > select array_element([1, 2, 3, 4], 3); +-----------------------------------------+ | array_element(List([1,2,3,4]),Int64(3)) | +-----------------------------------------+ | 3 | +-----------------------------------------+ ``` ###### Aliases - array_extract - list_element - list_extract ##### `array_empty` _Alias of [empty](#empty)._ ##### `array_except` Returns an array of the elements that appear in the first array but not in the second. ```sql array_except(array1, array2) ``` ###### Arguments - **array1**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **array2**: Array expression. Can be a constant, column, or function, and any combination of array operators. ###### Example ```sql > select array_except([1, 2, 3, 4], [5, 6, 3, 4]); +----------------------------------------------------+ | array_except([1, 2, 3, 4], [5, 6, 3, 4]); | +----------------------------------------------------+ | [1, 2] | +----------------------------------------------------+ > select array_except([1, 2, 3, 4], [3, 4, 5, 6]); +----------------------------------------------------+ | array_except([1, 2, 3, 4], [3, 4, 5, 6]); | +----------------------------------------------------+ | [1, 2] | +----------------------------------------------------+ ``` ###### Aliases - list_except ##### `array_extract` _Alias of [array_element](#array_element)._ ##### `array_has` Returns true if the array contains the element. ```sql array_has(array, element) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **element**: Scalar or Array expression. Can be a constant, column, or function, and any combination of array operators. ###### Example ```sql > select array_has([1, 2, 3], 2); +-----------------------------+ | array_has(List([1,2,3]), 2) | +-----------------------------+ | true | +-----------------------------+ ``` ###### Aliases - list_has - array_contains - list_contains ##### `array_has_all` Returns true if all elements of sub-array exist in array. ```sql array_has_all(array, sub-array) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **sub-array**: Array expression. Can be a constant, column, or function, and any combination of array operators. ###### Example ```sql > select array_has_all([1, 2, 3, 4], [2, 3]); +--------------------------------------------+ | array_has_all(List([1,2,3,4]), List([2,3])) | +--------------------------------------------+ | true | +--------------------------------------------+ ``` ###### Aliases - list_has_all ##### `array_has_any` Returns true if the arrays have any elements in common. ```sql array_has_any(array1, array2) ``` ###### Arguments - **array1**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **array2**: Array expression. Can be a constant, column, or function, and any combination of array operators. ###### Example ```sql > select array_has_any([1, 2, 3], [3, 4]); +------------------------------------------+ | array_has_any(List([1,2,3]), List([3,4])) | +------------------------------------------+ | true | +------------------------------------------+ ``` ###### Aliases - list_has_any - arrays_overlap ##### `array_indexof` _Alias of [array_position](#array_position)._ ##### `array_intersect` Returns an array of elements in the intersection of array1 and array2. ```sql array_intersect(array1, array2) ``` ###### Arguments - **array1**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **array2**: Array expression. Can be a constant, column, or function, and any combination of array operators. ###### Example ```sql > select array_intersect([1, 2, 3, 4], [5, 6, 3, 4]); +----------------------------------------------------+ | array_intersect([1, 2, 3, 4], [5, 6, 3, 4]); | +----------------------------------------------------+ | [3, 4] | +----------------------------------------------------+ > select array_intersect([1, 2, 3, 4], [5, 6, 7, 8]); +----------------------------------------------------+ | array_intersect([1, 2, 3, 4], [5, 6, 7, 8]); | +----------------------------------------------------+ | [] | +----------------------------------------------------+ ``` ###### Aliases - list_intersect ##### `array_join` _Alias of [array_to_string](#array_to_string)._ ##### `array_length` Returns the length of the array dimension. ```sql array_length(array, dimension) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **dimension**: Array dimension. ###### Example ```sql > select array_length([1, 2, 3, 4, 5], 1); +-------------------------------------------+ | array_length(List([1,2,3,4,5]), 1) | +-------------------------------------------+ | 5 | +-------------------------------------------+ ``` ###### Aliases - list_length ##### `array_max` Returns the maximum value in the array. ```sql array_max(array) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. ###### Example ```sql > select array_max([3,1,4,2]); +-----------------------------------------+ | array_max(List([3,1,4,2])) | +-----------------------------------------+ | 4 | +-----------------------------------------+ ``` ###### Aliases - list_max ##### `array_min` Returns the minimum value in the array. ```sql array_min(array) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. ###### Example ```sql > select array_min([3,1,4,2]); +-----------------------------------------+ | array_min(List([3,1,4,2])) | +-----------------------------------------+ | 1 | +-----------------------------------------+ ``` ##### `array_ndims` Returns the number of dimensions of the array. ```sql array_ndims(array, element) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **element**: Array element. ###### Example ```sql > select array_ndims([[1, 2, 3], [4, 5, 6]]); +----------------------------------+ | array_ndims(List([1,2,3,4,5,6])) | +----------------------------------+ | 2 | +----------------------------------+ ``` ###### Aliases - list_ndims ##### `array_pop_back` Returns the array without the last element. ```sql array_pop_back(array) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. ###### Example ```sql > select array_pop_back([1, 2, 3]); +-------------------------------+ | array_pop_back(List([1,2,3])) | +-------------------------------+ | [1, 2] | +-------------------------------+ ``` ###### Aliases - list_pop_back ##### `array_pop_front` Returns the array without the first element. ```sql array_pop_front(array) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. ###### Example ```sql > select array_pop_front([1, 2, 3]); +-------------------------------+ | array_pop_front(List([1,2,3])) | +-------------------------------+ | [2, 3] | +-------------------------------+ ``` ###### Aliases - list_pop_front ##### `array_position` Returns the position of the first occurrence of the specified element in the array, or NULL if not found. Comparisons are done using `IS DISTINCT FROM` semantics, so NULL is considered to match NULL. ```sql array_position(array, element) array_position(array, element, index) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **element**: Element to search for in the array. - **index**: Index at which to start searching (1-indexed). ###### Example ```sql > select array_position([1, 2, 2, 3, 1, 4], 2); +----------------------------------------------+ | array_position(List([1,2,2,3,1,4]),Int64(2)) | +----------------------------------------------+ | 2 | +----------------------------------------------+ > select array_position([1, 2, 2, 3, 1, 4], 2, 3); +----------------------------------------------------+ | array_position(List([1,2,2,3,1,4]),Int64(2), Int64(3)) | +----------------------------------------------------+ | 3 | +----------------------------------------------------+ ``` ###### Aliases - list_position - array_indexof - list_indexof ##### `array_positions` Searches for an element in the array, returns all occurrences. ```sql array_positions(array, element) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **element**: Element to search for in the array. ###### Example ```sql > select array_positions([1, 2, 2, 3, 1, 4], 2); +-----------------------------------------------+ | array_positions(List([1,2,2,3,1,4]),Int64(2)) | +-----------------------------------------------+ | [2, 3] | +-----------------------------------------------+ ``` ###### Aliases - list_positions ##### `array_prepend` Prepends an element to the beginning of an array. ```sql array_prepend(element, array) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **element**: Element to prepend to the array. ###### Example ```sql > select array_prepend(1, [2, 3, 4]); +---------------------------------------+ | array_prepend(Int64(1),List([2,3,4])) | +---------------------------------------+ | [1, 2, 3, 4] | +---------------------------------------+ ``` ###### Aliases - list_prepend - array_push_front - list_push_front ##### `array_push_back` _Alias of [array_append](#array_append)._ ##### `array_push_front` _Alias of [array_prepend](#array_prepend)._ ##### `array_remove` Removes the first element from the array equal to the given value. NULL elements already in the array are preserved when removing a non-NULL value. If `element` evaluates to NULL, the result is NULL rather than removing NULL entries. ```sql array_remove(array, element) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **element**: Element to be removed from the array. ###### Example ```sql > select array_remove([1, 2, 2, 3, 2, 1, 4], 2); +----------------------------------------------+ | array_remove(List([1,2,2,3,2,1,4]),Int64(2)) | +----------------------------------------------+ | [1, 2, 3, 2, 1, 4] | +----------------------------------------------+ > select array_remove([1, 2, NULL, 2, 4], 2); +---------------------------------------------------+ | array_remove(List([1,2,NULL,2,4]),Int64(2)) | +---------------------------------------------------+ | [1, NULL, 2, 4] | +---------------------------------------------------+ ``` ###### Aliases - list_remove ##### `array_remove_all` Removes all elements from the array equal to the given value. NULL elements already in the array are preserved when removing a non-NULL value. If `element` evaluates to NULL, the result is NULL rather than removing NULL entries. ```sql array_remove_all(array, element) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **element**: Element to be removed from the array. ###### Example ```sql > select array_remove_all([1, 2, 2, 3, 2, 1, 4], 2); +--------------------------------------------------+ | array_remove_all(List([1,2,2,3,2,1,4]),Int64(2)) | +--------------------------------------------------+ | [1, 3, 1, 4] | +--------------------------------------------------+ > select array_remove_all([1, 2, NULL, 2, 4], 2); +-----------------------------------------------------+ | array_remove_all(List([1,2,NULL,2,4]),Int64(2)) | +-----------------------------------------------------+ | [1, NULL, 4] | +-----------------------------------------------------+ ``` ###### Aliases - list_remove_all ##### `array_remove_n` Removes the first `max` elements from the array equal to the given value. NULL elements already in the array are preserved when removing a non-NULL value. If `element` evaluates to NULL, the result is NULL rather than removing NULL entries. ```sql array_remove_n(array, element, max) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **element**: Element to be removed from the array. - **max**: Number of first occurrences to remove. ###### Example ```sql > select array_remove_n([1, 2, 2, 3, 2, 1, 4], 2, 2); +---------------------------------------------------------+ | array_remove_n(List([1,2,2,3,2,1,4]),Int64(2),Int64(2)) | +---------------------------------------------------------+ | [1, 3, 2, 1, 4] | +---------------------------------------------------------+ > select array_remove_n([1, 2, NULL, 2, 4], 2, 2); +----------------------------------------------------------+ | array_remove_n(List([1,2,NULL,2,4]),Int64(2),Int64(2)) | +----------------------------------------------------------+ | [1, NULL, 4] | +----------------------------------------------------------+ ``` ###### Aliases - list_remove_n ##### `array_repeat` Returns an array containing element `count` times. ```sql array_repeat(element, count) ``` ###### Arguments - **element**: Element expression. Can be a constant, column, or function, and any combination of array operators. - **count**: Value of how many times to repeat the element. ###### Example ```sql > select array_repeat(1, 3); +---------------------------------+ | array_repeat(Int64(1),Int64(3)) | +---------------------------------+ | [1, 1, 1] | +---------------------------------+ > select array_repeat([1, 2], 2); +------------------------------------+ | array_repeat(List([1,2]),Int64(2)) | +------------------------------------+ | [[1, 2], [1, 2]] | +------------------------------------+ ``` ###### Aliases - list_repeat ##### `array_replace` Replaces the first occurrence of the specified element with another specified element. ```sql array_replace(array, from, to) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **from**: Initial element. - **to**: Final element. ###### Example ```sql > select array_replace([1, 2, 2, 3, 2, 1, 4], 2, 5); +--------------------------------------------------------+ | array_replace(List([1,2,2,3,2,1,4]),Int64(2),Int64(5)) | +--------------------------------------------------------+ | [1, 5, 2, 3, 2, 1, 4] | +--------------------------------------------------------+ ``` ###### Aliases - list_replace ##### `array_replace_all` Replaces all occurrences of the specified element with another specified element. ```sql array_replace_all(array, from, to) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **from**: Initial element. - **to**: Final element. ###### Example ```sql > select array_replace_all([1, 2, 2, 3, 2, 1, 4], 2, 5); +------------------------------------------------------------+ | array_replace_all(List([1,2,2,3,2,1,4]),Int64(2),Int64(5)) | +------------------------------------------------------------+ | [1, 5, 5, 3, 5, 1, 4] | +------------------------------------------------------------+ ``` ###### Aliases - list_replace_all ##### `array_replace_n` Replaces the first `max` occurrences of the specified element with another specified element. ```sql array_replace_n(array, from, to, max) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **from**: Initial element. - **to**: Final element. - **max**: Number of first occurrences to replace. ###### Example ```sql > select array_replace_n([1, 2, 2, 3, 2, 1, 4], 2, 5, 2); +-------------------------------------------------------------------+ | array_replace_n(List([1,2,2,3,2,1,4]),Int64(2),Int64(5),Int64(2)) | +-------------------------------------------------------------------+ | [1, 5, 5, 3, 2, 1, 4] | +-------------------------------------------------------------------+ ``` ###### Aliases - list_replace_n ##### `array_resize` Resizes the list to contain size elements. Initializes new elements with value or empty if value is not set. ```sql array_resize(array, size, value) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **size**: New size of given array. - **value**: Defines new elements' value or empty if value is not set. ###### Example ```sql > select array_resize([1, 2, 3], 5, 0); +-------------------------------------+ | array_resize(List([1,2,3],5,0)) | +-------------------------------------+ | [1, 2, 3, 0, 0] | +-------------------------------------+ ``` ###### Aliases - list_resize ##### `array_reverse` Returns the array with the order of the elements reversed. ```sql array_reverse(array) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. ###### Example ```sql > select array_reverse([1, 2, 3, 4]); +------------------------------------------------------------+ | array_reverse(List([1, 2, 3, 4])) | +------------------------------------------------------------+ | [4, 3, 2, 1] | +------------------------------------------------------------+ ``` ###### Aliases - list_reverse ##### `array_slice` Returns a slice of the array based on 1-indexed start and end positions. ```sql array_slice(array, begin, end) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **begin**: Index of the first element. If negative, it counts backward from the end of the array. - **end**: Index of the last element. If negative, it counts backward from the end of the array. - **stride**: Stride of the array slice. The default is 1. ###### Example ```sql > select array_slice([1, 2, 3, 4, 5, 6, 7, 8], 3, 6); +--------------------------------------------------------+ | array_slice(List([1,2,3,4,5,6,7,8]),Int64(3),Int64(6)) | +--------------------------------------------------------+ | [3, 4, 5, 6] | +--------------------------------------------------------+ ``` ###### Aliases - list_slice ##### `array_sort` Sort array. ```sql array_sort(array, desc, nulls_first) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **desc**: Whether to sort in ascending (`ASC`) or descending (`DESC`) order. The default is `ASC`. - **nulls_first**: Whether to sort nulls first (`NULLS FIRST`) or last (`NULLS LAST`). The default is `NULLS FIRST`. ###### Example ```sql > select array_sort([3, 1, 2]); +-----------------------------+ | array_sort(List([3,1,2])) | +-----------------------------+ | [1, 2, 3] | +-----------------------------+ ``` ###### Aliases - list_sort ##### `array_to_string` Converts each element to its text representation. ```sql array_to_string(array, delimiter[, null_string]) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **delimiter**: Array element separator. - **null_string**: Optional. String to use for null values in the output. If not provided, nulls will be omitted. ###### Example ```sql > select array_to_string([[1, 2, 3, 4], [5, 6, 7, 8]], ','); +----------------------------------------------------+ | array_to_string(List([1,2,3,4,5,6,7,8]),Utf8(",")) | +----------------------------------------------------+ | 1,2,3,4,5,6,7,8 | +----------------------------------------------------+ ``` ###### Aliases - list_to_string - array_join - list_join ##### `array_union` Returns an array of elements that are present in both arrays (all elements from both arrays) without duplicates. ```sql array_union(array1, array2) ``` ###### Arguments - **array1**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **array2**: Array expression. Can be a constant, column, or function, and any combination of array operators. ###### Example ```sql > select array_union([1, 2, 3, 4], [5, 6, 3, 4]); +----------------------------------------------------+ | array_union([1, 2, 3, 4], [5, 6, 3, 4]); | +----------------------------------------------------+ | [1, 2, 3, 4, 5, 6] | +----------------------------------------------------+ > select array_union([1, 2, 3, 4], [5, 6, 7, 8]); +----------------------------------------------------+ | array_union([1, 2, 3, 4], [5, 6, 7, 8]); | +----------------------------------------------------+ | [1, 2, 3, 4, 5, 6, 7, 8] | +----------------------------------------------------+ ``` ###### Aliases - list_union ##### `arrays_overlap` _Alias of [array_has_any](#array_has_any)._ ##### `arrays_zip` Returns an array of structs created by combining the elements of each input array at the same index. If the arrays have different lengths, shorter arrays are padded with NULLs. ```sql arrays_zip(array1[, ..., array_n]) ``` ###### Arguments - **array1**: First array expression. - **array_n**: Optional additional array expressions. ###### Example ```sql > select arrays_zip([1, 2, 3]); +---------------------------------------------------+ | arrays_zip([1, 2, 3]) | +---------------------------------------------------+ | [{1: 1}, {1: 2}, {1: 3}] | +---------------------------------------------------+ > select arrays_zip([1, 2], [3, 4, 5]); +---------------------------------------------------+ | arrays_zip([1, 2], [3, 4, 5]) | +---------------------------------------------------+ | [{1: 1, 2: 3}, {1: 2, 2: 4}, {1: NULL, 2: 5}] | +---------------------------------------------------+ ``` ###### Aliases - list_zip ##### `cardinality` Returns the total number of elements in the array. ```sql cardinality(array) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. ###### Example ```sql > select cardinality([[1, 2, 3, 4], [5, 6, 7, 8]]); +--------------------------------------+ | cardinality(List([1,2,3,4,5,6,7,8])) | +--------------------------------------+ | 8 | +--------------------------------------+ ``` ##### `empty` Returns 1 for an empty array or 0 for a non-empty array. ```sql empty(array) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. ###### Example ```sql > select empty([1]); +------------------+ | empty(List([1])) | +------------------+ | 0 | +------------------+ ``` ###### Aliases - array_empty - list_empty ##### `flatten` Converts an array of arrays to a flat array. - Applies to any depth of nested arrays - Does not change arrays that are already flat The flattened array contains all the elements from all source arrays. ```sql flatten(array) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. ###### Example ```sql > select flatten([[1, 2], [3, 4]]); +------------------------------+ | flatten(List([1,2], [3,4])) | +------------------------------+ | [1, 2, 3, 4] | +------------------------------+ ``` ##### `generate_series` Similar to the range function, but it includes the upper bound. ```sql generate_series(stop) generate_series(start, stop[, step]) ``` ###### Arguments - **start**: Start of the series. Ints, timestamps, dates or string types that can be coerced to Date32 are supported. - **end**: End of the series (included). Type must be the same as start. - **step**: Increase by step (can not be 0). Steps less than a day are supported only for timestamp ranges. ###### Example ```sql > select generate_series(1,3); +------------------------------------+ | generate_series(Int64(1),Int64(3)) | +------------------------------------+ | [1, 2, 3] | +------------------------------------+ ``` ##### `list_any_value` _Alias of [array_any_value](#array_any_value)._ ##### `list_append` _Alias of [array_append](#array_append)._ ##### `list_cat` _Alias of [array_concat](#array_concat)._ ##### `list_concat` _Alias of [array_concat](#array_concat)._ ##### `list_contains` _Alias of [array_has](#array_has)._ ##### `list_dims` _Alias of [array_dims](#array_dims)._ ##### `list_distance` _Alias of [array_distance](#array_distance)._ ##### `list_distinct` _Alias of [array_distinct](#array_distinct)._ ##### `list_element` _Alias of [array_element](#array_element)._ ##### `list_empty` _Alias of [empty](#empty)._ ##### `list_except` _Alias of [array_except](#array_except)._ ##### `list_extract` _Alias of [array_element](#array_element)._ ##### `list_has` _Alias of [array_has](#array_has)._ ##### `list_has_all` _Alias of [array_has_all](#array_has_all)._ ##### `list_has_any` _Alias of [array_has_any](#array_has_any)._ ##### `list_indexof` _Alias of [array_position](#array_position)._ ##### `list_intersect` _Alias of [array_intersect](#array_intersect)._ ##### `list_join` _Alias of [array_to_string](#array_to_string)._ ##### `list_length` _Alias of [array_length](#array_length)._ ##### `list_max` _Alias of [array_max](#array_max)._ ##### `list_ndims` _Alias of [array_ndims](#array_ndims)._ ##### `list_pop_back` _Alias of [array_pop_back](#array_pop_back)._ ##### `list_pop_front` _Alias of [array_pop_front](#array_pop_front)._ ##### `list_position` _Alias of [array_position](#array_position)._ ##### `list_positions` _Alias of [array_positions](#array_positions)._ ##### `list_prepend` _Alias of [array_prepend](#array_prepend)._ ##### `list_push_back` _Alias of [array_append](#array_append)._ ##### `list_push_front` _Alias of [array_prepend](#array_prepend)._ ##### `list_remove` _Alias of [array_remove](#array_remove)._ ##### `list_remove_all` _Alias of [array_remove_all](#array_remove_all)._ ##### `list_remove_n` _Alias of [array_remove_n](#array_remove_n)._ ##### `list_repeat` _Alias of [array_repeat](#array_repeat)._ ##### `list_replace` _Alias of [array_replace](#array_replace)._ ##### `list_replace_all` _Alias of [array_replace_all](#array_replace_all)._ ##### `list_replace_n` _Alias of [array_replace_n](#array_replace_n)._ ##### `list_resize` _Alias of [array_resize](#array_resize)._ ##### `list_reverse` _Alias of [array_reverse](#array_reverse)._ ##### `list_slice` _Alias of [array_slice](#array_slice)._ ##### `list_sort` _Alias of [array_sort](#array_sort)._ ##### `list_to_string` _Alias of [array_to_string](#array_to_string)._ ##### `list_union` _Alias of [array_union](#array_union)._ ##### `list_zip` _Alias of [arrays_zip](#arrays_zip)._ ##### `make_array` Returns an array using the specified input expressions. ```sql make_array(expression1[, ..., expression_n]) ``` ###### Arguments - **expression_n**: Expression to include in the output array. Can be a constant, column, or function, and any combination of arithmetic or string operators. ###### Example ```sql > select make_array(1, 2, 3, 4, 5); +----------------------------------------------------------+ | make_array(Int64(1),Int64(2),Int64(3),Int64(4),Int64(5)) | +----------------------------------------------------------+ | [1, 2, 3, 4, 5] | +----------------------------------------------------------+ ``` ###### Aliases - make_list ##### `make_list` _Alias of [make_array](#make_array)._ ##### `range` Returns an Arrow array between start and stop with step. The range start..end contains all values with start <= x < end. It is empty if start >= end. Step cannot be 0. ```sql range(stop) range(start, stop[, step]) ``` ###### Arguments - **start**: Start of the range. Ints, timestamps, dates or string types that can be coerced to Date32 are supported. - **end**: End of the range (not included). Type must be the same as start. - **step**: Increase by step (cannot be 0). Steps less than a day are supported only for timestamp ranges. ###### Example ```sql > select range(2, 10, 3); +-----------------------------------+ | range(Int64(2),Int64(10),Int64(3))| +-----------------------------------+ | [2, 5, 8] | +-----------------------------------+ > select range(DATE '1992-09-01', DATE '1993-03-01', INTERVAL '1' MONTH); +--------------------------------------------------------------------------+ | range(DATE '1992-09-01', DATE '1993-03-01', INTERVAL '1' MONTH) | +--------------------------------------------------------------------------+ | [1992-09-01, 1992-10-01, 1992-11-01, 1992-12-01, 1993-01-01, 1993-02-01] | +--------------------------------------------------------------------------+ ``` ##### `string_to_array` Splits a string into an array of substrings based on a delimiter. Any substrings matching the optional `null_str` argument are replaced with NULL. ```sql string_to_array(str, delimiter[, null_str]) ``` ###### Arguments - **str**: String expression to split. - **delimiter**: Delimiter string to split on. - **null_str**: Substring values to be replaced with `NULL`. ###### Example ```sql > select string_to_array('abc##def', '##'); +-----------------------------------+ | string_to_array(Utf8('abc##def')) | +-----------------------------------+ | ['abc', 'def'] | +-----------------------------------+ > select string_to_array('abc def', ' ', 'def'); +---------------------------------------------+ | string_to_array(Utf8('abc def'), Utf8(' '), Utf8('def')) | +---------------------------------------------+ | ['abc', NULL] | +---------------------------------------------+ ``` ###### Aliases - string_to_list ##### `string_to_list` _Alias of [string_to_array](#string_to_array)._ ### Struct Functions - [named_struct](#named_struct) - [row](#row) - [struct](#struct) ##### `named_struct` Returns an Arrow struct using the specified name and input expressions pairs. For information on comparing and ordering struct values (including `NULL` handling), see [Comparison and Ordering](df-functions/struct_coercion.md#comparison-and-ordering). ```sql named_struct(expression1_name, expression1_input[, ..., expression_n_name, expression_n_input]) ``` ###### Arguments - **expression_n_name**: Name of the column field. Must be a constant string. - **expression_n_input**: Expression to include in the output struct. Can be a constant, column, or function, and any combination of arithmetic or string operators. ###### Example For example, this query converts two columns `a` and `b` to a single column with a struct type of fields `field_a` and `field_b`: ```sql > select * from t; +---+---+ | a | b | +---+---+ | 1 | 2 | | 3 | 4 | +---+---+ > select named_struct('field_a', a, 'field_b', b) from t; +-------------------------------------------------------+ | named_struct(Utf8("field_a"),t.a,Utf8("field_b"),t.b) | +-------------------------------------------------------+ | {field_a: 1, field_b: 2} | | {field_a: 3, field_b: 4} | +-------------------------------------------------------+ ``` ##### `row` _Alias of [struct](#struct)._ ##### `struct` Returns an Arrow struct using the specified input expressions optionally named. Fields in the returned struct use the optional name or the `cN` naming convention. For example: `c0`, `c1`, `c2`, etc. For information on comparing and ordering struct values (including `NULL` handling), see [Comparison and Ordering](df-functions/struct_coercion.md#comparison-and-ordering). ```sql struct(expression1[, ..., expression_n]) ``` ###### Arguments - **expression1, expression_n**: Expression to include in the output struct. Can be a constant, column, or function, any combination of arithmetic or string operators. ###### Example For example, this query converts two columns `a` and `b` to a single column with a struct type of fields `field_a` and `c1`: ```sql > select * from t; +---+---+ | a | b | +---+---+ | 1 | 2 | | 3 | 4 | +---+---+ -- use default names `c0`, `c1` > select struct(a, b) from t; +-----------------+ | struct(t.a,t.b) | +-----------------+ | {c0: 1, c1: 2} | | {c0: 3, c1: 4} | +-----------------+ -- name the first field `field_a` select struct(a as field_a, b) from t; +--------------------------------------------------+ | named_struct(Utf8("field_a"),t.a,Utf8("c1"),t.b) | +--------------------------------------------------+ | {field_a: 1, c1: 2} | | {field_a: 3, c1: 4} | +--------------------------------------------------+ ``` ###### Aliases - row ### Map Functions - [element_at](#element_at) - [map](#map) - [map_entries](#map_entries) - [map_extract](#map_extract) - [map_keys](#map_keys) - [map_values](#map_values) ##### `element_at` _Alias of [map_extract](#map_extract)._ ##### `map` Returns an Arrow map with the specified key-value pairs. The `make_map` function creates a map from two lists: one for keys and one for values. Each key must be unique and non-null. ```sql map(key, value) map(key: value) make_map(['key1', 'key2'], ['value1', 'value2']) ``` ###### Arguments - **key**: For `map`: Expression to be used for key. Can be a constant, column, function, or any combination of arithmetic or string operators. For `make_map`: The list of keys to be used in the map. Each key must be unique and non-null. - **value**: For `map`: Expression to be used for value. Can be a constant, column, function, or any combination of arithmetic or string operators. For `make_map`: The list of values to be mapped to the corresponding keys. ###### Example ```sql -- Using map function SELECT MAP('type', 'test'); ---- {type: test} SELECT MAP(['POST', 'HEAD', 'PATCH'], [41, 33, null]); ---- {POST: 41, HEAD: 33, PATCH: NULL} SELECT MAP([[1,2], [3,4]], ['a', 'b']); ---- {[1, 2]: a, [3, 4]: b} SELECT MAP { 'a': 1, 'b': 2 }; ---- {a: 1, b: 2} -- Using make_map function SELECT MAKE_MAP(['POST', 'HEAD'], [41, 33]); ---- {POST: 41, HEAD: 33} SELECT MAKE_MAP(['key1', 'key2'], ['value1', null]); ---- {key1: value1, key2: } ``` ##### `map_entries` Returns a list of all entries in the map. ```sql map_entries(map) ``` ###### Arguments - **map**: Map expression. Can be a constant, column, or function, and any combination of map operators. ###### Example ```sql SELECT map_entries(MAP {'a': 1, 'b': NULL, 'c': 3}); ---- [{'key': a, 'value': 1}, {'key': b, 'value': NULL}, {'key': c, 'value': 3}] SELECT map_entries(map([100, 5], [42, 43])); ---- [{'key': 100, 'value': 42}, {'key': 5, 'value': 43}] ``` ##### `map_extract` Returns a list containing the value for the given key or an empty list if the key is not present in the map. ```sql map_extract(map, key) ``` ###### Arguments - **map**: Map expression. Can be a constant, column, or function, and any combination of map operators. - **key**: Key to extract from the map. Can be a constant, column, or function, any combination of arithmetic or string operators, or a named expression of the previously listed. ###### Example ```sql SELECT map_extract(MAP {'a': 1, 'b': NULL, 'c': 3}, 'a'); ---- [1] SELECT map_extract(MAP {1: 'one', 2: 'two'}, 2); ---- ['two'] SELECT map_extract(MAP {'x': 10, 'y': NULL, 'z': 30}, 'y'); ---- [] ``` ###### Aliases - element_at ##### `map_keys` Returns a list of all keys in the map. ```sql map_keys(map) ``` ###### Arguments - **map**: Map expression. Can be a constant, column, or function, and any combination of map operators. ###### Example ```sql SELECT map_keys(MAP {'a': 1, 'b': NULL, 'c': 3}); ---- [a, b, c] SELECT map_keys(map([100, 5], [42, 43])); ---- [100, 5] ``` ##### `map_values` Returns a list of all values in the map. ```sql map_values(map) ``` ###### Arguments - **map**: Map expression. Can be a constant, column, or function, and any combination of map operators. ###### Example ```sql SELECT map_values(MAP {'a': 1, 'b': NULL, 'c': 3}); ---- [1, , 3] SELECT map_values(map([100, 5], [42, 43])); ---- [42, 43] ``` ### Hashing Functions - [digest](#digest) - [md5](#md5) - [sha224](#sha224) - [sha256](#sha256) - [sha384](#sha384) - [sha512](#sha512) ##### `digest` Computes the binary hash of an expression using the specified algorithm. ```sql digest(expression, algorithm) ``` ###### Arguments - **expression**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **algorithm**: String expression specifying algorithm to use. Must be one of: - md5 - sha224 - sha256 - sha384 - sha512 - blake2s - blake2b - blake3 ###### Example ```sql > select digest('foo', 'sha256'); +------------------------------------------------------------------+ | digest(Utf8("foo"),Utf8("sha256")) | +------------------------------------------------------------------+ | 2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae | +------------------------------------------------------------------+ ``` ##### `md5` Computes an MD5 128-bit checksum for a string expression. ```sql md5(expression) ``` ###### Arguments - **expression**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > select md5('foo'); +----------------------------------+ | md5(Utf8("foo")) | +----------------------------------+ | acbd18db4cc2f85cedef654fccc4a4d8 | +----------------------------------+ ``` ##### `sha224` Computes the SHA-224 hash of a binary string. ```sql sha224(expression) ``` ###### Arguments - **expression**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > select sha224('foo'); +----------------------------------------------------------+ | sha224(Utf8("foo")) | +----------------------------------------------------------+ | 0808f64e60d58979fcb676c96ec938270dea42445aeefcd3a4e6f8db | +----------------------------------------------------------+ ``` ##### `sha256` Computes the SHA-256 hash of a binary string. ```sql sha256(expression) ``` ###### Arguments - **expression**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > select sha256('foo'); +------------------------------------------------------------------+ | sha256(Utf8("foo")) | +------------------------------------------------------------------+ | 2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae | +------------------------------------------------------------------+ ``` ##### `sha384` Computes the SHA-384 hash of a binary string. ```sql sha384(expression) ``` ###### Arguments - **expression**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > select sha384('foo'); +--------------------------------------------------------------------------------------------------+ | sha384(Utf8("foo")) | +--------------------------------------------------------------------------------------------------+ | 98c11ffdfdd540676b1a137cb1a22b2a70350c9a44171d6b1180c6be5cbb2ee3f79d532c8a1dd9ef2e8e08e752a3babb | +--------------------------------------------------------------------------------------------------+ ``` ##### `sha512` Computes the SHA-512 hash of a binary string. ```sql sha512(expression) ``` ###### Arguments - **expression**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > select sha512('foo'); +----------------------------------------------------------------------------------------------------------------------------------+ | sha512(Utf8("foo")) | +----------------------------------------------------------------------------------------------------------------------------------+ | f7fbba6e0636f890e56fbbf3283e524c6fa3204ae298382d624741d0dc6638326e282c41be5e4254d8820772c5518a2c5a8c0c7f7eda19594a7eb539453e1ed7 | +----------------------------------------------------------------------------------------------------------------------------------+ ``` ### Union Functions Functions to work with the union data type, also know as tagged unions, variant types, enums or sum types. Note: Not related to the SQL UNION operator - [union_extract](#union_extract) - [union_tag](#union_tag) ##### `union_extract` Returns the value of the given field in the union when selected, or NULL otherwise. ```sql union_extract(union, field_name) ``` ###### Arguments - **union**: Union expression to operate on. Can be a constant, column, or function, and any combination of operators. - **field_name**: String expression to operate on. Must be a constant. ###### Example ```sql ❯ select union_column, union_extract(union_column, 'a'), union_extract(union_column, 'b') from table_with_union; +--------------+----------------------------------+----------------------------------+ | union_column | union_extract(union_column, 'a') | union_extract(union_column, 'b') | +--------------+----------------------------------+----------------------------------+ | {a=1} | 1 | | | {b=3.0} | | 3.0 | | {a=4} | 4 | | | {b=} | | | | {a=} | | | +--------------+----------------------------------+----------------------------------+ ``` ##### `union_tag` Returns the name of the currently selected field in the union ```sql union_tag(union_expression) ``` ###### Arguments - **union**: Union expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql ❯ select union_column, union_tag(union_column) from table_with_union; +--------------+-------------------------+ | union_column | union_tag(union_column) | +--------------+-------------------------+ | {a=1} | a | | {b=3.0} | b | | {a=4} | a | | {b=} | b | | {a=} | a | +--------------+-------------------------+ ``` ### Other Functions - [arrow_cast](#arrow_cast) - [arrow_metadata](#arrow_metadata) - [arrow_try_cast](#arrow_try_cast) - [arrow_typeof](#arrow_typeof) - [get_field](#get_field) - [version](#version) ##### `arrow_cast` Casts a value to a specific Arrow data type. ```sql arrow_cast(expression, datatype) ``` ###### Arguments - **expression**: Expression to cast. The expression can be a constant, column, or function, and any combination of operators. - **datatype**: [Arrow data type](https://docs.rs/arrow/latest/arrow/datatypes/enum.DataType.html) name to cast to, as a string. The format is the same as that returned by [`arrow_typeof`] ###### Example ```sql > select arrow_cast(-5, 'Int8') as a, arrow_cast('foo', 'Dictionary(Int32, Utf8)') as b, arrow_cast('bar', 'LargeUtf8') as c; +----+-----+-----+ | a | b | c | +----+-----+-----+ | -5 | foo | bar | +----+-----+-----+ > select arrow_cast('2023-01-02T12:53:02', 'Timestamp(µs, "+08:00")') as d, arrow_cast('2023-01-02T12:53:02', 'Timestamp(µs)') as e; +---------------------------+---------------------+ | d | e | +---------------------------+---------------------+ | 2023-01-02T12:53:02+08:00 | 2023-01-02T12:53:02 | +---------------------------+---------------------+ ``` ##### `arrow_metadata` Returns the metadata of the input expression. If a key is provided, returns the value for that key. If no key is provided, returns a Map of all metadata. ```sql arrow_metadata(expression[, key]) ``` ###### Arguments - **expression**: The expression to retrieve metadata from. Can be a column or other expression. - **key**: Optional. The specific metadata key to retrieve. ###### Example ```sql > select arrow_metadata(col) from table; +----------------------------+ | arrow_metadata(table.col) | +----------------------------+ | {k: v} | +----------------------------+ > select arrow_metadata(col, 'k') from table; +-------------------------------+ | arrow_metadata(table.col, 'k')| +-------------------------------+ | v | +-------------------------------+ ``` ##### `arrow_try_cast` Casts a value to a specific Arrow data type, returning NULL if the cast fails. ```sql arrow_try_cast(expression, datatype) ``` ###### Arguments - **expression**: Expression to cast. The expression can be a constant, column, or function, and any combination of operators. - **datatype**: [Arrow data type](https://docs.rs/arrow/latest/arrow/datatypes/enum.DataType.html) name to cast to, as a string. The format is the same as that returned by [`arrow_typeof`] ###### Example ```sql > select arrow_try_cast('123', 'Int64') as a, arrow_try_cast('not_a_number', 'Int64') as b; +-----+------+ | a | b | +-----+------+ | 123 | NULL | +-----+------+ ``` ##### `arrow_typeof` Returns the name of the underlying [Arrow data type](https://docs.rs/arrow/latest/arrow/datatypes/enum.DataType.html) of the expression. ```sql arrow_typeof(expression) ``` ###### Arguments - **expression**: Expression to evaluate. The expression can be a constant, column, or function, and any combination of operators. ###### Example ```sql > select arrow_typeof('foo'), arrow_typeof(1); +---------------------------+------------------------+ | arrow_typeof(Utf8("foo")) | arrow_typeof(Int64(1)) | +---------------------------+------------------------+ | Utf8 | Int64 | +---------------------------+------------------------+ ``` ##### `get_field` Returns a field within a map or a struct with the given key. Supports nested field access by providing multiple field names. Note: most users invoke `get_field` indirectly via field access syntax such as `my_struct_col['field_name']` which results in a call to `get_field(my_struct_col, 'field_name')`. Nested access like `my_struct['a']['b']` is optimized to a single call: `get_field(my_struct, 'a', 'b')`. ```sql get_field(expression, field_name[, field_name2, ...]) ``` ###### Arguments - **expression**: The map or struct to retrieve a field from. - **field_name**: The field name(s) to access, in order for nested access. Must evaluate to strings. ###### Example ```sql > -- Access a field from a struct column > create table test( struct_col) as values ({name: 'Alice', age: 30}), ({name: 'Bob', age: 25}); > select struct_col from test; +-----------------------------+ | struct_col | +-----------------------------+ | {name: Alice, age: 30} | | {name: Bob, age: 25} | +-----------------------------+ > select struct_col['name'] as name from test; +-------+ | name | +-------+ | Alice | | Bob | +-------+ > -- Nested field access with multiple arguments > create table test(struct_col) as values ({outer: {inner_val: 42}}); > select struct_col['outer']['inner_val'] as result from test; +--------+ | result | +--------+ | 42 | +--------+ ``` ##### `version` Returns the version of DataFusion. ```sql version() ``` ###### Example ```sql > select version(); +--------------------------------------------+ | version() | +--------------------------------------------+ | Apache DataFusion 42.0.0, aarch64 on macos | +--------------------------------------------+ ``` ## Aggregate Functions Aggregate functions operate on a set of values to compute a single result. ### Filter clause Aggregate functions support the SQL `FILTER (WHERE ...)` clause to restrict which input rows contribute to the aggregate result. ```sql function([exprs]) FILTER (WHERE condition) ``` Example: ```sql SELECT sum(salary) FILTER (WHERE salary > 0) AS sum_positive_salaries, count(*) FILTER (WHERE active) AS active_count FROM employees; ``` Note: When no rows pass the filter, `COUNT` returns `0` while `SUM`/`AVG`/`MIN`/`MAX` return `NULL`. ### WITHIN GROUP / Ordered-set aggregates Some aggregate functions accept the SQL `WITHIN GROUP (ORDER BY ...)` clause to specify the ordering the aggregate relies on. In DataFusion this is opt-in: only aggregate functions whose implementation returns `true` from `AggregateUDFImpl::supports_within_group_clause()` accept the `WITHIN GROUP` clause. Attempting to use `WITHIN GROUP` with a regular aggregate (for example, `SELECT SUM(x) WITHIN GROUP (ORDER BY x)`) will fail during planning with an error: "WITHIN GROUP is only supported for ordered-set aggregate functions". Currently, the built-in aggregate functions that support `WITHIN GROUP` are: - `percentile_cont` — exact percentile aggregate (also available as `percentile_cont(column, percentile)`) - `approx_percentile_cont` — approximate percentile using the t-digest algorithm - `approx_percentile_cont_with_weight` — approximate weighted percentile using the t-digest algorithm Note: rank-like functions such as `rank()`, `dense_rank()`, and `percent_rank()` are window functions and use the `OVER (...)` clause; they are not ordered-set aggregates that accept `WITHIN GROUP` in DataFusion. Example (ordered-set aggregate): ```sql percentile_cont(0.5) WITHIN GROUP (ORDER BY value) ``` Example (invalid usage — planner will error): ```sql -- This will fail: SUM is not an ordered-set aggregate SELECT SUM(x) WITHIN GROUP (ORDER BY x) FROM t; ``` ### General Functions - [array_agg](#array_agg) - [avg](#avg) - [bit_and](#bit_and) - [bit_or](#bit_or) - [bit_xor](#bit_xor) - [bool_and](#bool_and) - [bool_or](#bool_or) - [count](#count) - [first_value](#first_value) - [grouping](#grouping) - [last_value](#last_value) - [max](#max) - [mean](#mean) - [median](#median) - [min](#min) - [percentile_cont](#percentile_cont) - [quantile_cont](#quantile_cont) - [string_agg](#string_agg) - [sum](#sum) - [var](#var) - [var_pop](#var_pop) - [var_population](#var_population) - [var_samp](#var_samp) - [var_sample](#var_sample) ##### `array_agg` Returns an array created from the expression elements. If ordering is required, elements are inserted in the specified order. This aggregation function can only mix DISTINCT and ORDER BY if the ordering expression is exactly the same as the argument expression. ```sql array_agg(expression [ORDER BY expression]) ``` ###### Arguments - **expression**: The expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT array_agg(column_name ORDER BY other_column) FROM table_name; +-----------------------------------------------+ | array_agg(column_name ORDER BY other_column) | +-----------------------------------------------+ | [element1, element2, element3] | +-----------------------------------------------+ > SELECT array_agg(DISTINCT column_name ORDER BY column_name) FROM table_name; +--------------------------------------------------------+ | array_agg(DISTINCT column_name ORDER BY column_name) | +--------------------------------------------------------+ | [element1, element2, element3] | +--------------------------------------------------------+ ``` ##### `avg` Returns the average of numeric values in the specified column. ```sql avg(expression) ``` ###### Arguments - **expression**: The expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT avg(column_name) FROM table_name; +---------------------------+ | avg(column_name) | +---------------------------+ | 42.75 | +---------------------------+ ``` ###### Aliases - mean ##### `bit_and` Computes the bitwise AND of all non-null input values. ```sql bit_and(expression) ``` ###### Arguments - **expression**: Integer expression to operate on. Can be a constant, column, or function, and any combination of operators. ##### `bit_or` Computes the bitwise OR of all non-null input values. ```sql bit_or(expression) ``` ###### Arguments - **expression**: Integer expression to operate on. Can be a constant, column, or function, and any combination of operators. ##### `bit_xor` Computes the bitwise exclusive OR of all non-null input values. ```sql bit_xor(expression) ``` ###### Arguments - **expression**: Integer expression to operate on. Can be a constant, column, or function, and any combination of operators. ##### `bool_and` Returns true if all non-null input values are true, otherwise false. ```sql bool_and(expression) ``` ###### Arguments - **expression**: The expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT bool_and(column_name) FROM table_name; +----------------------------+ | bool_and(column_name) | +----------------------------+ | true | +----------------------------+ ``` ##### `bool_or` Returns true if all non-null input values are true, otherwise false. ```sql bool_and(expression) ``` ###### Arguments - **expression**: The expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT bool_and(column_name) FROM table_name; +----------------------------+ | bool_and(column_name) | +----------------------------+ | true | +----------------------------+ ``` ##### `count` Returns the number of non-null values in the specified column. To include null values in the total count, use `count(*)`. ```sql count(expression) ``` ###### Arguments - **expression**: The expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT count(column_name) FROM table_name; +-----------------------+ | count(column_name) | +-----------------------+ | 100 | +-----------------------+ > SELECT count(*) FROM table_name; +------------------+ | count(*) | +------------------+ | 120 | +------------------+ ``` ##### `first_value` Returns the first element in an aggregation group according to the requested ordering. If no ordering is given, returns an arbitrary element from the group. ```sql first_value(expression [ORDER BY expression]) ``` ###### Arguments - **expression**: The expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT first_value(column_name ORDER BY other_column) FROM table_name; +-----------------------------------------------+ | first_value(column_name ORDER BY other_column)| +-----------------------------------------------+ | first_element | +-----------------------------------------------+ ``` ##### `grouping` Returns 1 if the data is aggregated across the specified column, or 0 if it is not aggregated in the result set. ```sql grouping(expression) ``` ###### Arguments - **expression**: Expression to evaluate whether data is aggregated across the specified column. Can be a constant, column, or function. ###### Example ```sql > SELECT column_name, GROUPING(column_name) AS group_column FROM table_name GROUP BY GROUPING SETS ((column_name), ()); +-------------+-------------+ | column_name | group_column | +-------------+-------------+ | value1 | 0 | | value2 | 0 | | NULL | 1 | +-------------+-------------+ ``` ##### `last_value` Returns the last element in an aggregation group according to the requested ordering. If no ordering is given, returns an arbitrary element from the group. ```sql last_value(expression [ORDER BY expression]) ``` ###### Arguments - **expression**: The expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT last_value(column_name ORDER BY other_column) FROM table_name; +-----------------------------------------------+ | last_value(column_name ORDER BY other_column) | +-----------------------------------------------+ | last_element | +-----------------------------------------------+ ``` ##### `max` Returns the maximum value in the specified column. ```sql max(expression) ``` ###### Arguments - **expression**: The expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT max(column_name) FROM table_name; +----------------------+ | max(column_name) | +----------------------+ | 150 | +----------------------+ ``` ##### `mean` _Alias of [avg](#avg)._ ##### `median` Returns the median value in the specified column. ```sql median(expression) ``` ###### Arguments - **expression**: The expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT median(column_name) FROM table_name; +----------------------+ | median(column_name) | +----------------------+ | 45.5 | +----------------------+ ``` ##### `min` Returns the minimum value in the specified column. ```sql min(expression) ``` ###### Arguments - **expression**: The expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT min(column_name) FROM table_name; +----------------------+ | min(column_name) | +----------------------+ | 12 | +----------------------+ ``` ##### `percentile_cont` Returns the exact percentile of input values, interpolating between values if needed. ```sql percentile_cont(percentile) WITHIN GROUP (ORDER BY expression) ``` ###### Arguments - **expression**: The expression to operate on. Can be a constant, column, or function, and any combination of operators. - **percentile**: Percentile to compute. Must be a float value between 0 and 1 (inclusive). ###### Example ```sql > SELECT percentile_cont(0.75) WITHIN GROUP (ORDER BY column_name) FROM table_name; +----------------------------------------------------------+ | percentile_cont(0.75) WITHIN GROUP (ORDER BY column_name) | +----------------------------------------------------------+ | 45.5 | +----------------------------------------------------------+ ``` An alternate syntax is also supported: ```sql > SELECT percentile_cont(column_name, 0.75) FROM table_name; +---------------------------------------+ | percentile_cont(column_name, 0.75) | +---------------------------------------+ | 45.5 | +---------------------------------------+ ``` ###### Aliases - quantile_cont ##### `quantile_cont` _Alias of [percentile_cont](#percentile_cont)._ ##### `string_agg` Concatenates the values of string expressions and places separator values between them. If ordering is required, strings are concatenated in the specified order. This aggregation function can only mix DISTINCT and ORDER BY if the ordering expression is exactly the same as the first argument expression. ```sql string_agg([DISTINCT] expression, delimiter [ORDER BY expression]) ``` ###### Arguments - **expression**: The string expression to concatenate. Can be a column or any valid string expression. - **delimiter**: A literal string used as a separator between the concatenated values. ###### Example ```sql > SELECT string_agg(name, ', ') AS names_list FROM employee; +--------------------------+ | names_list | +--------------------------+ | Alice, Bob, Bob, Charlie | +--------------------------+ > SELECT string_agg(name, ', ' ORDER BY name DESC) AS names_list FROM employee; +--------------------------+ | names_list | +--------------------------+ | Charlie, Bob, Bob, Alice | +--------------------------+ > SELECT string_agg(DISTINCT name, ', ' ORDER BY name DESC) AS names_list FROM employee; +--------------------------+ | names_list | +--------------------------+ | Charlie, Bob, Alice | +--------------------------+ ``` ##### `sum` Returns the sum of all values in the specified column. ```sql sum(expression) ``` ###### Arguments - **expression**: The expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT sum(column_name) FROM table_name; +-----------------------+ | sum(column_name) | +-----------------------+ | 12345 | +-----------------------+ ``` ##### `var` Returns the statistical sample variance of a set of numbers. ```sql var(expression) ``` ###### Arguments - **expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Aliases - var_sample - var_samp ##### `var_pop` Returns the statistical population variance of a set of numbers. ```sql var_pop(expression) ``` ###### Arguments - **expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Aliases - var_population ##### `var_population` _Alias of [var_pop](#var_pop)._ ##### `var_samp` _Alias of [var](#var)._ ##### `var_sample` _Alias of [var](#var)._ ### Statistical Functions - [corr](#corr) - [covar](#covar) - [covar_pop](#covar_pop) - [covar_samp](#covar_samp) - [nth_value](#nth_value) - [regr_avgx](#regr_avgx) - [regr_avgy](#regr_avgy) - [regr_count](#regr_count) - [regr_intercept](#regr_intercept) - [regr_r2](#regr_r2) - [regr_slope](#regr_slope) - [regr_sxx](#regr_sxx) - [regr_sxy](#regr_sxy) - [regr_syy](#regr_syy) - [stddev](#stddev) - [stddev_pop](#stddev_pop) - [stddev_samp](#stddev_samp) ##### `corr` Returns the coefficient of correlation between two numeric values. ```sql corr(expression1, expression2) ``` ###### Arguments - **expression1**: First expression to operate on. Can be a constant, column, or function, and any combination of operators. - **expression2**: Second expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT corr(column1, column2) FROM table_name; +--------------------------------+ | corr(column1, column2) | +--------------------------------+ | 0.85 | +--------------------------------+ ``` ##### `covar` _Alias of [covar_samp](#covar_samp)._ ##### `covar_pop` Returns the sample covariance of a set of number pairs. ```sql covar_samp(expression1, expression2) ``` ###### Arguments - **expression1**: First expression to operate on. Can be a constant, column, or function, and any combination of operators. - **expression2**: Second expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT covar_samp(column1, column2) FROM table_name; +-----------------------------------+ | covar_samp(column1, column2) | +-----------------------------------+ | 8.25 | +-----------------------------------+ ``` ##### `covar_samp` Returns the sample covariance of a set of number pairs. ```sql covar_samp(expression1, expression2) ``` ###### Arguments - **expression1**: First expression to operate on. Can be a constant, column, or function, and any combination of operators. - **expression2**: Second expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT covar_samp(column1, column2) FROM table_name; +-----------------------------------+ | covar_samp(column1, column2) | +-----------------------------------+ | 8.25 | +-----------------------------------+ ``` ###### Aliases - covar ##### `nth_value` Returns the nth value in a group of values. ```sql nth_value(expression, n ORDER BY expression) ``` ###### Arguments - **expression**: The column or expression to retrieve the nth value from. - **n**: The position (nth) of the value to retrieve, based on the ordering. ###### Example ```sql > SELECT dept_id, salary, NTH_VALUE(salary, 2) OVER (PARTITION BY dept_id ORDER BY salary ASC) AS second_salary_by_dept FROM employee; +---------+--------+-------------------------+ | dept_id | salary | second_salary_by_dept | +---------+--------+-------------------------+ | 1 | 30000 | NULL | | 1 | 40000 | 40000 | | 1 | 50000 | 40000 | | 2 | 35000 | NULL | | 2 | 45000 | 45000 | +---------+--------+-------------------------+ ``` ##### `regr_avgx` Computes the average of the independent variable (input) expression_x for the non-null paired data points. ```sql regr_avgx(expression_y, expression_x) ``` ###### Arguments - **expression_y**: Dependent variable expression to operate on. Can be a constant, column, or function, and any combination of operators. - **expression_x**: Independent variable expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql create table daily_sales(day int, total_sales int) as values (1,100), (2,150), (3,200), (4,NULL), (5,250); select * from daily_sales; +-----+-------------+ | day | total_sales | | --- | ----------- | | 1 | 100 | | 2 | 150 | | 3 | 200 | | 4 | NULL | | 5 | 250 | +-----+-------------+ SELECT regr_avgx(total_sales, day) AS avg_day FROM daily_sales; +----------+ | avg_day | +----------+ | 2.75 | +----------+ ``` ##### `regr_avgy` Computes the average of the dependent variable (output) expression_y for the non-null paired data points. ```sql regr_avgy(expression_y, expression_x) ``` ###### Arguments - **expression_y**: Dependent variable expression to operate on. Can be a constant, column, or function, and any combination of operators. - **expression_x**: Independent variable expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql create table daily_temperature(day int, temperature int) as values (1,30), (2,32), (3, NULL), (4,35), (5,36); select * from daily_temperature; +-----+-------------+ | day | temperature | | --- | ----------- | | 1 | 30 | | 2 | 32 | | 3 | NULL | | 4 | 35 | | 5 | 36 | +-----+-------------+ -- temperature as Dependent Variable(Y), day as Independent Variable(X) SELECT regr_avgy(temperature, day) AS avg_temperature FROM daily_temperature; +-----------------+ | avg_temperature | +-----------------+ | 33.25 | +-----------------+ ``` ##### `regr_count` Counts the number of non-null paired data points. ```sql regr_count(expression_y, expression_x) ``` ###### Arguments - **expression_y**: Dependent variable expression to operate on. Can be a constant, column, or function, and any combination of operators. - **expression_x**: Independent variable expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql create table daily_metrics(day int, user_signups int) as values (1,100), (2,120), (3, NULL), (4,110), (5,NULL); select * from daily_metrics; +-----+---------------+ | day | user_signups | | --- | ------------- | | 1 | 100 | | 2 | 120 | | 3 | NULL | | 4 | 110 | | 5 | NULL | +-----+---------------+ SELECT regr_count(user_signups, day) AS valid_pairs FROM daily_metrics; +-------------+ | valid_pairs | +-------------+ | 3 | +-------------+ ``` ##### `regr_intercept` Computes the y-intercept of the linear regression line. For the equation (y = kx + b), this function returns b. ```sql regr_intercept(expression_y, expression_x) ``` ###### Arguments - **expression_y**: Dependent variable expression to operate on. Can be a constant, column, or function, and any combination of operators. - **expression_x**: Independent variable expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql create table weekly_performance(week int, productivity_score int) as values (1,60), (2,65), (3, 70), (4,75), (5,80); select * from weekly_performance; +------+---------------------+ | week | productivity_score | | ---- | ------------------- | | 1 | 60 | | 2 | 65 | | 3 | 70 | | 4 | 75 | | 5 | 80 | +------+---------------------+ SELECT regr_intercept(productivity_score, week) AS intercept FROM weekly_performance; +----------+ |intercept| |intercept | +----------+ | 55 | +----------+ ``` ##### `regr_r2` Computes the square of the correlation coefficient between the independent and dependent variables. ```sql regr_r2(expression_y, expression_x) ``` ###### Arguments - **expression_y**: Dependent variable expression to operate on. Can be a constant, column, or function, and any combination of operators. - **expression_x**: Independent variable expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql create table weekly_performance(day int ,user_signups int) as values (1,60), (2,65), (3, 70), (4,75), (5,80); select * from weekly_performance; +-----+--------------+ | day | user_signups | +-----+--------------+ | 1 | 60 | | 2 | 65 | | 3 | 70 | | 4 | 75 | | 5 | 80 | +-----+--------------+ SELECT regr_r2(user_signups, day) AS r_squared FROM weekly_performance; +---------+ |r_squared| +---------+ | 1.0 | +---------+ ``` ##### `regr_slope` Returns the slope of the linear regression line for non-null pairs in aggregate columns. Given input column Y and X: regr_slope(Y, X) returns the slope (k in Y = k\*X + b) using minimal RSS fitting. ```sql regr_slope(expression_y, expression_x) ``` ###### Arguments - **expression_y**: Dependent variable expression to operate on. Can be a constant, column, or function, and any combination of operators. - **expression_x**: Independent variable expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql create table weekly_performance(day int, user_signups int) as values (1,60), (2,65), (3, 70), (4,75), (5,80); select * from weekly_performance; +-----+--------------+ | day | user_signups | +-----+--------------+ | 1 | 60 | | 2 | 65 | | 3 | 70 | | 4 | 75 | | 5 | 80 | +-----+--------------+ SELECT regr_slope(user_signups, day) AS slope FROM weekly_performance; +--------+ | slope | +--------+ | 5.0 | +--------+ ``` ##### `regr_sxx` Computes the sum of squares of the independent variable. ```sql regr_sxx(expression_y, expression_x) ``` ###### Arguments - **expression_y**: Dependent variable expression to operate on. Can be a constant, column, or function, and any combination of operators. - **expression_x**: Independent variable expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql create table study_hours(student_id int, hours int, test_score int) as values (1,2,55), (2,4,65), (3,6,75), (4,8,85), (5,10,95); select * from study_hours; +------------+-------+------------+ | student_id | hours | test_score | +------------+-------+------------+ | 1 | 2 | 55 | | 2 | 4 | 65 | | 3 | 6 | 75 | | 4 | 8 | 85 | | 5 | 10 | 95 | +------------+-------+------------+ SELECT regr_sxx(test_score, hours) AS sxx FROM study_hours; +------+ | sxx | +------+ | 40.0 | +------+ ``` ##### `regr_sxy` Computes the sum of products of paired data points. ```sql regr_sxy(expression_y, expression_x) ``` ###### Arguments - **expression_y**: Dependent variable expression to operate on. Can be a constant, column, or function, and any combination of operators. - **expression_x**: Independent variable expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql create table employee_productivity(week int, productivity_score int) as values(1,60), (2,65), (3,70); select * from employee_productivity; +------+--------------------+ | week | productivity_score | +------+--------------------+ | 1 | 60 | | 2 | 65 | | 3 | 70 | +------+--------------------+ SELECT regr_sxy(productivity_score, week) AS sum_product_deviations FROM employee_productivity; +------------------------+ | sum_product_deviations | +------------------------+ | 10.0 | +------------------------+ ``` ##### `regr_syy` Computes the sum of squares of the dependent variable. ```sql regr_syy(expression_y, expression_x) ``` ###### Arguments - **expression_y**: Dependent variable expression to operate on. Can be a constant, column, or function, and any combination of operators. - **expression_x**: Independent variable expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql create table employee_productivity(week int, productivity_score int) as values (1,60), (2,65), (3,70); select * from employee_productivity; +------+--------------------+ | week | productivity_score | +------+--------------------+ | 1 | 60 | | 2 | 65 | | 3 | 70 | +------+--------------------+ SELECT regr_syy(productivity_score, week) AS sum_squares_y FROM employee_productivity; +---------------+ | sum_squares_y | +---------------+ | 50.0 | +---------------+ ``` ##### `stddev` Returns the standard deviation of a set of numbers. ```sql stddev(expression) ``` ###### Arguments - **expression**: The expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT stddev(column_name) FROM table_name; +----------------------+ | stddev(column_name) | +----------------------+ | 12.34 | +----------------------+ ``` ###### Aliases - stddev_samp ##### `stddev_pop` Returns the population standard deviation of a set of numbers. ```sql stddev_pop(expression) ``` ###### Arguments - **expression**: The expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT stddev_pop(column_name) FROM table_name; +--------------------------+ | stddev_pop(column_name) | +--------------------------+ | 10.56 | +--------------------------+ ``` ##### `stddev_samp` _Alias of [stddev](#stddev)._ ### Approximate Functions - [approx_distinct](#approx_distinct) - [approx_median](#approx_median) - [approx_percentile_cont](#approx_percentile_cont) - [approx_percentile_cont_with_weight](#approx_percentile_cont_with_weight) ##### `approx_distinct` Returns the approximate number of distinct input values calculated using the HyperLogLog algorithm. ```sql approx_distinct(expression) ``` ###### Arguments - **expression**: The expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT approx_distinct(column_name) FROM table_name; +-----------------------------------+ | approx_distinct(column_name) | +-----------------------------------+ | 42 | +-----------------------------------+ ``` ##### `approx_median` Returns the approximate median (50th percentile) of input values. It is an alias of `approx_percentile_cont(0.5) WITHIN GROUP (ORDER BY x)`. ```sql approx_median(expression) ``` ###### Arguments - **expression**: The expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT approx_median(column_name) FROM table_name; +-----------------------------------+ | approx_median(column_name) | +-----------------------------------+ | 23.5 | +-----------------------------------+ ``` ##### `approx_percentile_cont` Returns the approximate percentile of input values using the t-digest algorithm. ```sql approx_percentile_cont(percentile [, centroids]) WITHIN GROUP (ORDER BY expression) ``` ###### Arguments - **expression**: The expression to operate on. Can be a constant, column, or function, and any combination of operators. - **percentile**: Percentile to compute. Must be a float value between 0 and 1 (inclusive). - **centroids**: Number of centroids to use in the t-digest algorithm. _Default is 100_. A higher number results in more accurate approximation but requires more memory. ###### Example ```sql > SELECT approx_percentile_cont(0.75) WITHIN GROUP (ORDER BY column_name) FROM table_name; +------------------------------------------------------------------+ | approx_percentile_cont(0.75) WITHIN GROUP (ORDER BY column_name) | +------------------------------------------------------------------+ | 65.0 | +------------------------------------------------------------------+ > SELECT approx_percentile_cont(0.75, 100) WITHIN GROUP (ORDER BY column_name) FROM table_name; +-----------------------------------------------------------------------+ | approx_percentile_cont(0.75, 100) WITHIN GROUP (ORDER BY column_name) | +-----------------------------------------------------------------------+ | 65.0 | +-----------------------------------------------------------------------+ ``` An alternate syntax is also supported: ```sql > SELECT approx_percentile_cont(column_name, 0.75) FROM table_name; +-----------------------------------------------+ | approx_percentile_cont(column_name, 0.75) | +-----------------------------------------------+ | 65.0 | +-----------------------------------------------+ > SELECT approx_percentile_cont(column_name, 0.75, 100) FROM table_name; +----------------------------------------------------------+ | approx_percentile_cont(column_name, 0.75, 100) | +----------------------------------------------------------+ | 65.0 | +----------------------------------------------------------+ ``` ##### `approx_percentile_cont_with_weight` Returns the weighted approximate percentile of input values using the t-digest algorithm. ```sql approx_percentile_cont_with_weight(weight, percentile [, centroids]) WITHIN GROUP (ORDER BY expression) ``` ###### Arguments - **expression**: The expression to operate on. Can be a constant, column, or function, and any combination of operators. - **weight**: Expression to use as weight. Can be a constant, column, or function, and any combination of arithmetic operators. - **percentile**: Percentile to compute. Must be a float value between 0 and 1 (inclusive). - **centroids**: Number of centroids to use in the t-digest algorithm. _Default is 100_. A higher number results in more accurate approximation but requires more memory. ###### Example ```sql > SELECT approx_percentile_cont_with_weight(weight_column, 0.90) WITHIN GROUP (ORDER BY column_name) FROM table_name; +---------------------------------------------------------------------------------------------+ | approx_percentile_cont_with_weight(weight_column, 0.90) WITHIN GROUP (ORDER BY column_name) | +---------------------------------------------------------------------------------------------+ | 78.5 | +---------------------------------------------------------------------------------------------+ > SELECT approx_percentile_cont_with_weight(weight_column, 0.90, 100) WITHIN GROUP (ORDER BY column_name) FROM table_name; +--------------------------------------------------------------------------------------------------+ | approx_percentile_cont_with_weight(weight_column, 0.90, 100) WITHIN GROUP (ORDER BY column_name) | +--------------------------------------------------------------------------------------------------+ | 78.5 | +--------------------------------------------------------------------------------------------------+ ``` An alternative syntax is also supported: ```sql > SELECT approx_percentile_cont_with_weight(column_name, weight_column, 0.90) FROM table_name; +--------------------------------------------------+ | approx_percentile_cont_with_weight(column_name, weight_column, 0.90) | +--------------------------------------------------+ | 78.5 | +--------------------------------------------------+ ``` ## Window Functions A _window function_ performs a calculation across a set of table rows that are somehow related to the current row. This is comparable to the type of calculation that can be done with an aggregate function. However, window functions do not cause rows to become grouped into a single output row like non-window aggregate calls would. Instead, the rows retain their separate identities. Behind the scenes, the window function is able to access more than just the current row of the query result Here is an example that shows how to compare each employee's salary with the average salary in his or her department: ```sql SELECT depname, empno, salary, avg(salary) OVER (PARTITION BY depname) FROM empsalary; +-----------+-------+--------+-------------------+ | depname | empno | salary | avg | +-----------+-------+--------+-------------------+ | personnel | 2 | 3900 | 3700.0 | | personnel | 5 | 3500 | 3700.0 | | develop | 8 | 6000 | 5020.0 | | develop | 10 | 5200 | 5020.0 | | develop | 11 | 5200 | 5020.0 | | develop | 9 | 4500 | 5020.0 | | develop | 7 | 4200 | 5020.0 | | sales | 1 | 5000 | 4866.666666666667 | | sales | 4 | 4800 | 4866.666666666667 | | sales | 3 | 4800 | 4866.666666666667 | +-----------+-------+--------+-------------------+ ``` A window function call always contains an OVER clause directly following the window function's name and argument(s). This is what syntactically distinguishes it from a normal function or non-window aggregate. The OVER clause determines exactly how the rows of the query are split up for processing by the window function. The PARTITION BY clause within OVER divides the rows into groups, or partitions, that share the same values of the PARTITION BY expression(s). For each row, the window function is computed across the rows that fall into the same partition as the current row. The previous example showed how to count the average of a column per partition. You can also control the order in which rows are processed by window functions using ORDER BY within OVER. (The window ORDER BY does not even have to match the order in which the rows are output.) Here is an example: ```sql SELECT depname, empno, salary, rank() OVER (PARTITION BY depname ORDER BY salary DESC) FROM empsalary; +-----------+-------+--------+--------+ | depname | empno | salary | rank | +-----------+-------+--------+--------+ | personnel | 2 | 3900 | 1 | | develop | 8 | 6000 | 1 | | develop | 10 | 5200 | 2 | | develop | 11 | 5200 | 2 | | develop | 9 | 4500 | 4 | | develop | 7 | 4200 | 5 | | sales | 1 | 5000 | 1 | | sales | 4 | 4800 | 2 | | personnel | 5 | 3500 | 2 | | sales | 3 | 4800 | 2 | +-----------+-------+--------+--------+ ``` There is another important concept associated with window functions: for each row, there is a set of rows within its partition called its window frame. Some window functions act only on the rows of the window frame, rather than of the whole partition. Here is an example of using window frames in queries: ```sql SELECT depname, empno, salary, avg(salary) OVER(ORDER BY salary ASC ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS avg, min(salary) OVER(ORDER BY empno ASC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS cum_min FROM empsalary ORDER BY empno ASC; +-----------+-------+--------+--------------------+---------+ | depname | empno | salary | avg | cum_min | +-----------+-------+--------+--------------------+---------+ | sales | 1 | 5000 | 5000.0 | 5000 | | personnel | 2 | 3900 | 3866.6666666666665 | 3900 | | sales | 3 | 4800 | 4700.0 | 3900 | | sales | 4 | 4800 | 4866.666666666667 | 3900 | | personnel | 5 | 3500 | 3700.0 | 3500 | | develop | 7 | 4200 | 4200.0 | 3500 | | develop | 8 | 6000 | 5600.0 | 3500 | | develop | 9 | 4500 | 4500.0 | 3500 | | develop | 10 | 5200 | 5133.333333333333 | 3500 | | develop | 11 | 5200 | 5466.666666666667 | 3500 | +-----------+-------+--------+--------------------+---------+ ``` When a query involves multiple window functions, it is possible to write out each one with a separate OVER clause, but this is duplicative and error-prone if the same windowing behavior is wanted for several functions. Instead, each windowing behavior can be named in a WINDOW clause and then referenced in OVER. For example: ```sql SELECT sum(salary) OVER w, avg(salary) OVER w FROM empsalary WINDOW w AS (PARTITION BY depname ORDER BY salary DESC); ``` ### Syntax The syntax for the OVER-clause is ```sql function([expr]) OVER( [PARTITION BY expr[, …]] [ORDER BY expr [ ASC | DESC ][, …]] [ frame_clause ] ) ``` where **frame_clause** is one of: ```sql { RANGE | ROWS | GROUPS } frame_start { RANGE | ROWS | GROUPS } BETWEEN frame_start AND frame_end ``` and **frame_start** and **frame_end** can be one of ```sql UNBOUNDED PRECEDING offset PRECEDING CURRENT ROW offset FOLLOWING UNBOUNDED FOLLOWING ``` where **offset** is an non-negative integer. RANGE and GROUPS modes require an ORDER BY clause (with RANGE the ORDER BY must specify exactly one column). ### Filter clause for aggregate window functions Aggregate window functions support the SQL `FILTER (WHERE ...)` clause to include only rows that satisfy the predicate from the window frame in the aggregation. ```sql sum(salary) FILTER (WHERE salary > 0) OVER (PARTITION BY depname ORDER BY salary ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) ``` If no rows in the frame satisfy the filter for a given output row, `COUNT` yields `0` while `SUM`/`AVG`/`MIN`/`MAX` yield `NULL`. ### Aggregate functions All [aggregate functions](#aggregate-functions) can be used as window functions. ### Ranking Functions - [cume_dist](#cume_dist) - [dense_rank](#dense_rank) - [ntile](#ntile) - [percent_rank](#percent_rank) - [rank](#rank) - [row_number](#row_number) ##### `cume_dist` Relative rank of the current row: (number of rows preceding or peer with the current row) / (total rows). ```sql cume_dist() ``` ###### Example ```sql -- Example usage of the cume_dist window function: SELECT salary, cume_dist() OVER (ORDER BY salary) AS cume_dist FROM employees; +--------+-----------+ | salary | cume_dist | +--------+-----------+ | 30000 | 0.33 | | 50000 | 0.67 | | 70000 | 1.00 | +--------+-----------+ ``` ##### `dense_rank` Returns the rank of the current row without gaps. This function ranks rows in a dense manner, meaning consecutive ranks are assigned even for identical values. ```sql dense_rank() ``` ###### Example ```sql -- Example usage of the dense_rank window function: SELECT department, salary, dense_rank() OVER (PARTITION BY department ORDER BY salary DESC) AS dense_rank FROM employees; +-------------+--------+------------+ | department | salary | dense_rank | +-------------+--------+------------+ | Sales | 70000 | 1 | | Sales | 50000 | 2 | | Sales | 50000 | 2 | | Sales | 30000 | 3 | | Engineering | 90000 | 1 | | Engineering | 80000 | 2 | +-------------+--------+------------+ ``` ##### `ntile` Integer ranging from 1 to the argument value, dividing the partition as equally as possible ```sql ntile(expression) ``` ###### Arguments - **expression**: An integer describing the number groups the partition should be split into ###### Example ```sql -- Example usage of the ntile window function: SELECT employee_id, salary, ntile(4) OVER (ORDER BY salary DESC) AS quartile FROM employees; +-------------+--------+----------+ | employee_id | salary | quartile | +-------------+--------+----------+ | 1 | 90000 | 1 | | 2 | 85000 | 1 | | 3 | 80000 | 2 | | 4 | 70000 | 2 | | 5 | 60000 | 3 | | 6 | 50000 | 3 | | 7 | 40000 | 4 | | 8 | 30000 | 4 | +-------------+--------+----------+ ``` ##### `percent_rank` Returns the percentage rank of the current row within its partition. The value ranges from 0 to 1 and is computed as `(rank - 1) / (total_rows - 1)`. ```sql percent_rank() ``` ###### Example ```sql -- Example usage of the percent_rank window function: SELECT employee_id, salary, percent_rank() OVER (ORDER BY salary) AS percent_rank FROM employees; +-------------+--------+---------------+ | employee_id | salary | percent_rank | +-------------+--------+---------------+ | 1 | 30000 | 0.00 | | 2 | 50000 | 0.50 | | 3 | 70000 | 1.00 | +-------------+--------+---------------+ ``` ##### `rank` Returns the rank of the current row within its partition, allowing gaps between ranks. This function provides a ranking similar to `row_number`, but skips ranks for identical values. ```sql rank() ``` ###### Example ```sql -- Example usage of the rank window function: SELECT department, salary, rank() OVER (PARTITION BY department ORDER BY salary DESC) AS rank FROM employees; +-------------+--------+------+ | department | salary | rank | +-------------+--------+------+ | Sales | 70000 | 1 | | Sales | 50000 | 2 | | Sales | 50000 | 2 | | Sales | 30000 | 4 | | Engineering | 90000 | 1 | | Engineering | 80000 | 2 | +-------------+--------+------+ ``` ##### `row_number` Number of the current row within its partition, counting from 1. ```sql row_number() ``` ###### Example ```sql -- Example usage of the row_number window function: SELECT department, salary, row_number() OVER (PARTITION BY department ORDER BY salary DESC) AS row_num FROM employees; +-------------+--------+---------+ | department | salary | row_num | +-------------+--------+---------+ | Sales | 70000 | 1 | | Sales | 50000 | 2 | | Sales | 50000 | 3 | | Sales | 30000 | 4 | | Engineering | 90000 | 1 | | Engineering | 80000 | 2 | +-------------+--------+---------+ ``` ### Analytical Functions - [first_value](#first_value) - [lag](#lag) - [last_value](#last_value) - [lead](#lead) - [nth_value](#nth_value) ##### `first_value` Returns value evaluated at the row that is the first row of the window frame. ```sql first_value(expression) ``` ###### Arguments - **expression**: Expression to operate on ###### Example ```sql -- Example usage of the first_value window function: SELECT department, employee_id, salary, first_value(salary) OVER (PARTITION BY department ORDER BY salary DESC) AS top_salary FROM employees; +-------------+-------------+--------+------------+ | department | employee_id | salary | top_salary | +-------------+-------------+--------+------------+ | Sales | 1 | 70000 | 70000 | | Sales | 2 | 50000 | 70000 | | Sales | 3 | 30000 | 70000 | | Engineering | 4 | 90000 | 90000 | | Engineering | 5 | 80000 | 90000 | +-------------+-------------+--------+------------+ ``` ##### `lag` Returns value evaluated at the row that is offset rows before the current row within the partition; if there is no such row, instead return default (which must be of the same type as value). ```sql lag(expression, offset, default) ``` ###### Arguments - **expression**: Expression to operate on - **offset**: Integer. Specifies how many rows back the value of expression should be retrieved. Defaults to 1. - **default**: The default value if the offset is not within the partition. Must be of the same type as expression. ###### Example ```sql -- Example usage of the lag window function: SELECT employee_id, salary, lag(salary, 1, 0) OVER (ORDER BY employee_id) AS prev_salary FROM employees; +-------------+--------+-------------+ | employee_id | salary | prev_salary | +-------------+--------+-------------+ | 1 | 30000 | 0 | | 2 | 50000 | 30000 | | 3 | 70000 | 50000 | | 4 | 60000 | 70000 | +-------------+--------+-------------+ ``` ##### `last_value` Returns value evaluated at the row that is the last row of the window frame. ```sql last_value(expression) ``` ###### Arguments - **expression**: Expression to operate on ###### Example ```sql -- SQL example of last_value: SELECT department, employee_id, salary, last_value(salary) OVER (PARTITION BY department ORDER BY salary) AS running_last_salary FROM employees; +-------------+-------------+--------+---------------------+ | department | employee_id | salary | running_last_salary | +-------------+-------------+--------+---------------------+ | Sales | 1 | 30000 | 30000 | | Sales | 2 | 50000 | 50000 | | Sales | 3 | 70000 | 70000 | | Engineering | 4 | 40000 | 40000 | | Engineering | 5 | 60000 | 60000 | +-------------+-------------+--------+---------------------+ ``` ##### `lead` Returns value evaluated at the row that is offset rows after the current row within the partition; if there is no such row, instead return default (which must be of the same type as value). ```sql lead(expression, offset, default) ``` ###### Arguments - **expression**: Expression to operate on - **offset**: Integer. Specifies how many rows forward the value of expression should be retrieved. Defaults to 1. - **default**: The default value if the offset is not within the partition. Must be of the same type as expression. ###### Example ```sql -- Example usage of lead window function: SELECT employee_id, department, salary, lead(salary, 1, 0) OVER (PARTITION BY department ORDER BY salary) AS next_salary FROM employees; +-------------+-------------+--------+--------------+ | employee_id | department | salary | next_salary | +-------------+-------------+--------+--------------+ | 1 | Sales | 30000 | 50000 | | 2 | Sales | 50000 | 70000 | | 3 | Sales | 70000 | 0 | | 4 | Engineering | 40000 | 60000 | | 5 | Engineering | 60000 | 0 | +-------------+-------------+--------+--------------+ ``` ##### `nth_value` Returns the value evaluated at the nth row of the window frame (counting from 1). Returns NULL if no such row exists. ```sql nth_value(expression, n) ``` ###### Arguments - **expression**: The column from which to retrieve the nth value. - **n**: Integer. Specifies the row number (starting from 1) in the window frame. ###### Example ```sql -- Sample employees table: CREATE TABLE employees (id INT, salary INT); INSERT INTO employees (id, salary) VALUES (1, 30000), (2, 40000), (3, 50000), (4, 60000), (5, 70000); -- Example usage of nth_value: SELECT nth_value(salary, 2) OVER ( ORDER BY salary ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS nth_value FROM employees; +-----------+ | nth_value | +-----------+ | 40000 | | 40000 | | 40000 | | 40000 | | 40000 | +-----------+ ``` ## Special Functions ### Expansion Functions - [unnest](#unnest) - [unnest(struct)](#unnest-struct) ##### `unnest` Expands an array or map into rows. ###### Arguments - **array**: Array expression to unnest. Can be a constant, column, or function, and any combination of array operators. ###### Examples ```sql > select unnest(make_array(1, 2, 3, 4, 5)) as unnested; +----------+ | unnested | +----------+ | 1 | | 2 | | 3 | | 4 | | 5 | +----------+ ``` ```sql > select unnest(range(0, 10)) as unnested_range; +----------------+ | unnested_range | +----------------+ | 0 | | 1 | | 2 | | 3 | | 4 | | 5 | | 6 | | 7 | | 8 | | 9 | +----------------+ ``` ##### `unnest (struct)` Expand a struct fields into individual columns. Each field of the struct will be prefixed with `__unnest_placeholder` and could be accessed via `"__unnest_placeholder()."`. ###### Arguments - **struct**: Object expression to unnest. Can be a constant, column, or function, and any combination of object operators. ###### Examples ```sql > create table foo as values ({a: 5, b: 'a string'}), ({a:6, b: 'another string'}); > create view foov as select column1 as struct_column from foo; > select * from foov; +---------------------------+ | struct_column | +---------------------------+ | {a: 5, b: a string} | | {a: 6, b: another string} | +---------------------------+ > select unnest(struct_column) from foov; +--------------------------------------------+--------------------------------------------+ | __unnest_placeholder(foov.struct_column).a | __unnest_placeholder(foov.struct_column).b | +--------------------------------------------+--------------------------------------------+ | 5 | a string | | 6 | another string | +--------------------------------------------+--------------------------------------------+ ``` --- ## Geospatial Functions This page lists all geospatial related functions in GreptimeDB. These functions are enabled when you have `common-function/geo` feature turned on (default: on). ## Geo Types Convert data between geospatial types. ### `wkt_point_from_latlng` Convert latitude and longitude to WKT point. ```sql SELECT wkt_point_from_latlng(37.76938, -122.3889) AS point; ``` ## Geohash See [more about geohash encoding algorithms](https://en.wikipedia.org/wiki/Geohash). ### `geohash` Get geohash encoded string from latitude, longitude and resolution. ```sql SELECT geohash(37.76938, -122.3889, 11); ``` ### `geohash_neighbours` Get all geohash neighbours for given coordinate and resolution. Note that this function returns a String array and it only works on our HTTP Query API and Postgres channel. ```sql SELECT geohash_neighbours(37.76938, -122.3889, 11); ``` ## H3 H3 is a geospatial index algorithm. See [more about h3 encoding](https://h3geo.org/). ### `h3_latlng_to_cell` Encode coordinate (latitude, longitude) into h3 index at given resolution. Returns UInt64 representation of the cell. ```sql SELECT h3_latlng_to_cell(37.76938, -122.3889, 1); ``` ### `h3_latlng_to_cell_string` Similar to `h3_latlng_to_cell` but returns hex encoding of the cell. ```sql SELECT h3_latlng_to_cell_string(37.76938, -122.3889, 1); ``` ### `h3_cell_to_string` Convert cell index (UInt64) to its string representation. ```sql SELECT h3_cell_to_string(h3_latlng_to_cell(37.76938, -122.3889, 8)); ``` ### `h3_string_to_cell` Convert hex-encoded cell ID to its UInt64 form ```sql SELECT h3_string_to_cell(h3_latlng_to_cell_string(37.76938, -122.3889, 8::UInt64)); ``` ### `h3_cell_center_latlng` Returns cell centroid as latitude and longitude. Note that this function returns a Float array and it only works on our HTTP Query API and Postgres channel. ```sql SELECT h3_cell_center_latlng(h3_latlng_to_cell(37.76938, -122.3889, 8)); ``` ### `h3_cell_resolution` Returns resolution for given cell. ```sql SELECT h3_cell_resolution(h3_latlng_to_cell(37.76938, -122.3889, 8)); ``` ### `h3_cell_base` Returns the base cell of given cell. ```sql SELECT h3_cell_base(h3_latlng_to_cell(37.76938, -122.3889, 8)); ``` ### `h3_cell_is_pentagon` Returns true if cell is a pentagon. ```sql SELECT h3_cell_is_pentagon(h3_latlng_to_cell(37.76938, -122.3889, 8)); ``` ### `h3_cell_parent` Returns parent cell at given resolution. ```sql SELECT h3_cell_parent(h3_latlng_to_cell(37.76938, -122.3889, 8), 6); ``` ### `h3_cell_to_children` Returns children cells at given resolution. Note that this function returns a UInt64 array and it only works on our HTTP Query API and Postgres channel. ```sql SELECT h3_cell_to_children(h3_latlng_to_cell(37.76938, -122.3889, 8), 10); ``` ### `h3_cell_to_children_size` Returns cell children count at given resolution. ```sql SELECT h3_cell_to_children_size(h3_latlng_to_cell(37.76938, -122.3889, 8), 10); ``` ### `h3_cell_to_child_pos` Return the child position for its parent at given resolution. Position is the index of child in its children. ```sql SELECT h3_cell_to_child_pos(h3_latlng_to_cell(37.76938, -122.3889, 8), 6) ``` ### `h3_child_pos_to_cell` Returns the cell at given position of the parent at given resolution. Arguments: - position - cell index - resolution ```sql SELECT h3_child_pos_to_cell(25, h3_latlng_to_cell(37.76938, -122.3889, 8), 11); ``` ### `h3_cells_contains` Return true if given cells contains cell, or cell's parent. Arguments: - cell set: it can be int64/uint64/string array, and comma-separated string cell ID. - cell index: the cell to test ```sql SELECT h3_cells_contains('86283470fffffff,862834777ffffff, 862834757ffffff, 86283471fffffff, 862834707ffffff', '8b283470d112fff') AS R00, h3_cells_contains(['86283470fffffff', '862834777ffffff', '862834757ffffff', '86283471fffffff', '862834707ffffff'], '8b283470d112fff') AS R11, h3_cells_contains([604189641255419903, 604189643000250367, 604189642463379455, 604189641523855359, 604189641121202175], 604189641792290815) AS R21; ``` ### `h3_grid_disk` Returns cells with k distances of given cell. Note that this function returns a UInt64 array and it only works on our HTTP Query API and Postgres channel. ```sql SELECT h3_grid_disk(h3_latlng_to_cell(37.76938, -122.3889, 8), 3); ``` ### `h3_grid_disk_distances` Returns all cells **within** k distances of given cell. Note that this function returns a UInt64 array and it only works on our HTTP Query API and Postgres channel. ```sql SELECT h3_grid_disk_distance(h3_latlng_to_cell(37.76938, -122.3889, 8), 3); ``` ### `h3_grid_distance` Returns distance between two cells. ```sql SELECT h3_grid_distance(cell1, cell2) AS distance, FROM ( SELECT h3_latlng_to_cell(37.76938, -122.3889, 8) AS cell1, h3_latlng_to_cell(39.634, -104.999, 8) AS cell2 ); ``` ### `h3_grid_path_cells` Returns path cells between two cells. Note that this function can fail if two cells are very far apart. ```sql SELECT h3_grid_path_cells(cell1, cell2) AS path_cells, FROM ( SELECT h3_latlng_to_cell(37.76938, -122.3889, 8) AS cell1, h3_latlng_to_cell(39.634, -104.999, 8) AS cell2 ); ``` ### `h3_distance_sphere_km` Returns sphere distance between centroid of two cells, in km ```sql SELECT round(h3_distance_sphere_km(cell1, cell2), 5) AS sphere_distance FROM ( SELECT h3_string_to_cell('86283082fffffff') AS cell1, h3_string_to_cell('86283470fffffff') AS cell2 ); ``` ### `h3_distance_degree` Returns euclidean distance between centroid of two cells, in degree. ```sql SELECT round(h3_distance_degree(cell1, cell2), 14) AS euclidean_distance FROM ( SELECT h3_string_to_cell('86283082fffffff') AS cell1, h3_string_to_cell('86283470fffffff') AS cell2 ); ``` ## S2 Learn [more about S2 encoding](http://s2geometry.io/). ### `s2_latlng_to_cell` Returns s2 cell index of given coordinate. ```sql SELECT s2_latlng_to_cell(37.76938, -122.3889); ``` ### `s2_cell_to_token` Returns string representation of given cell. ```sql SELECT s2_cell_to_token(s2_latlng_to_cell(37.76938, -122.3889)); ``` ### `s2_cell_level` Returns s2 level of given cell. ```sql SELECT s2_cell_level(s2_latlng_to_cell(37.76938, -122.3889)); ``` ### `s2_cell_parent` Returns parent of given cell at level. ```sql SELECT s2_cell_parent(s2_latlng_to_cell(37.76938, -122.3889), 3); ``` ## Encodings ### `json_encode_path` Encode rows of latitude, longitude in a JSON array, sorted by timestamp. Arguments: - latitude - longitude - timestamp Returns a JSON array in string type. Note that the sequence in result coordinate is [longitude, latitude] to align with GeoJSON spec. ```sql SELECT json_encode_path(lat, lon, ts); ``` Example output: ```json [[-122.3888,37.77001],[-122.3839,37.76928],[-122.3889,37.76938],[-122.382,37.7693]] ``` ## Spatial Relation ### `st_contains` Test spatial relationship between two objects: contains. Arguments: two spatial objects encoded with WKT. ```sql SELECT st_contains(polygon1, p1), st_contains(polygon2, p1), FROM ( SELECT wkt_point_from_latlng(37.383287, -122.01325) AS p1, 'POLYGON ((-122.031661 37.428252, -122.139829 37.387072, -122.135365 37.361971, -122.057759 37.332222, -121.987707 37.328946, -121.943754 37.333041, -121.919373 37.349145, -121.945814 37.376705, -121.975689 37.417345, -121.998696 37.409164, -122.031661 37.428252))' AS polygon1, 'POLYGON ((-121.491698 38.653343, -121.582353 38.556757, -121.469721 38.449287, -121.315883 38.541721, -121.491698 38.653343))' AS polygon2, ); ``` ### `st_within` Test spatial relationship between two objects: within. Arguments: two spatial objects encoded with WKT. ```sql SELECT st_within(p1, polygon1), st_within(p1, polygon2), FROM ( SELECT wkt_point_from_latlng(37.383287, -122.01325) AS p1, 'POLYGON ((-122.031661 37.428252, -122.139829 37.387072, -122.135365 37.361971, -122.057759 37.332222, -121.987707 37.328946, -121.943754 37.333041, -121.919373 37.349145, -121.945814 37.376705, -121.975689 37.417345, -121.998696 37.409164, -122.031661 37.428252))' AS polygon1, 'POLYGON ((-121.491698 38.653343, -121.582353 38.556757, -121.469721 38.449287, -121.315883 38.541721, -121.491698 38.653343))' AS polygon2, ); ``` ### `st_intersects` Test spatial relationship between two objects: intersects. Arguments: two spatial objects encoded with WKT. ```sql SELECT st_intersects(polygon1, polygon2), st_intersects(polygon1, polygon3), FROM ( SELECT 'POLYGON ((-122.031661 37.428252, -122.139829 37.387072, -122.135365 37.361971, -122.057759 37.332222, -121.987707 37.328946, -121.943754 37.333041, -121.919373 37.349145, -121.945814 37.376705, -121.975689 37.417345, -121.998696 37.409164, -122.031661 37.428252))' AS polygon1, 'POLYGON ((-121.491698 38.653343, -121.582353 38.556757, -121.469721 38.449287, -121.315883 38.541721, -121.491698 38.653343))' AS polygon2, 'POLYGON ((-122.089628 37.450332, -122.20535 37.378342, -122.093062 37.36088, -122.044301 37.372886, -122.089628 37.450332))' AS polygon3, ); ``` ## Spatial Measurement ### `st_distance` Returns WGS84(SRID: 4326) euclidean distance between two geometry object, in degree. Arguments: two spatial objects encoded with WKT. ```sql SELECT st_distance(p1, p2) AS euclidean_dist, st_distance(p1, polygon1) AS euclidean_dist_pp, FROM ( SELECT wkt_point_from_latlng(37.76938, -122.3889) AS p1, wkt_point_from_latlng(38.5216, -121.4247) AS p2, 'POLYGON ((-121.491698 38.653343, -121.582353 38.556757, -121.469721 38.449287, -121.315883 38.541721, -121.491698 38.653343))' AS polygon1, ); ``` ### `st_distance_sphere_m` Return great circle distance between two point, in meters. Arguments: two spatial objects encoded with WKT. ```sql SELECT st_distance_sphere_m(p1, p2) AS sphere_dist_m, FROM ( SELECT wkt_point_from_latlng(37.76938, -122.3889) AS p1, wkt_point_from_latlng(38.5216, -121.4247) AS p2, ); ``` ### `st_area` Returns area of given geometry object. Arguments: the spatial object encoded with WKT. ```sql SELECT st_area(p1) as area_point, st_area(polygon1) as area_polygon, FROM ( SELECT wkt_point_from_latlng(37.76938, -122.3889) AS p1, 'POLYGON ((-121.491698 38.653343, -121.582353 38.556757, -121.469721 38.449287, -121.315883 38.541721, -121.491698 38.653343))' AS polygon1, ); ``` --- ## GreptimeDB Functions ## String Functions DataFusion [String Function](./df-functions.md#string-functions). GreptimeDB provides: * `matches_term(expression, term)` for full text search. For details, read the [Fulltext Search](/user-guide/logs/fulltext-search.md). * `regexp_extract(str, regexp)` to extract the first substring in a string that matches a regular expression. Returns `NULL` if no match is found. **MySQL-Compatible String Functions:** GreptimeDB also provides the following MySQL-compatible string functions: * `locate(substr, str[, pos])` - Returns the position of the first occurrence of substring * `elt(N, str1, str2, ...)` - Returns the Nth string from the list * `field(str, str1, str2, ...)` - Returns the index of the first string that matches * `insert(str, pos, len, newstr)` - Inserts a substring at a specified position * `space(N)` - Returns a string of N space characters * `format(X, D)` - Formats a number with thousand separators and D decimal places ### regexp_extract Extracts the first substring in a string that matches a [regular expression](https://docs.rs/regex/latest/regex/#syntax). Returns `NULL` if no match is found. ```sql regexp_extract(str, regexp) ``` **Arguments:** - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **regexp**: Regular expression to match against. Can be a constant, column, or function. **Note on Escaping:** GreptimeDB's regex escape behavior differs between MySQL and PostgreSQL compatibility modes: - **MySQL mode**: Requires double backslashes for escape sequences (e.g., `\\d`, `\\s`) - **PostgreSQL mode**: Single backslashes work by default (e.g., `\d`, `\s`), or use `E''` prefix for consistency with MySQL (e.g., `E'\\d'`) **Examples:** ```sql SELECT regexp_extract('version 1.2.3', '\d+\.\d+\.\d+'); -- Returns: 1.2.3 SELECT regexp_extract('Phone: 123-456-7890', '\d{3}-\d{3}-\d{4}'); -- Returns: 123-456-7890 SELECT regexp_extract('no match here', '\d+\.\d+\.\d+'); -- Returns: NULL ``` ### locate Returns the position of the first occurrence of substring `substr` in string `str`. Optionally, you can specify a starting position `pos`. Returns 0 if the substring is not found. ```sql locate(substr, str[, pos]) ``` **Arguments:** - **substr**: The substring to search for. - **str**: The string to search in. - **pos** (optional): The position to start searching from (1-based). If omitted, searching starts from the beginning. **Examples:** ```sql SELECT locate('world', 'hello world'); -- Returns: 7 SELECT locate('o', 'hello world', 6); -- Returns: 8 (finds the second 'o') SELECT locate('xyz', 'hello world'); -- Returns: 0 (not found) ``` ### elt Returns the Nth string from a list of strings. Returns `NULL` if N is less than 1, greater than the number of strings, or `NULL`. ```sql elt(N, str1, str2, str3, ...) ``` **Arguments:** - **N**: The index of the string to return (1-based). - **str1, str2, str3, ...**: The list of strings. **Examples:** ```sql SELECT elt(2, 'apple', 'banana', 'cherry'); -- Returns: banana SELECT elt(0, 'apple', 'banana', 'cherry'); -- Returns: NULL ``` ### field Returns the index (1-based) of the first string that matches `str` in the list. Returns 0 if no match is found or if `str` is `NULL`. ```sql field(str, str1, str2, str3, ...) ``` **Arguments:** - **str**: The string to search for. - **str1, str2, str3, ...**: The list of strings to search in. **Examples:** ```sql SELECT field('banana', 'apple', 'banana', 'cherry'); -- Returns: 2 SELECT field('grape', 'apple', 'banana', 'cherry'); -- Returns: 0 (not found) ``` ### insert Inserts a substring into a string at a specified position, replacing a specified number of characters. ```sql insert(str, pos, len, newstr) ``` **Arguments:** - **str**: The original string. - **pos**: The position to start inserting (1-based). - **len**: The number of characters to replace. - **newstr**: The string to insert. **Examples:** ```sql SELECT insert('Quadratic', 3, 4, 'What'); -- Returns: QuWhattic SELECT insert('Quadratic', 3, 100, 'What'); -- Returns: QuWhat (replaces to end of string) ``` ### space Returns a string consisting of N space characters. ```sql space(N) ``` **Arguments:** - **N**: The number of spaces to return. Returns empty string if N is negative. **Examples:** ```sql SELECT space(5); -- Returns: ' ' (5 spaces) SELECT concat('hello', space(3), 'world'); -- Returns: 'hello world' ``` ### format Formats a number with thousand separators and a specified number of decimal places. ```sql format(X, D) ``` **Arguments:** - **X**: The number to format. - **D**: The number of decimal places (0-30). **Examples:** ```sql SELECT format(1234567.891, 2); -- Returns: 1,234,567.89 SELECT format(1234567.891, 0); -- Returns: 1,234,568 ``` ## Math Functions DataFusion [Math Function](./df-functions.md#math-functions). GreptimeDB provides: ### clamp * `clamp(value, lower, upper)` to restrict a given value between a lower and upper bound: ```sql SELECT CLAMP(10, 0, 1); +------------------------------------+ | clamp(Int64(10),Int64(0),Int64(1)) | +------------------------------------+ | 1 | +------------------------------------+ ``` ```sql SELECT CLAMP(0.5, 0, 1) +---------------------------------------+ | clamp(Float64(0.5),Int64(0),Int64(1)) | +---------------------------------------+ | 0.5 | +---------------------------------------+ ``` ### mod * `mod(x, y)` to get the remainder of a number divided by another number: ```sql SELECT mod(18, 4); +-------------------------+ | mod(Int64(18),Int64(4)) | +-------------------------+ | 2 | +-------------------------+ ``` ## Date and Time Functions DataFusion [Time and Date Function](./df-functions.md#time-and-date-functions). GreptimeDB provides: * [date_add](#date_add) * [date_sub](#date_sub) * [date_format](#date_format) * [to_unixtime](#to_unixtime) * [timezone](#timezone) ### date_add * `date_add(expression, interval)` to add an interval value to Timestamp, Date, or DateTime ```sql SELECT date_add('2023-12-06'::DATE, '3 month 5 day'); ``` ``` +----------------------------------------------------+ | date_add(Utf8("2023-12-06"),Utf8("3 month 5 day")) | +----------------------------------------------------+ | 2024-03-11 | +----------------------------------------------------+ ``` ### date_sub * `date_sub(expression, interval)` to subtract an interval value to Timestamp, Date, or DateTime ```sql SELECT date_sub('2023-12-06 07:39:46.222'::TIMESTAMP_MS, '5 day'::INTERVAL); ``` ``` +-----------------------------------------------------------------------------------------------------------------------------------------+ | date_sub(arrow_cast(Utf8("2023-12-06 07:39:46.222"),Utf8("Timestamp(Millisecond, None)")),IntervalMonthDayNano("92233720368547758080")) | +-----------------------------------------------------------------------------------------------------------------------------------------+ | 2023-12-01 07:39:46.222000 | +-----------------------------------------------------------------------------------------------------------------------------------------+ ``` ### date_format * `date_format(expression, fmt)` to format Timestamp, Date, or DateTime into string by the format: Supports `Date32`, `Date64`, and all `Timestamp` types. ```sql SELECT date_format('2023-12-06 07:39:46.222'::TIMESTAMP, '%Y-%m-%d %H:%M:%S:%3f'); ``` ``` +-----------------------------------------------------------------------------------------------------------------------------+ | date_format(arrow_cast(Utf8("2023-12-06 07:39:46.222"),Utf8("Timestamp(Millisecond, None)")),Utf8("%Y-%m-%d %H:%M:%S:%3f")) | +-----------------------------------------------------------------------------------------------------------------------------+ | 2023-12-06 07:39:46:222 | +-----------------------------------------------------------------------------------------------------------------------------+ ``` Supported specifiers refer to the [chrono::format::strftime](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) module. ### to_unixtime * `to_unixtime(expression)` to convert the expression into the Unix timestamp in seconds. The argument can be integers (Unix timestamp in milliseconds), Timestamp, Date, DateTime, or String. If the argument is the string type, the function will first try to convert it into a DateTime, Timestamp, or Date. ```sql select to_unixtime('2023-03-01T06:35:02Z'); ``` ``` +-------------------------------------------+ | to_unixtime(Utf8("2023-03-01T06:35:02Z")) | +-------------------------------------------+ | 1677652502 | +-------------------------------------------+ ``` ```sql select to_unixtime('2023-03-01'::date); ``` ``` +---------------------------------+ | to_unixtime(Utf8("2023-03-01")) | +---------------------------------+ | 1677628800 | +---------------------------------+ ``` ### timezone * `timezone()` to retrieve the current session timezone: ```sql select timezone(); ``` ``` +------------+ | timezone() | +------------+ | UTC | +------------+ ``` ## System Functions * `isnull(expression)` to check whether an expression is `NULL`: ```sql SELECT isnull(1); +------------------+ | isnull(Int64(1)) | +------------------+ | 0 | +------------------+ ``` ```sql SELECT isnull(NULL); +--------------+ | isnull(NULL) | +--------------+ | 1 | +--------------+ ``` * `build()` retrieves the GreptimeDB build info. * `version()` retrieves the GreptimeDB version. * `database()` retrieves the current session database: ```sql select database(); +------------+ | database() | +------------+ | public | +------------+ ``` ## Admin Functions GreptimeDB provides `ADMIN` statement to run the administration functions, please refer to [ADMIN](/reference/sql/admin.md) reference. --- ## IP Functions This document describes the IP address manipulation and comparison functions available. ### `ipv4_to_cidr(ip_string [, subnet_mask])` **Description:** Converts an IPv4 address string to CIDR notation. If a `subnet_mask` (UInt8, 0-32) is provided, it uses that mask. Otherwise, it automatically detects the subnet based on trailing zeros or the number of octets provided in the input string (e.g., '192.168' implies /16, '192' implies /8). The resulting IP address in the CIDR notation will have host bits zeroed out according to the mask. **Arguments:** * `ip_string`: String - The IPv4 address string (e.g., '192.168.1.1', '10.0.0.0', '172.16'). Partial addresses are completed with zeros. * `subnet_mask` (Optional): UInt8 - The desired subnet mask length (e.g., 24, 16, 8). **Return Type:** String - The IPv4 address in CIDR notation (e.g., '192.168.1.0/24'). Returns NULL for invalid inputs. **Examples:** ```sql -- Auto-detect subnet SELECT ipv4_to_cidr('192.168.1.0'); -- Output: '192.168.1.0/24' SELECT ipv4_to_cidr('172.16'); -- Output: '172.16.0.0/16' -- Explicit subnet mask SELECT ipv4_to_cidr('192.168.1.1', 24); -- Output: '192.168.1.0/24' SELECT ipv4_to_cidr('10.0.0.1', 16); -- Output: '10.0.0.0/16' ``` ### `ipv6_to_cidr(ip_string [, subnet_mask])` **Description:** Converts an IPv6 address string to CIDR notation. If a `subnet_mask` (UInt8, 0-128) is provided, it uses that mask. Otherwise, it attempts to automatically detect the subnet based on trailing zero segments or common prefixes (like `fe80::` for /16 or `2001:db8::` for /32). The resulting IP address in the CIDR notation will have host bits zeroed out according to the mask. **Arguments:** * `ip_string`: String - The IPv6 address string (e.g., '2001:db8::1', 'fe80::'). Partial addresses are completed if possible (e.g., '2001:db8' becomes '2001:db8::'). * `subnet_mask` (Optional): UInt8 - The desired subnet mask length (e.g., 48, 64, 128). **Return Type:** String - The IPv6 address in CIDR notation (e.g., '2001:db8::/32'). Returns NULL for invalid inputs. **Examples:** ```sql -- Auto-detect subnet SELECT ipv6_to_cidr('2001:db8::'); -- Output: '2001:db8::/32' SELECT ipv6_to_cidr('fe80::1'); -- Output: 'fe80::/16' SELECT ipv6_to_cidr('::1'); -- Output: '::1/128' -- Explicit subnet mask SELECT ipv6_to_cidr('2001:db8::', 48); -- Output: '2001:db8::/48' SELECT ipv6_to_cidr('fe80::1', 10); -- Output: 'fe80::/10' ``` ### `ipv4_num_to_string(ip_number)` **Description:** Converts a UInt32 number to an IPv4 address string in the standard A.B.C.D format. The number is interpreted as an IPv4 address in big-endian byte order. **Arguments:** * `ip_number`: UInt32 - The numeric representation of the IPv4 address. **Return Type:** String - The IPv4 address in dot-decimal notation (e.g., '192.168.0.1'). **Examples:** ```sql SELECT ipv4_num_to_string(3232235521::uint32); -- 0xC0A80001 -- Output: '192.168.0.1' SELECT ipv4_num_to_string(167772161::uint32); -- 0x0A000001 -- Output: '10.0.0.1' SELECT ipv4_num_to_string(0::uint32); -- Output: '0.0.0.0' ``` ### `ipv4_string_to_num(ip_string)` **Description:** Converts a string representation of an IPv4 address (A.B.C.D format) to its UInt32 numeric equivalent (big-endian). **Arguments:** * `ip_string`: String - The IPv4 address in dot-decimal notation. **Return Type:** UInt32 - The numeric representation of the IPv4 address. Returns NULL or throws an error for invalid input formats. **Examples:** ```sql SELECT ipv4_string_to_num('192.168.0.1'); -- Output: 3232235521 SELECT ipv4_string_to_num('10.0.0.1'); -- Output: 167772161 SELECT ipv4_string_to_num('0.0.0.0'); -- Output: 0 ``` ### `ipv6_num_to_string(hex_string)` **Description:** Converts a 32-character hexadecimal string representation of an IPv6 address to its standard formatted string representation (e.g., '2001:db8::1'). Handles IPv4-mapped IPv6 addresses correctly (e.g., '::ffff:192.168.0.1'). Case-insensitive for hex characters. **Arguments:** * `hex_string`: String - A 32-character hexadecimal string representing the 16 bytes of an IPv6 address. **Return Type:** String - The formatted IPv6 address string. Returns NULL or throws an error if the input is not a valid 32-character hex string. **Examples:** ```sql SELECT ipv6_num_to_string('20010db8000000000000000000000001'); -- Output: '2001:db8::1' SELECT ipv6_num_to_string('00000000000000000000ffffc0a80001'); -- Output: '::ffff:192.168.0.1' ``` ### `ipv6_string_to_num(ip_string)` **Description:** Converts a string representation of an IPv6 address (standard format) or an IPv4 address (dot-decimal format) to its 16-byte binary representation. If an IPv4 address string is provided, it is converted to its IPv6-mapped equivalent (e.g., '192.168.0.1' becomes '::ffff:192.168.0.1' internally before conversion to binary). **Arguments:** * `ip_string`: String - The IPv6 or IPv4 address string. **Return Type:** Binary - The 16-byte binary representation of the IPv6 address. Returns NULL or throws an error for invalid input formats. **Examples:** ```sql -- IPv6 input SELECT ipv6_string_to_num('2001:db8::1'); -- Output: Binary representation of 2001:db8::1 -- IPv4 input (gets mapped to IPv6) SELECT ipv6_string_to_num('192.168.0.1'); -- Output: Binary representation of ::ffff:192.168.0.1 -- IPv4-mapped IPv6 input SELECT ipv6_string_to_num('::ffff:192.168.0.1'); -- Output: Binary representation of ::ffff:192.168.0.1 ``` ### `ipv4_in_range(ip_string, cidr_string)` **Description:** Checks if a given IPv4 address string falls within a specified CIDR range string. **Arguments:** * `ip_string`: String - The IPv4 address to check (e.g., '192.168.1.5'). * `cidr_string`: String - The CIDR range to check against (e.g., '192.168.1.0/24'). **Return Type:** Boolean - `true` if the IP address is within the range, `false` otherwise. Returns NULL or throws an error for invalid inputs. **Examples:** ```sql SELECT ipv4_in_range('192.168.1.5', '192.168.1.0/24'); -- Output: true SELECT ipv4_in_range('192.168.2.1', '192.168.1.0/24'); -- Output: false SELECT ipv4_in_range('10.0.0.1', '10.0.0.0/8'); -- Output: true SELECT ipv4_in_range('8.8.8.8', '0.0.0.0/0'); -- /0 matches everything -- Output: true SELECT ipv4_in_range('192.168.1.1', '192.168.1.1/32'); -- /32 is an exact match -- Output: true ``` ### `ipv6_in_range(ip_string, cidr_string)` **Description:** Checks if a given IPv6 address string falls within a specified CIDR range string. **Arguments:** * `ip_string`: String - The IPv6 address to check (e.g., '2001:db8::1'). * `cidr_string`: String - The CIDR range to check against (e.g., '2001:db8::/32'). **Return Type:** Boolean - `true` if the IP address is within the range, `false` otherwise. Returns NULL or throws an error for invalid inputs. **Examples:** ```sql SELECT ipv6_in_range('2001:db8::1', '2001:db8::/32'); -- Output: true SELECT ipv6_in_range('2001:db8:1::', '2001:db8::/32'); -- Output: true SELECT ipv6_in_range('2001:db9::1', '2001:db8::/32'); -- Output: false SELECT ipv6_in_range('::1', '::1/128'); -- Output: true SELECT ipv6_in_range('fe80::1', 'fe80::/16'); -- Output: true ``` --- ## JSON Functions (Experimental) This page lists all json type related functions in GreptimeDB. :::warning The JSON feature is currently experimental and may change in future releases. ::: ## Conversion Conversion between JSON and other types. * `parse_json(string)` to parse a JSON string into a JSON value. Illegal JSON strings will return an error. * `json_to_string(json)` to convert a JSON value to a string. ```sql SELECT json_to_string(parse_json('{"a": 1, "b": 2}')); +----------------------------------------------------------+ | json_to_string(parse_json(Utf8("{\"a\": 1, \"b\": 2}"))) | +----------------------------------------------------------+ | {"a":1,"b":2} | +----------------------------------------------------------+ ``` ## Extraction Extracts values with specific types from JSON values through specific paths. * `json_get_bool(json, path)` to extract a boolean value from a JSON value by the path. * `json_get_int(json, path)` to extract an integer value from a JSON value by the path, while boolean values will be converted to integers. * `json_get_float(json, path)` to extract a float value from a JSON value by the path, while integer and boolean values will be converted to floats. * `json_get_string(json, path)` to extract a string value from a JSON value by the path. All valid JSON values will be converted to strings, including null values, objects and arrays. * `json_get_object(json, path)` to extract an object value from a JSON value by the path. Returns NULL if the path does not point to an object. `path` is a string that select and extract elements from a json value. The following operators in the path are supported: | Operator | Description | Examples | | ------------------------ | ------------------------------------------------------------ | ------------------ | | `$` | The root element | `$` | | `@` | The current element in the filter expression | `$.event?(@ == 1)` | | `.*` | Selecting all elements in an Object | `$.*` | | `.` | Selecting element that match the name in an Object | `$.event` | | `:` | Alias of `.` | `$:event` | | `[""]` | Alias of `.` | `$["event"]` | | `[*]` | Selecting all elements in an Array | `$[*]` | | `[, ..]` | Selecting 0-based `n-th` elements in an Array | `$[1, 2]` | | `[last - , ..]` | Selecting `n-th` element before the last element in an Array | `$[0, last - 1]` | | `[ to , ..]` | Selecting all elements of a range in an Array | `$[1 to last - 2]` | | `?()` | Selecting all elements that matched the filter expression | `$?(@.price < 10)` | If the path is invalid, the function will return a NULL value. ```sql SELECT json_get_int(parse_json('{"a": {"c": 3}, "b": 2}'), 'a.c'); +-----------------------------------------------------------------------+ | json_get_int(parse_json(Utf8("{"a": {"c": 3}, "b": 2}")),Utf8("a.c")) | +-----------------------------------------------------------------------+ | 3 | +-----------------------------------------------------------------------+ SELECT json_to_string(json_get_object(parse_json('{"a": {"b": {"c": {"d": 42}}}}'), 'a.b.c')); +---------------------------------------------------------------------------------------------------+ | json_to_string(json_get_object(parse_json(Utf8("{"a": {"b": {"c": {"d": 42}}}}")),Utf8("a.b.c"))) | +---------------------------------------------------------------------------------------------------+ | {"d":42} | +---------------------------------------------------------------------------------------------------+ ``` ## Validation Check the type of a JSON value. * `json_is_null(json)` to check whether a JSON value is a null value. * `json_is_bool(json)` to check whether a JSON value is a boolean value. * `json_is_int(json)` to check whether a JSON value is an integer value. * `json_is_float(json)` to check whether a JSON value is a float value. * `json_is_string(json)` to check whether a JSON value is a string value. * `json_is_object(json)` to check whether a JSON value is an object value. * `json_is_array(json)` to check whether a JSON value is an array value. ```sql SELECT json_is_array(parse_json('[1, 2, 3]')); +----------------------------------------------+ | json_is_array(parse_json(Utf8("[1, 2, 3]"))) | +----------------------------------------------+ | 1 | +----------------------------------------------+ SELECT json_is_object(parse_json('1')); +---------------------------------------+ | json_is_object(parse_json(Utf8("1"))) | +---------------------------------------+ | 0 | +---------------------------------------+ ``` * `json_path_exists(json, path)` to check whether a path exists in a JSON value. If the path is invalid, the function will return an error. If the path or the JSON value is `NULL`, the function will return a `NULL` value. ```sql SELECT json_path_exists(parse_json('{"a": 1, "b": 2}'), 'a'); +------------------------------------------------------------------+ | json_path_exists(parse_json(Utf8("{"a": 1, "b": 2}")),Utf8("a")) | +------------------------------------------------------------------+ | 1 | +------------------------------------------------------------------+ SELECT json_path_exists(parse_json('{"a": 1, "b": 2}'), 'c.d'); +--------------------------------------------------------------------+ | json_path_exists(parse_json(Utf8("{"a": 1, "b": 2}")),Utf8("c.d")) | +--------------------------------------------------------------------+ | 0 | +--------------------------------------------------------------------+ SELECT json_path_exists(parse_json('{"a": 1, "b": 2}'), NULL); +-------------------------------------------------------------+ | json_path_exists(parse_json(Utf8("{"a": 1, "b": 2}")),NULL) | +-------------------------------------------------------------+ | NULL | +-------------------------------------------------------------+ ``` * `json_path_match(json, path)` to check whether a JSON value matches the predicate in the specified JSON path expression. Only predicate expressions are supported. If the path is invalid or does not evaluate to a predicate, the function will return a `NULL` value. If the JSON value is `NULL`, the function will return a `NULL` value. ```sql SELECT json_path_match(parse_json('{"a": 1, "b": 2}'), '$.a == 1'); +------------------------------------------------------------------------+ | json_path_match(parse_json(Utf8("{"a": 1, "b": 2}")),Utf8("$.a == 1")) | +------------------------------------------------------------------------+ | 1 | +------------------------------------------------------------------------+ SELECT json_path_match(parse_json('{"a":1,"b":[1,2,3]}'), '$.b[1 to last] >= 2'); +--------------------------------------------------------------------------------------+ | json_path_match(parse_json(Utf8("{"a":1,"b":[1,2,3]}")),Utf8("$.b[1 to last] >= 2")) | +--------------------------------------------------------------------------------------+ | 1 | +--------------------------------------------------------------------------------------+ SELECT json_path_match(parse_json('{"a":1,"b":[1,2,3]}'), '$.b[0] > 1'); +-----------------------------------------------------------------------------+ | json_path_match(parse_json(Utf8("{"a":1,"b":[1,2,3]}")),Utf8("$.b[0] > 1")) | +-----------------------------------------------------------------------------+ | 0 | +-----------------------------------------------------------------------------+ ``` --- ## Functions Use this page as a quick index to GreptimeDB function references. ## Function References - [DataFusion Functions](./df-functions.md) - GreptimeDB Functions - [Core Functions (string, math, date/time, system, admin)](./greptimedb.md) - [Geospatial Functions](./geo.md) - [IP Functions](./ip.md) - [JSON Functions](./json.md) - [Vector Functions](./vector.md) - [Approximate Functions](./approximate.md) - [Anomaly Detection Functions](./anomaly.md) --- ## Vector Functions This page lists all supported vector-related functions in GreptimeDB. Vector functions are primarily used for handling vector operations, such as basic arithmetic, distance calculations, conversion functions, and more. ## Basic Operations ### `vec_scalar_add` Adds a scalar to a vector. Each element in the vector is added to the scalar, returning a new vector. Examples: ```sql SELECT vec_to_string(vec_scalar_add(2.0, parse_vec('[1.0, 2.0, 3.0]'))); ``` ```sql +------------------------------------------------------------------------------+ | vec_to_string(vec_scalar_add(Float64(2),parse_vec(Utf8("[1.0, 2.0, 3.0]")))) | +------------------------------------------------------------------------------+ | [3,4,5] | +------------------------------------------------------------------------------+ ``` ``` SELECT vec_to_string(vec_scalar_add(2.0, '[1.0, 2.0, 3.0]')); -- Implicitly convert string to vector ``` ```sql +-------------------------------------------------------------------+ | vec_to_string(vec_scalar_add(Float64(2),Utf8("[1.0, 2.0, 3.0]"))) | +-------------------------------------------------------------------+ | [3,4,5] | +-------------------------------------------------------------------+ ``` ``` SELECT vec_to_string(vec_scalar_add(-2.0, parse_vec('[1.0, 2.0, 3.0]'))); -- Subtraction ``` ```sql +-------------------------------------------------------------------------------+ | vec_to_string(vec_scalar_add(Float64(-2),parse_vec(Utf8("[1.0, 2.0, 3.0]")))) | +-------------------------------------------------------------------------------+ | [-1,0,1] | +-------------------------------------------------------------------------------+ ``` ### `vec_scalar_mul` Multiplies a vector by a scalar. Each element in the vector is multiplied by the scalar, returning a new vector. Examples: ```sql SELECT vec_to_string(vec_scalar_mul(2.0, parse_vec('[1.0, 2.0, 3.0]'))); ``` ```sql +------------------------------------------------------------------------------+ | vec_to_string(vec_scalar_mul(Float64(2),parse_vec(Utf8("[1.0, 2.0, 3.0]")))) | +------------------------------------------------------------------------------+ | [2,4,6] | +------------------------------------------------------------------------------+ ``` ```sql SELECT vec_to_string(vec_scalar_mul(2.0, '[1.0, 2.0, 3.0]')); -- Implicitly convert string to vector ``` ```sql +------------------------------------------------------------------------------+ | vec_to_string(vec_scalar_mul(Float64(2),parse_vec(Utf8("[1.0, 2.0, 3.0]")))) | +------------------------------------------------------------------------------+ | [2,4,6] | +------------------------------------------------------------------------------+ ``` ```sql SELECT vec_to_string(vec_scalar_mul(1.0/2.0, parse_vec('[1.0, 2.0, 3.0]'))); -- Division ``` ```sql +-------------------------------------------------------------------------------------------+ | vec_to_string(vec_scalar_mul(Float64(1) / Float64(2),parse_vec(Utf8("[1.0, 2.0, 3.0]")))) | +-------------------------------------------------------------------------------------------+ | [0.5,1,1.5] | +-------------------------------------------------------------------------------------------+ ``` ### `vec_add` Adds two vectors element-wise. Returns a new vector where each element is the sum of corresponding elements in the input vectors. Examples: ```sql SELECT vec_to_string(vec_add(parse_vec('[1.0, 2.0, 3.0]'), parse_vec('[2.0, 1.0, 4.0]'))); ``` ```sql +-----------------------------------------------------------------------------------------------+ | vec_to_string(vec_add(parse_vec(Utf8("[1.0, 2.0, 3.0]")),parse_vec(Utf8("[2.0, 1.0, 4.0]")))) | +-----------------------------------------------------------------------------------------------+ | [3,3,7] | +-----------------------------------------------------------------------------------------------+ ``` ```sql SELECT vec_to_string(vec_add('[1.0, 2.0, 3.0]', '[2.0, 1.0, 4.0]')); -- Implicitly convert strings to vectors ``` ```sql +-------------------------------------------------------------------------+ | vec_to_string(vec_add(Utf8("[1.0, 2.0, 3.0]"),Utf8("[2.0, 1.0, 4.0]"))) | +-------------------------------------------------------------------------+ | [3,3,7] | +-------------------------------------------------------------------------+ ``` ### `vec_sub` Subtracts two vectors element-wise. Returns a new vector where each element is the difference of corresponding elements in the input vectors. Examples: ```sql SELECT vec_to_string(vec_sub(parse_vec('[1.0, 2.0, 3.0]'), parse_vec('[2.0, 1.0, 4.0]'))); ``` ```sql +-----------------------------------------------------------------------------------------------+ | vec_to_string(vec_sub(parse_vec(Utf8("[1.0, 2.0, 3.0]")),parse_vec(Utf8("[2.0, 1.0, 4.0]")))) | +-----------------------------------------------------------------------------------------------+ | [-1,1,-1] | +-----------------------------------------------------------------------------------------------+ ``` ```sql SELECT vec_to_string(vec_sub('[1.0, 2.0, 3.0]', '[2.0, 1.0, 4.0]')); -- Implicitly convert strings to vectors ``` ```sql +-------------------------------------------------------------------------+ | vec_to_string(vec_sub(Utf8("[1.0, 2.0, 3.0]"),Utf8("[2.0, 1.0, 4.0]"))) | +-------------------------------------------------------------------------+ | [-1,1,-1] | +-------------------------------------------------------------------------+ ``` ### `vec_mul` Multiplies two vectors element-wise. Returns a new vector where each element is the product of corresponding elements in the input vectors. Examples: ```sql SELECT vec_to_string(vec_mul(parse_vec('[1.0, 2.0, 3.0]'), parse_vec('[2.0, 1.0, 4.0]'))); ``` ```sql +-----------------------------------------------------------------------------------------------+ | vec_to_string(vec_mul(parse_vec(Utf8("[1.0, 2.0, 3.0]")),parse_vec(Utf8("[2.0, 1.0, 4.0]")))) | +-----------------------------------------------------------------------------------------------+ | [2,2,12] | +-----------------------------------------------------------------------------------------------+ ``` ```sql SELECT vec_to_string(vec_mul('[1.0, 2.0, 3.0]', '[2.0, 1.0, 4.0]')); -- Implicitly convert strings to vectors ``` ```sql +-------------------------------------------------------------------------+ | vec_to_string(vec_mul(Utf8("[1.0, 2.0, 3.0]"),Utf8("[2.0, 1.0, 4.0]"))) | +-------------------------------------------------------------------------+ | [2,2,12] | +-------------------------------------------------------------------------+ ``` ### `vec_div` Divides two vectors element-wise. Returns a new vector where each element is the quotient of corresponding elements in the input vectors. Examples: ```sql SELECT vec_to_string(vec_div(parse_vec('[1.0, 2.0, 3.0]'), parse_vec('[2.0, 1.0, 4.0]'))); ``` ```sql +-----------------------------------------------------------------------------------------------+ | vec_to_string(vec_div(parse_vec(Utf8("[1.0, 2.0, 3.0]")),parse_vec(Utf8("[2.0, 1.0, 4.0]")))) | +-----------------------------------------------------------------------------------------------+ | [0.5,2,0.75] | +-----------------------------------------------------------------------------------------------+ ``` ```sql SELECT vec_to_string(vec_div('[1.0, 2.0, 3.0]', '[2.0, 1.0, 4.0]')); -- Implicitly convert strings to vectors ``` ```sql +-------------------------------------------------------------------------+ | vec_to_string(vec_div(Utf8("[1.0, 2.0, 3.0]"),Utf8("[2.0, 1.0, 4.0]"))) | +-------------------------------------------------------------------------+ | [0.5,2,0.75] | +-------------------------------------------------------------------------+ ``` ### `vec_elem_sum` Sums all elements of a vector, returning a scalar value. Examples: ```sql SELECT vec_elem_sum(parse_vec('[1.0, 2.0, 3.0]')); ``` ```sql +--------------------------------------------------+ | vec_elem_sum(parse_vec(Utf8("[1.0, 2.0, 3.0]"))) | +--------------------------------------------------+ | 6 | +--------------------------------------------------+ ``` ```sql SELECT vec_elem_sum('[1.0, 2.0, 3.0]'); -- Implicitly convert string to vector ``` ```sql +---------------------------------------+ | vec_elem_sum(Utf8("[1.0, 2.0, 3.0]")) | +---------------------------------------+ | 6 | +---------------------------------------+ ``` ### `vec_elem_product` Computes the product of all elements in a vector, returning a scalar value. Examples: ```sql SELECT vec_elem_product(parse_vec('[1.0, 2.0, 3.0]')); ``` ```sql +------------------------------------------------------+ | vec_elem_product(parse_vec(Utf8("[1.0, 2.0, 3.0]"))) | +------------------------------------------------------+ | 6 | +------------------------------------------------------+ ``` ```sql SELECT vec_elem_product('[1.0, 2.0, 3.0]'); -- Implicitly convert string to vector ``` ```sql +-------------------------------------------+ | vec_elem_product(Utf8("[1.0, 2.0, 3.0]")) | +-------------------------------------------+ | 6 | +-------------------------------------------+ ``` ### `vec_norm` Normalizes a vector. Divides each element of the vector by the L2 norm of the vector, returning a new unit vector. Equivalent to `vec_scalar_mul(1.0 / sqrt(vec_elem_sum(vec_mul(vec, vec))), vec)`. Examples: ```sql SELECT vec_to_string(vec_norm(parse_vec('[1.0, 2.0, 3.0]'))); ``` ```sql +-------------------------------------------------------------+ | vec_to_string(vec_norm(parse_vec(Utf8("[1.0, 2.0, 3.0]")))) | +-------------------------------------------------------------+ | [0.26726124,0.5345225,0.8017837] | +-------------------------------------------------------------+ -- Equivalent to: -- SELECT vec_to_string(vec_scalar_mul(1.0 / sqrt(vec_elem_sum(vec_mul(vec, vec))), vec)) -- FROM (SELECT '[1.0, 2.0, 3.0]' AS vec); -- +--------------------------------------------------------------------------------------+ -- | vec_to_string(vec_scalar_mul(Float64(1) / sqrt(vec_elem_sum(vec_mul(vec,vec))),vec)) | -- +--------------------------------------------------------------------------------------+ -- | [0.26726124,0.5345225,0.8017837] | -- +--------------------------------------------------------------------------------------+ ``` ```sql SELECT vec_to_string(vec_norm('[1.0, 2.0, 3.0]')); -- Implicitly convert string to vector ``` ```sql +--------------------------------------------------+ | vec_to_string(vec_norm(Utf8("[1.0, 2.0, 3.0]"))) | +--------------------------------------------------+ | [0.26726124,0.5345225,0.8017837] | +--------------------------------------------------+ ``` ## Aggregate Functions ### `vec_sum` Sums all vectors in a vector column element-wise, returning a new vector. Examples: ```sql CREATE TABLE vectors ( ts TIMESTAMP TIME INDEX, vec_col VECTOR(3), ); INSERT INTO vectors (ts, vec_col) VALUES ('2024-11-18 00:00:01', '[1.0, 2.0, 3.0]'); INSERT INTO vectors (ts, vec_col) VALUES ('2024-11-18 00:00:02', '[2.0, 1.0, 4.0]'); INSERT INTO vectors (ts, vec_col) VALUES ('2024-11-18 00:00:03', '[3.0, 3.0, 3.0]'); SELECT vec_to_string(vec_sum(vec_col)) FROM vectors; ``` ```sql +-----------------------------------------+ | vec_to_string(vec_sum(vectors.vec_col)) | +-----------------------------------------+ | [6,6,10] | +-----------------------------------------+ ``` ### `vec_product` Multiplies all vectors in a vector column element-wise, returning a new vector. Examples: ```sql CREATE TABLE vectors ( ts TIMESTAMP TIME INDEX, vec_col VECTOR(3), ); INSERT INTO vectors (ts, vec_col) VALUES ('2024-11-18 00:00:01', '[1.0, 2.0, 3.0]'); INSERT INTO vectors (ts, vec_col) VALUES ('2024-11-18 00:00:02', '[2.0, 1.0, 4.0]'); INSERT INTO vectors (ts, vec_col) VALUES ('2024-11-18 00:00:03', '[3.0, 3.0, 3.0]'); SELECT vec_to_string(vec_product(vec_col)) FROM vectors; ``` ```sql +---------------------------------------------+ | vec_to_string(vec_product(vectors.vec_col)) | +---------------------------------------------+ | [6,6,36] | +---------------------------------------------+ ``` ## Distance Calculations * `vec_l2sq_distance(vec1, vec2)`: Computes the squared L2 distance between two vectors. * `vec_cos_distance(vec1, vec2)`: Computes the cosine distance between two vectors. * `vec_dot_product(vec1, vec2)`: Computes the dot product of two vectors. These functions accept vector values as parameters. You can use the `parse_vec` function to convert a string into a vector value, such as `parse_vec('[1.0, 2.0, 3.0]')`. Also, vector strings (e.g., `[1.0, 2.0, 3.0]`) can be used directly and will be automatically converted. Regardless of the method used, the dimensionality of the vectors must remain consistent. --- ### `vec_l2sq_distance` Calculates the squared Euclidean distance (squared L2 distance) between two vectors. L2 distance is the straight-line distance between two points in geometric space. This function returns the squared value to improve computational efficiency. Example: ```sql SELECT vec_l2sq_distance(parse_vec('[1.0, 2.0, 3.0]'), parse_vec('[2.0, 1.0, 4.0]')); ``` Or ```sql SELECT vec_l2sq_distance('[1.0, 2.0, 3.0]', '[2.0, 1.0, 4.0]'); ``` Details: * Parameters are two vectors with consistent dimensions. * Output: A scalar value of type `Float32`. --- ### `vec_cos_distance` Calculates the cosine distance between two vectors. Cosine distance measures the cosine of the angle between two vectors and is used to quantify similarity. Example: ```sql SELECT vec_cos_distance(parse_vec('[1.0, 2.0, 3.0]'), parse_vec('[2.0, 1.0, 4.0]')); ``` Or ```sql SELECT vec_cos_distance('[1.0, 2.0, 3.0]', '[2.0, 1.0, 4.0]'); ``` Details: * Parameters are two vectors with consistent dimensions. * Output: A scalar value of type `Float32`. --- ### `vec_dot_product` Computes the dot product of two vectors. The dot product is the sum of the element-wise multiplications of two vectors. It is commonly used to measure similarity or for linear transformations in machine learning. Example: ```sql SELECT vec_dot_product(parse_vec('[1.0, 2.0, 3.0]'), parse_vec('[2.0, 1.0, 4.0]')); ``` Or ```sql SELECT vec_dot_product('[1.0, 2.0, 3.0]', '[2.0, 1.0, 4.0]'); ``` Details: * Parameters are two vectors with consistent dimensions. * Output: A scalar value of type `Float32`. ## Conversion Functions When dealing with vector data in the database, GreptimeDB provides convenient functions for converting between strings and vector values. ### `parse_vec` Converts a string to a vector value. The string must be enclosed in square brackets `[]` and contain elements of type `Float32`, separated by commas. Example: ```sql CREATE TABLE vectors ( ts TIMESTAMP, vec_col VECTOR(3) ); INSERT INTO vectors (ts, vec_col) VALUES ('2024-11-18 00:00:01', parse_vec('[1.0, 2.0, 3.0]')); ``` ### `vec_to_string` Converts a vector object to a string. The converted string format is `[, , ...]`. Example: ```sql SELECT vec_to_string(vec_col) FROM vectors; ``` --- ## Greptime Private GreptimeDB stores some important internal information as system tables in the `greptime_private` database. Similar to the normal tables, the system tables will be persistently stored. You can obtain system configurations and statistical information through the system tables. ## Tables | Table Name | Description | | ----------------------------------- | --------------------------------------------------------------------------------------------- | | [`slow_queries`](./slow_queries.md) | Contains GreptimeDB slow query information, including query statements, execution times, etc. | | [`pipelines`](./pipelines.md) | Contains GreptimeDB Pipeline information. | --- ## pipelines The `pipelines` table contains GreptimeDB Pipeline information. ```sql USE greptime_private; SELECT * FROM pipelines; ``` The output is as follows: ```sql +----------------+--------+--------------+----------------------------------------------------------------------------------------------------------------------------------+----------------------------+ | name | schema | content_type | pipeline | created_at | +----------------+--------+--------------+----------------------------------------------------------------------------------------------------------------------------------+----------------------------+ | nginx_pipeline | | yaml | transform: | 2025-07-03 07:23:15.227539 | - fields: - response_size type: int32 - fields: - timestamp type: time index: timestamp +----------------+--------+--------------+----------------------------------------------------------------------------------------------------------------------------------+----------------------------+ ``` - `name`: The name of the pipeline; - `schema`: Deprecated. If you create the pipeline after `v0.15`, this field should be an empty string. - `content_type`: The type of the pipeline; - `pipeline`: The content of the pipeline; - `created_at`: The creation time of the pipeline; For more details, please refer to the [Manage Pipelines](/user-guide/logs/manage-pipelines.md) documentation. --- ## slow_queries The `slow_queries` table contains the slow queries of GreptimeDB: :::tip NOTE The `slow_queries` table requires slow query logging to be enabled. See [Slow Query](/user-guide/deployments-administration/monitoring/slow-query.md) for configuration details. ::: ```sql USE greptime_private; SELECT * FROM slow_queries; ``` The output is as follows: ```sql +------+-----------+---------------------------------------------+-----------+----------------------------+--------------+-------------+---------------------+---------------------+ | cost | threshold | query | is_promql | timestamp | promql_range | promql_step | promql_start | promql_end | +------+-----------+---------------------------------------------+-----------+----------------------------+--------------+-------------+---------------------+---------------------+ | 2 | 0 | irate(process_cpu_seconds_total[1h]) | 1 | 2025-05-14 13:59:36.368575 | 86400000 | 3600000 | 2024-11-24 00:00:00 | 2024-11-25 00:00:00 | | 22 | 0 | SELECT * FROM greptime_private.slow_queries | 0 | 2025-05-14 13:59:44.844201 | 0 | 0 | 1970-01-01 00:00:00 | 1970-01-01 00:00:00 | +------+-----------+---------------------------------------------+-----------+----------------------------+--------------+-------------+---------------------+---------------------+ ``` - `cost`: The cost of the query in milliseconds. - `threshold`: The threshold of the query in milliseconds. - `query`: The query string. It can be SQL or PromQL. - `is_promql`: Whether the query is a PromQL query. - `timestamp`: The timestamp of the query. - `promql_range`: The range of the query. Only used when is_promql is true. - `promql_step`: The step of the query. Only used when is_promql is true. - `promql_start`: The start time of the query. Only used when is_promql is true. - `promql_end`: The end time of the query. Only used when is_promql is true. You can refer to the [Slow Query](/user-guide/deployments-administration/monitoring/slow-query.md) documentation for more details. --- ## GROUP BY The `GROUP BY` clause in SQL is used to group rows that have the same values in one or more columns. This clause is typically used with aggregate functions such as `COUNT`, `SUM`, `AVG`, etc., to generate summary reports. ## Syntax The basic syntax of the `GROUP BY` clause is as follows: ```sql SELECT column1, column2, ..., aggregate_function(column_name) FROM table_name GROUP BY column1, column2, ...; ``` The `GROUP BY` clause groups the result set based on the columns specified in the clause. The aggregate function is applied to each group of rows that have the same values in the specified columns. ## Examples Consider the following table named "system_metrics": ```sql +-------+-------+----------+-------------+-----------+---------------------+ | host | idc | cpu_util | memory_util | disk_util | ts | +-------+-------+----------+-------------+-----------+---------------------+ | host1 | idc_a | 11.8 | 10.3 | 10.3 | 2022-11-03 03:39:57 | | host1 | idc_b | 50 | 66.7 | 40.6 | 2022-11-03 03:39:57 | | host1 | idc_c | 50.1 | 66.8 | 40.8 | 2022-11-03 03:39:57 | | host1 | idc_e | NULL | 66.7 | 40.6 | 2022-11-03 03:39:57 | | host2 | idc_a | 80.1 | 70.3 | 90 | 2022-11-03 03:39:57 | +-------+-------+----------+-------------+-----------+---------------------+ ``` ### Group by Tags To get the avg memory_util for each idc, the following SQL query can be used: ```sql SELECT idc, AVG(memory_util) FROM system_metrics GROUP BY idc; ``` The result of the above query would be: ```sql +-------+---------------------------------+ | idc | AVG(system_metrics.memory_util) | +-------+---------------------------------+ | idc_b | 66.7 | | idc_c | 66.8 | | idc_e | 66.7 | | idc_a | 40.3 | +-------+---------------------------------+ ``` ### Group by Time Interval To get the avg memory_util for each day, the following SQL query can be used: ```sql SELECT date_trunc('day', ts) as dt, avg(memory_util) FROM system_metrics GROUP BY dt ``` Please refer to [date_trunc](./functions/overview.md#date_trunc) for more details. --- ## HAVING The `HAVING` clause allows you to filter grouped (aggregated) results—it works like `WHERE`, but after grouping has taken place. The `HAVING` clause was added to SQL because the `WHERE` clause cannot be used with aggregate functions. ## Examples Find days where the average CPU utilization exceeded 80%: ```sql SELECT date_trunc('day', ts) AS day, AVG(cpu_util) AS avg_cpu_util FROM system_metrics GROUP BY day HAVING avg_cpu_util > 80; ``` Find hours where the number of error logs is greater than 100: ```sql SELECT DATE_TRUNC('hour', log_time) AS hour, COUNT(*) AS error_count FROM application_logs WHERE log_level = 'ERROR' GROUP BY hour HAVING error_count > 100; ``` --- ## Alerts :::tip NOTE This feature is only available in the GreptimeDB Enterprise database. ::: The `ALERTS` table provides the information about all alert instances generated by triggers. ```sql DESC TABLE INFORMATION_SCHEMA.ALERTS; ``` ```sql +--------------+---------------------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +--------------+---------------------+------+------+---------+---------------+ | trigger_id | UInt64 | | NO | | FIELD | | trigger_name | String | | NO | | FIELD | | labels | Json | | NO | | FIELD | | annotations | Json | | YES | | FIELD | | status | String | | NO | | FIELD | | active_at | TimestampNanosecond | | NO | | FIELD | | fired_at | TimestampNanosecond | | YES | | FIELD | | resolved_at | TimestampNanosecond | | YES | | FIELD | | last_sent_at | TimestampNanosecond | | YES | | FIELD | +--------------+---------------------+------+------+---------+---------------+ ``` The columns in table: * `trigger_id`: the id of the trigger that generated the alert instance. * `trigger_name`: the name of the trigger that generated the alert instance. * `labels`: the key-value pairs associated with the alert instance. And the label set uniquely identifies an alert instance. * `annotations`: the key-value pairs associated with the alert instance. * `status`: the current status of the alert instance. * `active_at`: the timestamp when the alert instance became active. * `fired_at`: the timestamp when the alert instance first entered the `Firing` state. * `resolved_at`: the timestamp when the alert instance was resolved. * `last_sent_at`: the timestamp when the last notification for the alert instance was sent. --- ## BUILD_INFO The `BUILD_INFO` table provides the system build info: ```sql USE INFORMATION_SCHEMA; SELECT * FROM BUILD_INFO; ``` The output is as follows: ```sql +------------+------------------------------------------+------------------+-----------+-------------+ | git_branch | git_commit | git_commit_short | git_clean | pkg_version | +------------+------------------------------------------+------------------+-----------+-------------+ | | c595a56ac89bef78b19a76aa60d8c6bcac7354a5 | c595a56a | true | 0.9.0 | +------------+------------------------------------------+------------------+-----------+-------------+ ``` The columns in the output: * `branch`: the build git branch name. * `git_commit`: the build commit revision. * `git_commit_short`: the short commit revision. * `git_clean`: `true` if the build source directory contains all the committed changes. * `pkg_version`: the GreptimeDB version. --- ## CHARACTER_SETS The `CHARACTER_SETS` provides the available character sets that GreptimeDB supports. ```sql USE INFORMATION_SCHEMA; SELECT * FROM CHARACTER_SETS; ``` The output is as follows: ```sql +--------------------+----------------------+---------------+--------+ | character_set_name | default_collate_name | description | maxlen | +--------------------+----------------------+---------------+--------+ | utf8 | utf8_bin | UTF-8 Unicode | 4 | +--------------------+----------------------+---------------+--------+ ``` The columns in the output: * `character_set_name`: the name of the character set. * `default_collate_name`: the default collation name of the character set. * `description`: the description of the character set. * `MAXLEN`: the maximum number of bytes required to store one character. --- ## CLUSTER_INFO The `CLUSTER_INFO` table provides the topology information of the cluster. ```sql USE INFORMATION_SCHEMA; DESC TABLE CLUSTER_INFO; ``` The output is as follows: ```sql +-----------------------+----------------------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +-----------------------+----------------------+------+------+---------+---------------+ | peer_id | Int64 | | NO | | FIELD | | peer_type | String | | NO | | FIELD | | peer_addr | String | | YES | | FIELD | | peer_hostname | String | | YES | | FIELD | | total_cpu_millicores | Int64 | | NO | | FIELD | | total_memory_bytes | Int64 | | NO | | FIELD | | cpu_usage_millicores | Int64 | | NO | | FIELD | | memory_usage_bytes | Int64 | | NO | | FIELD | | version | String | | NO | | FIELD | | git_commit | String | | NO | | FIELD | | start_time | TimestampMillisecond | | YES | | FIELD | | uptime | String | | YES | | FIELD | | active_time | String | | YES | | FIELD | | node_status | String | | YES | | FIELD | +-----------------------+----------------------+------+------+---------+---------------+ ``` The columns in table: * `peer_id`: the server id of the node. It's always `0` for standalone mode and `-1` for frontends because it doesn't make sense in such cases. * `peer_type`: the node type, `METASRV`,`FRONTEND`, or `DATANODE` for distributed clusters and `STANDALONE` for standalone deployments. * `peer_addr`: the GRPC server address of the node. It's always empty for standalone deployments. * `peer_hostname`: the hostname of the peer. * `total_cpu_millicores`: the total CPU millicores of the node. * `total_memory_bytes`: the total memory bytes of the node. * `cpu_usage_millicores`: the CPU usage millicores of the node. This only works in a containerized environment (cgroup v2). * `memory_usage_bytes`: the memory usage bytes of the node. This only works in a containerized environment (cgroup v2). * `version`: The build version of the node, such as `0.7.2` etc. * `git_commit`: The build git commit of the node. * `start_time`: The node start time. * `uptime`: The uptime of the node, in the format of duration string `24h 10m 59s 150ms`. * `active_time`: The duration string in the format of `24h 10m 59s 150ms` since the node's last active time(sending the heartbeats), it's always empty for standalone deployments. * `node_status`: the status info of the peer. Query the table: ```sql SELECT * FROM CLUSTER_INFO; ``` An example output in standalone deployments: ```sql +---------+------------+-----------+---------------+----------------------+--------------------+----------------------+--------------------+---------+-----------+----------------------------+--------+-------------+-------------+ | peer_id | peer_type | peer_addr | peer_hostname | total_cpu_millicores | total_memory_bytes | cpu_usage_millicores | memory_usage_bytes | version | git_commit| start_time | uptime | active_time | node_status | +---------+------------+-----------+---------------+----------------------+--------------------+----------------------+--------------------+---------+-----------+----------------------------+--------+-------------+-------------+ | 0 | STANDALONE | | | 16000 | 17179869184 | 0 | 0 | 0.7.2 | 86ab3d9 | 2024-04-30T06:40:02.074 | 18ms | | NULL | +---------+------------+-----------+---------------+----------------------+--------------------+----------------------+--------------------+---------+-----------+----------------------------+--------+-------------+-------------+ ``` Another example is from a distributed cluster that has three Datanodes, one Frontend, and one Metasrv. ```sql +---------+-----------+----------------+-------------------------------------+----------------------+--------------------+----------------------+--------------------+---------+-----------+----------------------------+----------+-------------+-------------------------------------------------------------------+ | peer_id | peer_type | peer_addr | peer_hostname | total_cpu_millicores | total_memory_bytes | cpu_usage_millicores | memory_usage_bytes | version | git_commit| start_time | uptime | active_time | node_status | +---------+-----------+----------------+-------------------------------------+----------------------+--------------------+----------------------+--------------------+---------+-----------+----------------------------+----------+-------------+-------------------------------------------------------------------+ | 1 | DATANODE | 127.0.0.1:4101 | mycluster-datanode-0 | 1000 | 1073741824 | 1 | 34570240 | 0.7.2 | 86ab3d9 | 2024-04-30T06:40:04.791 | 4s 478ms | 1s 467ms | {"workloads":["hybrid"],"leader_regions":46,"follower_regions":0} | | 2 | DATANODE | 127.0.0.1:4102 | mycluster-datanode-1 | 1000 | 1073741824 | 1 | 38170624 | 0.7.2 | 86ab3d9 | 2024-04-30T06:40:06.098 | 3s 171ms | 162ms | {"workloads":["hybrid"],"leader_regions":46,"follower_regions":0} | | 3 | DATANODE | 127.0.0.1:4103 | mycluster-datanode-2 | 1000 | 1073741824 | 1 | 37085184 | 0.7.2 | 86ab3d9 | 2024-04-30T06:40:07.425 | 1s 844ms | 1s 839ms | {"workloads":["hybrid"],"leader_regions":46,"follower_regions":0} | | -1 | FRONTEND | 127.0.0.1:4001 | mycluster-frontend-6c5d4bcf78-m7jtx | 1000 | 1073741824 | 1 | 45465600 | 0.7.2 | 86ab3d9 | 2024-04-30T06:40:08.815 | 454ms | 47ms | NULL | | 0 | METASRV | 127.0.0.1:3002 | mycluster-meta-54bd44bd94-g8dzm | 1000 | 1073741824 | 0 | 28368896 | unknown | unknown | | | | {"is_leader":true} | +---------+-----------+----------------+-------------------------------------+----------------------+--------------------+----------------------+--------------------+---------+-----------+----------------------------+----------+-------------+-------------------------------------------------------------------+ ``` --- ## COLLATION_CHARACTER_SET_APPLICABILITY The `COLLATION_CHARACTER_SET_APPLICABILITY` table indicates what character set is applicable for what collation. ```sql USE INFORMATION_SCHEMA; SELECT * FROM COLLATION_CHARACTER_SET_APPLICABILITY; ``` The output is as follows: ```sql +----------------+--------------------+ | collation_name | character_set_name | +----------------+--------------------+ | utf8_bin | utf8 | +----------------+--------------------+ ``` The output has these columns: * `collation_name`: the collation name. * `character_set_name`: the name of the character set with which the collation is associated. --- ## COLLATIONS The `COLLATIONS` provides information about collations for each character set. ```sql USE INFORMATION_SCHEMA; SELECT * FROM COLLATIONS; ``` The output is as follows: ```sql +----------------+--------------------+------+------------+-------------+---------+ | collation_name | character_set_name | id | is_default | is_compiled | sortlen | +----------------+--------------------+------+------------+-------------+---------+ | utf8_bin | utf8 | 1 | Yes | Yes | 1 | +----------------+--------------------+------+------------+-------------+---------+ ``` The table has these columns: * `collation_name`: the collation name. * `character_set_name`: the name of the character set. * `id`: the collation ID. * `is_default`: Whether this collation is the default collation of the character set it belongs to. * `is_compiled`: Whether the character set is compiled into the system. * `sortlen`: the minimum amount of memory required to sort strings expressed in the character set. --- ## COLUMNS The `COLUMNS` provides detailed information about columns in tables. ```sql USE INFORMATION_SCHEMA; DESC COLUMNS; ``` The output is as follows: ```sql +--------------------------+--------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +--------------------------+--------+------+------+---------+---------------+ | table_catalog | String | | NO | | FIELD | | table_schema | String | | NO | | FIELD | | table_name | String | | NO | | FIELD | | column_name | String | | NO | | FIELD | | ordinal_position | Int64 | | NO | | FIELD | | character_maximum_length | Int64 | YES | | FIELD | | character_octet_length | Int64 | YES | | FIELD | | numeric_precision | Int64 | YES | | FIELD | | numeric_scale | Int64 | YES | | FIELD | | datetime_precision | Int64 | YES | | FIELD | | character_set_name | String | | YES | | FIELD | | collation_name | String | | YES | | FIELD | | column_key | String | | NO | | FIELD | | extra | String | | NO | | FIELD | | privileges | String | | NO | | FIELD | | generation_expression | String | | NO | | FIELD | | greptime_data_type | String | | NO | | FIELD | | data_type | String | | NO | | FIELD | | semantic_type | String | | NO | | FIELD | | column_default | String | | YES | | FIELD | | is_nullable | String | | NO | | FIELD | | column_type | String | | NO | | FIELD | | column_comment | String | | YES | | FIELD | | srs_id | Int64 | | YES | | FIELD | +--------------------------+--------+------+------+---------+---------------+ 24 rows in set (0.00 sec) ``` Create a table `public.t1` and query the information in the `COLUMNS` table: ```sql CREATE TABLE public.t1 (h STRING, v FLOAT64, ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP() TIME INDEX, PRIMARY KEY(h)); SELECT * FROM COLUMNS WHERE table_schema='public' AND TABLE_NAME='t1'\G ``` The output is as follows: ```sql *************************** 1. row *************************** table_catalog: greptime table_schema: public table_name: t1 column_name: h ordinal_position: 1 character_maximum_length: 2147483647 character_octet_length: 2147483647 numeric_precision: NULL numeric_scale: NULL datetime_precision: NULL character_set_name: utf8 collation_name: utf8_bin column_key: PRI extra: privileges: select,insert generation_expression: greptime_data_type: String data_type: string semantic_type: TAG column_default: NULL is_nullable: Yes column_type: string column_comment: NULL srs_id: NULL *************************** 2. row *************************** table_catalog: greptime table_schema: public table_name: t1 column_name: v ordinal_position: 2 character_maximum_length: NULL character_octet_length: NULL numeric_precision: 22 numeric_scale: NULL datetime_precision: NULL character_set_name: NULL collation_name: NULL column_key: extra: privileges: select,insert generation_expression: greptime_data_type: Float64 data_type: double semantic_type: FIELD column_default: NULL is_nullable: Yes column_type: double column_comment: NULL srs_id: NULL *************************** 3. row *************************** table_catalog: greptime table_schema: public table_name: t1 column_name: ts ordinal_position: 3 character_maximum_length: NULL character_octet_length: NULL numeric_precision: NULL numeric_scale: NULL datetime_precision: 3 character_set_name: NULL collation_name: NULL column_key: TIME INDEX extra: privileges: select,insert generation_expression: greptime_data_type: TimestampMillisecond data_type: timestamp(3) semantic_type: TIMESTAMP column_default: current_timestamp() is_nullable: No column_type: timestamp(3) column_comment: NULL srs_id: NULL 3 rows in set (0.03 sec) ``` The description of columns in the `COLUMNS` table is as follows: - `table_catalog`: The name of the catalog to which the table with the column belongs. The value is always `greptime` in OSS project. - `table_schema`: The name of the database in which the table with the column is located. - `table_name`: The name of the table with the column. - `column_name`: The name of the column. - `ordinal_position`: The position of the column in the table. - `character_maximum_length`: For string columns, the maximum length in characters. - `character_octet_length`: For string columns, the maximum length in bytes. - `numeric_precision`: The precision of the column for numeric data types. - `numeric_scale`: The scale of the column for numeric data types. - `datetime_precision`: The fractional seconds precision of the column for datetime data types. - `character_set_name`: The name of the character set of a string column. - `collation_name`: The name of the collation of a string column. - `column_key`: The key type of the column. It can be one of the following: `PRI`, `TIME INDEX`, or an empty string. - `extra`: Additional information about the column. - `privileges`: The privilege that the current user has on this column. - `generation_expression`: For generated columns, this value displays the expression used to calculate the column value. For non-generated columns, the value is empty. - `greptime_data_type`: The GreptimeDB [data type](/reference/sql/data-types.md) of the column. - `data_type`: The type of data in the column. - `semantic_type`: The type of the column. It can be one of the following: `TAG`, `FIELD`, or `TIMESTAMP`. - `column_default`: The default value of the column. If the explicit default value is `NULL`, or if the column definition does not include the `default` clause, this value is `NULL`. - `is_nullable`: Whether the column is nullable. If the column can store null values, this value is `YES`; otherwise, it is `NO`. - `column_type`: The data type of the column. It is the same as the `DATA_TYPE` column. - `column_comment`: Comments contained in the column definition. - `srs_id`: The ID of the spatial reference system (SRS) of the column. The corresponding `SHOW` statement is as follows: ```sql SHOW COLUMNS FROM t1 FROM public; ``` The output is as follows: ```sql +-------+--------------+------+------------+---------------------+-------+----------------------+ | Field | Type | Null | Key | Default | Extra | Greptime_type | +-------+--------------+------+------------+---------------------+-------+----------------------+ | h | string | Yes | PRI | NULL | | String | | ts | timestamp(3) | No | TIME INDEX | current_timestamp() | | TimestampMillisecond | | v | double | Yes | | NULL | | Float64 | +-------+--------------+------+------------+---------------------+-------+----------------------+ 3 rows in set (0.01 sec) ``` --- ## ENGINES The `ENGINES` table provides information about storage engines. This is particularly useful for checking whether a storage engine is supported, or to see what the default engine is. The `ENGINES` table has the following columns: * `engine`: the storage engine name. * `support`: the level of support for the storage engine: | Value | Meaning | | --- | --- | | `YES` | The engine is supported and is active | | `DEFAULT` | Like `YES`, plus this is the default engine | | `NO` | The engine is not supported | | `DISABLED` | The engine is supported but has been disabled | * `comment`: A brief description of the storage engine. * `transactions`: Whether the storage engine supports transactions. * `xa`: Whether the storage engine supports XA transactions. * `savepoints`: Whether the storage engine supports savepoints. For example: ```sql SELECT * from INFORMATION_SCHEMA.ENGINES\G ``` The output is as follows: ```sql *************************** 1. row *************************** engine: mito support: DEFAULT comment: Storage engine for time-series data transactions: NO xa: NO savepoints: NO *************************** 2. row *************************** engine: metric support: YES comment: Storage engine for observability scenarios, which is adept at handling a large number of small tables, making it particularly suitable for cloud-native monitoring transactions: NO xa: NO savepoints: NO ``` --- ## FLOWS The `Flows` table provides the flow task information. ```sql DESC TABLE INFORMATION_SCHEMA.FLOWS; ``` ```sql Column | Type | Key | Null | Default | Semantic Type ------------------+--------+-----+------+---------+--------------- flow_name | String | | NO | | FIELD flow_id | UInt32 | | NO | | FIELD table_catalog | String | | NO | | FIELD flow_definition | String | | NO | | FIELD comment | String | | YES | | FIELD expire_after | Int64 | | YES | | FIELD source_table_ids | String | | YES | | FIELD sink_table_name | String | | NO | | FIELD flownode_ids | String | | YES | | FIELD options | String | | YES | | FIELD (10 rows) ``` The columns in table: * `flow_name`: the flow task's name. * `flow_id`: the flow task's id. * `table_catalog`: the catalog this flow belongs to, named as `table_catalog` to keep consistent with the `INFORMATION_SCHEMA` standard. * `flow_definition`: the flow task's definition. It's the SQL statement used to create the flow task. * `comment`: the comment of the flow task. * `expire_after`: the expire time of the flow task. * `source_table_ids`: the source table ids of the flow task. * `sink_table_name`: the sink table name of the flow task. * `flownode_ids`: the flownode ids used by the flow task. * `options`: extra options of the flow task. --- ## KEY_COLUMN_USAGE The `KEY_COLUMN_USAGE` table describes the key constraints of the columns, such as the time index key constraint. ```sql USE INFORMATION_SCHEMA; DESC KEY_COLUMN_USAGE; ``` The output is as follows: ```sql +-------------------------------+--------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +-------------------------------+--------+------+------+---------+---------------+ | constraint_catalog | String | | NO | | FIELD | | constraint_schema | String | | NO | | FIELD | | constraint_name | String | | NO | | FIELD | | table_catalog | String | | NO | | FIELD | | real_table_catalog | String | | NO | | FIELD | | table_schema | String | | NO | | FIELD | | table_name | String | | NO | | FIELD | | column_name | String | | NO | | FIELD | | ordinal_position | UInt32 | | NO | | FIELD | | position_in_unique_constraint | UInt32 | | YES | | FIELD | | referenced_table_schema | String | | YES | | FIELD | | referenced_table_name | String | | YES | | FIELD | | referenced_column_name | String | | YES | | FIELD | +-------------------------------+--------+------+------+---------+---------------+ ``` ```sql SELECT * FROM key_column_usage WHERE table_schema='public' and table_name='monitor'\G ``` ```sql *************************** 1. row *************************** constraint_catalog: def constraint_schema: public constraint_name: TIME INDEX table_catalog: def real_table_catalog: greptime table_schema: public table_name: monitor column_name: ts ordinal_position: 1 position_in_unique_constraint: NULL referenced_table_schema: NULL referenced_table_name: NULL referenced_column_name: NULL *************************** 2. row *************************** constraint_catalog: def constraint_schema: public constraint_name: PRIMARY table_catalog: def real_table_catalog: greptime table_schema: public table_name: monitor column_name: host ordinal_position: 1 position_in_unique_constraint: NULL referenced_table_schema: NULL referenced_table_name: NULL referenced_column_name: NULL 2 rows in set (0.02 sec) ``` The description of columns in the `KEY_COLUMN_USAGE` table is as follows: - `constraint_catalog`: The name of the catalog to which the constraint belongs. The value is always `def`. - `constraint_schema`: The name of the database to which the constraint belongs. - `constraint_name`: The name of the constraint. - `table_catalog`: The name of the catalog to which the table with the constraint belongs. The value is always `def`. - `real_table_catalog`: The real name of the catalog to which the table with the constraint belongs. The value is always `greptime`. - `table_schema`: The name of the database to which the table belongs. - `table_name`: The name of the table with the constraint. - `column_name`: The name of the column with the constraint. - `ordinal_position`: The position of the column in the constraint, rather than in the table. The position number starts from `1`. - `position_in_unique_constraint`: The unique constraint and the primary key constraint are empty. For foreign key constraints, this column is the position of the referenced table's key. - `referenced_table_schema`: The name of the schema referenced by the constraint. Currently in GreptimeDB, the value of this column in all constraints is `NULL`, except for the foreign key constraint. - `referenced_table_name`: The name of the table referenced by the constraint. Currently in GreptimeDB, the value of this column in all constraints is `NULL`, except for the foreign key constraint. - `referenced_column_name`: The name of the column referenced by the constraint. Currently in TiDB, the value of this column in all constraints is `NULL`, except for the foreign key constraint. --- ## INFORMATION_SCHEMA `INFORMATION_SCHEMA` provides access to system metadata, such as the name of a database or table, the data type of a column, etc. GreptimeDB also provides some custom `INFORMATION_SCHEMA` tables to query metadata about the GreptimeDB system itself, cluster information, and runtime telemetry for example. Many `INFORMATION_SCHEMA` tables have a corresponding `SHOW` command. The benefit of querying `INFORMATION_SCHEMA` is that it is possible to join between tables. There is still lots of work to do for `INFORMATION_SCHEMA`. The tracking [issue](https://github.com/GreptimeTeam/greptimedb/issues/2931) for `INFORMATION_SCHEMA`. ## Tables for MySQL compatibility | Table Name | Description | | --- | --- | | [`CHARACTER_SETS`](./character-sets.md) | provides information about available character sets. | | `CHECK_CONSTRAINTS`| Not implemented. Returns zero rows. | | [`COLLATIONS`](./collations.md) | Provides a list of collations that the server supports. | | [`COLLATION_CHARACTER_SET_APPLICABILITY`](./collation-character-set-applicability.md) | Explains which collations apply to which character sets. | | [`COLUMNS`](./columns.md) | Provides a list of columns for all tables. | | `COLUMN_PRIVILEGES` | Not implemented. Returns zero rows. | | `COLUMN_STATISTICS` | Not supported. | | [`ENGINES`](./engines.md) | Provides a list of supported storage engines. | | `EVENTS` | Not implemented. Returns zero rows. | | `FILES` | Not implemented. Returns zero rows. | | `GLOBAL_STATUS` | Not implemented. Returns zero rows. | | `GLOBAL_VARIABLES` | Not supported. | | [`KEY_COLUMN_USAGE`](./key-column-usage.md) | Describes the key constraints of the columns, such as the primary key, and time index constraint. | | `OPTIMIZER_TRACE` | Not implemented. Returns zero rows. | | `PARAMETERS` | Not implemented. Returns zero rows. | | [`PARTITIONS`](./partitions.md) | Provides a list of table partitions. | | `PLUGINS` | Not supported.| | `PROCESSLIST` | Not supported, please use `PROCESS_LIST` instead. | | `PROFILING` | Not implemented. Returns zero rows. | | `REFERENTIAL_CONSTRAINTS` | Not implemented. Returns zero rows. | | `ROUTINES` | Not implemented. Returns zero rows. | | [`SCHEMATA`](./schemata.md) | Provides similar information to `SHOW DATABASES`. | | `SCHEMA_PRIVILEGES` | Not implemented. Returns zero rows. | | `SESSION_STATUS` | Not implemented. Returns zero rows. | | `SESSION_VARIABLES` | Not supported. | | `STATISTICS` | Not supported. | | [`TABLES`](./tables.md) | Provides a list of tables that the current user has visibility of. Similar to `SHOW TABLES`. | | `TABLESPACES` | Not supported. | | `TABLE_PRIVILEGES` | Not implemented. Returns zero rows. | | `TRIGGERS` | Not supported. | | `USER_ATTRIBUTES` | Not supported. | | `USER_PRIVILEGES` | Not supported.| | `VARIABLES_INFO` | Not supported. | | [`VIEWS`](./views.md)| Provides a list of views that the current user has visibility of. Similar to running `SHOW FULL TABLES WHERE table_type = 'VIEW'` | | [`TABLE_CONSTRAINTS`](./table-constraints.md) | Provides information on primary keys, unique indexes, and foreign keys. | ## Tables that GreptimeDB provides | Table Name | Description | | --- | --- | | [`BUILD_INFO`](./build-info.md) | Provides the system build info. | | [`REGION_PEERS`](./region-peers.md) | Provides details about where regions are stored. | | [`REGION_STATISTICS`](./region-statistics.md) | Provides details about region statistics info, such as disk size, etc. | | [`CLUSTER_INFO`](./cluster-info.md)| Provides the topology information of the cluster.| | [`FLOWS`](./flows.md) | Provides the flow information.| | [`PROCEDURE_INFO`](./procedure-info.md) | Procedure information.| | [`PROCESS_LIST`](./process-list.md) | Running queries information.| | [`SSTS_INDEX_META`](./ssts-index-meta.md) | Provides SST index metadata including inverted indexes, fulltext indexes, and bloom filters.| | [`SSTS_MANIFEST`](./ssts-manifest.md) | Provides SST file information from the manifest including file paths, sizes, time ranges, and row counts.| | [`SSTS_STORAGE`](./ssts-storage.md) | Provides SST file information from the storage layer for verification and debugging.| | [`TRIGGERS`](./triggers.md) | Provides the trigger information. | | [`ALERTS`](./alerts.md) | Provides the alert information. | --- ## PARTITIONS The `PARTITIONS` table provides information about partitioned tables. ```sql USE INFORMATION_SCHEMA; DESC PARTITIONS; ``` The output is as follows: ```sql +-------------------------------+----------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +-------------------------------+----------+------+------+---------+---------------+ | table_catalog | String | | NO | | FIELD | | table_schema | String | | NO | | FIELD | | table_name | String | | NO | | FIELD | | partition_name | String | | NO | | FIELD | | subpartition_name | String | | YES | | FIELD | | partition_ordinal_position | Int64 | | YES | | FIELD | | subpartition_ordinal_position | Int64 | | YES | | FIELD | | partition_method | String | | YES | | FIELD | | subpartition_method | String | | YES | | FIELD | | partition_expression | String | | YES | | FIELD | | subpartition_expression | String | | YES | | FIELD | | partition_description | String | | YES | | FIELD | | table_rows | Int64 | | YES | | FIELD | | avg_row_length | Int64 | | YES | | FIELD | | data_length | Int64 | | YES | | FIELD | | max_data_length | Int64 | | YES | | FIELD | | index_length | Int64 | | YES | | FIELD | | data_free | Int64 | | YES | | FIELD | | create_time | TimestampSecond | | YES | | FIELD | | update_time | TimestampSecond | | YES | | FIELD | | check_time | TimestampSecond | | YES | | FIELD | | checksum | Int64 | | YES | | FIELD | | partition_comment | String | | YES | | FIELD | | nodegroup | String | | YES | | FIELD | | tablespace_name | String | | YES | | FIELD | | greptime_partition_id | UInt64 | | YES | | FIELD | +-------------------------------+----------+------+------+---------+---------------+ 26 rows in set (0.01 sec) ``` Main columns: * `table_catalog`: The name of the catalog to which the table belongs. This value is always `def`. * `table_schema`: The name of the schema (database) to which the table belongs. * `table_name`: The name of the table containing the partition(region). * `partition_name`: The name of the partition(region). * `partition_ordinal_position`: All partitions are indexed in the same order as they are defined, with 1 being the number assigned to the first partition. * `partition_method`: This value is always `RANGE`, GreptimeDB only supports range partitioning. * `partition_expression`: The expression of this partition. * `create_time`: The time that the partition was created. * `greptime_partition_id`: GreptimeDB extended field, it's the Region Id. For example, create a partitioned table: ```sql CREATE TABLE public.test_p ( a INT PRIMARY KEY, b STRING, ts TIMESTAMP TIME INDEX, ) PARTITION ON COLUMNS (a) ( a < 10, a >= 10 AND a < 20, a >= 20 ); -- Query the partitions of the table SELECT * FROM PARTITIONS WHERE table_schema='public' AND table_name='test_p'\G ``` Outputs: ```sql *************************** 1. row *************************** table_catalog: greptime table_schema: public table_name: test_p partition_name: p0 subpartition_name: NULL partition_ordinal_position: 1 subpartition_ordinal_position: NULL partition_method: RANGE subpartition_method: NULL partition_expression: (a) VALUES LESS THAN (PartitionExpr { lhs: Column("a"), op: Lt, rhs: Value(Int32(10)) }) subpartition_expression: NULL partition_description: NULL table_rows: NULL avg_row_length: NULL data_length: NULL max_data_length: NULL index_length: NULL data_free: NULL create_time: 2024-04-01 10:49:49.468000 update_time: NULL check_time: NULL checksum: NULL partition_comment: NULL nodegroup: NULL tablespace_name: NULL greptime_partition_id: 4453881085952 *************************** 2. row *************************** table_catalog: greptime table_schema: public table_name: test_p partition_name: p1 subpartition_name: NULL partition_ordinal_position: 2 subpartition_ordinal_position: NULL partition_method: RANGE subpartition_method: NULL partition_expression: (a) VALUES LESS THAN (PartitionExpr { lhs: Column("a"), op: GtEq, rhs: Value(Int32(20)) }) subpartition_expression: NULL partition_description: NULL table_rows: NULL avg_row_length: NULL data_length: NULL max_data_length: NULL index_length: NULL data_free: NULL create_time: 2024-04-01 10:49:49.468000 update_time: NULL check_time: NULL checksum: NULL partition_comment: NULL nodegroup: NULL tablespace_name: NULL greptime_partition_id: 4453881085954 *************************** 3. row *************************** table_catalog: greptime table_schema: public table_name: test_p partition_name: p2 subpartition_name: NULL partition_ordinal_position: 3 subpartition_ordinal_position: NULL partition_method: RANGE subpartition_method: NULL partition_expression: (a) VALUES LESS THAN (PartitionExpr { lhs: Expr(PartitionExpr { lhs: Column("a"), op: Gt, rhs: Value(Int32(10)) }), op: And, rhs: Expr(PartitionExpr { lhs: Column("a"), op: Lt, rhs: Value(Int32(20)) }) }) subpartition_expression: NULL partition_description: NULL table_rows: NULL avg_row_length: NULL data_length: NULL max_data_length: NULL index_length: NULL data_free: NULL create_time: 2024-04-01 10:49:49.468000 update_time: NULL check_time: NULL checksum: NULL partition_comment: NULL nodegroup: NULL tablespace_name: NULL greptime_partition_id: 4453881085953 ``` --- ## PROCEDURE_INFO The `PROCEDURE_INFO` table provides detailed information about various procedures. ```sql DESC TABLE INFORMATION_SCHEMA.PROCEDURE_INFO; ``` ```sql +----------------+----------------------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +----------------+----------------------+------+------+---------+---------------+ | procedure_id | String | | NO | | FIELD | | procedure_type | String | | NO | | FIELD | | start_time | TimestampMillisecond | | YES | | FIELD | | end_time | TimestampMillisecond | | YES | | FIELD | | status | String | | NO | | FIELD | | lock_keys | String | | YES | | FIELD | +----------------+----------------------+------+------+---------+---------------+ ``` Fields in the `PROCEDURE_INFO` table are described as follows: - `procedure_id`: The ID of the Procedure. - `procedure_type`: The type of the Procedure. - `start_time`: Timestamp indicating when the procedure started. - `end_time`: Timestamp indicating when the procedure ended. - `status`: Current status of the procedure. - `lock_keys`: Keys locked by the procedure, if any. --- ## PROCESS_LIST The `PROCESS_LIST` table provides a view of all running queries in GreptimeDB cluster. :::tip NOTE It's intentionally to have a different table name than MySQL's `PROCESSLIST` because it has a very different set of columns. ::: ```sql USE INFORMATION_SCHEMA; DESC PROCESS_LIST; ``` The output is as follows: ```sql +-----------------+----------------------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +-----------------+----------------------+------+------+---------+---------------+ | id | String | | NO | | FIELD | | catalog | String | | NO | | FIELD | | schemas | String | | NO | | FIELD | | query | String | | NO | | FIELD | | client | String | | NO | | FIELD | | frontend | String | | NO | | FIELD | | start_timestamp | TimestampMillisecond | | NO | | FIELD | | elapsed_time | DurationMillisecond | | NO | | FIELD | +-----------------+----------------------+------+------+---------+---------------+ ``` Fields in the `PROCESS_LIST` table are described as follows: - `id`: The ID of query. - `catalog`: The catalog name of the query. - `schemas`: The schema name in which client issues the query. - `query`: The query statement. - `client`: Client information, including client address and channel. - `frontend`: On which frontend instance the query is running. - `start_timestamp`: The start timestamp of query. - `elapsed_time`: How long the query has been running. :::tip NOTE You can also use `SHOW [FULL] PROCESSLIST` statement as an alternative to querying from `INFORMATION_SCHEMA.PROCESS_LIST` table. ::: # Terminating a query When identified a running query from `PROCESS_LIST` table, you can terminate the query using `KILL ` statement, where the `` is the `id` field in `PROCESS_LIST` table. ```sql mysql> select * from process_list; +-----------------------+----------+--------------------+----------------------------+------------------------+---------------------+----------------------------+-----------------+ | id | catalog | schemas | query | client | frontend | start_timestamp | elapsed_time | +-----------------------+----------+--------------------+----------------------------+------------------------+---------------------+----------------------------+-----------------+ | 112.40.36.208/7 | greptime | public | SELECT * FROM some_very_large_table | mysql[127.0.0.1:34692] | 112.40.36.208:4001 | 2025-06-30 07:04:11.118000 | 00:00:12.002000 | +-----------------------+----------+--------------------+----------------------------+------------------------+---------------------+----------------------------+-----------------+ KILL '112.40.36.208/7'; Query OK, 1 row affected (0.00 sec) ``` --- ## REGION_PEERS The `REGION_PEERS` table shows detailed information of a single Region node in GreptimeDB, such as whether it is a learner or leader. ```sql USE INFORMATION_SCHEMA; DESC REGION_PEERS; ``` The output is as follows: ```sql +---------------+--------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +---------------+--------+------+------+---------+---------------+ | table_catalog | String | | NO | | FIELD | | table_schema | String | | NO | | FIELD | | table_name | String | | NO | | FIELD | | region_id | UInt64 | | NO | | FIELD | | peer_id | UInt64 | | YES | | FIELD | | peer_addr | String | | YES | | FIELD | | is_leader | String | | YES | | FIELD | | status | String | | YES | | FIELD | | down_seconds | Int64 | | YES | | FIELD | +---------------+--------+------+------+---------+---------------+ 6 rows in set (0.00 sec) ``` Fields in the `REGION_PEERS` table are described as follows: - `table_catalog`: The catalog of the table. - `table_schema`: The schema of the table. - `table_name`: The name of the table. - `region_id`: The ID of the Region. - `peer_id`: The ID of the Region peer. - `peer_addr`: The address of the peer. - `is_leader`: Whether the peer is the leader. - `status`: The status of the peer, `ALIVE` or `DOWNGRADED`. - `ALIVE`: The peer is online. - `DOWNGRADED`: The Region peer is unavailable (e.g., crashed, network disconnected), or the Region peer was planned to migrate to another peer. - `down_seconds`: The duration of being offline, in seconds. --- ## REGION_STATISTICS The `REGION_STATISTICS` table provides detailed information about a region's statistics, including the total number of rows, disk size, and more. These statistics are approximate values. ```sql USE INFORMATION_SCHEMA; DESC REGION_STATISTICS; ``` The output is as follows: ```sql +--------------------------+--------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +--------------------------+--------+------+------+---------+---------------+ | region_id | UInt64 | | NO | | FIELD | | table_id | UInt32 | | NO | | FIELD | | region_number | UInt32 | | NO | | FIELD | | region_rows | UInt64 | | YES | | FIELD | | written_bytes_since_open | UInt64 | | YES | | FIELD | | disk_size | UInt64 | | YES | | FIELD | | memtable_size | UInt64 | | YES | | FIELD | | manifest_size | UInt64 | | YES | | FIELD | | sst_size | UInt64 | | YES | | FIELD | | sst_num | UInt64 | | YES | | FIELD | | index_size | UInt64 | | YES | | FIELD | | engine | String | | YES | | FIELD | | region_role | String | | YES | | FIELD | +--------------------------+--------+------+------+---------+---------------+ ``` Fields in the `REGION_STATISTICS` table are described as follows: - `region_id`: The ID of the Region. - `table_id`: The ID of the table. - `region_number`: The number of the region in the table. - `region_rows`: The number of rows in the region. - `written_bytes_since_open`: The number of bytes written to the region since the region was opened. - `disk_size`: The total size of data files in the region, including data, index and metadata etc. - `memtable_size`: The region's total size of memtables. - `manifest_size`: The region's total size of manifest files. - `sst_num`: The region's total number of SST files. - `sst_size`: The region's total size of SST files. - `index_size`: The region's total size of index files. - `engine`: The engine type of the region, `mito` or `metric`. - `region_role`: The region's role, `Leader` or `Follower`. Retrieve a table's region statistics information as follows: ```sql SELECT r.* FROM REGION_STATISTICS r LEFT JOIN TABLES t on r.table_id = t.table_id \ WHERE t.table_name = 'system_metrics'; ``` Output: ```sql +---------------+----------+---------------+-------------+--------------------------+-----------+---------------+---------------+----------+---------+------------+--------+-------------+ | region_id | table_id | region_number | region_rows | written_bytes_since_open | disk_size | memtable_size | manifest_size | sst_size | sst_num | index_size | engine | region_role | +---------------+----------+---------------+-------------+--------------------------+-----------+---------------+---------------+----------+---------+------------+--------+-------------+ | 4398046511104 | 1024 | 0 | 8 | 0 | 4922 | 0 | 1338 | 3249 | 1 | 335 | mito | Leader | +---------------+----------+---------------+-------------+--------------------------+-----------+---------------+---------------+----------+---------+------------+--------+-------------+ ``` --- ## SCHEMATA The `SCHEMATA` table provides information about databases. The table data is equivalent to the result of the `SHOW DATABASES` statement. ```sql USE INFORMATION_SCHEMA; DESC SCHEMATA; ``` The output is as follows: ```sql +----------------------------+--------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +----------------------------+--------+------+------+---------+---------------+ | catalog_name | String | | NO | | FIELD | | schema_name | String | | NO | | FIELD | | default_character_set_name | String | | NO | | FIELD | | default_collation_name | String | | NO | | FIELD | | sql_path | String | | YES | | FIELD | | options | String | | YES | | FIELD | +----------------------------+--------+------+------+---------+---------------+ ``` ```sql SELECT * FROM SCHEMATA; ``` ```sql +--------------+--------------------+----------------------------+------------------------+----------+-------------+ | catalog_name | schema_name | default_character_set_name | default_collation_name | sql_path | options | +--------------+--------------------+----------------------------+------------------------+----------+-------------+ | greptime | greptime_private | utf8 | utf8_bin | NULL | | | greptime | information_schema | utf8 | utf8_bin | NULL | | | greptime | public | utf8 | utf8_bin | NULL | | | greptime | test | utf8 | utf8_bin | NULL | ttl='7days' | +--------------+--------------------+----------------------------+------------------------+----------+-------------+ ``` Fields in the `SCHEMATA` table are described as follows: - `catalog_name`: The catalog to which the database belongs. - `schema_name`: The name of the database. - `default_character_set_name`: The default character set of the database. - `default_collation_name`: The default collation of the database. - `sql_path`: The value of this item is always `NULL`. - `options`: Extending column in GreptimeDB. The database options. --- ## SSTS_INDEX_META The `SSTS_INDEX_META` table provides access to SST (Sorted String Table) index metadata collected from the manifest. This table surfaces information about Puffin index metadata, including inverted indexes, fulltext indexes, and bloom filters. ```sql USE INFORMATION_SCHEMA; DESC SSTS_INDEX_META; ``` The output is as follows: ```sql +-----------------+--------+-----+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +-----------------+--------+-----+------+---------+---------------+ | table_dir | String | | NO | | FIELD | | index_file_path | String | | NO | | FIELD | | region_id | UInt64 | | NO | | FIELD | | table_id | UInt32 | | NO | | FIELD | | region_number | UInt32 | | NO | | FIELD | | region_group | UInt8 | | NO | | FIELD | | region_sequence | UInt32 | | NO | | FIELD | | file_id | String | | NO | | FIELD | | index_file_size | UInt64 | | YES | | FIELD | | index_type | String | | NO | | FIELD | | target_type | String | | NO | | FIELD | | target_key | String | | NO | | FIELD | | target_json | String | | NO | | FIELD | | blob_size | UInt64 | | NO | | FIELD | | meta_json | String | | YES | | FIELD | | node_id | UInt64 | | YES | | FIELD | +-----------------+--------+-----+------+---------+---------------+ ``` Fields in the `SSTS_INDEX_META` table are described as follows: - `table_dir`: The directory path of the table. - `index_file_path`: The full path to the Puffin index file. - `region_id`: The ID of the region. - `table_id`: The ID of the table. - `region_number`: The region number within the table. - `region_group`: The group identifier for the region. - `region_sequence`: The sequence number of the region. - `file_id`: The unique identifier of the index file (UUID). - `index_file_size`: The size of the index file in bytes. - `index_type`: The type of index. Possible values include: - `inverted`: Inverted index for fast term lookups - `fulltext_bloom`: Combined fulltext and bloom filter index - `bloom_filter`: Bloom filter for fast membership tests - `target_type`: The type of target being indexed. Typically `column` for column-based indexes. - `target_key`: The key identifying the target (e.g., column ID). - `target_json`: JSON representation of the target configuration, such as `{"column":0}`. - `blob_size`: The size of the blob data in bytes. - `meta_json`: JSON metadata containing index-specific information such as: - For inverted indexes: FST size, bitmap type, segment row count, etc. - For bloom filters: bloom filter size, row count, segment count - For fulltext indexes: analyzer type, case sensitivity settings - `node_id`: The ID of the datanode where the index is located. ## Examples Query all index metadata: ```sql SELECT * FROM INFORMATION_SCHEMA.SSTS_INDEX_META; ``` Query index metadata for a specific table by joining with the `TABLES` table: ```sql SELECT s.* FROM INFORMATION_SCHEMA.SSTS_INDEX_META s JOIN INFORMATION_SCHEMA.TABLES t ON s.table_id = t.table_id WHERE t.table_name = 'my_table'; ``` Query only inverted index metadata: ```sql SELECT table_dir, index_file_path, index_type, target_json, meta_json FROM INFORMATION_SCHEMA.SSTS_INDEX_META WHERE index_type = 'inverted'; ``` Query index metadata grouped by index type: ```sql SELECT index_type, COUNT(*) as count, SUM(index_file_size) as total_size FROM INFORMATION_SCHEMA.SSTS_INDEX_META GROUP BY index_type; ``` Output example: ```sql mysql> SELECT * FROM INFORMATION_SCHEMA.SSTS_INDEX_META LIMIT 1\G; *************************** 1. row *************************** table_dir: data/greptime/public/1814/ index_file_path: data/greptime/public/1814/1814_0000000000/data/index/aba4af59-1247-4bfb-a20b-69242cdd9374.puffin region_id: 7791070674944 table_id: 1814 region_number: 0 region_group: 0 region_sequence: 0 file_id: aba4af59-1247-4bfb-a20b-69242cdd9374 index_file_size: 838 index_type: bloom_filter target_type: column target_key: 2147483652 target_json: {"column":2147483652} blob_size: 688 meta_json: {"bloom":{"bloom_filter_size":640,"row_count":2242,"rows_per_segment":1024,"segment_count":3}} node_id: 0 1 row in set (0.02 sec) ``` --- ## SSTS_MANIFEST The `SSTS_MANIFEST` table provides access to SST (Sorted String Table) file information collected from the manifest. This table surfaces detailed information about each SST file, including file paths, sizes, levels, time ranges, and row counts. ```sql USE INFORMATION_SCHEMA; DESC SSTS_MANIFEST; ``` The output is as follows: ```sql +------------------+---------------------+-----+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +------------------+---------------------+-----+------+---------+---------------+ | table_dir | String | | NO | | FIELD | | region_id | UInt64 | | NO | | FIELD | | table_id | UInt32 | | NO | | FIELD | | region_number | UInt32 | | NO | | FIELD | | region_group | UInt8 | | NO | | FIELD | | region_sequence | UInt32 | | NO | | FIELD | | file_id | String | | NO | | FIELD | | level | UInt8 | | NO | | FIELD | | file_path | String | | NO | | FIELD | | file_size | UInt64 | | NO | | FIELD | | index_file_path | String | | YES | | FIELD | | index_file_size | UInt64 | | YES | | FIELD | | num_rows | UInt64 | | NO | | FIELD | | num_row_groups | UInt64 | | NO | | FIELD | | min_ts | TimestampNanosecond | | YES | | FIELD | | max_ts | TimestampNanosecond | | YES | | FIELD | | sequence | UInt64 | | YES | | FIELD | | origin_region_id | UInt64 | | NO | | FIELD | | node_id | UInt64 | | YES | | FIELD | | visible | Boolean | | NO | | FIELD | +------------------+---------------------+-----+------+---------+---------------+ ``` Fields in the `SSTS_MANIFEST` table are described as follows: - `table_dir`: The directory path of the table. - `region_id`: The ID of the region that refers to the file. - `table_id`: The ID of the table. - `region_number`: The region number within the table. - `region_group`: The group identifier for the region. - `region_sequence`: The sequence number of the region. - `file_id`: The unique identifier of the SST file (UUID). - `level`: The SST level in the LSM tree (0 for uncompacted, 1 for compacted). - `file_path`: The full path to the SST file in object storage. - `file_size`: The size of the SST file in bytes. - `index_file_path`: The full path to the index file in object storage (if exists). - `index_file_size`: The size of the index file in bytes (if exists). - `num_rows`: The number of rows in the SST file. - `num_row_groups`: The number of row groups in the SST file. - `min_ts`: The minimum timestamp in the SST file. - `max_ts`: The maximum timestamp in the SST file. - `sequence`: The sequence number associated with this file. - `origin_region_id`: The ID of the region that created the file. - `node_id`: The ID of the datanode where the file is located. - `visible`: Whether this file is visible in the current version. ## Examples Query all SST files in the manifest: ```sql SELECT * FROM INFORMATION_SCHEMA.SSTS_MANIFEST; ``` Query SST files for a specific table by joining with the `TABLES` table: ```sql SELECT s.* FROM INFORMATION_SCHEMA.SSTS_MANIFEST s JOIN INFORMATION_SCHEMA.TABLES t ON s.table_id = t.table_id WHERE t.table_name = 'my_table'; ``` Query only compacted SST files (level 1): ```sql SELECT file_path, file_size, num_rows, level FROM INFORMATION_SCHEMA.SSTS_MANIFEST WHERE level = 1; ``` Query SST files with their time ranges: ```sql SELECT table_id, file_path, num_rows, min_ts, max_ts FROM INFORMATION_SCHEMA.SSTS_MANIFEST ORDER BY table_id, min_ts; ``` Calculate total SST file size per table: ```sql SELECT table_id, COUNT(*) as sst_count, SUM(file_size) as total_size FROM INFORMATION_SCHEMA.SSTS_MANIFEST GROUP BY table_id; ``` Output example: ```sql mysql> SELECT * FROM INFORMATION_SCHEMA.SSTS_MANIFEST LIMIT 1\G; *************************** 1. row *************************** table_dir: data/greptime/public/1024/ region_id: 4398046511104 table_id: 1024 region_number: 0 region_group: 0 region_sequence: 0 file_id: 01234567-89ab-cdef-0123-456789abcdef level: 0 file_path: data/greptime/public/1024/4398046511104_0/01234567-89ab-cdef-0123-456789abcdef.parquet file_size: 1234 index_file_path: data/greptime/public/1024/4398046511104_0/index/01234567-89ab-cdef-0123-456789abcdef.puffin index_file_size: 256 num_rows: 100 num_row_groups: 1 min_ts: 2025-01-01 00:00:00.000000000 max_ts: 2025-01-01 00:01:00.000000000 sequence: 1 origin_region_id: 4398046511104 node_id: 0 visible: true 1 row in set (0.02 sec) ``` --- ## SSTS_STORAGE The `SSTS_STORAGE` table provides access to SST (Sorted String Table) file information listed directly from the storage layer. This table shows raw file metadata from object storage, which may include files that are not yet reflected in the manifest or files that have been orphaned. ```sql USE INFORMATION_SCHEMA; DESC SSTS_STORAGE; ``` The output is as follows: ```sql +------------------+----------------------+-----+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +------------------+----------------------+-----+------+---------+---------------+ | file_path | String | | NO | | FIELD | | file_size | UInt64 | | YES | | FIELD | | last_modified_ms | TimestampMillisecond | | YES | | FIELD | | node_id | UInt64 | | YES | | FIELD | +------------------+----------------------+-----+------+---------+---------------+ ``` Fields in the `SSTS_STORAGE` table are described as follows: - `file_path`: The full path to the file in object storage. - `file_size`: The size of the file in bytes (if available from storage). - `last_modified_ms`: The last modified time in milliseconds (if available from storage). - `node_id`: The ID of the datanode where the file is located. ## Use Cases The `SSTS_STORAGE` table is useful for: - **Storage verification**: Compare files in storage against the manifest to detect orphaned files or inconsistencies. - **Storage debugging**: Identify files that exist in storage but may not be properly tracked in the manifest. - **Cleanup operations**: Find and remove orphaned SST files that are no longer referenced. - **Storage auditing**: Get a complete view of all SST files in the storage layer. ## Examples Query all SST files in storage: ```sql SELECT * FROM INFORMATION_SCHEMA.SSTS_STORAGE; ``` Find files in storage that are not in the manifest (potential orphaned files): ```sql SELECT s.file_path, s.file_size, s.last_modified_ms FROM INFORMATION_SCHEMA.SSTS_STORAGE s LEFT JOIN INFORMATION_SCHEMA.SSTS_MANIFEST m ON s.file_path = m.file_path WHERE m.file_path IS NULL; ``` Find the largest SST files in storage: ```sql SELECT file_path, file_size FROM INFORMATION_SCHEMA.SSTS_STORAGE WHERE file_size IS NOT NULL ORDER BY file_size DESC LIMIT 10; ``` Calculate total storage usage by SST files: ```sql SELECT COUNT(*) as file_count, SUM(file_size) as total_size FROM INFORMATION_SCHEMA.SSTS_STORAGE WHERE file_size IS NOT NULL; ``` Output example: ```sql mysql> SELECT * FROM INFORMATION_SCHEMA.SSTS_STORAGE LIMIT 1\G; *************************** 1. row *************************** file_path: data/greptime/public/1024/4398046511104_0/01234567-89ab-cdef-0123-456789abcdef.parquet file_size: 1234 last_modified_ms: 2025-01-01 00:00:00.000 node_id: 0 1 row in set (0.02 sec) ``` ## Differences from SSTS_MANIFEST | Aspect | SSTS_MANIFEST | SSTS_STORAGE | |--------|---------------|--------------| | **Data Source** | Manifest metadata | Storage layer directly | | **Information** | Detailed SST metadata (rows, time ranges, etc.) | Basic file metadata only | | **File Coverage** | Only files tracked in manifest | All files in storage | | **Use Case** | Query SST metadata for analysis | Verify storage, find orphaned files | | **Performance** | Fast (reads from manifest) | Slower (scans storage) | --- ## TABLE_CONSTRAINTS The `TABLE_CONSTRAINTS` table describes which tables have constraints. ```sql DESC INFORMATION_SCHEMA.table_constraints; ``` ```sql +--------------------+--------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +--------------------+--------+------+------+---------+---------------+ | constraint_catalog | String | | NO | | FIELD | | constraint_schema | String | | NO | | FIELD | | constraint_name | String | | NO | | FIELD | | table_schema | String | | NO | | FIELD | | table_name | String | | NO | | FIELD | | constraint_type | String | | NO | | FIELD | | enforced | String | | NO | | FIELD | +--------------------+--------+------+------+---------+---------------+ ``` The columns in the table: * `CONSTRAINT_CATALOG`: The name of the catalog to which the constraint belongs. This value is always `def`. * `CONSTRAINT_SCHEMA`: The name of the database to which the constraint belongs. * `CONSTRAINT_NAME`: The name of the constraint, `TIME INDEX` or `PRIMARY`. * `TABLE_NAME`: The name of the table. * `CONSTRAINT_TYPE`: The type of the constraint. The value can be `TIME INDEX` or `PRIMARY KEY`. The `TIME INDEX` and `PRIMARY KEY` information is similar to the execution result of the `SHOW INDEX` statement. * `enforced`: Doesn't support `CHECK` constraints, the value is always` YES`. ```sql select * from INFORMATION_SCHEMA.table_constraints WHERE table_name = 'monitor'\G; ``` The output: ```sql *************************** 1. row *************************** constraint_catalog: def constraint_schema: public constraint_name: TIME INDEX table_schema: public table_name: monitor constraint_type: TIME INDEX enforced: YES *************************** 2. row *************************** constraint_catalog: def constraint_schema: public constraint_name: PRIMARY table_schema: public table_name: monitor constraint_type: PRIMARY KEY enforced: YES --- ## TABLES The `TABLES` table provides information about tables in databases: ```sql USE INFORMATION_SCHEMA; DESC TABLES; ``` The output is as follows: ```sql +------------------+----------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +------------------+----------+------+------+---------+---------------+ | table_catalog | String | | NO | | FIELD | | table_schema | String | | NO | | FIELD | | table_name | String | | NO | | FIELD | | table_type | String | | NO | | FIELD | | table_id | UInt32 | | YES | | FIELD | | data_length | UInt64 | | YES | | FIELD | | max_data_length | UInt64 | | YES | | FIELD | | index_length | UInt64 | | YES | | FIELD | | max_index_length | UInt64 | | YES | | FIELD | | avg_row_length | UInt64 | | YES | | FIELD | | engine | String | | YES | | FIELD | | version | UInt64 | | YES | | FIELD | | row_format | String | | YES | | FIELD | | table_rows | UInt64 | | YES | | FIELD | | data_free | UInt64 | | YES | | FIELD | | auto_increment | UInt64 | | YES | | FIELD | | create_time | TimestampSecond | | YES | | FIELD | | update_time | TimestampSecond | | YES | | FIELD | | check_time | TimestampSecond | | YES | | FIELD | | table_collation | String | | YES | | FIELD | | checksum | UInt64 | | YES | | FIELD | | create_options | String | | YES | | FIELD | | table_comment | String | | YES | | FIELD | | temporary | String | | YES | | FIELD | +------------------+----------+------+------+---------+---------------+ ``` ```sql SELECT * FROM tables WHERE table_schema='public' AND table_name='monitor'\G ``` ```sql *************************** 1. row *************************** table_catalog: greptime table_schema: public table_name: monitor table_type: BASE TABLE table_id: 1054 data_length: 0 max_data_length: 0 index_length: 0 max_index_length: 0 avg_row_length: 0 engine: mito version: 11 row_format: Fixed table_rows: 0 data_free: 0 auto_increment: 0 create_time: 2024-07-24 22:06:18.085000 update_time: NULL check_time: NULL table_collation: NULL checksum: 0 create_options: table_comment: NULL temporary: N 1 row in set (0.01 sec) ``` The following statements are equivalent: ```sql SELECT table_name FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = '' [AND table_name LIKE 'monitor'] SHOW TABLES FROM db_name [LIKE 'monitor'] ``` The description of columns in the `TABLES` table is as follows: - `table_catalog`: The catalog to which the table belongs. The value is always `greptime`. - `table_schema`: The database to which the table belongs. - `table_name`: The name of the table. - `table_type`: The type of the table. - `BASE TABLE` for a table. - `TEMPORARY` for a temporary result set. - `VIEW` for a view. - `table_id`: The ID of the table. - `data_length`: The table size, representing the total length of the table's SST files in bytes. This is an approximate value. - `index_length`: The size of all indexes of the table, representing the total length of the table's index files in bytes. This is an approximate value. - `table_rows`: The table's total row number, which is an approximate value. - `avg_row_length`: The average row length in bytes, which is an approximate value. - `engine`: The storage engine of the table used. - `version`: Version. The value is `11` by default. - `create_time`: The table created timestamp. - `table_comment`: The table comment. - Other columns such as `auto_increment`, `row_format` etc. are not supported, just for compatibility with MySQL. GreptimeDB may support some of them in the future. --- ## Triggers :::tip NOTE This feature is only available in the GreptimeDB Enterprise database. ::: The `TRIGGERS` table provides metadata information about all triggers. ```sql DESC TABLE INFORMATION_SCHEMA.TRIGGERS; ``` ```sql +-----------------+--------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +-----------------+--------+------+------+---------+---------------+ | trigger_name | String | | NO | | FIELD | | trigger_id | UInt64 | | NO | | FIELD | | raw_sql | String | | NO | | FIELD | | interval | UInt64 | | NO | | FIELD | | labels | Json | | YES | | FIELD | | annotations | Json | | YES | | FIELD | | for | UInt64 | | YES | | FIELD | | keep_firing_for | UInt64 | | YES | | FIELD | | channels | Json | | YES | | FIELD | | flownode_id | UInt64 | | YES | | FIELD | +-----------------+--------+------+------+---------+---------------+ ``` The columns in table: * `trigger_name`: the name of the trigger. * `trigger_id`: the id of the trigger. * `raw_sql`: the SQL query executed periodically by the trigger. * `interval`: the execution interval of the trigger, in seconds. * `labels`: static key-value pairs defined through the `LABELS` clause. * `annotations`: static key-value pairs defined through the `ANNOTATIONS` clause. * `for`: how long an alert must remain active before it fires, in seconds. * `keep_firing_for`: how long an alert instance should remain in the `Firing` state after it first enters that state, in seconds. * `channels`: the notification channels used by the trigger. * `flownode_id`: the id of the flownode responsible for executing the trigger. --- ## VIEWS The `VIEWS` table provides a list of views that the current user has visibility of. ```sql DESC TABLE INFORMATION_SCHEMA.VIEWS; ``` ```sql +----------------------+---------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +----------------------+---------+------+------+---------+---------------+ | table_catalog | String | | NO | | FIELD | | table_schema | String | | NO | | FIELD | | table_name | String | | NO | | FIELD | | view_definition | String | | NO | | FIELD | | check_option | String | | YES | | FIELD | | is_updatable | Boolean | | YES | | FIELD | | definer | String | | YES | | FIELD | | security_type | String | | YES | | FIELD | | character_set_client | String | | YES | | FIELD | | collation_connection | String | | YES | | FIELD | +----------------------+---------+------+------+---------+---------------+ ``` The columns in table: * `table_catalog`: The name of the catalog to which the view belongs. * `table_schema`: The name of the database to which the view belongs. * `table_name`: The view name. * `view_definition`: The definition of view, which is made by the `SELECT` statement when the view is created. * `check_option`: Doesn't support, is always `NULL`. * `is_updatable`: Whether `UPDATE/INSERT/DELETE` is applicable to the view, always `NO`. * `definer`: The name of the user who creates the view. * `security_type`: Doesn't support, is always `NULL`. * `character_set_client`: The value of the `character_set_client` session variable when the view is created, is always `utf8`. * `collation_connection`: The value of the `collation_connection` session variable when the view is created, is always `utf8_bin`. --- ## INSERT The `INSERT` statement is used to insert one or more records into a table in the GreptimeDB. ## `INSERT INTO` Statement ### Syntax The syntax for the INSERT INTO statement is as follows: ```sql INSERT INTO table_name (column1, column2, column3, ...) VALUES (value1, value2, value3, ...); ``` In the above syntax, `table_name` is the name of the table into which you want to insert data, and `column1`, `column2`, `column3`, etc. are the names of the columns in the table. You can specify the columns in the `INSERT INTO` statement if you want to insert data into specific columns. If you do not specify the columns, the values will be inserted into all the columns in the table. The `VALUES` keyword is followed by a list of values that correspond to the columns in the `INSERT INTO` statement. The values must be in the same order as the columns. The following types of values are supported: - The `DEFAULT` keyword specifies that the default value for that column should be inserted. This is useful when you do not want to explicitly specify values for some columns when inserting records. It allows the column's default value, as defined in the table schema, to be used instead. If no default value is defined for the column, the database's default value will be used (often NULL). - Use hexadecimal literal to insert a literal binary. - use the `{Value}::{Type}` syntax to cast the special numeric values `Infinity`, `-Infinity`, and `NaN` into the desired numeric type. ### Examples #### Insert Data Here is an example of an `INSERT INTO` statement that inserts a record into a table named `system_metrics`: ```sql INSERT INTO system_metrics (host, idc, cpu_util, memory_util, disk_util, ts) VALUES ("host1", "idc_b", 50.0, 66.7, 40.6, 1667446797462); ``` This statement inserts a record with the host "host1", idc "idc_b", cpu_util 50.0, memory_util 66.7, disk_util 40.6, ts 1667446797462 into the `system_metrics` table. You can also use the `INSERT INTO` statement to insert multiple records into a table at the same time. Here is an example of an `INSERT INTO` statement that inserts multiple records into the `system_metrics` table: ```sql INSERT INTO system_metrics (host, idc, cpu_util, memory_util, disk_util, ts) VALUES ("host1", "idc_a", 11.8, 10.3, 10.3, 1667446797460), ("host2", "idc_a", 80.1, 70.3, 90.0, 1667446797461), ("host1", "idc_c", 50.1, 66.8, 40.8, 1667446797463); ``` This statement inserts three records into the `system_metrics` table with the specified values for each column. #### Insert Data with Default Values The following sql statement use `DEFAULT` keyword to insert the default value for the `cpu_util` column: ```sql INSERT INTO system_metrics (host, idc, cpu_util, memory_util, disk_util, ts) VALUES ("host1", "idc_a", DEFAULT, 10.3, 10.3, 1667446797460); ``` #### Insert Binary Data When we want to insert binary data which their column datatypes are `blob` or `bytea`: ```sql CREATE TABLE test(b BLOB, ts TIMESTAMP TIME INDEX); ``` Recommend using the prepared statement, JDBC for example: ```java PreparedStatement pstmt = conn.prepareStatement("insert into test values(?,?)"); pstmt.setBytes(1, "hello".getBytes()); pstmt.setInt(2, 1687867163); pstmt.addBatch(); ...... pstmt.executeBatch(); ``` If we want to insert a literal binary, we can insert a hexadecimal literal: ```sql INSERT INTO test VALUES(X'9fad5e9eefdfb449', 1687867163); -- or -- INSERT INTO test VALUES(0x9fad5e9eefdfb449, 1687867163); ``` #### Insert Special Numeric Values Use `{Value}::{Type}` to cast `Infinity`, `-Infinity`, and `NaN` into the desired numeric type: ```sql INSERT INTO system_metrics (host, idc, cpu_util, memory_util, disk_util, ts) VALUES ("host1", "idc_a", 66.6, 'NaN'::double, 'Infinity'::double, 1667446797460); ``` ## `INSERT INTO SELECT` Statement The statement copies data from one table and inserts it into another table. ### Syntax The syntax for the `INSERT INTO SELECT` statement is as follows: ```sql INSERT INTO table2 (column1, column2, ...) SELECT column1, column2, ... FROM table1; ``` In the above syntax, `table1` is the source table from which you want to copy data, and `table2` is the target table into which the data will be inserted. `table1` and `table2` should have the same names and data types for the columns that you want to copy. The `SELECT` statement selects the columns you want to insert from the source table. If you do not specify the column names in the `INSERT INTO` statement, then the data will be inserted into all columns in the target table. The `INSERT INTO SELECT` statement is useful when you want to copy data from one table to another, for example when archiving or backing up data. It is more efficient than creating a backup of the entire database and restoring it. ### Examples Here is an example of an `INSERT INTO SELECT` statement: ```sql INSERT INTO system_metrics2 (host, idc, cpu_util, memory_util, disk_util, ts) SELECT host, idc, cpu_util, memory_util, disk_util, ts FROM system_metrics; ``` --- ## JOIN `JOIN` is used to combine rows from two or more tables based on a related column between them. It allows you to extract data from multiple tables and present it as a single result set. There are several types of JOIN clauses: - INNER JOIN: Returns only the rows that have matching values in both tables. - LEFT JOIN: Returns all the rows from the left table and the matching rows from the right table. - RIGHT JOIN: Returns all the rows from the right table and the matching rows from the left table. - FULL OUTER JOIN: Returns all the rows from both tables. ## Examples Here are some examples of using JOIN clauses: ```sql -- Select all rows from the system_metrics table and idc_info table where the idc_id matches SELECT a.* FROM system_metrics a JOIN idc_info b ON a.idc = b.idc_id; -- Select all rows from the idc_info table and system_metrics table where the idc_id matches, and include null values for idc_info without any matching system_metrics SELECT a.* FROM idc_info a LEFT JOIN system_metrics b ON a.idc_id = b.idc; -- Select all rows from the system_metrics table and idc_info table where the idc_id matches, and include null values for idc_info without any matching system_metrics SELECT b.* FROM system_metrics a RIGHT JOIN idc_info b ON a.idc = b.idc_id; ``` --- ## LIMIT `LIMIT` clause is used to limit the number of rows returned by a query. This clause is particularly useful when working with large data sets, as it allows for faster query performance by reducing the amount of data that needs to be processed. ## Syntax The basic syntax of the `LIMIT` clause is as follows: ```sql SELECT column1, column2, ... FROM table_name LIMIT number_of_rows; ``` The number_of_rows parameter specifies the maximum number of rows to be returned. If the value of this parameter is negative, no rows will be returned. ## Examples Consider the following table named "system_metrics": ```sql +-------+-------+----------+-------------+-----------+---------------------+ | host | idc | cpu_util | memory_util | disk_util | ts | +-------+-------+----------+-------------+-----------+---------------------+ | host1 | idc_a | 11.8 | 10.3 | 10.3 | 2022-11-03 03:39:57 | | host1 | idc_b | 50 | 66.7 | 40.6 | 2022-11-03 03:39:57 | | host1 | idc_c | 50.1 | 66.8 | 40.8 | 2022-11-03 03:39:57 | | host1 | idc_e | NULL | 66.7 | 40.6 | 2022-11-03 03:39:57 | | host2 | idc_a | 80.1 | 70.3 | 90 | 2022-11-03 03:39:57 | +-------+-------+----------+-------------+-----------+---------------------+ ``` To retrieve the top 3 rows by `memory_util`, we can use the`LIMIT` clause: ```sql SELECT host, idc, memory_util FROM system_metrics ORDER BY memory_util DESC LIMIT 3; ``` The result of the above query would be: ```sql +-------+-------+-------------+ | host | idc | memory_util | +-------+-------+-------------+ | host2 | idc_a | 70.3 | | host1 | idc_c | 66.8 | | host1 | idc_b | 66.7 | +-------+-------+-------------+ ``` `LIMIT n, m` allows to select the m rows from the result after skipping the first n rows. The `LIMIT m OFFSET n` syntax is equivalent. ```sql SELECT host, idc, memory_util FROM system_metrics ORDER BY memory_util DESC LIMIT 2 OFFSET 1; ``` OR ```sql SELECT host, idc, memory_util FROM system_metrics ORDER BY memory_util DESC LIMIT 1, 2; ``` The result of the above query would be: ```sql +-------+-------+-------------+ | host | idc | memory_util | +-------+-------+-------------+ | host1 | idc_c | 66.8 | | host1 | idc_b | 66.7 | +-------+-------+-------------+ ``` --- ## OFFSET The `OFFSET` clause specifies how many rows to skip before starting to return rows from a query. It's commonly used with LIMIT for paginating through large result sets. For example: ```sql SELECT * FROM system_metrics ORDER BY cpu_util DESC LIMIT 10 OFFSET 10; ``` It selects all columns from rows ranked 11th to 20th (by descending `cpu_util`) from the `system_metrics` table. Although combining `OFFSET` and `LIMIT` with an `ORDER BY` clause can achieve pagination, this approach is not very efficient. We recommend recording the time index (timestamp) of the last record returned on each page and using this value to filter and limit the data for subsequent pages. This method provides much better pagination performance. ## Efficient Pagination Using Timestamps Suppose your `system_metrics` table has a `ts` column that acts as a time index (timestamp). You can use the last record’s timestamp from the previous page to efficiently fetch the next page. First Page (Latest 10 Records): ```sql SELECT * FROM system_metrics ORDER BY ts DESC LIMIT 10; ``` Second Page (Using Last Timestamp from Previous Page): If the last record from the first page has a `ts` value of `'2024-07-01 16:03:00'`, you can get the next page like this: ```sql SELECT * FROM system_metrics WHERE ts < '2024-07-01 16:03:00' ORDER BY ts DESC LIMIT 10; ``` After each query, record the `ts` value of the last row and use it for the next query’s filter. This method eliminates the need to scan and skip rows (as with OFFSET), making pagination much more efficient, especially for large tables. --- ## ORDER BY The `ORDER BY` clause is used to order the data in ascending or descending order based on one or more columns in the `SELECT` statement. ## Syntax The basic syntax of the `ORDER BY` clause is as follows: ```sql SELECT column1, column2, ... FROM table_name ORDER BY column1 [ASC | DESC], column2 [ASC | DESC], ...; ``` The `ORDER BY` clause can be used with one or more columns. The ASC keyword is used to sort the data in ascending order (default), and the DESC keyword is used to sort the data in descending order. ## Examples Consider the following table named "system_metrics": ```sql +-------+-------+----------+-------------+-----------+---------------------+ | host | idc | cpu_util | memory_util | disk_util | ts | +-------+-------+----------+-------------+-----------+---------------------+ | host1 | idc_a | 11.8 | 10.3 | 10.3 | 2022-11-03 03:39:57 | | host1 | idc_b | 50 | 66.7 | 40.6 | 2022-11-03 03:39:57 | | host1 | idc_c | 50.1 | 66.8 | 40.8 | 2022-11-03 03:39:57 | | host1 | idc_e | NULL | 66.7 | 40.6 | 2022-11-03 03:39:57 | | host2 | idc_a | 80.1 | 70.3 | 90 | 2022-11-03 03:39:57 | +-------+-------+----------+-------------+-----------+---------------------+ ``` To sort the data in ascending order based on the "memory_util" column, the following SQL query can be used: ```sql SELECT * FROM system_metrics ORDER BY memory_util ASC; ``` The result of the above query would be: ```sql +-------+-------+----------+-------------+-----------+---------------------+ | host | idc | cpu_util | memory_util | disk_util | ts | +-------+-------+----------+-------------+-----------+---------------------+ | host1 | idc_a | 11.8 | 10.3 | 10.3 | 2022-11-03 03:39:57 | | host1 | idc_b | 50 | 66.7 | 40.6 | 2022-11-03 03:39:57 | | host1 | idc_e | NULL | 66.7 | 40.6 | 2022-11-03 03:39:57 | | host1 | idc_c | 50.1 | 66.8 | 40.8 | 2022-11-03 03:39:57 | | host2 | idc_a | 80.1 | 70.3 | 90 | 2022-11-03 03:39:57 | +-------+-------+----------+-------------+-----------+---------------------+ ``` To sort the data in descending order based on the "disk_util" column, the following SQL query can be used: ```sql SELECT * FROM system_metrics ORDER BY disk_util DESC; ``` The result of the above query would be: ```sql +-------+-------+----------+-------------+-----------+---------------------+ | host | idc | cpu_util | memory_util | disk_util | ts | +-------+-------+----------+-------------+-----------+---------------------+ | host2 | idc_a | 80.1 | 70.3 | 90 | 2022-11-03 03:39:57 | | host1 | idc_c | 50.1 | 66.8 | 40.8 | 2022-11-03 03:39:57 | | host1 | idc_b | 50 | 66.7 | 40.6 | 2022-11-03 03:39:57 | | host1 | idc_e | NULL | 66.7 | 40.6 | 2022-11-03 03:39:57 | | host1 | idc_a | 11.8 | 10.3 | 10.3 | 2022-11-03 03:39:57 | +-------+-------+----------+-------------+-----------+---------------------+ ``` --- ## SQL(Sql) ## Data Types * [Data Types](data-types.md) ## Statements and Clauses * [ADMIN](./admin.md) * [ALTER](./alter.md) * [ANSI Compatibility](./compatibility.md) * [CASE](./case.md) * [CAST](./cast.md) * [COPY](./copy.md) * [CREATE](./create.md) * [DELETE](./delete.md) * [DESCRIBE TABLE](./describe_table.md) * [DISTINCT](./distinct.md) * [DROP](./drop.md) * [EXPLAIN](./explain.md) * [GROUP BY](./group_by.md) * [HAVING](./having.md) * [INSERT](./insert.md) * [JOIN](./join.md) * [LIMIT](./limit.md) * [OFFSET](./offset.md) * [ORDER BY](./order_by.md) * [RANGE](./range.md) * [REPLACE](./replace.md) * [SELECT](./select.md) * [SHOW](./show.md) * [TQL](./tql.md) * [TRUNCATE](./truncate.md) * [WHERE](./where.md) * [WITH](./with.md) ## Functions * [Functions](./functions/overview.md) ## Information Schema * [INFORMATION_SCHEMA](./information-schema/overview.md) ## Greptime Private * [Greptime Private](./greptime-private/overview.md) --- ## RANGE QUERY Querying and aggregating data within a range of time is a common query pattern for time series data, such as the `Range selector` in `PromQL`. GreptimeDB supports Range queries in SQL, which is used to summarize time series data into time chunks and aggregate data on time chunks. As part of the `SELECT` statement, Range query can be flexibly combined with SQL to provide more powerful time series data query capabilities in SQL. ## Syntax Range query uses `Time Index` column as the timeline basis for aggregation. A legal Range query syntax structure is as follows: ```sql SELECT AGGR_FUNCTION(column1, column2,..) RANGE INTERVAL [FILL FILL_OPTION], ... FROM table_name [ WHERE ] ALIGN INTERVAL [ TO TO_OPTION ] [BY (columna, columnb,..)] [FILL FILL_OPTION] [ ORDER BY ] [ LIMIT ]; INTERVAL := TIME_INTERVAL | ( INTERVAL expr ) ``` - Keyword `ALIGN`, required field, followed by parameter `INTERVAL`, `ALIGN` specifies the step of Range query. - Subkeyword `TO`, optional field, specifies the time point to which Range query is aligned. For legal `TO_OPTION` parameters, see [TO Option](#to-option). - Subkeyword `BY`, optional field, followed by parameter `(columna, columnb,..)`, describes the aggregate key. For legal `BY_OPTION` parameters, see [BY Option](#by-option). - The parameter `INTERVAL` is mainly used to give the length of a period of time. There are two parameter forms: - Strings based on the `PromQL Time Durations` format (eg: `3h`, `1h30m`). Visit the [Prometheus documentation](https://prometheus.io/docs/prometheus/latest/querying/basics/#float-literals-and-time-durations) for a more detailed description of this format. - `Interval` type. To use the `Interval` type, you need to carry parentheses, (for example: `('1 year 3 hours 20 minutes'::INTERVAL)`). Visit [Interval](./data-types.md#interval-type) for a more detailed description of this format. - `AGGR_FUNCTION(column1, column2,..) RANGE INTERVAL [FILL FILL_OPTION]` is called a Range expression. - `AGGR_FUNCTION(column1, column2,..)` is an aggregate function that represents the expression that needs to be aggregated. - Keyword `RANGE`, required field, followed by parameter `INTERVAL` specifies the time range of each data aggregation. - Keyword `FILL`, optional field, please see [`FILL` Option](#fill-option) for details. - Range expressions can be combined with other operations to implement more complex queries. For details, see [Nested Range Expressions](#nested-range-expressions). - `FILL` keyword after `ALIGN`, optional field. See [FILL Option](#fill-option) for details. ## `FILL` Option The `FILL` option specifies the data filling method when there is no data in an aggregated time slot, or the value of the aggregate field is empty. The `FILL` keyword can be used after the `RANGE` keyword to indicate the filling method for the Range expression. The `FILL` keyword can also be used after the `ALIGN` keyword to specify the default filling method for a Range expression if no fill option is provided. For example, in the following SQL code, the `max(val) RANGE '10s'` Range expression uses the fill option `LINEAR`, while the `min(val) RANGE '10s'` Range expression, which does not specify a fill option, uses the fill option `PREV` specified after the `ALIGN` keyword. ```sql SELECT ts, host, min(val) RANGE '10s', max(val) RANGE '10s' FILL LINEAR FROM host_val ALIGN '5s' BY (host) FILL PREV; ``` `FILL` has the following filling methods: | FILL | DESCRIPTION | | :------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | | `NULL` | Fill directly with `NULL` | | `PREV` | Fill with data from previous point | | `LINEAR` | Use [linear interpolation](https://en.wikipedia.org/wiki/Linear_interpolation) to fill the data. If an integer type is filled with `LINEAR`, the variable type of the column will be implicitly converted to a floating point type during calculation | | `X` | Fill in a constant, the data type of the constant must be consistent with the variable type of the Range expression | Take the following table as an example: ```sql DROP TABLE IF EXISTS host_val; CREATE TABLE host_val ( ts TIMESTAMP TIME INDEX, host STRING, val DOUBLE, PRIMARY KEY (host) ); INSERT INTO host_val VALUES ('1970-01-01 00:00:00', 'host1', 0), ('1970-01-01 00:00:15', 'host1', 6), ('1970-01-01 00:00:00', 'host2', 6), ('1970-01-01 00:00:15', 'host2', 12); ``` ```sql +---------------------+-------+------+ | ts | host | val | +---------------------+-------+------+ | 1970-01-01 00:00:00 | host1 | 0 | | 1970-01-01 00:00:15 | host1 | 6 | | 1970-01-01 00:00:00 | host2 | 6 | | 1970-01-01 00:00:15 | host2 | 12 | +---------------------+-------+------+ ``` The result of each `FILL` option is as follows: ```sql SELECT ts, host, min(val) RANGE '5s' FROM host_val ALIGN '5s'; ``` ```sql +---------------------+-------+----------------------------+ | ts | host | min(host_val.val) RANGE 5s | +---------------------+-------+----------------------------+ | 1970-01-01 00:00:00 | host1 | 0 | | 1970-01-01 00:00:15 | host1 | 6 | | 1970-01-01 00:00:00 | host2 | 6 | | 1970-01-01 00:00:15 | host2 | 12 | +---------------------+-------+----------------------------+ ``` ```sql SELECT ts, host, min(val) RANGE '5s' FILL NULL FROM host_val ALIGN '5s'; ``` ```sql +---------------------+-------+--------------------------------------+ | ts | host | min(host_val.val) RANGE 5s FILL NULL | +---------------------+-------+--------------------------------------+ | 1970-01-01 00:00:00 | host2 | 6 | | 1970-01-01 00:00:05 | host2 | NULL | | 1970-01-01 00:00:10 | host2 | NULL | | 1970-01-01 00:00:15 | host2 | 12 | | 1970-01-01 00:00:00 | host1 | 0 | | 1970-01-01 00:00:05 | host1 | NULL | | 1970-01-01 00:00:10 | host1 | NULL | | 1970-01-01 00:00:15 | host1 | 6 | +---------------------+-------+--------------------------------------+ ``` ```sql SELECT ts, host, min(val) RANGE '5s' FILL PREV FROM host_val ALIGN '5s'; ``` ```sql +---------------------+-------+--------------------------------------+ | ts | host | min(host_val.val) RANGE 5s FILL PREV | +---------------------+-------+--------------------------------------+ | 1970-01-01 00:00:00 | host1 | 0 | | 1970-01-01 00:00:05 | host1 | 0 | | 1970-01-01 00:00:10 | host1 | 0 | | 1970-01-01 00:00:15 | host1 | 6 | | 1970-01-01 00:00:00 | host2 | 6 | | 1970-01-01 00:00:05 | host2 | 6 | | 1970-01-01 00:00:10 | host2 | 6 | | 1970-01-01 00:00:15 | host2 | 12 | +---------------------+-------+--------------------------------------+ ``` ```sql SELECT ts, host, min(val) RANGE '5s' FILL LINEAR FROM host_val ALIGN '5s'; ``` ```sql +---------------------+-------+----------------------------------------+ | ts | host | min(host_val.val) RANGE 5s FILL LINEAR | +---------------------+-------+----------------------------------------+ | 1970-01-01 00:00:00 | host2 | 6 | | 1970-01-01 00:00:05 | host2 | 8 | | 1970-01-01 00:00:10 | host2 | 10 | | 1970-01-01 00:00:15 | host2 | 12 | | 1970-01-01 00:00:00 | host1 | 0 | | 1970-01-01 00:00:05 | host1 | 2 | | 1970-01-01 00:00:10 | host1 | 4 | | 1970-01-01 00:00:15 | host1 | 6 | +---------------------+-------+----------------------------------------+ ``` ```sql [FILL Constant Value 6.0] SELECT ts, host, min(val) RANGE '5s' FILL 6 FROM host_val ALIGN '5s'; ``` ```sql +---------------------+-------+-----------------------------------+ | ts | host | min(host_val.val) RANGE 5s FILL 6 | +---------------------+-------+-----------------------------------+ | 1970-01-01 00:00:00 | host2 | 6 | | 1970-01-01 00:00:05 | host2 | 6 | | 1970-01-01 00:00:10 | host2 | 6 | | 1970-01-01 00:00:15 | host2 | 12 | | 1970-01-01 00:00:00 | host1 | 0 | | 1970-01-01 00:00:05 | host1 | 6 | | 1970-01-01 00:00:10 | host1 | 6 | | 1970-01-01 00:00:15 | host1 | 6 | +---------------------+-------+-----------------------------------+ ``` If there are multiple Range expressions but only one of them specifies the `Fill` option, the other Range expressions will use the `FILL NULL` method to fill in the missing time slots. The following two SQL statements are equivalent in output: ```sql SELECT ts, host, min(val) RANGE '10s', max(val) RANGE '10s' FILL LINEAR FROM host_val ALIGN '5s'; ``` ```sql SELECT ts, host, min(val) RANGE '10s' FILL NULL, max(val) RANGE '10s' FILL LINEAR FROM host_val ALIGN '5s'; ``` The result of the above SQL is as follows: ```sql +---------------------+-------+---------------------------------------+-----------------------------------------+ | ts | host | min(host_val.val) RANGE 10s FILL NULL | max(host_val.val) RANGE 10s FILL LINEAR | +---------------------+-------+---------------------------------------+-----------------------------------------+ | 1969-12-31 23:59:55 | host1 | 0 | 0 | | 1970-01-01 00:00:00 | host1 | 0 | 0 | | 1970-01-01 00:00:05 | host1 | NULL | 2.9999999999999996 | | 1970-01-01 00:00:10 | host1 | 6 | 6 | | 1970-01-01 00:00:15 | host1 | 6 | 6 | | 1969-12-31 23:59:55 | host2 | 6 | 6 | | 1970-01-01 00:00:00 | host2 | 6 | 6 | | 1970-01-01 00:00:05 | host2 | NULL | 9 | | 1970-01-01 00:00:10 | host2 | 12 | 12 | | 1970-01-01 00:00:15 | host2 | 12 | 12 | +---------------------+-------+---------------------------------------+-----------------------------------------+ ``` ## `TO` Option The `TO` keyword specifies the origin time point to which the range query is aligned. `TO` option along with `RANGE` option and `ALIGN INTERVAL` determine the time range windows. Please refer to [Time Range Window](/user-guide/query-data/sql.md#time-range-window) for details. The default value of the `TO` option is the current query client timezone. To set the timezone, please refer to [MySQL client](/user-guide/protocols/mysql.md#time-zone) or [PostgreSQL client](/user-guide/protocols/postgresql.md#time-zone). Other valid `TO` options are: | TO | DESCRIPTION | | :---------: | :----------------------------------------------------------------------------------: | | `NOW` | Align to current query time | | `Timestamp` | Align to a user-specified timestamp, supports timestamp format `RFC3339` / `ISO8601` | Suppose we have a table `host_val` with the following data: ```sql DROP TABLE IF EXISTS host_val; CREATE TABLE host_val ( ts TIMESTAMP TIME INDEX, host STRING, val DOUBLE, PRIMARY KEY (host) ); INSERT INTO host_val VALUES ('2023-01-01 23:00:00', 'host1', 0), ('2023-01-02 01:00:00', 'host1', 1), ('2023-01-01 23:00:00', 'host2', 2), ('2023-01-02 01:00:00', 'host2', 3); ``` ```sql +---------------------+-------+------+ | ts | host | val | +---------------------+-------+------+ | 2023-01-01 23:00:00 | host1 | 0 | | 2023-01-02 01:00:00 | host1 | 1 | | 2023-01-01 23:00:00 | host2 | 2 | | 2023-01-02 01:00:00 | host2 | 3 | +---------------------+-------+------+ ``` The query results by each `TO` options shown below: ```sql -- Querying the database timezone using the MySQL protocol, currently in the UTC timezone SELECT @@time_zone; ``` ```sql +-------------+ | @@time_zone | +-------------+ | UTC | +-------------+ ``` ```sql -- If we do not specify the `TO` keyword, -- the timezone will be used as the default origin alignment time. SELECT ts, host, min(val) RANGE '1d' FROM host_val ALIGN '1d'; ``` ```sql +---------------------+-------+----------------------------+ | ts | host | min(host_val.val) RANGE 1d | +---------------------+-------+----------------------------+ | 2023-01-01 00:00:00 | host1 | 0 | | 2023-01-02 00:00:00 | host1 | 1 | | 2023-01-01 00:00:00 | host2 | 2 | | 2023-01-02 00:00:00 | host2 | 3 | +---------------------+-------+----------------------------+ ``` ```sql -- If you want to align the origin time to the current time, -- use the `NOW` keyword. -- Assume that the current query time is `2023-01-02T09:16:40.503000`. SELECT ts, host, min(val) RANGE '1d' FROM host_val ALIGN '1d' TO NOW; ``` ```sql +----------------------------+-------+----------------------------+ | ts | host | min(host_val.val) RANGE 1d | +----------------------------+-------+----------------------------+ | 2023-01-01 09:54:55.456000 | host1 | 0 | | 2023-01-01 09:54:55.456000 | host2 | 2 | +----------------------------+-------+----------------------------+ ``` ```sql -- If you want to align the origin time to a specific timestamp, -- for example, "+08:00" Beijing time on December 1, 2023, -- you can set the `TO` option to the specific timestamp '2023-01-01T00:00:00+08:00'. SELECT ts, host, min(val) RANGE '1d' FROM host_val ALIGN '1d' TO '2023-01-01T00:00:00+08:00'; ``` ```sql +---------------------+-------+----------------------------+ | ts | host | min(host_val.val) RANGE 1d | +---------------------+-------+----------------------------+ | 2023-01-01 16:00:00 | host1 | 0 | | 2023-01-01 16:00:00 | host2 | 2 | +---------------------+-------+----------------------------+ ``` If you want to query data for a specific time range, you can specify the timestamp using the `TO` keyword. For example, to query the daily minimum value of `val` between `00:45` and `06:45`, you can use `2023-01-01T00:45:00` as the `TO` option along with a `6h` range. ```sql SELECT ts, host, min(val) RANGE '6h' FROM host_val ALIGN '1d' TO '2023-01-01T00:45:00'; ``` ```sql +---------------------+-------+----------------------------+ | ts | host | min(host_val.val) RANGE 6h | +---------------------+-------+----------------------------+ | 2023-01-02 00:45:00 | host2 | 3 | | 2023-01-02 00:45:00 | host1 | 1 | +---------------------+-------+----------------------------+ ``` ## `BY` Option `BY` option describes the aggregate key. If this field is not given, the primary key of the table is used as the aggregate key by default. If the table does not specify a primary key, the `BY` keyword cannot be omitted. Suppose we have a tale `host_val` with the following data: ```sql DROP TABLE IF EXISTS host_val; CREATE TABLE host_val ( ts TIMESTAMP TIME INDEX, host STRING, val DOUBLE, PRIMARY KEY (host) ); INSERT INTO host_val VALUES ('2023-01-01 23:00:00', 'host1', 0), ('2023-01-02 01:00:00', 'host1', 1), ('2023-01-01 23:00:00', 'host2', 2), ('2023-01-02 01:00:00', 'host2', 3); ``` ```sql +---------------------+-------+------+ | ts | host | val | +---------------------+-------+------+ | 2023-01-01 23:00:00 | host1 | 0 | | 2023-01-02 01:00:00 | host1 | 1 | | 2023-01-01 23:00:00 | host2 | 2 | | 2023-01-02 01:00:00 | host2 | 3 | +---------------------+-------+------+ ``` The following SQL uses `host` as the aggregate key: ```sql SELECT ts, host, min(val) RANGE '10s' FROM host_val ALIGN '5s' BY (host); ``` ```sql +---------------------+-------+-----------------------------+ | ts | host | min(host_val.val) RANGE 10s | +---------------------+-------+-----------------------------+ | 2023-01-01 22:59:55 | host1 | 0 | | 2023-01-01 23:00:00 | host1 | 0 | | 2023-01-02 00:59:55 | host1 | 1 | | 2023-01-02 01:00:00 | host1 | 1 | | 2023-01-01 22:59:55 | host2 | 2 | | 2023-01-01 23:00:00 | host2 | 2 | | 2023-01-02 00:59:55 | host2 | 3 | | 2023-01-02 01:00:00 | host2 | 3 | +---------------------+-------+-----------------------------+ ``` You can also use the `BY` keyword to declare other columns as the basis for data aggregation. For example, the following RANGE query uses the string length `length(host)` of the `host` column as the basis for data aggregation. ```sql SELECT ts, length(host), min(val) RANGE '10s' FROM host_val ALIGN '5s' BY (length(host)); ``` Get after running ```sql +---------------------+---------------------------------+-----------------------------+ | ts | character_length(host_val.host) | min(host_val.val) RANGE 10s | +---------------------+---------------------------------+-----------------------------+ | 2023-01-01 22:59:55 | 5 | 0 | | 2023-01-01 23:00:00 | 5 | 0 | | 2023-01-02 00:59:55 | 5 | 1 | | 2023-01-02 01:00:00 | 5 | 1 | +---------------------+---------------------------------+-----------------------------+ ``` You can explicitly use `BY ()`, which means you do not need to use aggregation keys and aggregate all data into a group. **However, if you omit the `BY` keyword directly, it means using the primary key of the table as the aggregate key.** ```sql SELECT ts, min(val) RANGE '10s' FROM host_val ALIGN '5s' BY (); ``` Get after running ```sql +---------------------+-----------------------------+ | ts | min(host_val.val) RANGE 10s | +---------------------+-----------------------------+ | 2023-01-01 22:59:55 | 0 | | 2023-01-01 23:00:00 | 0 | | 2023-01-02 00:59:55 | 1 | | 2023-01-02 01:00:00 | 1 | +---------------------+-----------------------------+ ``` ## `ORDER BY` option in aggregate functions Range queries support the use of `order by` expressions in the parameters of the `first_value` and `last_value` aggregate functions. By default, the data is sorted in ascending order based on the time index column. Take this table as an example: ```sql DROP TABLE IF EXISTS host_val; CREATE TABLE host_val ( ts TIMESTAMP TIME INDEX, host STRING, val DOUBLE, addon DOUBLE, PRIMARY KEY (host) ); INSERT INTO host_val VALUES ('1970-01-01 00:00:00', 'host1', 0, 3), ('1970-01-01 00:00:01', 'host1', 1, 2), ('1970-01-01 00:00:02', 'host1', 2, 1); ``` ```sql +---------------------+-------+------+-------+ | ts | host | val | addon | +---------------------+-------+------+-------+ | 1970-01-01 00:00:00 | host1 | 0 | 3 | | 1970-01-01 00:00:01 | host1 | 1 | 2 | | 1970-01-01 00:00:02 | host1 | 2 | 1 | +---------------------+-------+------+-------+ ``` When the `order by` expression is not specified in the function parameter, the default behavior is to sort the data in ascending order based on the time index column. The following two SQL statements are equivalent: ```sql SELECT ts, first_value(val) RANGE '5s', last_value(val) RANGE '5s' FROM host_val ALIGN '5s'; ``` ```sql SELECT ts, first_value(val order by ts ASC) RANGE '5s', last_value(val order by ts ASC) RANGE '5s' FROM host_val ALIGN '5s'; ``` Get after query ```sql +---------------------+------------------------------------+-----------------------------------+ | ts | first_value(host_val.val) RANGE 5s | last_value(host_val.val) RANGE 5s | +---------------------+------------------------------------+-----------------------------------+ | 1970-01-01 00:00:00 | 0 | 2 | +---------------------+------------------------------------+-----------------------------------+ ``` You can specify your own sorting rules. For example, the following SQL sorts the data by the `addon` column in ascending order: ```sql SELECT ts, first_value(val ORDER BY addon ASC) RANGE '5s', last_value(val ORDER BY addon ASC) RANGE '5s' FROM host_val ALIGN '5s'; ``` Get after query ```sql +---------------------+-----------------------------------------------------------------------------+----------------------------------------------------------------------------+ | ts | first_value(host_val.val) ORDER BY [host_val.addon ASC NULLS LAST] RANGE 5s | last_value(host_val.val) ORDER BY [host_val.addon ASC NULLS LAST] RANGE 5s | +---------------------+-----------------------------------------------------------------------------+----------------------------------------------------------------------------+ | 1970-01-01 00:00:00 | 2 | 0 | +---------------------+-----------------------------------------------------------------------------+----------------------------------------------------------------------------+ ``` ## Nested Range Expressions Range expressions support flexible nesting, and range expressions can be combined with various operations to provide more powerful query capabilities. Take the following table as an example: ```sql DROP TABLE IF EXISTS host_val; CREATE TABLE host_val ( ts TIMESTAMP TIME INDEX, host STRING, val DOUBLE, PRIMARY KEY (host) ); INSERT INTO host_val VALUES ('2023-01-01 08:00:00', 'host1', 1.1), ('2023-01-01 08:00:05', 'host1', 2.2), ('2023-01-01 08:00:00', 'host2', 3.3), ('2023-01-01 08:00:05', 'host2', 4.4); ``` ```sql +---------------------+-------+------+ | ts | host | val | +---------------------+-------+------+ | 2023-01-01 08:00:00 | host1 | 1.1 | | 2023-01-01 08:00:05 | host1 | 2.2 | | 2023-01-01 08:00:00 | host2 | 3.3 | | 2023-01-01 08:00:05 | host2 | 4.4 | +---------------------+-------+------+ ``` 1. Aggregation functions support calculations both internally and externally: ```sql SELECT ts, host, 2.0 * min(val * 2.0) RANGE '10s' FROM host_val ALIGN '5s'; ``` Get after running ```sql +---------------------+-------+-------------------------------------------------------+ | ts | host | Float64(2) * min(host_val.val * Float64(2)) RANGE 10s | +---------------------+-------+-------------------------------------------------------+ | 2023-01-01 07:59:55 | host1 | 4.4 | | 2023-01-01 08:00:00 | host1 | 4.4 | | 2023-01-01 08:00:05 | host1 | 8.8 | | 2023-01-01 07:59:55 | host2 | 13.2 | | 2023-01-01 08:00:00 | host2 | 13.2 | | 2023-01-01 08:00:05 | host2 | 17.6 | +---------------------+-------+-------------------------------------------------------+ ``` 2. Scalar functions are supported both inside and outside aggregate functions: - `min(round(val)) RANGE '10s'` means that each value is rounded using the `round` function before aggregation - `round(min(val) RANGE '10s')` means rounding the result of each aggregation using the `round` function ```sql SELECT ts, host, min(round(val)) RANGE '10s' FROM host_val ALIGN '5s'; ``` Get after running ```sql +---------------------+-------+------------------------------------+ | ts | host | min(round(host_val.val)) RANGE 10s | +---------------------+-------+------------------------------------+ | 2023-01-01 07:59:55 | host1 | 1 | | 2023-01-01 08:00:00 | host1 | 1 | | 2023-01-01 08:00:05 | host1 | 2 | | 2023-01-01 07:59:55 | host2 | 3 | | 2023-01-01 08:00:00 | host2 | 3 | | 2023-01-01 08:00:05 | host2 | 4 | +---------------------+-------+------------------------------------+ ``` ```sql SELECT ts, host, round(min(val) RANGE '10s') FROM host_val ALIGN '5s'; ``` Get after running ```sql +---------------------+-------+------------------------------------+ | ts | host | round(min(host_val.val) RANGE 10s) | +---------------------+-------+------------------------------------+ | 2023-01-01 07:59:55 | host2 | 3 | | 2023-01-01 08:00:00 | host2 | 3 | | 2023-01-01 08:00:05 | host2 | 4 | | 2023-01-01 07:59:55 | host1 | 1 | | 2023-01-01 08:00:00 | host1 | 1 | | 2023-01-01 08:00:05 | host1 | 2 | +---------------------+-------+------------------------------------+ ``` 3. Multiple Range expressions can also evaluate together, and Range expressions support the distributive law. The following two Range query are legal and equivalent: ```sql SELECT ts, host, max(val) RANGE '10s' - min(val) RANGE '10s' FROM host_val ALIGN '5s'; ``` ```sql SELECT ts, host, (max(val) - min(val)) RANGE '10s' FROM host_val ALIGN '5s'; ``` Get after running ```sql +---------------------+-------+-----------------------------------------------------------+ | ts | host | max(host_val.val) RANGE 10s - min(host_val.val) RANGE 10s | +---------------------+-------+-----------------------------------------------------------+ | 2023-01-01 07:59:55 | host2 | 0 | | 2023-01-01 08:00:00 | host2 | 1.1000000000000005 | | 2023-01-01 08:00:05 | host2 | 0 | | 2023-01-01 07:59:55 | host1 | 0 | | 2023-01-01 08:00:00 | host1 | 1.1 | | 2023-01-01 08:00:05 | host1 | 0 | +---------------------+-------+-----------------------------------------------------------+ ``` But note that the `RANGE` keyword apply to the expression before the `RANGE` keyword. The following Range query is illegal because the `RANGE` keyword apply to the expression `2.0`, not the expression `min(val * 2.0) * 2.0` ```sql SELECT ts, host, min(val * 2.0) * 2.0 RANGE '10s' FROM host_val ALIGN '5s'; ``` ```sql ERROR 1815 (HY000): sql parser error: Can't use the RANGE keyword in Expr 2.0 without function ``` Expressions can be bracketed, and the `RANGE` keyword is automatically applied to any aggregate functions contained within the brackets: ```sql SELECT ts, host, (min(val * 2.0) * 2.0) RANGE '10s' FROM host_val ALIGN '5s'; ``` After running, we get: ```sql +---------------------+-------+-------------------------------------------------------+ | ts | host | min(host_val.val * Float64(2)) RANGE 10s * Float64(2) | +---------------------+-------+-------------------------------------------------------+ | 2023-01-01 07:59:55 | host2 | 13.2 | | 2023-01-01 08:00:00 | host2 | 13.2 | | 2023-01-01 08:00:05 | host2 | 17.6 | | 2023-01-01 07:59:55 | host1 | 4.4 | | 2023-01-01 08:00:00 | host1 | 4.4 | | 2023-01-01 08:00:05 | host1 | 8.8 | +---------------------+-------+-------------------------------------------------------+ ``` Nesting of Range expressions is not allowed. Nested Range queries are illegal: ```sql SELECT ts, host, max(min(val) RANGE '10s') RANGE '10s' FROM host_val ALIGN '5s'; ``` ```sql ERROR 1815 (HY000): Range Query: Nest Range Query is not allowed ``` --- ## REPLACE The `REPLACE` statement is used to insert new records into a table. In GreptimeDB, this statement is exactly the same as the `INSERT` statement. Please refer to [`INSERT`](/reference/sql/insert.md) for more details. ## `REPLACE INTO` Statement ### Syntax The syntax for the REPLACE INTO statement is as follows: ```sql REPLACE INTO table_name (column1, column2, column3, ...) VALUES (value1, value2, value3, ...); ``` ### Examples Here is an example of an `REPLACE INTO` statement that inserts a record into a table named `system_metrics`: ```sql REPLACE INTO system_metrics (host, idc, cpu_util, memory_util, disk_util, ts) VALUES ("host1", "idc_b", 50.0, 66.7, 40.6, 1667446797462); ``` Here is an example of an `REPLACE INTO` statement that inserts multiple records into the `system_metrics` table: ```sql REPLACE INTO system_metrics (host, idc, cpu_util, memory_util, disk_util, ts) VALUES ("host1", "idc_a", 11.8, 10.3, 10.3, 1667446797460), ("host2", "idc_a", 80.1, 70.3, 90.0, 1667446797461), ("host1", "idc_c", 50.1, 66.8, 40.8, 1667446797463); ``` --- ## SELECT The `SELECT` statement is the foundation of data retrieval in SQL and GreptimeDB. It allows you to extract specific columns or expressions from one or more tables: ## Basic Syntax The basic syntax for a `SELECT` statement is as follows: ```sql SELECT column1, column2, ... FROM table_name [WHERE condition] [GROUP BY column] [HAVING condition] [ORDER BY column] [LIMIT number] [OFFSET number] ``` Here, column1, column2, etc. refer to the names of the columns from which we want to retrieve data, and table_name refers to the name of the table from which we want to retrieve the data. This statement selects all the columns from the table specified in the `FROM` clause. If you want to select all columns from the table, you can use the asterisk (*) wildcard character instead of listing individual columns. ```sql SELECT * FROM table_name; ``` ## Conditional Filtering (WHERE clause) The `WHERE` clause is used to filter the results of a `SELECT` statement based on a specified condition. The syntax for using WHERE clause is as follows: ```sql SELECT column1, column2, ..., columnN FROM table_name WHERE condition; ``` Here, the condition is an expression that evaluates to either true or false. Only the rows that satisfy the condition will be included in the result set. Supported comparisons include: * Logical operators: `AND`, `OR`, `NOT` * Comparison operators: `=`, `!=`, `>`, `<`, `>=`, `<=` * Pattern matching: `LIKE`, `IN`, `BETWEEN` For example: ```sql -- Select all rows from the system_metrics table where idc is 'idc0' SELECT * FROM system_metrics WHERE idc = 'idc0'; -- Select all rows from the system_metrics table where the idc is 'idc0' or 'idc0' SELECT * FROM system_metrics WHERE idc IN ('idc0', 'idc1'); -- Select all rows from the system_metrics table where the idc is 'idc0' or 'idc0' and the cpu utilization is greater than 60% SELECT * FROM system_metrics WHERE idc IN ('idc0', 'idc1') AND cpu_util > 0.6; ``` Please refer to [WHERE](where.md) for more information. ## Order Results(ORDER BY clause) The `ORDER BY` clause is used to order the data in ascending or descending order based on one or more columns in the SELECT statement. For example: ```sql -- Sort the results by cpu_util in ascending order SELECT * FROM system_metrics ORDER BY cpu_util ASC; -- Sort the results by cpu_util in descending order SELECT * FROM system_metrics ORDER BY cpu_util DESC; ``` Please refer to [ORDER](order_by.md) for more information. ## Limiting Results (LIMIT clause) The `LIMIT` clause is used to limit the number of rows returned by a SELECT statement. The syntax for using `LIMIT` clause is as follows: ```sql SELECT column1, column2, ... FROM table_name LIMIT number_of_rows; ``` Here, the number_of_rows parameter specifies the maximum number of rows to return. Here are some examples of using the `LIMIT` clause: ```sql -- Select the top 10 high cpu rows from the system_metrics table SELECT * FROM system_metrics ORDER BY cpu_util DESC LIMIT 10; ``` ## Pagination Results (LIMIT and OFFSET) The `OFFSET` clause specifies how many rows to skip before starting to return rows from the query. It's commonly used with LIMIT for paginating through large result sets. For example: ```sql SELECT * FROM system_metrics ORDER BY cpu_util DESC LIMIT 10 OFFSET 10; ``` It selects all columns from rows ranked 11th to 20th (by descending `cpu_util`) from the `system_metrics` table. Although combining `OFFSET` and `LIMIT` with an `ORDER BY` clause can achieve pagination, this approach is not very efficient. We recommend recording the time index (timestamp) of the last record returned on each page and using this value to filter and limit the data for subsequent pages. Please refer to [OFFSET](offset.md) for more information. ## Joining Tables (JOIN) The `JOIN` clause is used to combine rows from two or more tables based on a related column between them. The syntax for using `JOIN` clause is as follows: ```sql SELECT column1, column2, ... FROM table1 JOIN table2 ON table1.column = table2.column; ``` Here, the table1 and table2 are the names of the tables to be joined. The column is the related column between the two tables. Please refer to [JOIN](join.md) for more information. ## Grouping and Aggregation (GROUP BY and Aggregate Functions) Use `GROUP BY` to cluster data by one or more columns and perform calculations like counting or averaging within those groups. ```sql SELECT column1, column2, ..., aggregate_function(column) FROM table_name GROUP BY column1, column2, ...; ``` Common aggregate functions supported: * COUNT * SUM * AVG * MAX * MIN For more functions, see [Aggregate Functions](/reference/sql/functions/df-functions.md#aggregate-functions) and [Window Functions](/reference/sql/functions/df-functions.md#window-functions). For example: ```sql -- Select the total number of idc for each idc SELECT idc, COUNT(host) as host_num FROM system_metrics GROUP BY idc; -- Select the idc's average cpu_util SELECT idc, AVG(cpu_util) as cpu_avg FROM system_metrics GROUP BY idc; ``` Please refer to [GROUP BY](group_by.md) for more information. ## Filtering Groups (HAVING clause) The `HAVING` clause allows you to filter grouped (aggregated) results—it works like `WHERE`, but after grouping has taken place. Example: ```sql SELECT DATE_TRUNC('day', event_time) AS log_date, COUNT(*) AS error_count FROM application_logs WHERE log_level = 'ERROR' GROUP BY log_date HAVING error_count > 10; ``` Explanation: * Groups logs by day and counts occurrences where the log level is `'ERROR'`. * Only dates where the number of errors exceeds 10 are returned. Please refer to [HAVING](having.md) for more information. ## RANGE query ```sql SELECT ts, host, min(cpu) RANGE '10s', max(cpu) RANGE '10s' FILL LINEAR FROM host_cpu ALIGN '5s' BY (host) FILL PREV; ``` Please refer to [RANGE QUERY](range.md) for more information. --- ## SHOW The `SHOW` keyword provides database and table information. ## SHOW DATABASES Show all databases: ```sql SHOW [FULL] DATABASES; ``` ```sql +----------+ | Database | +----------+ | public | +----------+ 1 row in set (0.01 sec) ``` Show databases by `LIKE` pattern: ```sql SHOW DATABASES LIKE 'p%'; ``` Show databases by `where` expr: ```sql SHOW DATABASES WHERE Database='test_public_schema'; ``` Show all databases with options: ```sql CREATE DATABASE test WITH(ttl='7d'); SHOW FULL DATABASES; ``` ```sql +--------------------+-------------+ | Database | Options | +--------------------+-------------+ | greptime_private | | | information_schema | | | public | | | test | ttl='7days' | +--------------------+-------------+ ``` ## SHOW CREATE DATABASE Shows the `CREATE DATABASE` statement that creates the named database: ```sql SHOW CREATE DATABASE test; ``` ```sql +----------+------------------------------------------------------------+ | Database | Create Database | +----------+------------------------------------------------------------+ | test | CREATE DATABASE IF NOT EXISTS test WITH( ttl = '7days' ) | +----------+------------------------------------------------------------+ 1 row in set (0.01 sec) ``` ## SHOW TABLES Show all tables: ```sql SHOW TABLES; ``` ```sql +---------+ | Tables | +---------+ | numbers | | scripts | +---------+ 2 rows in set (0.00 sec) ``` Show tables in the `test` database: ```sql SHOW TABLES FROM test; ``` Show tables by `like` pattern: ```sql SHOW TABLES like '%prometheus%'; ``` Show tables by `where` expr: ```sql SHOW TABLES FROM test WHERE Tables='numbers'; ``` ## SHOW FULL TABLES ```sql SHOW FULL TABLES [IN | FROM] [DATABASE] [LIKE pattern] [WHERE query] ``` It will list all tables and table types in the database: ```sql SHOW FULL TABLES; ``` ```sql +---------+------------+ | Tables | Table_type | +---------+------------+ | monitor | BASE TABLE | | numbers | TEMPORARY | +---------+------------+ 2 rows in set (0.00 sec) ``` * `Tables`: the table names. * `Table_type`: the table types, such as `BASE_TABLE`, `TEMPORARY`, and `VIEW` etc. It supports `like` and `where` query too: ```sql SHOW FULL TABLES FROM public like '%mo%'; ``` ```sql +---------+------------+ | Tables | Table_type | +---------+------------+ | monitor | BASE TABLE | +---------+------------+ 1 row in set (0.01 sec) ``` ```sql SHOW FULL TABLES WHERE Table_type='BASE TABLE'; ``` ```sql +---------+------------+ | Tables | Table_type | +---------+------------+ | monitor | BASE TABLE | +---------+------------+ 1 row in set (0.01 sec) ``` ## SHOW CREATE TABLE Shows the `CREATE TABLE` statement that creates the named table: ```sql SHOW CREATE TABLE [table] ``` For example: ```sql SHOW CREATE TABLE system_metrics; ``` ```sql +----------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Table | Create Table | +----------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | system_metrics | CREATE TABLE IF NOT EXISTS `system_metrics` ( `host` STRING NULL, `idc` STRING NULL, `cpu_util` DOUBLE NULL, `memory_util` DOUBLE NULL, `disk_util` DOUBLE NULL, `ts` TIMESTAMP(3) NOT NULL DEFAULT current_timestamp(), TIME INDEX (`ts`), PRIMARY KEY (`host`, `idc`) ) ENGINE=mito WITH( regions = 1 ) | +----------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ``` * `Table`: the table name. * `Create Table`: The SQL to create the table. :::note When a table has no explicit `ttl` or `compaction.*` settings, `SHOW CREATE TABLE` displays the database-level settings in the `WITH(...)` clause. This reflects the actual effective settings for the table, as these options are dynamically resolved at runtime with the following priority: table-level > database-level > defaults. ::: ## SHOW CREATE FLOW Shows the `CREATE FLOW` statement that creates the flow task. For example: ```sql public=> SHOW CREATE FLOW filter_numbers; ``` ```sql Flow | Create Flow ----------------+------------------------------------------------------- filter_numbers | CREATE OR REPLACE FLOW IF NOT EXISTS filter_numbers + | SINK TO out_num_cnt + | AS SELECT number FROM numbers_input WHERE number > 10 (1 row) ``` ## SHOW FLOWS Show all flows: ```sql public=> SHOW FLOWS; ``` ```sql Flows ---------------- filter_numbers (1 row) ``` also support `LIKE` expression: ```sql public=> show flows like "filter%"; ``` ```sql Flows ---------------- filter_numbers (1 row) ``` ## SHOW CREATE VIEW To show the view's definition: ```sql SHOW CREATE VIEW cpu_monitor; ``` ``` +-------------+--------------------------------------------------------------+ | View | Create View | +-------------+--------------------------------------------------------------+ | cpu_monitor | CREATE VIEW cpu_monitor AS SELECT cpu, host, ts FROM monitor | +-------------+--------------------------------------------------------------+ ``` ## SHOW VIEWS List all views: ```sql SHOW VIEWS; ``` ```sql +----------------+ | Views | +----------------+ | cpu_monitor | | memory_monitor | +----------------+ ``` Of course, it supports `LIKE`: ```sql SHOW VIEWS LIKE 'cpu%'; ``` ```sql +-------------+ | Views | +-------------+ | cpu_monitor | +-------------+ ``` And `where`: ```sql SHOW VIEWS WHERE Views = 'memory_monitor'; ``` ```sql +----------------+ | Views | +----------------+ | memory_monitor | +----------------+ ``` ## SHOW PROCESSLIST List all currently running queries, essentially an alias for `SELECT id, catalog, query, elapsed_time FROM INFORMATION_SCHEMA.PROCESS_LIST`: ```sql SHOW PROCESSLIST; ``` Output: ``` +-----------------------+----------+------------------+-----------------+ | Id | Catalog | Query | Elapsed Time | +-----------------------+----------+------------------+-----------------+ | 192.168.50.164:4001/0 | greptime | SHOW PROCESSLIST | 00:00:00.002000 | +-----------------------+----------+------------------+-----------------+ 1 row in set (0.00 sec) ``` At the same time, you can specify the `FULL` parameter to output all columns of the `INFORMATION_SCHEMA.PROCESS_LIST` table: ```sql SHOW FULL PROCESSLIST; ``` Output: ```sql +-----------------------+----------+--------------------+------------------------+---------------------+----------------------------+-----------------+-----------------------+ | Id | Catalog | Schema | Client | Frontend | Start Time | Elapsed Time | Query | +-----------------------+----------+--------------------+------------------------+---------------------+----------------------------+-----------------+-----------------------+ | 192.168.50.164:4001/0 | greptime | information_schema | mysql[127.0.0.1:34692] | 192.168.50.164:4001 | 2025-06-30 07:17:46.423000 | 00:00:00.003000 | SHOW FULL PROCESSLIST | +-----------------------+----------+--------------------+------------------------+---------------------+----------------------------+-----------------+-----------------------+ ``` ## SHOW TRIGGERS Please refer to the [Trigger syntax](/reference/sql/trigger-syntax.md#show-triggers) documentation. ## SHOW CREATE TRIGGER Please refer to the [Trigger syntax](/reference/sql/trigger-syntax.md#show-create-trigger) documentation. ## Extensions to SHOW Statements Some extensions to `SHOW` statements accompany the implementation of [`INFORMATION_SCHEMA`](/reference/sql/information-schema/overview.md) just like MySQL, they also accept a `WHERE` clause that provides more flexibility in specifying which rows to display. GreptimeDB supports some extensions for MySQL compatibility, it's good for tools like [Navicat for MySQL](https://www.navicat.com/en/products/navicat-for-mysql) or [dbeaver](https://dbeaver.io/) to connect GreptimeDB. ```sql SHOW CHARACTER SET; ``` Output just like the `INFORMATION_SCHEMA.CHARACTER_SETS` table: ```sql +---------+---------------+-------------------+--------+ | Charset | Description | Default collation | Maxlen | +---------+---------------+-------------------+--------+ | utf8 | UTF-8 Unicode | utf8_bin | 4 | +---------+---------------+-------------------+--------+ ``` `SHOW COLLATION` for `INFORMATION_SCHEMA.COLLATIONS` table. ```sql SHOW INDEX FROM monitor; ``` To list all indexes in a table: ```sql +---------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+----------------------------+---------+---------------+---------+------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression | +---------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+----------------------------+---------+---------------+---------+------------+ | monitor | 1 | PRIMARY | 1 | host | A | NULL | NULL | NULL | YES | greptime-inverted-index-v1 | | | YES | NULL | | monitor | 1 | TIME INDEX | 1 | ts | A | NULL | NULL | NULL | NO | greptime-inverted-index-v1 | | | YES | NULL | +---------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+----------------------------+---------+---------------+---------+------------+ ``` Which is the extension of `INFORMATION_SCHEMA.TABLE_CONSTRAINTS`. List all the columns in a table: ```sql SHOW COLUMNS FROM monitor; ``` Output just like `INFORMATION_SCHEMA.COLUMNS`: ```sql +--------+--------------+------+------------+---------------------+-------+----------------------+ | Field | Type | Null | Key | Default | Extra | Greptime_type | +--------+--------------+------+------------+---------------------+-------+----------------------+ | cpu | double | Yes | | 0 | | Float64 | | host | string | Yes | PRI | NULL | | String | | memory | double | Yes | | NULL | | Float64 | | ts | timestamp(3) | No | TIME INDEX | current_timestamp() | | TimestampMillisecond | +--------+--------------+------+------------+---------------------+-------+----------------------+ ``` All these `SHOW` extensions accept `WHERE`: ```sql SHOW COLUMNS FROM monitor WHERE Field = 'cpu'; ``` ```sql +-------+--------+------+------+---------+-------+---------------+ | Field | Type | Null | Key | Default | Extra | Greptime_type | +-------+--------+------+------+---------+-------+---------------+ | cpu | double | Yes | | 0 | | Float64 | +-------+--------+------+------+---------+-------+---------------+ ``` To list all regions in a table: ```sql SHOW REGION FROM monitor; ``` ```sql +----------------+---------------+------+--------+ | Table | Region | Peer | Leader | +----------------+---------------+------+--------+ | monitor | 4398046511104 | 0 | Yes | +----------------+---------------+------+--------+ ``` It is the extension of `INFORMATION_SCHEMA.REGION_PEERS` and supports `WHERE` too. The syntax is ```sql SHOW REGION FROM [table] [IN database] [WHERE where] ``` Other `SHOW` statements: * `SHOW STATUS` and `SHOW VARIABLES` are not supported, just return empty results. * `SHOW TABLE STATUS` is the extension of `INFORMATION_SCHEMA.TABLES`. --- ## TQL The `TQL` keyword executes TQL language in SQL. The TQL is Telemetry Query Language, which is an extension for Prometheus's [PromQL](https://prometheus.io/docs/prometheus/latest/querying/basics/) in GreptimeDB. ## EVAL ### Syntax ```sql TQL [EVAL | EVALUATE] (start, end, step, [lookback]) expr [AS alias] ``` The `start`, `end` and `step` are the query parameters just like [Prometheus Query API](https://prometheus.io/docs/prometheus/latest/querying/api/): - `start`: ``: The start timestamp of the query; the range is inclusive of this value. - `end`: ``: The end timestamp of the query; the range is inclusive of this value. - `step`: ``: The query resolution step, specified as a `duration` or a floating-point number of seconds. - `lookback`: ``: The maximum lookback duration for evaluation, default is 5 minutes and optional. `expr` is the TQL (PromQL) query string. The optional `AS alias` clause allows you to specify a custom name for the value column in the result. This is useful for: - Giving meaningful names to query results - Using TQL results in SQL queries (e.g., CTEs, JOINs) - Improving readability of complex queries **Note**: Value aliasing currently supports single-field results only. ### Examples Return the per-second rate for all time series with the `http_requests_total` metric name, as measured over the last 5 minutes: ```sql TQL eval (1677057993, 1677058993, '1m') rate(prometheus_http_requests_total{job="prometheus"}[5m]); ``` will get a result just like other normal SQL queries. Using value aliasing to give a custom name to the result: ```sql TQL EVAL (0, 30, '10s') http_requests_total AS requests; ``` This will return results with the value column named `requests` instead of the default field name. Value aliasing with aggregation: ```sql TQL EVAL (0, 10, '5s') count by (k) (test) AS count_value; ``` This query counts values grouped by `k` and names the result column `count_value`. `start` and `end` can also be time expressions that evaluate to constants. For example, to query the past 3 hours: ```sql TQL EVAL (now() - interval '3' hours, now(), '1m') sum by (namespace, pod) ( increase(kube_pod_container_status_restarts_total[10m:30s]) ); ``` To query data for the past day: ```sql TQL EVAL ( date_trunc('day', now() - interval '1' day), date_trunc('day', now()), '1m' ) sum by (namespace) ( rate(http_requests_total[5m:30s]) ); ``` ### Using TQL in CTEs TQL `EVAL` can be used within Common Table Expressions (CTEs) to combine PromQL-style queries with SQL processing. For detailed examples and usage guidelines, see [Using TQL in CTEs](/user-guide/query-data/cte.md#using-tql-in-ctes). ## EXPLAIN `EXPLAIN` displays both the logical plan and execution plan for a given PromQL query. The syntax is as follows: ``` TQL EXPLAIN [VERBOSE] [FORMAT format] [(start, end, step, [lookback])] expr [AS alias]; ``` For example, to explain the PromQL `sum by (instance) (rate(node_disk_written_bytes_total[2m])) > 50`, we can use ``` TQL EXPLAIN sum by (instance) (rate(node_disk_written_bytes_total[2m])) > 50; ``` Notice that since the given query won't be actually executed, the triple `(start, end, step, [lookback])` is not necessary. But you can still provide it like in `TQL EVAL`: ``` TQL EXPLAIN (0, 100, '10s') sum by (instance) (rate(node_disk_written_bytes_total[2m])) > 50; ``` You can also use value aliasing with EXPLAIN: ``` TQL EXPLAIN (0, 10, '5s') test AS series; ``` The result should be like the following: ```txt +---------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | plan_type | plan | +---------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | logical_plan | Sort: node_disk_written_bytes_total.instance ASC NULLS LAST, node_disk_written_bytes_total.ts ASC NULLS LAST Filter: SUM(prom_rate(ts_range,field,ts)) > Float64(50) Aggregate: groupBy=[[node_disk_written_bytes_total.instance, node_disk_written_bytes_total.ts]], aggr=[[SUM(prom_rate(ts_range,field,ts))]] Projection: node_disk_written_bytes_total.ts, prom_rate(ts_range, field, node_disk_written_bytes_total.ts) AS prom_rate(ts_range,field,ts), node_disk_written_bytes_total.instance Filter: prom_rate(ts_range, field, node_disk_written_bytes_total.ts) IS NOT NULL Projection: node_disk_written_bytes_total.ts, node_disk_written_bytes_total.instance, field, ts_range PromRangeManipulate: req range=[0..0], interval=[300000], eval range=[120000], time index=[ts], values=["field"] PromSeriesNormalize: offset=[0], time index=[ts], filter NaN: [true] PromSeriesDivide: tags=["instance"] Sort: node_disk_written_bytes_total.instance DESC NULLS LAST, node_disk_written_bytes_total.ts DESC NULLS LAST TableScan: node_disk_written_bytes_total projection=[ts, instance, field], partial_filters=[ts >= TimestampMillisecond(-420000, None), ts <= TimestampMillisecond(300000, None)] | | physical_plan | SortPreservingMergeExec: [instance@0 ASC NULLS LAST,ts@1 ASC NULLS LAST] SortExec: expr=[instance@0 ASC NULLS LAST,ts@1 ASC NULLS LAST] CoalesceBatchesExec: target_batch_size=8192 FilterExec: SUM(prom_rate(ts_range,field,ts))@2 > 50 AggregateExec: mode=FinalPartitioned, gby=[instance@0 as instance, ts@1 as ts], aggr=[SUM(prom_rate(ts_range,field,ts))] CoalesceBatchesExec: target_batch_size=8192 RepartitionExec: partitioning=Hash([Column { name: "instance", index: 0 }, Column { name: "ts", index: 1 }], 32), input_partitions=32 AggregateExec: mode=Partial, gby=[instance@2 as instance, ts@0 as ts], aggr=[SUM(prom_rate(ts_range,field,ts))] ProjectionExec: expr=[ts@0 as ts, prom_rate(ts_range@3, field@2, ts@0) as prom_rate(ts_range,field,ts), instance@1 as instance] CoalesceBatchesExec: target_batch_size=8192 FilterExec: prom_rate(ts_range@3, field@2, ts@0) IS NOT NULL ProjectionExec: expr=[ts@0 as ts, instance@1 as instance, field@2 as field, ts_range@3 as ts_range] PromInstantManipulateExec: req range=[0..0], interval=[300000], eval range=[120000], time index=[ts] PromSeriesNormalizeExec: offset=[0], time index=[ts], filter NaN: [true] PromSeriesDivideExec: tags=["instance"] RepartitionExec: partitioning=RoundRobinBatch(32), input_partitions=1 ExecutionPlan(PlaceHolder) | +---------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ``` ## ANALYZE TQL also supports `ANALYZE` keyword to analyze the given PromQL query's execution. The syntax is as follows: ``` TQL ANALYZE [VERBOSE] [FORMAT format] (start, end, step, [lookback]) expr [AS alias]; ``` For example: ``` TQL ANALYZE (0, 10, '5s') test; ``` will get a result like ``` +-------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | plan_type | plan | +-------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Plan with Metrics | CoalescePartitionsExec, metrics=[output_rows=0, elapsed_compute=14.99µs] PromInstantManipulateExec: range=[0..10000], lookback=[300000], interval=[5000], time index=[j], metrics=[output_rows=0, elapsed_compute=1.08µs] PromSeriesNormalizeExec: offset=[0], time index=[j], filter NaN: [false], metrics=[output_rows=0, elapsed_compute=1.11µs] PromSeriesDivideExec: tags=["k"], metrics=[output_rows=0, elapsed_compute=1.3µs] RepartitionExec: partitioning=RoundRobinBatch(32), input_partitions=32, metrics=[send_time=32ns, repart_time=32ns, fetch_time=11.578016ms] RepartitionExec: partitioning=RoundRobinBatch(32), input_partitions=1, metrics=[send_time=1ns, repart_time=1ns, fetch_time=21.07µs] ExecutionPlan(PlaceHolder), metrics=[] | +-------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ``` Using `TQL ANALYZE VERBOSE` will get a verbose result of the execution. ``` TQL ANALYZE VERBOSE (0, 10, '5s') test; ``` --- ## Trigger Syntax :::tip NOTE This feature is only available in the GreptimeDB Enterprise database. ::: ## CREATE TRIGGER The syntax for creating a Trigger: ```sql CREATE TRIGGER [IF NOT EXISTS] ON () EVERY [LABELS (=, ...)] [ANNOTATIONS (=, ...)] [FOR ] [KEEP FIRING FOR ] NOTIFY ( WEBHOOK URL '' [WITH (=, ...)], WEBHOOK URL '' [WITH (=, ...)] ); ``` - Trigger name: the unique identifier of the Trigger at the catalog level. - IF NOT EXISTS: prevent errors that would occur if the Trigger being created. ### On clause #### Query expression The SQL query specified in the `ON` clause is executed periodically. Its evaluation result may produce one or more alert instances, depending on the returned rows. The Trigger extracts `labels` and `annotations` from the query result and attaches them to each alert instance. These values are combined with the static key-value pairs specified in the `LABELS` and `ANNOTATIONS` clauses. The extraction rules are as follows: - Extract columns whose name or alias starts with `label_` to `LABELS`. The key of labels is the column name or alias without the `label_` prefix. - Extract the other columns to `ANNOTATIONS`. The key of annotations is the column name. It is worth noting that each alert instance is uniquely identified by its label set. Multiple rows with the same labels will only create a single alert instance. For example, the query expression is as follows: ```sql SELECT collect as label_collector, host as label_host, val FROM host_load1 WHERE val > 10 and ts >= now() - '1 minutes'::INTERVAL ``` Assume the query result is not empty and looks like this: | label_collector | label_host | val | |------------------|------------|-----| | collector1 | host1 | 12 | | collector2 | host2 | 15 | This will generate two alert instances. The first alert instance will have the following labels and annotations: - Labels: - collector: collector1 - host: host1 - the labels defined in the `LABELS` clause - Annotations: - val: 12 - the annotations defined in the `ANNOTATIONS` clause The second alert instance will have the following labels and annotations: - Labels: - collector: collector2 - host: host2 - the labels defined in the `LABELS` clause - Annotations: - val: 15 - the annotations defined in the `ANNOTATIONS` clause #### Interval expression It indicates how often the query is executed. e.g., `'5 minute'::INTERVAL`, `'1 hour'::INTERVAL` etc. - `Years` and `months` are **prohibited** in INTERVAL expressions. Because the duration of a month or year is variable and depends on the specific month or year, it is not suitable for defining fixed intervals. - The minimum interval is 1 second. Any interval specified less than 1 second will be automatically rounded up to 1 second. For more details about how to write INTERVAL time, see [interval-type](/reference/sql/data-types.md#interval-type). ### FOR clause The `FOR` clause controls how long an alert must remain active before it fires. Its behavior is similar to the `for` option in Prometheus Alerting Rules. When an alert instance appears in the evaluation results for the first time, it enters the `Pending` state, during which no notification is sent. If the alert instance remains active throughout every evaluation within the duration specified by `FOR`, its state transitions from `Pending` to `Firing`, and a notification is sent immediately. If the `FOR` clause is not specified, the alert will not enter the `Pending` state. Instead, an alert instance transitions to the `Firing` state immediately upon its first appearance in the evaluation results, and a notification is sent immediately. ### KEEP FIRING FOR clause The `KEEP FIRING FOR` clause controls how long an alert instance should remain in the `Firing` state after it first enters that state. Its behavior is similar to the `keep_firing_for` option in Prometheus Alerting Rules. Once an alert instance enters the `Firing` state, it will remain firing for at least the duration specified by `KEEP FIRING FOR`, even if it no longer appears in subsequent evaluation results. After the `KEEP FIRING FOR` duration has passed, if the alert instance does not appear in the next evaluation, it will be marked as resolved and will no longer remain in the `Firing` state. If the `KEEP FIRING FOR` clause is not specified, an alert instance will be marked as resolved in the first evaluation where it no longer appears in the query results after entering the `Firing` state. ### Labels and Annotations clauses The LABELS and ANNOTATIONS clauses allow you to attach static key-value pairs to the notification messages sent by Trigger. These can be used to provide additional context or metadata about the Trigger. - LABELS: serve as labels for Alertmanager routing, grouping, and inhibition. - ANNOTATIONS: typically for human-readable descriptions. ### Notify clause The NOTIFY clause allows you to specify one or more notification channels. Currently, GreptimeDB supports the following notification channel: #### Webhook The webhook channel will send HTTP requests to a specified URL when the Trigger fires. The payload of the http request is compatible with [Prometheus Alertmanager](https://prometheus.io/docs/alerting/latest/alertmanager/), which means you can use GreptimeDB's Trigger with Prometheus Alertmanager without any extra glue code. The optional `WITH` clause allows you to specify additional parameters: - timeout: The timeout for the HTTP request, e.g., `timeout='1m'`. ## SHOW TRIGGERS Show all triggers: ```sql SHOW TRIGGERS; ``` Show triggers by `like` pattern: ```sql SHOW TRIGGERS LIKE ''; ``` For example: ```sql SHOW TRIGGERS LIKE 'load%'; ``` Show triggers by `where` condition: ```sql SHOW TRIGGERS WHERE ; ``` For example: ```sql SHOW TRIGGERS WHERE name = 'load1_monitor'; ``` ## SHOW CREATE TRIGGER To show the Trigger's definition: ```sql SHOW CREATE TRIGGER ; ``` For example: ```sql SHOW CREATE TRIGGER load1_monitor; ``` ## DROP TRIGGER To delete a trigger, use the following `DROP TRIGGER` clause: ```sql DROP TRIGGER [IF EXISTS] ; ``` For example: ```sql DROP TRIGGER IF EXISTS load1_monitor; ``` ## Example Please refer to the [Trigger](/enterprise/trigger.md) documentation in the enterprise user guide for examples. --- ## TRUNCATE The `TRUNCATE TABLE table` statement is used to delete all data from a table. It's much more efficient than `DELETE FROM table`. ```sql TRUNCATE TABLE monitor; ``` ```sql Query OK, 0 rows affected (0.02 sec) ``` --- ## WHERE `WHERE` clause allows to filter the data by specifying conditions. ## Syntax ```sql SELECT * FROM table_name WHERE condition; ``` If there is a `WHERE` clause, it must contain an expression with the Boolean type. This is usually an expression with comparison and logical operators. Rows where this expression evaluates to false are excluded from further transformations or result. ## Examples ### Logical operators Supports `AND`, `OR` as logical operators and can assemble conditions using brackets (). ```sql SELECT * FROM system_metrics WHERE idc = 'idc0' AND (host = 'host1' OR host = 'host2'); ``` ### Numeric Supports `=`, `!=`, `>`, `>=`, `<`, `<=` as comparison operators. ```sql SELECT * FROM system_metrics WHERE cpu_util = 20.0; SELECT * FROM system_metrics WHERE cpu_util != 20.0; SELECT * FROM system_metrics WHERE cpu_util > 20.0; SELECT * FROM system_metrics WHERE cpu_util >= 20.0; SELECT * FROM system_metrics WHERE cpu_util < 20.0; SELECT * FROM system_metrics WHERE cpu_util <= 20.0; ``` ### List search Evaluates match or mismatch against a list of elements. ### List match ```sql SELECT * FROM system_metrics WHERE idc IN ('idc_a', 'idc_b'); ``` ### List mismatch ```sql SELECT * FROM system_metrics WHERE idc NOT IN ('idc_a', 'idc_b'); ``` ### String For string columns, we can use the `LIKE` operator to search for a specified pattern in a column. There are two wildcards often used in conjunction with the LIKE operator: * The percent sign `%` represents zero, one, or multiple characters * The underscore sign `_` represents a single character Select all records that the `host` column starts with the letter "a": ```sql SELECT * FROM system_metrics WHERE host LIKE 'a%'; ``` Selects all records from the `go_info` table where the instance column matches the pattern `'localhost:____'`, meaning `'localhost:'` followed by exactly four characters. ```sql SELECT * FROM go_info WHERE instance LIKE 'localhost:____'; ``` For searching terms in logs, please read [Fulltext Search](/user-guide/logs/fulltext-search.md). --- ## WITH Use `WITH` to specify a Common Table Expression. ## What is a Common Table Expression (CTE)? A Common Table Expression (CTE) is a temporary result set that you can reference within a `SELECT`, `INSERT`, `UPDATE`, or `DELETE` statement. CTEs help to break down complex queries into more readable parts and can be referenced multiple times within the same query. ## Basic syntax of CTE CTEs are typically defined using the `WITH` keyword. The basic syntax is as follows: ```sql WITH cte_name [(column1, column2, ...)] AS ( QUERY ) SELECT ... FROM cte_name; ``` ## Examples ### Non-recursive CTE ```sql WITH cte AS (SELECT 0 AS number UNION ALL SELECT 1) SELECT * FROM cte t1, cte t2; ``` ```sql +--------+--------+ | number | number | +--------+--------+ | 0 | 0 | | 0 | 1 | | 1 | 0 | | 1 | 1 | +--------+--------+ ``` If a parenthesized list of names follows the CTE name, those names are the column names: ```sql WITH cte (col1, col2) AS ( SELECT 1, 2 UNION ALL SELECT 3, 4 ) SELECT col1, col2 FROM cte; ``` The number of names in the list must be the same as the number of columns in the result set. ```sql +------+------+ | col1 | col2 | +------+------+ | 1 | 2 | | 3 | 4 | +------+------+ ``` Join two CTEs: ```sql WITH cte1 AS (SELECT 0 AS a UNION ALL SELECT 1), cte2 AS (SELECT 0 AS b UNION ALL SELECT 1) SELECT * FROM cte1 JOIN cte2 ON cte1.a = cte2.b; ``` ```sql +------+------+ | a | b | +------+------+ | 1 | 1 | | 0 | 0 | +------+------+ ``` ### Recursive CTE Recursive CTE is not implemented currently. --- ## SQL Tools GreptimeDB uses SQL as its main query language and supports many popular SQL tools. This document guides you on how to use SQL tools with GreptimeDB. ## Language drivers It is recommended to use mature SQL drivers to query data. ### Recommended libraries Java Database Connectivity (JDBC) is the JavaSoft specification of a standard application programming interface (API) that allows Java programs to access database management systems. Many databases, such as MySQL or PostgreSQL, have implemented their own drivers based on the JDBC API. Since GreptimeDB supports [multiple protocols](/user-guide/protocols/overview.md), we use MySQL as an example to demonstrate how to use JDBC. If you want to use other protocols, just replace the MySQL driver with the corresponding driver. It is recommended to use the [GORM](https://gorm.io/) library, which is popular and developer-friendly. ### Installation If you are using [Maven](https://maven.apache.org/), add the following to your `pom.xml` dependencies list: ```xml mysql mysql-connector-java 8.0.33 ``` Use the following command to install the GORM library: ```shell go get -u gorm.io/gorm ``` Then install the MySQL driver: ```shell go get -u gorm.io/driver/mysql ``` Import the libraries in your code: ```go "gorm.io/gorm" "gorm.io/driver/mysql" ) ``` ### Connect to database The following use MySQL as an example to demonstrate how to connect to GreptimeDB. ```java public static Connection getConnection() throws IOException, ClassNotFoundException, SQLException { Properties prop = new Properties(); prop.load(QueryJDBC.class.getResourceAsStream("/db-connection.properties")); String dbName = (String) prop.get("db.database-driver"); String dbConnUrl = (String) prop.get("db.url"); String dbUserName = (String) prop.get("db.username"); String dbPassword = (String) prop.get("db.password"); Class.forName(dbName); Connection dbConn = DriverManager.getConnection(dbConnUrl, dbUserName, dbPassword); return Objects.requireNonNull(dbConn, "Failed to make connection!"); } ``` You need a properties file to store the DB connection information. Place it in the resources directory and name it `db-connection.properties`. The file content is as follows: ```txt # DataSource db.database-driver=com.mysql.cj.jdbc.Driver db.url=jdbc:mysql://localhost:4002/public db.username= db.password= ``` Or you can get the file from [here](https://github.com/GreptimeTeam/greptimedb-ingester-java/blob/main/ingester-example/src/main/resources/db-connection.properties). ```go type Mysql struct { Host string Port string User string Password string Database string DB *gorm.DB } m := &Mysql{ Host: "127.0.0.1", Port: "4002", // default port for MySQL User: "username", Password: "password", Database: "public", } dsn := fmt.Sprintf("tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", m.Host, m.Port, m.Database) dsn = fmt.Sprintf("%s:%s@%s", m.User, m.Password, dsn) db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) if err != nil { // error handling } m.DB = db ``` #### Time zone Set the JDBC time zone by setting URL parameters: ```txt jdbc:mysql://127.0.0.1:4002?connectionTimeZone=Asia/Shanghai&forceConnectionTimeZoneToSession=true ``` * `connectionTimeZone={LOCAL|SERVER|user-defined-time-zone}` specifies the connection time zone. * `forceConnectionTimeZoneToSession=true` sets the session `time_zone` variable to the value specified in `connectionTimeZone`. Set the time zone in the DSN. For example, set the time zone to `Asia/Shanghai`: ```go dsn := fmt.Sprintf("tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local&time_zone=%27Asia%2FShanghai%27", m.Host, m.Port, m.Database) ``` For more information, see the [MySQL Driver Documentation](https://github.com/go-sql-driver/mysql?tab=readme-ov-file#system-variables). ### Raw SQL It is recommended to use raw SQL to experience the full features of GreptimeDB. The following example shows how to use raw SQL to query data. ```java try (Connection conn = getConnection()) { Statement statement = conn.createStatement(); // DESC table; ResultSet rs = statement.executeQuery("DESC cpu_metric"); LOG.info("Column | Type | Key | Null | Default | Semantic Type "); while (rs.next()) { LOG.info("{} | {} | {} | {} | {} | {}", rs.getString(1), rs.getString(2), rs.getString(3), rs.getString(4), rs.getString(5), rs.getString(6)); } // SELECT COUNT(*) FROM cpu_metric; rs = statement.executeQuery("SELECT COUNT(*) FROM cpu_metric"); while (rs.next()) { LOG.info("Count: {}", rs.getInt(1)); } // SELECT * FROM cpu_metric ORDER BY ts DESC LIMIT 5; rs = statement.executeQuery("SELECT * FROM cpu_metric ORDER BY ts DESC LIMIT 5"); LOG.info("host | ts | cpu_user | cpu_sys"); while (rs.next()) { LOG.info("{} | {} | {} | {}", rs.getString("host"), rs.getTimestamp("ts"), rs.getDouble("cpu_user"), rs.getDouble("cpu_sys")); } } ``` For the complete code of the demo, please refer to [here](https://github.com/GreptimeTeam/greptimedb-ingester-java/blob/main/ingester-example/src/main/java/io/greptime/QueryJDBC.java). The following code declares a GORM object model: ```go type CpuMetric struct { Host string `gorm:"column:host;primaryKey"` Ts time.Time `gorm:"column:ts;primaryKey"` CpuUser float64 `gorm:"column:cpu_user"` CpuSys float64 `gorm:"column:cpu_sys"` } ``` If you are using the [High-level API](/user-guide/ingest-data/for-iot/grpc-sdks/go.md#high-level-api) to insert data, you can declare the model with both GORM and GreptimeDB tags. ```go type CpuMetric struct { Host string `gorm:"column:host;primaryKey" greptime:"tag;column:host;type:string"` Ts time.Time `gorm:"column:ts;primaryKey" greptime:"timestamp;column:ts;type:timestamp;precision:millisecond"` CpuUser float64 `gorm:"column:cpu_user" greptime:"field;column:cpu_user;type:float64"` CpuSys float64 `gorm:"column:cpu_sys" greptime:"field;column:cpu_sys;type:float64"` } ``` Declare the table name as follows: ```go func (CpuMetric) TableName() string { return "cpu_metric" } ``` Use raw SQL to query data: ```go var cpuMetric CpuMetric db.Raw("SELECT * FROM cpu_metric LIMIT 10").Scan(&result) ``` ### Query library reference For more information about how to use the query library, please see the documentation of the corresponding library: - [JDBC Online Tutorials](https://docs.oracle.com/javase/tutorial/jdbc/basics/index.html) - [GORM](https://gorm.io/docs/index.html) ## Command line tools ### MySQL You can use the `mysql` command line tool to connect to the GreptimeDB. Please refer to the [MySQL protocol](/user-guide/protocols/mysql.md) document for connection information. After you connect to the server, you can use all [GreptimeDB SQL commands](/reference/sql/overview.md) to interact with the database. ### PostgreSQL You can use the `psql` command line tool to connect to the GreptimeDB. Please refer to the [PostgreSQL protocol](/user-guide/protocols/postgresql.md) document for connection information. After you connect to the server, you can use all [GreptimeDB SQL commands](/reference/sql/overview.md) to interact with the database. ## GreptimeDB Dashboard You can run SQL and visualize data in the [GreptimeDB Dashboard](/getting-started/installation/greptimedb-dashboard.md). ## GUI tools ### DBeaver Please refer to the [DBeaver Integration Guide](/user-guide/integrations/dbeaver.md). ## HTTP API You can POST SQL queries to the GreptimeDB HTTP API to query data. Please refer to the [HTTP API](/user-guide/protocols/http.md) document for more information. --- ## Telemetry To enhance our service, GreptimeDB collects certain telemetry data. This includes information like the GreptimeDB version, the number of nodes, the operating system used, the environment's architecture, and similar technical details. However, we respect your privacy and make sure not to collect any user-specific data, which entails database names, table names, query content, and the like. This telemetry collection can easily be managed according to your preferences. You may choose to enable or disable it through the configurations. Your experience and privacy are our top priority. ## What data will be collected? The usage details that get shared might change over time. These changes (if any) will be announced in release notes. When telemetry is enabled, GreptimeDB will collect the following information every 0.5 hours: - GreptimeDB version - GreptimeDB build git hash - The operating system of the machine on which GreptimeDB is running(Linux, macOS, etc.) - Architecture of the machine on which GreptimeDB is running(x86_64, arm64, etc.) - Mode in which GreptimeDB is running(standalone, distributed) - A randomly generated installation ID - The number of datanodes in the GreptimeDB cluster - System uptime, not exact figures, only time ranges like `hours`, `weeks` with no numbers Sample telemetry data: ```json { "os": "linux", "version": "0.15.1", "arch": "aarch64", "mode": "Standalone", "git_commit": "00d759e828f5e148ec18141904e20cb1cb7577b0", "nodes": 1, "uuid": "43717682-baa8-41e0-b126-67b797b66606", "uptime": "hours" } ``` ## How to disable telemetry? Telemetry will be enabled by default starting from v0.4.0. You can disable it by configuring the settings. ### Standalone mode Set `enable_telemetry` in the standalone config file to `false`: ```toml # Whether to enable greptimedb telemetry, true by default. enable_telemetry = false ``` Or configure it by the environment variable `GREPTIMEDB_STANDALONE__ENABLE_TELEMETRY=false` on startup. ### Distributed mode Set `enable_telemetry` in the metasrv config file to `false`: ```toml # metasrv config file # Whether to enable greptimedb telemetry, true by default. enable_telemetry = false ``` Or set the environment variable `GREPTIMEDB_METASRV__ENABLE_TELEMETRY=false` on startup. --- ## Time Durations GreptimeDB utilizes time durations to represent time spans in various contexts, including SQL queries, configuration files, and API requests. For more information on using time durations, please refer to: - The TTL options and the `time_window` parameter of the TWCS compaction strategy in the [ALTER](/reference/sql/alter.md) statement. - The TTL options in the [CREATE](/reference/sql/create.md) statement. A time duration is expressed as a string composed of concatenated time spans, each represented by a sequence of decimal numbers followed by a unit suffix. These suffixes are case-insensitive and support both singular and plural forms. For example, `1hour 12min 5s`. Each time span consists of an integer and a suffix. The supported suffixes are: - `nsec`, `ns`: nanoseconds - `usec`, `us`: microseconds - `msec`, `ms`: milliseconds - `seconds`, `second`, `sec`, `s` - `minutes`, `minute`, `min`, `m` - `hours`, `hour`, `hr`, `h` - `days`, `day`, `d` - `weeks`, `week`, `w` - `months`, `month`, `M`: defined as 30.44 days - `years`, `year`, `y`: defined as 365.25 days Appending a decimal integer with one of the above units represents the equivalent number of seconds as a bare float literal. Examples: - `1s`: Equivalent to 1 second - `2m`: Equivalent to 120 seconds - `1ms`: Equivalent to 0.001 seconds - `2h`: Equivalent to 7200 seconds The following examples are invalid: - `0xABm`: Hexadecimal numbers are not supported - `1.5h`: Floating point numbers are not supported - `+Infd`: `±Inf` or `NaN` values are not supported The following are some valid time duration examples: - `1h`: one hour - `1h30m`, `1h 30m`: one hour and thirty minutes - `1h30m10s`, `1h 30m 10s`: one hour, thirty minutes, and ten seconds --- ## GreptimeDB FAQ # Frequently Asked Questions :::tip Looking for introductory information? - What is GreptimeDB / Use cases → [Why GreptimeDB](/user-guide/concepts/why-greptimedb.md) - Performance benchmarks → [Key Features](/user-guide/concepts/features-that-you-concern.md#how-is-greptimedbs-performance-compared-to-other-solutions) - Metrics, logs, and traces → [Key Features](/user-guide/concepts/features-that-you-concern.md#how-does-greptimedb-handle-metrics-logs-and-traces) - High cardinality → [Key Features](/user-guide/concepts/features-that-you-concern.md#how-does-greptimedb-address-the-high-cardinality-issue) - Data model → [Data Model](/user-guide/concepts/data-model.md) ::: ## General ### Where can I find ready-to-run demos? Check out the [demo-scene](https://github.com/GreptimeTeam/demo-scene) repository. It contains end-to-end examples covering common use cases (metrics, logs, IoT, etc.) that you can run locally with Docker Compose. ### How is GreptimeDB's performance compared to other solutions? GreptimeDB is designed for high-throughput write, low-latency query, and cost-efficient storage across metrics, logs, and traces workloads. Benchmark results are available in the following reports: - [GreptimeDB vs. InfluxDB](https://greptime.com/blogs/2024-08-07-performance-benchmark) - [GreptimeDB vs. TimescaleDB](https://greptime.com/blogs/2025-12-09-greptimedb-vs-timescaledb-benchmark) - [GreptimeDB vs. Grafana Mimir](https://greptime.com/blogs/2024-08-02-datanode-benchmark) - [GreptimeDB vs. ClickHouse vs. Elasticsearch (Log Benchmark)](https://greptime.com/blogs/2025-03-10-log-benchmark-greptimedb) - [GreptimeDB vs. SQLite](https://greptime.com/blogs/2024-08-30-sqlite) - [GreptimeDB vs. Loki](https://greptime.com/blogs/2025-08-07-beyond-loki-greptimedb-log-scenario-performance-report) - [JSONBench #1 (1 Billion Cold Run)](https://greptime.com/blogs/2025-03-18-jsonbench-greptimedb-performance) For a summary of how GreptimeDB compares architecturally, see the [comparison table](/user-guide/concepts/why-greptimedb.md#how-greptimedb-compares). ### What are GreptimeDB's design trade-offs? GreptimeDB is optimized for observability and time-series workloads, which means it makes different trade-offs than a general-purpose OLTP database: - **No ACID transactions**: Prioritizes high-throughput writes over transactional consistency. - **Delete is supported but not optimized for high-frequency use**: GreptimeDB supports [row deletion](/user-guide/manage-data/overview.md#delete-data) and [TTL-based expiration](/user-guide/manage-data/overview.md#manage-data-retention-with-ttl-policies), but it is not designed for workloads that require frequent, fine-grained deletes — as is typical for append-heavy observability data. - **Joins are functional but currently not the primary focus**: GreptimeDB supports SQL joins, but the query engine is optimized for time-series filter-aggregate patterns rather than complex multi-way relational joins. Simple joins (e.g., enrichment lookups, correlating metrics with logs) work well. - **Time-series focused**: Optimized for IoT, metrics, logs, and traces rather than general OLTP. ### What's the difference between GreptimeDB and InfluxDB? Key differences: - **Open Source**: GreptimeDB's entire distributed system is fully open source. - **Architecture**: Region-based sharding design optimized for observability workloads. - **Query Languages**: SQL + PromQL vs. InfluxQL + SQL. - **Unified Model**: Native support for metrics, logs, and traces in one system. - **Storage**: Pluggable engines with dedicated optimizations. - **Cloud-Native**: Built for Kubernetes with disaggregated compute/storage (see [Kubernetes Deployment Guide](/user-guide/deployments-administration/deploy-on-kubernetes/overview.md)). For a detailed comparison, see [GreptimeDB vs InfluxDB](https://greptime.com/compare/influxdb). Additional product comparisons (vs. ClickHouse, Loki, etc.) are available in the Compare menu on the [website](https://greptime.com). ## Data Model & Schema ### What's the difference between Tag and Field columns? GreptimeDB uses three semantic column types: **Tag**, **Timestamp**, and **Field**. - **Tag** columns identify a time-series. Rows with the same tag values belong to the same series. Tags are indexed by default for fast filtering. In SQL, tag columns are declared via `PRIMARY KEY`. - **Field** columns contain the measured values (numbers, strings, etc.). Fields are not indexed by default, but you can add [indexes](/user-guide/manage-data/data-index.md) as needed. - **Timestamp** is the time index — every table must have exactly one. For example, in a `system_metrics` table, `host` and `idc` are tags, `cpu_util` and `memory_util` are fields, and `ts` is the timestamp. For full details and examples, see [Data Model](/user-guide/concepts/data-model.md) and the [schema design guide](/user-guide/deployments-administration/performance-tuning/design-table.md). ### Does GreptimeDB support schemaless data ingestion? Yes. When writing via gRPC, InfluxDB Line Protocol, OpenTSDB, Prometheus Remote Write, OpenTelemetry, Loki, or Elasticsearch-compatible APIs, GreptimeDB creates tables and columns automatically on first write. No manual schema definition is needed. For details, see [Automatic Schema Generation](/user-guide/ingest-data/overview.md#automatic-schema-generation). ### How do I set default table options (TTL, append mode, etc.) for auto-created tables? There are three ways to control table options such as `ttl`, `append_mode`, `merge_mode`, `skip_wal`, and `sst_format` for tables created via [automatic schema generation](/user-guide/ingest-data/overview.md#automatic-schema-generation): 1. **Set options at ingestion time via HTTP header**: Use the `x-greptime-hints` header to pass table options when writing data. For example, `x-greptime-hints: ttl=7d, append_mode=true`. These options apply when the table is auto-created. See [HTTP Hints](/user-guide/protocols/http.md#hints) for all supported hints. 2. **Modify options after table creation**: Some options can be changed on an existing table via `ALTER TABLE`. For example, `ttl`, `append_mode`, `compaction.*`, and `sst_format` are supported: ```sql ALTER TABLE my_table SET 'ttl' = '7d'; ALTER TABLE my_table SET 'append_mode' = 'true'; ``` Note that `merge_mode` and `skip_wal` cannot be altered after creation — they must be set at table creation time. See [ALTER TABLE](/reference/sql/alter.md#alter-table-options) for all supported options and constraints. 3. **Set database-level defaults**: Create or alter the database with default options. New auto-created tables will inherit these values: ```sql CREATE DATABASE my_db WITH (ttl = '7d', append_mode = 'true'); -- or ALTER DATABASE my_db SET 'ttl' = '7d'; ``` Note that `ttl` and `compaction.*` options have ongoing effect — tables without their own settings continuously inherit the database value. Other options (`append_mode`, `merge_mode`, `skip_wal`, `sst_format`) only serve as defaults for newly created tables. See [CREATE DATABASE](/reference/sql/create.md#create-database) for all available options. ### How do I customize the default column names for InfluxDB / Prometheus protocols? When writing via certain protocols, GreptimeDB generates default column names with a `greptime_` prefix. The timestamp column is named `greptime_timestamp` for all schemaless protocols. The value column `greptime_value` is used by single-value protocols such as Prometheus Remote Write and OpenTelemetry Metrics, where each time series carries only one numeric value. Multi-field protocols like InfluxDB Line Protocol use the field names from the input data directly — only the timestamp column gets the default prefix. To change the prefix, set the `default_column_prefix` option in your `standalone.toml` or `frontend.toml`: ```toml # Remove the "greptime_" prefix — columns become "value" and "timestamp" default_column_prefix = "" # Or use a custom prefix — columns become "my_value" and "my_timestamp" # default_column_prefix = "my" ``` If unset, the default `greptime_` prefix is used. This is a top-level configuration option and requires a restart to take effect. ### Can I change a column's type after table creation? Yes. Use `ALTER TABLE ... MODIFY COLUMN` to change a field column's data type: ```sql ALTER TABLE monitor MODIFY COLUMN load_15 STRING; ``` The column must be a field (not a tag or time index) and must be nullable, so that values that cannot be cast return `NULL` instead of failing. For the full `ALTER TABLE` syntax, see the [SQL reference](/reference/sql/alter.md). ### How does GreptimeDB handle late-arriving or out-of-order data? GreptimeDB accepts writes with any timestamp — there is no ingestion-time window or ordering requirement. Late-arriving and out-of-order data is written normally and becomes queryable immediately. The storage engine's [compaction](/user-guide/deployments-administration/manage-data/compaction.md) process merges and sorts data in the background. For append-only tables (commonly used for logs), rows are never deduplicated, so late-arriving data simply adds new rows. For tables with a primary key, rows with the same tag + timestamp combination follow the [update semantics](/user-guide/manage-data/overview.md#update-data). ## Integration & Migration ### What protocols, tools, and SDKs does GreptimeDB support? **Write protocols**: [OpenTelemetry (OTLP)](/user-guide/ingest-data/for-observability/opentelemetry.md), [Prometheus Remote Write](/user-guide/ingest-data/for-observability/prometheus.md), [InfluxDB Line Protocol](/user-guide/ingest-data/for-iot/influxdb-line-protocol.md), [Loki](/user-guide/ingest-data/for-observability/loki.md), [Elasticsearch](/user-guide/ingest-data/for-observability/elasticsearch.md), [MySQL](/user-guide/protocols/mysql.md), [PostgreSQL](/user-guide/protocols/postgresql.md), [gRPC](/user-guide/protocols/grpc.md) — see [Protocols Overview](/user-guide/protocols/overview.md). **Query languages**: [SQL](/user-guide/query-data/sql.md), [PromQL](/user-guide/query-data/promql.md). **Visualization**: [Grafana](/user-guide/integrations/grafana.md) (official plugin + MySQL/PostgreSQL data sources), and any tool that speaks MySQL or PostgreSQL wire protocol. **Data pipeline**: Vector, Fluent Bit, Telegraf, Kafka — see [Integrations Overview](/user-guide/integrations/overview.md). **SDKs**: - [Go](https://github.com/GreptimeTeam/greptimedb-ingester-go) - [Java](https://github.com/GreptimeTeam/greptimedb-ingester-java) - [Rust](https://github.com/GreptimeTeam/greptimedb-ingester-rust) - [Erlang](https://github.com/GreptimeTeam/greptimedb-ingester-erl) - [.NET](https://github.com/GreptimeTeam/greptimedb-ingester-dotnet) - [TypeScript](https://github.com/GreptimeTeam/greptimedb-ingester-ts) - For other languages (Python, Ruby, etc.): use any OpenTelemetry SDK, InfluxDB client library, or MySQL/PostgreSQL driver — GreptimeDB is compatible with all of them. ### How do I choose the right ingestion protocol? GreptimeDB supports multiple ingestion protocols with very different throughput characteristics. The following results are from a local benchmark at 1 million time series (batch size 1,000) — **focus on the relative ratios rather than absolute numbers**, as actual throughput varies by hardware and workload: | Protocol | Relative throughput | | --- | --- | | gRPC Bulk (Arrow Flight) | Highest (~37x SQL) | | gRPC Stream | ~21x SQL | | gRPC SDK (Unary) | ~16x SQL | | InfluxDB Line Protocol | ~12x SQL | | OTLP Logs | ~8.5x SQL | | MySQL / PostgreSQL INSERT | Baseline | **How to choose:** - **General workloads**: gRPC SDK — best balance of simplicity and performance, with schemaless support. - **Bulk operations** (migrations, backfills): gRPC Bulk — maximum throughput, requires pre-created tables. - **Continuous streams** (IoT, monitoring collectors): gRPC Stream — sustained high throughput over persistent connections. - **Ecosystem integration**: InfluxDB Line Protocol (Telegraf-compatible) or OTLP (OpenTelemetry-compatible) — good throughput with broad tool support. - **Development / debugging**: SQL protocols (MySQL / PostgreSQL) — lower throughput but easier to inspect and debug. For the full benchmark details and methodology, see the [Ingestion Protocol Benchmark](https://greptime.com/blogs/2026-03-24-ingestion-protocol-benchmark) blog post. ### How do I connect Grafana to GreptimeDB? GreptimeDB works with Grafana through three data source options: - **[GreptimeDB plugin](/user-guide/integrations/grafana.md#greptimedb-data-source-plugin)**: Official plugin with full SQL and PromQL support. - **[Prometheus data source](/user-guide/integrations/grafana.md#prometheus-data-source)**: Use GreptimeDB's Prometheus-compatible endpoint for PromQL dashboards. - **[MySQL data source](/user-guide/integrations/grafana.md#mysql-data-source)**: Use the built-in MySQL data source with GreptimeDB's MySQL protocol endpoint. See [Grafana Integration](/user-guide/integrations/grafana.md) for setup instructions. ### How can I migrate from other databases? GreptimeDB provides migration guides for: - **From InfluxDB**: Line protocol and data migration - **From Prometheus**: Remote write and historical data migration - **From ClickHouse**: Table schema and data migration - **From MySQL/PostgreSQL**: SQL-based migration For detailed instructions, see [Migration Overview](/user-guide/migrate-to-greptimedb/overview.md). ## Deployment & Operations ### What are the deployment options? **Cluster deployment** (production): - Minimum 3 nodes for high availability - Three components: metasrv, frontend, and datanode - Components can be co-located or separated depending on scale - See [Capacity Planning Guide](/user-guide/deployments-administration/capacity-plan.md) **Standalone** (development / edge / IoT): - Single binary, all components in one process - Runs on Linux, macOS, Android ARM64, Raspberry Pi - See [Installation Guide](/getting-started/installation/overview.md) **Storage backends**: S3, GCS, Azure Blob (recommended for production); local disk (development, testing, or small-scale). Metadata: RDS or etcd (cluster), local storage (standalone). For a full overview, see [Deployments & Administration](/user-guide/deployments-administration/overview.md). ### Which metadata storage backend should I use for metasrv? GreptimeDB supports etcd, MySQL, and PostgreSQL as metadata storage backends for the metasrv component. For production deployments, **PostgreSQL or MySQL (including cloud RDS services) is generally recommended** — most teams already have operational experience, monitoring, backup, and disaster recovery strategies for relational databases. That said, **etcd remains fully supported and actively maintained**. It is not deprecated. If your team has strong etcd expertise and operational tooling, it is a perfectly valid choice. The decision ultimately comes down to your team's skill set and existing infrastructure. See [Metadata Storage Configuration](/user-guide/deployments-administration/manage-metadata/configuration.md) for setup instructions for each backend. ### How do I manage GreptimeDB? GreptimeDB uses **standard SQL as its management interface**. You can [create tables](/user-guide/deployments-administration/manage-data/basic-table-operations.md), [alter schemas](/reference/sql/alter.md), set [TTL policies](/user-guide/manage-data/overview.md#manage-data-retention-with-ttl-policies), and configure [indexes](/user-guide/manage-data/data-index.md) — all through SQL. No config files to write, no proprietary APIs to call. For configuration beyond SQL (e.g., node-level settings), see the [Configuration Guide](/user-guide/deployments-administration/configuration.md). ### How do I upgrade GreptimeDB? See the [Upgrade Guide](/user-guide/deployments-administration/upgrade.md) for version-specific instructions, compatibility notes, and breaking changes. ### How do I back up and restore data? GreptimeDB provides export and import tools for full database backup and restoration, including schema-only operations and S3 export support. See [Data Export & Import](/user-guide/deployments-administration/disaster-recovery/back-up-&-restore-data.md). ### Can I migrate data between standalone and cluster mode? Yes. Use [`COPY TO`](/reference/sql/copy.md) to export tables from standalone mode, then [`COPY FROM`](/reference/sql/copy.md) to import them into a cluster (or vice versa). Data is exported in Parquet format and can be staged locally or in object storage (S3, GCS). ### My WAL directory is growing large. Is this normal? WAL (Write-Ahead Log) space is cyclically reused after data is flushed to persistent storage. If the WAL directory appears large, it usually means data has not been flushed yet, or the WAL retention settings need tuning. WAL space is temporary — when measuring storage consumption, measure only the data directory (`data`). For WAL configuration options, see the [Configuration Guide](/user-guide/deployments-administration/configuration.md). ### Queries fail with `Too many files to read concurrently`. What should I do? This error means a single query is trying to scan more SST files than the per-query concurrency cap. A typical message: ``` Too many files to read concurrently: 1528, max allowed: 384 ``` Two common causes: - **Too many small SST files** — often seen after backfilling historical data with widely-spread timestamps, before compaction has merged them. - **The default file concurrency cap is too conservative** for your CPU/memory budget. **Diagnose**: use the [SSTS_MANIFEST](/reference/sql/information-schema/ssts-manifest.md) view to inspect file counts per table per day. Filter by `min_ts` to keep the result set manageable: ```sql SELECT table_id, date_trunc('day', min_ts), COUNT(*) AS files, SUM(num_rows) AS rows FROM information_schema.ssts_manifest WHERE min_ts > '2026-05-01 00:00:00' GROUP BY table_id, date_trunc('day', min_ts) ORDER BY files DESC; ``` **Mitigate**: 1. Raise the per-query file cap on the datanode (or standalone) under `[region_engine.mito]`: ```toml [region_engine.mito] max_concurrent_scan_files = 1024 ``` The default `384` is intentionally conservative. On hosts with more CPU and memory headroom, a larger value lets heavier scans finish without being rejected. Restart the affected datanodes after editing. 2. Trigger manual compaction using the Strict Window Compaction Strategy. If a single day holds many small files, use a window smaller than the default 1 day — see [Compaction](/user-guide/deployments-administration/manage-data/compaction.md): ```sql -- 1-hour window, parallelism=2 ADMIN COMPACT_TABLE('', 'swcs', 'window=3600,parallelism=2'); ``` ### What are GreptimeDB's scalability characteristics? - No strict limitations on table or column count; performance scales with primary key design rather than table count. - Automatic time-based organization within regions. - Manual distributed sharding via `PARTITION` clause — see [Table Sharding Guide](/user-guide/deployments-administration/manage-data/table-sharding.md). - Multi-tiered caching (write cache + LRU read cache) for optimal performance. - Object storage backend (S3/GCS/Azure Blob) provides virtually unlimited storage capacity. - Distributed query execution with MPP for large datasets. ### How does data distribution work? - Manual partitioning via `PARTITION` clause during table creation — see [Table Sharding Guide](/user-guide/deployments-administration/manage-data/table-sharding.md). - Time-based automatic organization within regions. - Manual region migration for load balancing — see [Region Migration Guide](/user-guide/deployments-administration/manage-data/region-migration.md). - Automatic region failover for disaster recovery — see [Region Failover](/user-guide/deployments-administration/manage-data/region-failover.md). ### What disaster recovery options are available? GreptimeDB offers multiple disaster recovery strategies: - **Standalone DR**: Remote WAL + object storage, RPO=0, RTO in minutes. - **Region Failover**: Automatic failover for individual regions with minimal downtime. - **Active-Active Failover** (Enterprise): Synchronous request replication between two nodes. - **Cross-Region Single Cluster**: Spans three regions with zero RPO and region-level fault tolerance. - **Backup and Restore**: Periodic data backups with RPO depending on backup frequency. See [Disaster Recovery Overview](/user-guide/deployments-administration/disaster-recovery/overview.md). ### What should I do if ingestion fails with `Procedure poison key already exists`? This error blocks ingestion when a schema-on-write `ALTER TABLE` (typically adding a new column for an incoming attribute) fails after exhausting retries (12 by default), leaving a stale poison key in the metadata store. Subsequent writes that try to evolve the same table are then rejected. A typical error looks like: ``` Procedure poison key already exists with a different value Key: /__procedure_poison/table/ ``` **Recovery steps**: 1. Delete the poison key from the metadata store. Replace `--backend` and `--store-addrs` with your own — see [Metadata Interaction](/reference/command-lines/utilities/metadata-interaction.md#delete-key-value-pair): ```bash greptime cli meta del key \ --store-addrs=$ENDPOINT \ --backend=postgres-store \ /__procedure_poison/table/ ``` 2. Run table reconciliation so that Metasrv and Datanode metadata converge. Use the schema and table that were affected — see [Table Reconciliation](/user-guide/deployments-administration/maintenance/table-reconciliation.md): ```sql USE ; ADMIN reconcile_table(''); ``` 3. If ingestion still fails with `Column ... not found in logical region`, the logical table's column metadata is out of sync with its physical table. Repair it via the CLI — see [Repair logical tables](/reference/command-lines/utilities/repair-logical-tables.md): ```bash greptime cli meta repair logical-tables \ --store-addrs=$ENDPOINT \ --backend=postgres-store \ --table-names= \ --schema-name= \ --catalog-name=greptime ``` **Troubleshooting tip**: If `ADMIN reconcile_*` returns `Done` immediately but Metasrv logs show no `Reconciling table:` entries, you are likely talking to a different Metasrv than expected — for example, another GreptimeDB cluster deployed in a separate namespace. Verify the topology (e.g. `kubectl get pods -A | grep meta`) before retrying. ### How do I monitor and troubleshoot GreptimeDB? GreptimeDB exposes Prometheus-compatible metrics and provides health check endpoints. For monitoring setup and troubleshooting guides, see [Monitoring Overview](/user-guide/deployments-administration/monitoring/overview.md). ## Open Source vs Enterprise vs Cloud ### What are the differences between GreptimeDB versions? - **Open Source**: Full distributed system, multiple protocol support, basic authentication. - **Enterprise**: Adds cost-based query optimizer, active-active failover, automatic scaling/indexing, RBAC/LDAP, and 24/7 support. - **GreptimeCloud**: Fully managed with resource and performance guarantees for production workloads, predictable pricing, and SLA guarantees. For a detailed feature comparison, see [Pricing & Features](https://greptime.com/pricing#differences). ### Does the GreptimeDB Dashboard have authentication? The open-source [GreptimeDB Dashboard](/getting-started/installation/greptimedb-dashboard.md) does not include built-in authentication. To restrict access, you can: - Place a reverse proxy (e.g., Nginx, Caddy) in front of the dashboard and configure HTTP Basic Auth or other authentication mechanisms. - Host the dashboard behind your organization's internal authentication system. **GreptimeDB Enterprise** provides a management console with built-in authentication and access control. ### What security features are available? **Open Source**: - Basic username/password authentication - User-level read/write access control - TLS/SSL support for connections **Enterprise / Cloud**: - Role-based access control (RBAC) - LDAP support - Team management and API keys - Data encryption at rest - Audit logging for compliance --- ## FAQ and Others In this section, we present the [most frequently asked questions](./faq.md) and some additional information. --- ## For AI Agents GreptimeDB is built to work with AI coding agents. An agent can deploy, configure, ingest, and query GreptimeDB on its own through standard protocols (OTLP, Prometheus, MySQL/PostgreSQL, SQL/PromQL), and the resources below help it do that reliably. ## Quickest start: one instruction The entry-point quickstart guide is hosted as a fetchable markdown file. Give your agent the prompt below and it takes it from there — fetching the guide at runtime, deciding whether GreptimeDB fits, picking the right install and write path, and navigating the docs via `llms.txt`. No installation required. > **AGENT ONBOARDING:** Read https://docs.greptime.com/SKILL.md and follow the instructions to use GreptimeDB with your AI agent — deploy, configure, ingest, and query. ## GreptimeDB MCP Server The [GreptimeDB MCP Server](../user-guide/integrations/mcp.md) implements the Model Context Protocol, so agents can securely explore and analyze your databases — list tables, read data, and run SQL, TQL (PromQL-compatible), and range queries. It enforces read-only access and supports data masking, and ships with built-in scenario templates for metrics, trace, and PromQL analysis, IoT monitoring, table operations, and log pipeline creation. ```shell pip install greptimedb-mcp-server ``` See the [greptimedb-mcp-server](https://github.com/GreptimeTeam/greptimedb-mcp-server) repo for transports (stdio, SSE, Streamable HTTP) and configuration. ## GreptimeDB Skills GreptimeDB already speaks open standards that most coding agents know. For our own features — pipelines, flows, triggers — a Skill teaches the agent the complete workflow and gives it the best results. Skills tell the agent *what* to do; the MCP Server provides the tools to *execute* it (for example, the pipeline skill uses `dryrun_pipeline` to verify a config before applying it). - **`greptimedb-quickstart`** — the entry point. When to use GreptimeDB, how to install, which write protocol to choose, how to query, plus pointers to deeper docs. Start here. - **`greptimedb-pipeline`** — parse, transform, and route logs (Learn → Create → Verify → Refine). - **`greptimedb-flow`** — continuous aggregation and materialized views. - **`greptimedb-trigger`** — alerting rules, including converting Prometheus alert rules to `CREATE TRIGGER` (Enterprise). - **`self-monitoring-export`** — for cluster incidents: infer the log export time range from the user's description, then export cluster self-monitoring logs and metrics for investigation. Skills follow the [Agent Skills](https://agentskills.io/) open standard, so they work with Claude Code, OpenAI Codex CLI, GitHub Copilot, Cursor, and others. Every Skill is also hosted as a fetchable markdown file at `https://docs.greptime.com/skills//SKILL.md` (for example, [`greptimedb-pipeline`](https://docs.greptime.com/skills/greptimedb-pipeline/SKILL.md)), so an agent can load one at runtime without installing anything. To install a Skill persistently into your agent's config, use the `skills` CLI: ```shell npx skills add https://github.com/GreptimeTeam/docs/tree/main/skills/greptimedb-quickstart ``` See the [skills](https://github.com/GreptimeTeam/docs/tree/main/skills) repo for the full list and install commands. ## Machine-readable docs The whole documentation site is built to be consumed by agents, following the [llmstxt.org](https://llmstxt.org) standard: - [`llms.txt`](https://docs.greptime.com/llms.txt) — a structured index linking every documentation section with a short description. Point an agent at it to find the right page without crawling the site. - [`llms-full.txt`](https://docs.greptime.com/llms-full.txt) — the entire documentation concatenated into one file, for loading the full corpus at once. - **Any page as markdown** — append `.md` to any documentation URL to get the raw markdown of that page (for example, [`/user-guide/integrations/mcp.md`](https://docs.greptime.com/user-guide/integrations/mcp.md)). For ad-hoc questions, the **Ask AI** assistant on [docs.greptime.com](https://docs.greptime.com/) answers in plain language, grounded in the official documentation. ## References - [What GreptimeDB is doing for AI agents](https://greptime.com/blogs/2026-04-08-greptimedb-agent-friendly-infrastructure) --- ## Data Persistence and Indexing Similar to all LSMT-like storage engines, data in MemTables is persisted to durable storage, for example, the local disk file system or object storage service. GreptimeDB adopts [Apache Parquet][1] as its persistent file format. ## SST File Format Parquet is an open source columnar format that provides fast data querying and has already been adopted by many projects, such as Delta Lake. Parquet has a hierarchical structure like "row groups-columns-data pages". Data in a Parquet file is horizontally partitioned into row groups, in which all values of the same column are stored together to form a data page. Data page is the minimal storage unit. This structure greatly improves performance. First, clustering data by column makes file scanning more efficient, especially when only a few columns are queried, which is very common in analytical systems. Second, data of the same column tends to be homogeneous which helps with compression when apply techniques like dictionary and Run-Length Encoding (RLE). ## Data Persistence GreptimeDB provides a configuration item `storage.flush.global_write_buffer_size`, which is flush threshold of the total memory usage for all MemTables. When the size of data buffered in MemTables reaches that threshold, GreptimeDB will pick MemTables and flush them to SST files. ## Indexing Data in SST Files Apache Parquet file format provides inherent statistics in headers of column chunks and data pages, which are used for pruning and skipping. For example, in the above Parquet file, if you want to filter rows where `name` = `Emily`, you can easily skip row group 0 because the max value for `name` field is `Charlie`. This statistical information reduces IO operations. ## Index Files For each SST file, GreptimeDB not only maintains an internal index but also generates a separate file to store the index structures specific to that SST file. The index files utilize the [Puffin][3] format, which offers significant flexibility, allowing for the storage of additional metadata and supporting a broader range of index structures. ![Puffin](/puffin.png) Currently, the inverted index is the first supported index structure, and it is stored within the index file as a Blob. ## Inverted Index In version 0.7, GreptimeDB introduced the inverted index to accelerate queries. The inverted index is a common index structure used for full-text searches, mapping each word in the document to a list of documents containing that word. Greptime has adopted this technology, which originates from search engines, for use in the time series databases. Search engines and time series databases operate in separate domains, yet the principle behind the applied inverted index technology is similar. This similarity requires some conceptual adjustments: 1. Term: In GreptimeDB, it refers to the column value of the time series. 2. Document: In GreptimeDB, it refers to the data segment containing multiple time series. The inverted index enables GreptimeDB to skip data segments that do not meet query conditions, thus improving scanning efficiency. ![Inverted index searching](/inverted-index-searching.png) For instance, the query above uses the inverted index to identify data segments where `job` equals `apiserver`, `handler` matches the regex `.*users`, and `status` matches the regex `4...`. It then scans these data segments to produce the final results that meet all conditions, significantly reducing the number of IO operations. ### Inverted Index Format ![Inverted index format](/inverted-index-format.png) GreptimeDB builds inverted indexes by column, with each inverted index consisting of an FST and multiple Bitmaps. The FST (Finite State Transducer) enables GreptimeDB to store mappings from column values to Bitmap positions in a compact format and provides excellent search performance and supports complex search capabilities (such as regular expression matching). The Bitmaps maintain a list of data segment IDs, with each bit representing a data segment. ### Index Data Segments GreptimeDB divides an SST file into multiple indexed data segments, with each segment housing an equal number of rows. This segmentation is designed to optimize query performance by scanning only the data segments that match the query conditions. For example, if a data segment contains 1024 rows and the list of data segments identified through the inverted index for the query conditions is `[0, 2]`, then only the 0th and 2nd data segments in the SST file—from rows 0 to 1023 and 2048 to 3071, respectively—need to be scanned. The number of rows in a data segment is controlled by the engine option `index.inverted_index.segment_row_count`, which defaults to `1024`. A smaller value means more precise indexing and often results in better query performance but increases the cost of index storage. By adjusting this option, a balance can be struck between storage costs and query performance. ## Unified Data Access Layer: OpenDAL GreptimeDB uses [OpenDAL][2] to provide a unified data access layer, thus, the storage engine does not need to interact with different storage APIs, and data can be migrated to cloud-based storage like AWS S3 seamlessly. [1]: https://parquet.apache.org [2]: https://github.com/datafuselabs/opendal [3]: https://iceberg.apache.org/puffin-spec --- ## Metric Engine ## Overview The `Metric` engine is a component of GreptimeDB, and it's an implementation of the storage engine. It mainly targets scenarios with a large number of small tables for observable metrics. Its main feature is to use synthetic physical wide tables to store a large amount of small table data, achieving effects such as reuse of the same column and metadata. This reduces storage overhead for small tables and improves columnar compression efficiency. The concept of a table becomes even more lightweight under the `Metric` engine. ## Concepts The `Metric` engine introduces two new concepts: "logical table" and "physical table". From the user's perspective, logical tables are exactly like ordinary ones. From a storage point-of-view, physical Regions are just regular Regions. ### Logical Table A logical table refers to user-defined tables. Just like any other ordinary table, its definition includes the name of the table, column definitions, index definitions etc. All operations such as queries or write-ins by users are based on these logical tables. Users don't need to worry about differences between logical and ordinary tables during usage. From an implementation standpoint, a logical table is virtual; it doesn't directly read or write physical data but maps read/write requests into corresponding requests for physical tables in order to implement data storage and querying. ### Physical Table A physical table is a table that actually stores data, possessing several physical Regions defined by partition rules. ## Architecture and Design The main design architecture of the `Metric` engine is as follows: ![Arch](/metric-engine-arch.png) In the current version implementation, the `Metric` engine reuses the `Mito` engine to achieve storage and query capabilities for physical data. It also provides access to both physical tables and logical tables simultaneously. Regarding partitioning, logical tables have identical partition rules and Region distribution as physical tables. This makes sense because the data of logical tables are directly stored in physical tables, so their partition rules are consistent. Concerning routing metadata, the routing address of a logical table is a logical address - what its corresponding physical table is - then through this physical table for secondary routing to obtain the real physical address. This indirect routing method can significantly reduce the number of metadata modifications required when Region migration scheduling occurs in Metric engines. Operationally speaking, The `Metric` engine supports standard DML operations (INSERT, DELETE, SELECT) on logical tables. However, it only supports limited operations on physical tables to prevent misoperations - for example, writing directly to a physical table is prohibited as it could affect user's logical table data. Generally speaking, users can consider that they have read-only access to these physical tables. To improve performance during simultaneous DDL (Data Definition Language) operations on many tables, the 'Metric' engine has introduced some batch DDL operations. These batch DDL operations can merge lots of DDL actions into one request thereby reducing queries and modifications times for metadata thus enhancing performance. This feature is particularly beneficial in scenarios such as the automatic creation requests brought about by large amounts of metrics during Prometheus Remote Write cold start-up, as well as the modification requests for numerous route-tables mentioned earlier during migration of many physical regions. Apart from physical data regions belonging to physical tables, the 'Metric' engine creates an additional metadata region physically for each individual physical data region used in storing some metadata needed by itself while maintaining mapping and other states. This metadata includes the mapping relationship between logical tables and physical tables, the mapping relationship between logical columns and physical columns etc. --- ## Datanode(Datanode) ## Introduction `Datanode` is mainly responsible for storing the actual data for GreptimeDB. As we know, in GreptimeDB, a `table` can have one or more `Region`s, and `Datanode` is responsible for managing the reading and writing of these `Region`s. `Datanode` is not aware of `table` and can be considered as a `region server`. Therefore, `Frontend` and `Metasrv` operate `Datanode` at the granularity of `Region`. ![Datanode](/datanode.png) ## Components A `Datanode` contains all the components needed for a `region server`. Here we list some of the vital parts: - A gRPC service is provided for reading and writing region data, and `Frontend` uses this service to read and write data from `Datanode`s. - An HTTP service, through which you can obtain metrics, configuration information, etc., of the current node. - `Heartbeat Task` is used to send heartbeat to the `Metasrv`. The heartbeat plays a crucial role in the distributed architecture of GreptimeDB and serves as a basic communication channel for distributed coordination. The upstream heartbeat messages contain important information such as the workload of a `Region`. If the `Metasrv `has made scheduling(such as `Region` migration) decisions, it will send instructions to the `Datanode` via downstream heartbeat messages. - The `Datanode` does not include components like the `Physical Planner`, `Optimizer`, etc. (these are placed in the `Frontend`). The user's query requests for one or more `Table`s will be transformed into `Region` query requests in the `Frontend`. The `Datanode` is responsible for handling these `Region` query requests. - A `Region Manager` is used to manage all `Region`s on a `Datanode`. - GreptimeDB supports a pluggable multi-engine architecture, with existing engines including `File Engine` and `Mito Engine`. --- ## Query Engine ## Introduction GreptimeDB's query engine is built on [Apache DataFusion][1] (subproject under [Apache Arrow][2]), a brilliant query engine written in Rust. It provides a set of well functional components from logical plan, physical plan and the execution runtime. Below explains how each component is orchestrated and their positions during execution. ![Execution Procedure](/execution-procedure.png) The entry point is the logical plan, which is used as the general intermediate representation of a query or execution logic etc. Two noticeable sources of logical plan are from: 1. the user query, like SQL through SQL parser and planner; 2. the Frontend's distributed query, which is explained in details in the following section. Next is the physical plan, or the execution plan. Unlike the logical plan which is a big enumeration containing all the logical plan variants (except the special extension plan node), the physical plan is in fact a trait that defines a group of methods invoked during execution. All data processing logics are packed in corresponding structures that implement the trait. They are the actual operations performed on the data, like aggregator `MIN` or `AVG`, and table scan `SELECT ... FROM`. The optimization phase which improves execution performance by transforming both logical and physical plans, is now all based on rules. It is also called, "Rule Based Optimization". Some of the rules are DataFusion native and others are customized in Greptime DB. In the future, we plan to add more rules and leverage the data statistics for Cost Based Optimization/CBO. The last phase "execute" is a verb, stands for the procedure that reads data from storage, performs calculations and generates the expected results. Although it's more abstract than previously mentioned concepts, you can just simply imagine it as executing a Rust async function. And it's indeed a future (stream). `EXPLAIN [VERBOSE] ` is very useful if you want to see how your SQL is represented in the logical or physical plan. ## Data Representation GreptimeDB uses [Apache Arrow][2] as the in-memory data representation. It's column-oriented, in cross-platform format, and also contains many high-performance data operators. These features make it easy to share data in many different environments and implement calculation logic. ## Indexing In time series data, there are two important dimensions: timestamp and tag columns (or like primary key in a general relational database). GreptimeDB groups data in time buckets, so it's efficient to locate and extract data within the expected time range at a very low cost. The mainly used persistent file format [Apache Parquet][3] in GreptimeDB helps a lot -- it provides multi-level indices and filters that make it easy to prune data during querying. In the future, we will make more use of this feature, and develop our separated index to handle more complex use cases. ## Extensibility Extending operations in GreptimeDB is extremely simple. You can implement your operator like [this][5]. ## Distributed Execution Covered in [Distributed Querying][6]. [1]: https://github.com/apache/arrow-datafusion [2]: https://arrow.apache.org/ [3]: https://parquet.apache.org [4]: python-scripts.md [5]: https://github.com/GreptimeTeam/greptimedb/blob/main/docs/how-to/how-to-write-aggregate-function.md [6]: ../frontend/distributed-querying.md --- ## Storage Engine ## Introduction The `storage engine` is responsible for storing the data of the database. Mito, based on [LSMT][1] (Log-structured Merge-tree), is the storage engine we use by default. We have made significant optimizations for handling time-series data scenarios, so mito engine is not suitable for general purposes. ## Architecture The picture below shows the architecture and process procedure of the storage engine. ![Architecture](/storage-engine-arch.png) The architecture is the same as a traditional LSMT engine: - [WAL][2] - Guarantees high durability for data that is not yet being flushed. - Based on the `Log Store` API, thus it doesn't care about the underlying storage media. - Log records of the WAL can be stored in the local disk, or a distributed log service which implements the `Log Store` API. - Memtables: - Data is written into the `active memtable`, aka `mutable memtable` first. - When a `mutable memtable` is full, it will be changed to a `read-only memtable`, aka `immutable memtable`. - SST - The full name of SST, aka SSTable is `Sorted String Table`. - `Immutable memtable` is flushed to persistent storage and produces an SST file. - Compactor - Small `SST` is merged into large `SST` by the compactor via compaction. - The default compaction strategy is [TWCS][3]. - Manifest - The manifest stores the metadata of the engine, such as the metadata of the `SST`. - Cache - Speed up queries. [1]: https://en.wikipedia.org/wiki/Log-structured_merge-tree [2]: https://en.wikipedia.org/wiki/Write-ahead_logging [3]: https://cassandra.apache.org/doc/latest/cassandra/operating/compaction/twcs.html ## Data Model The data model provided by the storage engine is between the `key-value` model and the tabular model. ```txt tag-1, ..., tag-m, timestamp -> field-1, ..., field-n ``` Each row of data contains multiple tag columns, one timestamp column, and multiple field columns. - `0 ~ m` tag columns - Tag columns can be nullable. - Specified during table creation using `PRIMARY KEY`. - Must include one timestamp column - Timestamp column cannot be null. - Specified during table creation using `TIME INDEX`. - `0 ~ n` field columns - Field columns can be nullable. - Data is sorted by tag columns and timestamp column. ### Region Data in the storage engine is stored in `regions`, which are logical isolated storage units within the engine. Rows within a `region` must have the same `schema`, which defines the tag columns, timestamp column, and field columns within the `region`. The data of tables in the database is stored in one or multiple `regions`. --- ## Write-Ahead Logging ## Introduction Our storage engine is inspired by the Log-structured Merge Tree (LSMT). Mutating operations are applied to a MemTable instead of persisting to disk, which significantly improves performance but also brings durability-related issues, especially when the Datanode crashes unexpectedly. Similar to all LSMT-like storage engines, GreptimeDB uses a write-ahead log (WAL) to ensure data durability and is safe from crashing. WAL is an append-only file group. All `INSERT`, `UPDATE` and `DELETE` operations are transformed into operation entries and then appended to WAL. Once operation entries are persisted to the underlying file, the operation can be further applied to MemTable. When the Datanode restarts, operation entries in WAL are replayed to reconstruct the correct in-memory state. ![WAL in Datanode](/wal.png) ## Namespace Namespace of WAL is used to separate entries from different tables (different regions). Append and read operations must provide a Namespace. Currently, region ID is used as the Namespace, because each region has a MemTable that needs to be reconstructed when Datanode restarts. ## Synchronous/Asynchronous flush By default, appending to WAL is asynchronous, which means the writer will not wait until entries are flushed to disk. This setting provides higher performance, but may lose data when running host shutdown unexpectedly. In the other hand, synchronous flush provides higher durability at the cost of performance. In v0.4 version, the new region worker architecture can use batching to alleviate the overhead of sync flush. --- ## Arrangement Arrangement stores the state in the dataflow's process. It stores the streams of update flows for further querying and updating. The arrangement essentially stores key-value pairs with timestamps to mark their change time. Internally, the arrangement receives tuples like `((Key Row, Value Row), timestamp, diff)` and stores them in memory. One can query key-value pairs at a certain time using the `get(now: Timestamp, key: Row)` method. The arrangement also assumes that everything older than a certain time (also known as the low watermark) has already been ingested to the sink tables and does not keep a history for them. :::tip NOTE The arrangement allows for the removal of keys by setting the `diff` to -1 in incoming tuples. Moreover, if a row has been previously added to the arrangement and the same key is inserted with a different value, the original value is overwritten with the new value. ::: --- ## Flownode Batching Mode Developer Guide This guide provides a brief overview of the batching mode in `flownode`. It's intended for developers who want to understand the internal workings of this mode. ## Overview The batching mode in `flownode` is designed for continuous data aggregation. It periodically executes a user-defined SQL query over small, discrete time windows. This is in contrast to a streaming mode where data is processed as it arrives. The core idea is to: 1. Define a `flow` with a SQL query that aggregates data from a source table into a sink table. 2. The query typically includes a time window function (e.g., `date_bin`) on a timestamp column. 3. When new data is inserted into the source table, the system marks the corresponding time windows as "dirty." 4. A background task periodically wakes up, identifies these dirty windows, and re-runs the aggregation query for those specific time ranges. 5. The results are then inserted into the sink table, effectively updating the aggregated view. ## Architecture The batching mode consists of several key components that work together to achieve this continuous aggregation. As shown in the diagram below: ![batching mode architecture](/batching_mode_arch.png) ### `BatchingEngine` The `BatchingEngine` is the heart of the batching mode. It's a central component that manages all active flows. Its primary responsibilities are: - **Task Management**: It maintains a map of `FlowId` to `BatchingTask`. It handles the creation, deletion, and retrieval of these tasks. - **Event Dispatching**: When new data arrives (via `handle_inserts_inner`) or when time windows are explicitly marked as dirty (`handle_mark_dirty_time_window`), the `BatchingEngine` identifies which flows are affected and forwards the information to the corresponding `BatchingTask`s. ### `BatchingTask` A `BatchingTask` represents a single, independent data flow. Each task is associated with one `flow` definition and runs in its own asynchronous loop. - **Configuration (`TaskConfig`)**: This struct holds the immutable configuration for a flow, such as the SQL query, source and sink table names, and time window expression. - **State (`TaskState`)**: This contains the dynamic, mutable state of the task, most importantly the `DirtyTimeWindows`. - **Execution Loop**: The task runs an infinite loop (`start_executing_loop`) that: 1. Checks for a shutdown signal. 2. Waits for a scheduled interval or until it's woken up. 3. Generates a new query plan (`gen_insert_plan`) based on the current set of dirty time windows. 4. Executes the query (`execute_logical_plan`) against the database. 5. Cleans up the processed dirty windows. ### `TaskState` and `DirtyTimeWindows` - **`TaskState`**: This struct tracks the runtime state of a `BatchingTask`. It includes `dirty_time_windows`, which is crucial for determining what work needs to be done. - **`DirtyTimeWindows`**: This is a key data structure that keeps track of which time windows have received new data since the last query execution. It stores a set of non-overlapping time ranges. When a task's execution loop runs, it consults this structure to build a `WHERE` clause that filters the source table for only the dirty time windows. ### `TimeWindowExpr` The `TimeWindowExpr` is a helper utility for dealing with time window functions like `TUMBLE`. - **Evaluation**: It can take a timestamp and evaluate the time window expression to determine the start and end of the window that the timestamp falls into. - **Window Size**: It can also determine the size (duration) of the time window from the expression. This is essential for both marking windows as dirty and for generating the correct filter conditions when querying the source table. ## Query Execution Flow Here's a simplified step-by-step walkthrough of how a query is executed in batch mode: 1. **Data Ingestion**: New data is written to a source table. 2. **Marking Dirty**: The `BatchingEngine` receives a notification about the new data. It uses the `TimeWindowExpr` associated with each relevant flow to determine which time windows are affected by the new data points. These windows are then added to the `DirtyTimeWindows` set in the corresponding `TaskState`. 3. **Task Wake-up**: The `BatchingTask`'s execution loop wakes up, either due to its periodic schedule or because it was notified of a large backlog of dirty windows. 4. **Plan Generation**: The task calls `gen_insert_plan`. This method: - Inspects the `DirtyTimeWindows`. - Generates a series of `OR`'d `WHERE` clauses (e.g., `(ts >= 't1' AND ts < 't2') OR (ts >= 't3' AND ts < 't4') ...`) that cover the dirty windows. - Rewrites the original SQL query to include this new filter, ensuring that only the necessary data is processed. 5. **Execution**: The modified query plan is sent to the `Frontend` for execution. The database processes the aggregation on the filtered data. 6. **Upsert**: The results are inserted into the sink table. The sink table is typically defined with a primary key that includes the time window column, so new results for an existing window will overwrite (upsert) the old ones. 7. **State Update**: The `DirtyTimeWindows` set is cleared of the windows that were just processed. The task then goes back to sleep until the next interval. --- ## Dataflow The `dataflow` module (see `flow::compute` module) is the core computing module of `flow`. It takes a SQL query and transforms it into flow's internal execution plan. This execution plan is then rendered into an actual dataflow, which is essentially a directed acyclic graph (DAG) of functions with input and output ports. The dataflow is triggered to run when needed. Currently, this dataflow only supports `map` and `reduce` operations. Support for `join` operations will be added in the future. Internally, the dataflow handles data in row format, using a tuple `(row, time, diff)`. Here, `row` represents the actual data being passed, which may contain multiple `Value` objects. `time` is the system time which tracks the progress of the dataflow, and `diff` typically represents the insertion or deletion of the row (+1 or -1). Therefore, the tuple represents the insert/delete operation of the `row` at a given system `time`. --- ## Flownode(Flownode) ## Introduction `Flownode` provides a simple streaming process (known as `flow`) ability to the database. `Flownode` manages `flows` which are tasks that receive data from the `source` and send data to the `sink`. `Flownode` support both `standalone` and `distributed` mode. In `standalone` mode, `Flownode` runs in the same process as the database. In `distributed` mode, `Flownode` runs in a separate process and communicates with the database through the network. There are two execution modes for a flow: - **Streaming Mode**: The original mode where data is processed as it arrives. - **Batching Mode**: A newer mode designed for continuous data aggregation. It periodically executes a user-defined SQL query over small, discrete time windows. All aggregation queries now use this mode. For more details, see the [Batching Mode Developer Guide](./batching_mode.md). ## Components A `Flownode` contains all the components needed to execute a flow. The specific components involved depend on the execution mode (Streaming vs. Batching). At a high level, the key parts are: - **Flow Manager**: A central component responsible for managing the lifecycle of all flows. - **Task Executor**: The runtime environment where the flow logic is executed. In streaming mode, this is typically a `FlowWorker`; in batching mode, it's a `BatchingTask`. - **Flow Task**: Represents a single, independent data flow, containing the logic for transforming data from a source to a sink. --- ## Distributed Querying Most steps of querying in frontend and datanode are identical. The only difference is that Frontend have a "special" step in planning phase to make the logical query plan distributed. Let's reference it as "dist planner" in the following text. The modified, distributed logical plan has multiple stages, each of them is executed in different server node. ![Frontend query](/frontend-query.png) ## Dist Planner Planner will traverse the input logical plan, and split it into multiple stages by the "[commutativity rule](https://github.com/GreptimeTeam/greptimedb/blob/main/docs/rfcs/2023-05-09-distributed-planner.md)". This rule is under heavy development. At present it will consider things like: - whether the operator itself is commutative - how the partition rule is configured - etc... ## Dist Plan Except the first stage, which have to read data from files in storage. All other stages' leaf node are actually a gRPC call to its previous stage. Sub-plan in a stage is itself a complete logical plan, and can be executed independently without the follow up stages. The plan is encoded in [substrait format](https://substrait.io). --- ## Frontend(Frontend) The **Frontend** is a stateless service that serves as the entry point for client requests in GreptimeDB. It provides a unified interface for multiple database protocols and acts as a proxy that forwards read/write requests to appropriate Datanodes in the distributed system. ## Core Functions - **Protocol Support**: Multiple database protocols including SQL, PromQL, MySQL, and PostgreSQL. See [Protocols][1] for details - **Request Routing**: Routes requests to appropriate Datanodes based on metadata - **Query Distribution**: Splits distributed queries across multiple nodes - **Response Aggregation**: Combines results from multiple Datanodes - **Authorization**: Security and access control validation ## Architecture ### Key Components - **Protocol Handlers**: Handle different database protocols - **Catalog Manager**: Caches metadata from Metasrv to enable efficient request routing and schema validation - **Dist Planner**: Converts logical plans to distributed execution plans - **Request Router**: Determines target Datanodes for each request ### Request Flow ![request flow](/request_flow.png) ### Deployment The following picture shows a typical deployment of GreptimeDB in the cloud. The `Frontend` instances form a cluster to serve the requests from clients: ![frontend](/frontend.png) ## Details - [Table Sharding][2] - [Distributed Querying][3] [1]: /user-guide/protocols/overview.md [2]: ./table-sharding.md [3]: ./distributed-querying.md --- ## Table Sharding(Frontend) The sharding of stored data is essential to any distributed database. This document will describe how table's data in GreptimeDB is being sharded, and distributed. ## Partition For the syntax of creating a partitioned table, please refer to the [Table Sharding](/user-guide/deployments-administration/manage-data/table-sharding.md) section in the User Guide. ## Region The data within a table is logically split after creating partitions. You may ask the question " how are the data, after being logically partitioned, stored in the GreptimeDB? The answer is in "`Region`"s. Each region is corresponding to a partition, and stores the data in the partition. The regions are distributed among `Datanode`s. Our `metasrv` will move regions among Datanodes automatically, according to the states of Datanodes. Also, `metasrv` can split or merge regions according to their data volume or access pattern. The relationship between partition and region can be viewed as the following diagram: ```text ┌───────┐ │ │ │ Table │ │ │ └───┬───┘ │ Range [Start, end) │ Horizontally Split Data ┌──────────────────┼──────────────────┐ │ │ │ │ │ │ ┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐ │ │ │ │ │ │ │ Partition │ │ Partition │ │ Partition │ │ │ │ │ │ │ │ P0 │ │ P1 │ │ Px │ └─────┬─────┘ └─────┬─────┘ └─────┬─────┘ │ │ │ │ │ │ One-to-one mapping of ┌───────┼──────────────────┼───────┐ │ Partition and Region │ │ │ │ │ │ ┌─────▼─────┐ ┌─────▼─────┐ │ ┌─────▼─────┐ │ │ │ │ │ │ │ │ │ │ Region │ │ Region │ │ │ Region │ │ │ │ │ │ │ │ │ │ │ R0 │ │ R1 │ │ │ Ry │ │ └───────────┘ └───────────┘ │ └───────────┘ │ │ └──────────────────────────────────┘ Could be placed in one Datanode --- ## Getting started This page describes how to run GreptimeDB from source in your local environment. ## Prerequisite ### System & Architecture At the moment, GreptimeDB supports Linux(both amd64 and arm64), macOS (both amd64 and Apple Silicone) and Windows. ### Build Dependencies - [Git](https://git-scm.com/book/en/v2/Getting-Started-The-Command-Line) (optional) - C/C++ Toolchain: provides essential tools for compiling and linking. This is available either as `build-essential` on ubuntu or a similar name on other platforms. - Rust ([guide][1]) - Compile the source code - Protobuf ([guide][2]) - Compile the proto file - Note that the version needs to be >= 3.15. You can check it with `protoc --version` - Machine: Recommended memory is 16GB or more, or use the [mold](https://github.com/rui314/mold) tool to reduce memory usage during linking. [1]: [2]: ## Compile and Run Start GreptimeDB standalone instance in just a few commands! ```shell git clone https://github.com/GreptimeTeam/greptimedb.git cd greptimedb cargo run -- standalone start ``` Next, you can choose the protocol you like to interact with in GreptimeDB. Or if you just want to build the server without running it: ```shell cargo build # --release ``` The artifacts can be found under `$REPO/target/debug` or `$REPO/target/release`, depending on the build mode (whether the `--release` option is passed) ## Unit test GreptimeDB is well-tested, the entire unit test suite is shipped with source code. To test them, run with [nextest](https://nexte.st/index.html). To install nextest using cargo, run: ```shell cargo install cargo-nextest --locked ``` Or you can check their [docs](https://nexte.st/docs/installation/pre-built-binaries/) for other ways to install. After nextest is ready, you can run the test suite with: ```shell cargo nextest run ``` ## Docker We also provide pre-build binary via Docker. It's which is available in dockerhub: [https://hub.docker.com/r/greptime/greptimedb](https://hub.docker.com/r/greptime/greptimedb) --- ## How to trace GreptimeDB GreptimeDB uses Rust's [tracing](https://docs.rs/tracing/latest/tracing/) framework for code instrument. For the specific details and usage of tracing, please refer to the official documentation of tracing. By transparently transmitting `trace_id` and other information on the entire distributed system, we can record the function call chain of the entire distributed link, know the time of each tracked function take and other related information, so as to monitor the entire system. ## Define tracing context in RPC Because the tracing framework does not natively support distributed tracing, we need to manually pass information such as `trace_id` in the RPC message to correctly identify the function calling relationship. We use standards based on [w3c](https://www.w3.org/TR/trace-context/#traceparent-header-field-values) to encode relevant information into `tracing_context` and attach the message to the RPC header. Mainly defined in: - `frontend` interacts with `datanode`: `tracing_context` is defined in [`RegionRequestHeader`](https://github.com/GreptimeTeam/greptime-proto/blob/main/proto/greptime/v1/region/server.proto) - `frontend` interacts with `metasrv`: `tracing_context` is defined in [`RequestHeader`](https://github.com/GreptimeTeam/greptime-proto/blob/main/proto/greptime/v1/meta/common.proto) - Client interacts with `frontend`: `tracing_context` is defined in [`RequestHeader`](https://github.com/GreptimeTeam/greptime-proto/blob/main/proto/greptime/v1/common.proto) ## Pass tracing context in RPC call We build a `TracingContext` structure that encapsulates operations related to the tracing context. [Related code](https://github.com/GreptimeTeam/greptimedb/blob/main/src/common/telemetry/src/tracing_context.rs) GreptimeDB uses `TracingContext::from_current_span()` to obtain the current tracing context, uses the `to_w3c()` method to encode the tracing context into a w3c-compliant format, and attaches it to the RPC message, so that the tracing context is correctly distributed passed within the component. The following example illustrates how to obtain the current tracing context and pass the parameters correctly when constructing the RPC message, so that the tracing context is correctly passed among the distributed components. ```rust let request = RegionRequest { header: Some(RegionRequestHeader { tracing_context: TracingContext::from_current_span().to_w3c(), ..Default::default() }), body: Some(region_request::Body::Alter(request)), }; ``` On the receiver side of the RPC message, the tracing context needs to be correctly decoded and used to build the first `span` to trace the function call. For example, the following code will correctly decode the `tracing_context` in the received RPC message using the `TracingContext::from_w3c` method. And use the `attach` method to attach the context message to the newly created `info_span!("RegionServer::handle_read")`, so that the call can be tracked across distributed components. ```rust ... let tracing_context = request .header .as_ref() .map(|h| TracingContext::from_w3c(&h.tracing_context)) .unwrap_or_default(); let result = self .handle_read(request) .trace(tracing_context.attach(info_span!("RegionServer::handle_read"))) .await?; ... ``` ## Use `tracing::instrument` to instrument the code We use the `instrument` macro provided by tracing to instrument the code. We only need to annotate the `instrument` macro in the function that needs to be instrument. The `instrument` macro will print every function parameter on each function call into the span in the form of `Debug`. For parameters that do not implement the `Debug` trait, or the structure is too large and has too many parameters, resulting in a span that is too large. If you want to avoid these situations, you need to use `skip_all` to skip printing all parameters. ```rust #[tracing::instrument(skip_all)] async fn instrument_function(....) { ... } ``` ## Code instrument across runtime Rust's tracing library will automatically handle the nested relationship between instrument functions in the same runtime, but if a function call across the runtime, tracing library cannot automatically trace such calls, and we need to manually pass the context across the runtime. ```rust let tracing_context = TracingContext::from_current_span(); let handle = runtime.spawn(async move { handler .handle(query) .trace(tracing_context.attach(info_span!("xxxxx"))) ... }); ``` For example, the above code needs to perform tracing across runtimes. We first obtain the current tracing context through `TracingContext::from_current_span()`, create a span in another runtime, and attach the span to the current context, and we are done. The hidden code points that span the runtime are eliminated, and the call chain is correctly traced. --- ## How to use tokio-console in GreptimeDB This document introduces how to use the [tokio-console](https://github.com/tokio-rs/console) in GreptimeDB. First, build GreptimeDB with feature `cmd/tokio-console`. Also the `tokio_unstable` cfg must be enabled: ```bash RUSTFLAGS="--cfg tokio_unstable" cargo build -F cmd/tokio-console ``` Then start GreptimeDB with tokio console binding address config: `--tokio-console-addr`. Remember to run with the `tokio_unstable` cfg. For example: ```bash RUSTFLAGS="--cfg tokio_unstable" greptime --tokio-console-addr="127.0.0.1:6669" standalone start ``` Now you can use `tokio-console` to connect to GreptimeDB's tokio console subscriber: ```bash tokio-console [TARGET_ADDR] ``` "TARGET_ADDR" defaults to "\". :::tip Note You can refer to [tokio-console](https://github.com/tokio-rs/console) to see the installation of `tokio-console`. ::: --- ## How to write a gRPC SDK for GreptimeDB A GreptimeDB gRPC SDK only needs to handle the writes. The reads are standard SQL and PromQL, can be handled by any JDBC client or Prometheus client. This is also why GreptimeDB gRPC SDKs are all named like "`greptimedb-ingester-`". Please make sure your GreptimeDB SDK follow the same naming convention. ## `GreptimeDatabase` Service GreptimeDB defines a custom gRPC service called `GreptimeDatabase`. All you need to do in your SDK are implement it. You can find its Protobuf definitions [here](https://github.com/GreptimeTeam/greptime-proto/blob/main/proto/greptime/v1/database.proto). The service contains two RPC methods: ```protobuf service GreptimeDatabase { rpc Handle(GreptimeRequest) returns (GreptimeResponse); rpc HandleRequests(stream GreptimeRequest) returns (GreptimeResponse); } ``` The `Handle` method is for unary call: when a `GreptimeRequest` is received and processed by a GreptimeDB server, it responds with a `GreptimeResponse` immediately. The `HandleRequests` acts in a "[Client streaming RPC](https://grpc.io/docs/what-is-grpc/core-concepts/#client-streaming-rpc)" style. It ingests a stream of `GreptimeRequest`, and handles them on the fly. After all the requests have been handled, it returns a summarized `GreptimeResponse`. Through `HandleRequests`, we can achieve a very high throughput of requests handling. ### `GreptimeRequest` The `GreptimeRequest` is a Protobuf message defined like this: ```protobuf message GreptimeRequest { RequestHeader header = 1; oneof request { InsertRequests inserts = 2; QueryRequest query = 3; DdlRequest ddl = 4; DeleteRequests deletes = 5; RowInsertRequests row_inserts = 6; RowDeleteRequests row_deletes = 7; } } ``` A `RequestHeader` is needed, it includes some context, authentication and others. The "oneof" field contains the request to the GreptimeDB server. Note that we have two types of insertions, one is in the form of "column" (the `InsertRequests`), and the other is " row" (`RowInsertRequests`). It's generally recommended to use the "row" form, since it's more natural for insertions on a table, and easier to use. However, if there's a need to insert a large number of columns at once, or there're plenty of "null" values to insert, the "column" form is better to be used. ### `GreptimeResponse` The `GreptimeResponse` is a Protobuf message defined like this: ```protobuf message GreptimeResponse { ResponseHeader header = 1; oneof response {AffectedRows affected_rows = 2;} } ``` The `ResponseHeader` contains the response's status code, and error message (if there's any). The "oneof" response only contains the affected rows for now. GreptimeDB has a lot of SDKs now, you can refer to them [here](https://github.com/GreptimeTeam?q=ingester&type=all&language=&sort=) for some examples. --- ## Admin API :::tip Note that all Admin API endpoints in this document listen on Metasrv's `HTTP_PORT`, which defaults to `4000`. ::: The Admin API provides a simple way to view cluster information, including metasrv health detection, metasrv leader query, database metadata query, and datanode heartbeat detection. The Admin API is an HTTP service that provides a set of RESTful APIs that can be called through HTTP requests. The Admin API is simple, user-friendly and safe. Available APIs: - /health - /leader - /heartbeat - /maintenance All these APIs are under the parent resource `/admin`. In the following sections, we assume that your metasrv instance is running on localhost port 4000. ## /health HTTP endpoint The `/health` endpoint accepts GET HTTP requests and you can use this endpoint to check the health of your metasrv instance. ### Definition ```bash curl -X GET http://localhost:4000/admin/health ``` ### Examples #### Request ```bash curl -X GET http://localhost:4000/admin/health ``` #### Response ```json OK ``` ## /leader HTTP endpoint The `/leader` endpoint accepts GET HTTP requests and you can use this endpoint to query the leader's addr of your metasrv instance. ### Definition ```bash curl -X GET http://localhost:4000/admin/leader ``` ### Examples #### Request ```bash curl -X GET http://localhost:4000/admin/leader ``` #### Response ```json 127.0.0.1:4000 ``` ## /heartbeat HTTP endpoint The `/heartbeat` endpoint accepts GET HTTP requests and you can use this endpoint to query the heartbeat of all datanodes. You can also query the heartbeat data of the datanode for a specified `addr`, however, specifying `addr` in the path is optional. ### Definition ```bash curl -X GET http://localhost:4000/admin/heartbeat ``` | Query String Parameter | Type | Optional/Required | Definition | |:-----------------------|:-------|:------------------|:--------------------------| | addr | String | Optional | The addr of the datanode. | ### Examples #### Request ```bash curl -X GET 'http://localhost:4000/admin/heartbeat?addr=127.0.0.1:4100' ``` #### Response ```json [ [{ "timestamp_millis": 1677049348651, "cluster_id": 0, "id": 1, "addr": "127.0.0.1:4100", "is_leader": false, "rcus": 0, "wcus": 0, "table_num": 0, "region_num": 2, "cpu_usage": 0.0, "load": 0.0, "read_io_rate": 0.0, "write_io_rate": 0.0, "region_stats": [] }, { "timestamp_millis": 1677049344048, "cluster_id": 0, "id": 1, "addr": "0.0.0.0:4100", "is_leader": false, "rcus": 0, "wcus": 0, "table_num": 0, "region_num": 2, "cpu_usage": 0.0, "load": 0.0, "read_io_rate": 0.0, "write_io_rate": 0.0, "region_stats": [] }, { "timestamp_millis": 1677049343624, "cluster_id": 0, "id": 1, "addr": "127.0.0.1:4100", "is_leader": false, "rcus": 0, "wcus": 0, "table_num": 0, "region_num": 2, "cpu_usage": 0.0, "load": 0.0, "read_io_rate": 0.0, "write_io_rate": 0.0, "region_stats": [] }, { "timestamp_millis": 1677049339036, "cluster_id": 0, "id": 1, "addr": "0.0.0.0:4100", "is_leader": false, "rcus": 0, "wcus": 0, "table_num": 0, "region_num": 2, "cpu_usage": 0.0, "load": 0.0, "read_io_rate": 0.0, "write_io_rate": 0.0, "region_stats": [] }, { "timestamp_millis": 1677049338609, "cluster_id": 0, "id": 1, "addr": "127.0.0.1:4100", "is_leader": false, "rcus": 0, "wcus": 0, "table_num": 0, "region_num": 2, "cpu_usage": 0.0, "load": 0.0, "read_io_rate": 0.0, "write_io_rate": 0.0, "region_stats": [] }, { "timestamp_millis": 1677049334019, "cluster_id": 0, "id": 1, "addr": "0.0.0.0:4100", "is_leader": false, "rcus": 0, "wcus": 0, "table_num": 0, "region_num": 2, "cpu_usage": 0.0, "load": 0.0, "read_io_rate": 0.0, "write_io_rate": 0.0, "region_stats": [] }, { "timestamp_millis": 1677049333592, "cluster_id": 0, "id": 1, "addr": "127.0.0.1:4100", "is_leader": false, "rcus": 0, "wcus": 0, "table_num": 0, "region_num": 2, "cpu_usage": 0.0, "load": 0.0, "read_io_rate": 0.0, "write_io_rate": 0.0, "region_stats": [] }, { "timestamp_millis": 1677049329002, "cluster_id": 0, "id": 1, "addr": "0.0.0.0:4100", "is_leader": false, "rcus": 0, "wcus": 0, "table_num": 0, "region_num": 2, "cpu_usage": 0.0, "load": 0.0, "read_io_rate": 0.0, "write_io_rate": 0.0, "region_stats": [] }, { "timestamp_millis": 1677049328573, "cluster_id": 0, "id": 1, "addr": "127.0.0.1:4100", "is_leader": false, "rcus": 0, "wcus": 0, "table_num": 0, "region_num": 2, "cpu_usage": 0.0, "load": 0.0, "read_io_rate": 0.0, "write_io_rate": 0.0, "region_stats": [] }, { "timestamp_millis": 1677049323986, "cluster_id": 0, "id": 1, "addr": "0.0.0.0:4100", "is_leader": false, "rcus": 0, "wcus": 0, "table_num": 0, "region_num": 2, "cpu_usage": 0.0, "load": 0.0, "read_io_rate": 0.0, "write_io_rate": 0.0, "region_stats": [] }] ] ``` ## /maintenance HTTP endpoint Cluster Maintenance Mode is a safety feature in GreptimeDB that temporarily disables automatic cluster management operations. This mode is particularly useful during cluster upgrades, planned downtime, and any operation that might temporarily affect cluster stability. For more details, please refer to [Cluster Maintenance Mode](/user-guide/deployments-administration/maintenance/maintenance-mode.md). ## /procedure-manager HTTP endpoint This endpoint is used to manage the Procedure Manager status. For more details, please refer to [Prevent Metadata Changes](/user-guide/deployments-administration/maintenance/prevent-metadata-changes.md). --- ## Metasrv(Metasrv) ![meta](/meta.png) ## What's in Metasrv - Store metadata (Catalog, Schema, Table, Region, etc.) - Request-Router. It tells the Frontend where to write and read data. - Load balancing for Datanode, determines who should handle new table creation requests, more precisely, it makes resource allocation decisions. - Election & High Availability, GreptimeDB is designed in a Leader-Follower architecture, only Leader nodes can write while Follower nodes can read, the number of Follower nodes is usually >= 1, and Follower nodes need to be able to switch to Leader quickly when Leader is not available. - Statistical data collection (reported via Heartbeats on each node), such as CPU, Load, number of Tables on the node, average/peak data read/write size, etc., can be used as the basis for distributed scheduling. ## How the Frontend interacts with Metasrv First, the routing table in Request-Router is in the following structure (note that this is only the logical structure, the actual storage structure varies, for example, endpoints may have dictionary compression). ``` table_A table_name table_schema // for physical plan regions region_1 mutate_endpoint select_endpoint_1, select_endpoint_2 region_2 mutate_endpoint select_endpoint_1, select_endpoint_2, select_endpoint_3 region_xxx table_B ... ``` ### Create Table 1. The Frontend sends `CREATE TABLE` requests to Metasrv. 2. Plan the number of Regions according to the partition rules contained in the request. 3. Check the global view of resources available to Datanodes (collected by Heartbeats) and assign one node to each region. 4. The Frontend creates the table and stores the `Schema` to Metasrv after successful creation. ### Insert 1. The Frontend fetches the routes of the specified table from Metasrv. Note that the smallest routing unit is the route of the table (several regions), i.e., it contains the addresses of all regions of this table. 2. The best practice is that the Frontend first fetches the routes from its local cache and forwards the request to the Datanode. If the route is no longer valid, then Datanode is obliged to return an `Invalid Route` error, and the Frontend re-fetches the latest data from Metasrv and updates its cache. Route information does not change frequently, thus, it's sufficient for Frontend uses the Lazy policy to maintain the cache. 3. The Frontend processes a batch of writes that may contain multiple tables and multiple regions, so the Frontend needs to split user requests based on the 'route table'. ### Select 1. As with `Insert`, the Frontend first fetches the route table from the local cache. 2. Unlike `Insert`, for `Select`, the Frontend needs to extract the read-only node (follower) from the route table, then dispatch the request to the leader or follower node depending on the priority. 3. The distributed query engine in the Frontend distributes multiple sub-query tasks based on the routing information and aggregates the query results. ## Metasrv Architecture ![metasrv-architecture](/metasrv-architecture.png) ## Distributed Consensus As you can see, Metasrv has a dependency on distributed consensus because: 1. First, Metasrv has to elect a leader, Datanode only sends heartbeats to the leader, and we only use a single metasrv node to receive heartbeats, which makes it easy to do some calculations or scheduling accurately and quickly based on global information. As for how the Datanode connects to the leader, this is for MetaClient to decide (using a redirect, Heartbeat requests becomes a gRPC stream, and using redirect will be less error-prone than forwarding), and it is transparent to the Datanode. 2. Second, Metasrv must provide an election API for Datanode to elect "write" and "read-only" nodes and help Datanode achieve high availability. 3. Finally, `Metadata`, `Schema` and other data must be reliably and consistently stored on Metasrv. Therefore, consensus-based algorithms are the ideal approach for storing them. For the first version of Metasrv, we choose Etcd as the consensus algorithm component (Metasrv is designed to consider adapting different implementations and even creating a new wheel) for the following reasons: 1. Etcd provides exactly the API we need, such as `Watch`, `Election`, `KV`, etc. 2. We only perform two tasks with distributed consensus: elections (using the `Watch` mechanism) and storing (a small amount of metadata), and neither of them requires us to customize our own state machine, nor do we need to customize our own state machine based on raft; the small amount of data also does not require multi-raft-group support. 3. The initial version of Metasrv uses Etcd, which allows us to focus on the capabilities of Metasrv and not spend too much effort on distributed consensus algorithms, which improves the design of the system (avoiding coupling with consensus algorithms) and helps with rapid development at the beginning, as well as allows easy access to good consensus algorithm implementations in the future through good architectural designs. ## Heartbeat Management The primary means of communication between Datanode and Metasrv is the Heartbeat Request/Response Stream, and we want this to be the only way to communicate. This idea is inspired by the design of [TiKV PD](https://github.com/tikv/pd), and we have practical experience in [RheaKV](https://github.com/sofastack/sofa-jraft/tree/master/jraft-rheakv/rheakv-pd). The request sends its state, while Metasrv sends different scheduling instructions via Heartbeat Response. A heartbeat will probably carry the data listed below, but this is not the final design, and we are still discussing and exploring exactly which data should be mostly collected. ``` service Heartbeat { // Heartbeat, there may be many contents of the heartbeat, such as: // 1. Metadata to be registered to metasrv and discoverable by other nodes. // 2. Some performance metrics, such as Load, CPU usage, etc. // 3. The number of computing tasks being executed. rpc Heartbeat(stream HeartbeatRequest) returns (stream HeartbeatResponse) {} } message HeartbeatRequest { RequestHeader header = 1; // Self peer Peer peer = 2; // Leader node bool is_leader = 3; // Actually reported time interval TimeInterval report_interval = 4; // Node stat NodeStat node_stat = 5; // Region stats in this node repeated RegionStat region_stats = 6; // Follower nodes and stats, empty on follower nodes repeated ReplicaStat replica_stats = 7; } message NodeStat { // The read capacity units during this period uint64 rcus = 1; // The write capacity units during this period uint64 wcus = 2; // Table number in this node uint64 table_num = 3; // Region number in this node uint64 region_num = 4; double cpu_usage = 5; double load = 6; // Read disk I/O in the node double read_io_rate = 7; // Write disk I/O in the node double write_io_rate = 8; // Others map attrs = 100; } message RegionStat { uint64 region_id = 1; TableName table_name = 2; // The read capacity units during this period uint64 rcus = 3; // The write capacity units during this period uint64 wcus = 4; // Approximate region size uint64 approximate_size = 5; // Approximate number of rows uint64 approximate_rows = 6; // Others map attrs = 100; } message ReplicaStat { Peer peer = 1; bool in_sync = 2; bool is_learner = 3; } ``` ## Central Nervous System (CNS) We are to build an algorithmic system, which relies on real-time and historical heartbeat data from each node, should make some smarter scheduling decisions and send them to Metasrv's Autoadmin unit, which distributes the scheduling decisions, either by the Datanode itself or more likely by the PaaS platform. ## Abstraction of Workloads The level of workload abstraction determines the efficiency and quality of the scheduling strategy generated by Metasrv such as resource allocation. DynamoDB defines RCUs & WCUs (Read Capacity Units / Write Capacity Units), explaining that a RCU is a read request of 4KB data, and a WCU is a write request of 1KB data. When using RCU and WCU to describe workloads, it's easier to achieve performance measurability and get more informative resource preallocation because we can abstract different hardware capabilities as a combination of RCU and WCU. However, GreptimeDB still faces a more complex situation than DynamoDB, in particular, RCU doesn't fit to describe GreptimeDB's read workloads which require a lot of computation. We are working on that. --- ## Selector ## Introduction What is the `Selector`? As its name suggests, it allows users to select specific items from a given `namespace` and `context`. There is a related trait, also named `Selector`, whose definition can be found [below][0]. [0]: https://github.com/GreptimeTeam/greptimedb/blob/main/src/meta-srv/src/selector.rs There is a specific scenario in `Metasrv` service. When a request to create a table is sent to the `Metasrv` service, it creates a routing table (the details of table creation will not be described here). The `Metasrv` service needs to select the appropriate `Datanode` list when creating a routing table. ## Selector Type The `Metasrv` service currently offers the following types of `Selectors`: ### LeasebasedSelector `LeasebasedSelector` randomly selects from all available (in lease) `Datanode`s, its characteristic is simplicity and fast. ### LoadBasedSelector The `LoadBasedSelector` load value is determined by the number of regions on each `Datanode`, fewer regions indicate lower load, and `LoadBasedSelector` prioritizes selecting low-load `Datanodes`. ### RoundRobinSelector [default] `RoundRobinSelector` selects `Datanode`s in a round-robin fashion. It is recommended and the default option in most cases. If you're unsure which to choose, it's usually the right choice. ## Configuration You can configure the `Selector` by its name when starting the `Metasrv` service. - LeasebasedSelector: `lease_based` or `LeaseBased` - LoadBasedSelector: `load_based` or `LoadBased` - RoundRobinSelector: `round_robin` or `RoundRobin` For example: ```shell cargo run -- metasrv start --selector round_robin ``` ```shell cargo run -- metasrv start --selector RoundRobin ``` --- ## Contributor Guide DeepWiki provides a detailed and clear explanation of GreptimeDB's architecture and implementation. Highly recommended: [https://deepwiki.com/GreptimeTeam/greptimedb](https://deepwiki.com/GreptimeTeam/greptimedb) ## Architecture For the architecture and components of GreptimeDB, please see the [Architecture](/user-guide/concepts/architecture.md) document in the user guide. For more details on each component, see the following guides: - [frontend][1] - [datanode][2] - [metasrv][3] [1]: /contributor-guide/frontend/overview.md [2]: /contributor-guide/datanode/overview.md [3]: /contributor-guide/metasrv/overview.md --- ## Integration Test ## Introduction Integration testing is written with Rust test harness (`#[test]`), unlike unit testing, they are placed separately [here](https://github.com/GreptimeTeam/greptimedb/tree/main/tests-integration). It covers scenarios involving multiple components, in which one typical case is HTTP/gRPC-related features. You can check its [documentation](https://github.com/GreptimeTeam/greptimedb/blob/main/tests-integration/README.md) for more information. --- ## Tests Our team has conducted lots of tests to ensure the behaviours of `GreptimeDB` . This chapter will introduce several significant methods used to test `GreptimeDB`, and how to work with them. --- ## Sqlness Test ## Introduction SQL is an important user interface for `GreptimeDB`. We have a separate test suite for it (named `sqlness`). ## Sqlness manual ### Case file Sqlness has three types of file - `.sql`: test input, SQL only - `.result`: expected test output, SQL and its results - `.output`: different output, SQL and its results Both `.result` and `.output` are output (execution result) files. The difference is that `.result` is the the standard (expected) output, and `.output` is the error output. Therefore, if you see `.output` files generated, it means this test gets a different result and indicates it fails. You should check change logs to solve the problem. You only need to write test SQL in `.sql` file, and run the test. On the first run it produces an `.output` file because there is no `.result` to compare with. If you can make sure the content in `.output` is correct, you can rename it to `.result`, which means it is the expected output. And at any time there should only be two file types, `.sql` and `.result` -- otherwise, an existing `.output` file means your test fails. That's why we should not ignore `.output` file type in `.gitignore`, instead, track it and make sure it doesn't exist. ### Case organization The root dir of input cases is `tests/cases`. It contains several sub-directories stand for different test modes. E.g., `standalone/` contains all the tests to run under `greptimedb standalone start` mode. Under the first level of sub-directory (e.g. the `cases/standalone`), you can organize your cases as you like. Sqlness walks through every file recursively and runs them. ## Run the test Unlike other tests, this harness is in a binary target form. You can run it with ```shell cargo run --bin sqlness-runner bare ``` It automatically finishes the following procedures: compile `GreptimeDB`, start it, grab tests and feed it to the server, then collect and compare the results. You only need to check whether there are new `.output` files. If not, congratulations, the test is passed 🥳! ### Run a specific test ```shell cargo sqlness bare -t your_test ``` If you specify a second argument, only test cases containing the specified string in their names will be executed. Sqlness also supports filtering based on environment. The filter is accepted as a regex string and the case name will be examined in the format of `env:case`. --- ## Unit Test ## Introduction Unit tests are embedded into the codebase, usually placed next to the logic being tested. They are written using Rust's `#[test]` attribute and can run with `cargo nextest run`. The default test runner ships with `cargo` is not supported in GreptimeDB codebase. It's recommended to use [`nextest`](https://nexte.st/) instead. You can install it with ```shell cargo install cargo-nextest --locked ``` And run the tests (here the `--workspace` is not necessary) ```shell cargo nextest run ``` Notes if your Rust is installed via `rustup`, be sure to install `nextest` with `cargo` rather than the package manager like `homebrew`. Otherwise it will mess up your local environment. ## Coverage Our continuous integration (CI) jobs have a "coverage checking" step. It will report how many codes are covered by unit tests. Please add the necessary unit test to your patch. --- ## Create Service To experience the full power of GreptimeCloud, you need to create a service which contains a database with authentication. Open the [GreptimeCloud console](https://greptime.cloud), signup and login. Then click the `New Service` button and config the following: * Service Name: The name you want to describe your service. * Description: More information about your service. * Region: Select the region where the database is located. * Plan: Select the pricing plan you want to use. Now create the service and we are ready to write some metrics to it. --- ## Go(Getting-started) ## Create Service ## Write data The following command collects system metric data, such as CPU and memory usage, and sends them to GreptimeDB. This demo is based on OpenTelemetry OTLP/http. The source code is available on [GitHub](https://github.com/GreptimeCloudStarters/quick-start-go). ```shell go run github.com/GreptimeCloudStarters/quick-start-go@latest -endpoint=https:///v1/otlp/v1/metrics -db= -username= -password= ``` ## Visualize Data --- ## InfluxDB Line Protocol(Getting-started) ## Create Service ## Write data To quickly get started with InfluxDB line protocol, we can use Bash to collect system metrics, such as CPU and memory usage, and send it to GreptimeDB. The source code is available on [GitHub](https://github.com/GreptimeCloudStarters/quick-start-influxdb-line-protocol). ```shell curl -L https://raw.githubusercontent.com/GreptimeCloudStarters/quick-start-influxdb-line-protocol/main/quick-start.sh | bash -s -- -e https:///v1/influxdb/write -d -u -p ``` ## Visualize Data --- ## Java ## Create Service ## Write data Use the following command to collect JVM runtime metrics, such as CPU and memory usage, and send them to GreptimeDB. This demo is based on OpenTelemetry OTLP/http. The source code is available on [GitHub](https://github.com/GreptimeCloudStarters/quick-start-java). ```shell curl -L https://github.com/GreptimeCloudStarters/quick-start-java/releases/latest/download/greptime-quick-start-java-all.jar \ --output quick-start.jar && java -jar quick-start.jar -e https:///v1/otlp/v1/metrics -db -u -p ``` ## Visualize Data --- ## MySQL(Getting-started) ## Create Service ## Write data To quickly get started with MySQL, we can use Bash to collect system metrics, such as CPU and memory usage, and send it to GreptimeDB via MySQL CLI. The source code is available on [GitHub](https://github.com/GreptimeCloudStarters/quick-start-mysql). ```shell curl -L https://raw.githubusercontent.com/GreptimeCloudStarters/quick-start-mysql/main/quick-start.sh | bash -s -- -h -d -u -p ``` ## Visualize Data --- ## Node.js ## Create Service ## Write data The following command collects system metric data, such as CPU and memory usage, and sends them to GreptimeCloud. This demo is based on OpenTelemetry OTLP/http. The source code is available on [GitHub](https://github.com/GreptimeCloudStarters/quick-start-node-js). ```shell npx greptime-cloud-quick-start@latest --endpoint=https:///v1/otlp/v1/metrics --db= --username= --password= ``` ## Visualize Data --- ## Getting Started(Getting-started) Getting Started with your familiar protocols or languages! --- ## Prometheus(Getting-started) ## Create Service ## Write data ### If you already have a Prometheus instance running Add the following section to your Prometheus configuration. ```yaml remote_write: - url: https:///v1/prometheus/write?db= basic_auth: username: password: ``` ### Or if you prefer a fresh start Spin up a Docker container to write sample data to your database: ```shell docker run --rm -e GREPTIME_URL='https:///v1/prometheus/write?db=' -e GREPTIME_USERNAME='' -e GREPTIME_PASSWORD='' --name greptime-node-exporter greptime/node-exporter ``` :::tip NOTE To avoid accidentally exit the Docker container, you may want to run it in the "detached" mode: add the `-d` flag to the `docker run` command. ::: ## Visualize Data --- ## Python ## Create Service ## Write data Run the following command with Python 3.10+ to collect system metric data, such as CPU and memory usage, and sends them to GreptimeDB. This demo is based on OpenTelemetry OTLP/http. The source code is available on [GitHub](https://github.com/GreptimeCloudStarters/quick-start-python). :::tip [pipx](https://pypa.github.io/pipx/) is a tool to help you install and run end-user applications written in Python. ::: ```shell pipx run --no-cache greptime-cloud-quick-start -e https:///v1/otlp/v1/metrics -db -u -p ``` ## Visualize Data --- ## Vector(Getting-started) ## Create Service ## Write data The following configuration, written in the `vector.toml` file, collects [host_metrics](https://vector.dev/docs/reference/configuration/sources/host_metrics/) as a Vector source and uses GreptimeDB as the sink destination. ```toml [sources.in] type = "host_metrics" scrape_interval_secs = 30 [sinks.greptime] inputs = ["in"] type = "greptimedb" endpoint = ":5001" dbname = "" username = "" password = "" new_naming = true tls = {} ``` Then start vector with the specified configuration file: ```shell vector --config vector.toml ``` ## Visualize Data --- ## Visualize Data After successfully writing data to the service, you can view the data on the GreptimeCloud dashboard. The dashboard provides a variety of visualizations to help you understand, monitor and analyze the data. Here, we create a panel that displays the 95% CPU usage as an example. To do this, click the `Add Panel` button, select a table that contains the CPU usage data, and then choose the `95%` aggregation method. Finally, click the `Save` button to save the panel. You can now see the new panel and set up an alert rule for it. --- ## Langchain ## Installation ```python pip install greptimeai ``` ## Setup Before get started, export the following to your environment variables: ```shell export GREPTIMEAI_HOST='' export GREPTIMEAI_DATABASE='' export GREPTIMEAI_TOKEN=':' ``` ## How-To Assume you have OpenAI account: - Set `OPENAI_API_KEY` environment variable ```shell export OPENAI_API_KEY='sk-xxx' ``` - Instrument your LLM application ```python from greptimeai.langchain.callback import GreptimeCallbackHandler from langchain.chains import LLMChain from langchain.llms import OpenAI from langchain.prompts import PromptTemplate callbacks = [GreptimeCallbackHandler()] llm = OpenAI() prompt = PromptTemplate.from_template("1 + {number} = ") chain = LLMChain(llm=llm, prompt=prompt) chain.run(number=2, callbacks=callbacks) ``` You can find more details in [example](https://github.com/GreptimeTeam/greptimeai/blob/main/examples/langchain.ipynb) and [cookbook](https://github.com/GreptimeTeam/greptimeai-cookbook/tree/main/examples/langchain) --- ## Openai ## Installation ```python pip install greptimeai ``` ## Setup Before get started, export the following to your environment variables: ```shell export GREPTIMEAI_HOST='' export GREPTIMEAI_DATABASE='' export GREPTIMEAI_TOKEN=':' ``` ## How-To ```shell export OPENAI_API_KEY='sk-xxx' ``` ```python from greptimeai import openai_patcher from openai import OpenAI client = OpenAI() openai_patcher.setup(client=client) # This is the only line you need to add chat_completion = client.chat.completions.create( messages=[ { "role": "user", "content": "Say this is a test", } ], model="gpt-3.5-turbo", user="user_123", ) ``` You can find more details in [example](https://github.com/GreptimeTeam/greptimeai/blob/main/examples/openai.ipynb) and [cookbook](https://github.com/GreptimeTeam/greptimeai-cookbook/tree/main/examples/openai) --- ## Alloy [Grafana Alloy](https://grafana.com/docs/alloy/latest/) is an observability data pipeline as well as an OpenTelemetry collector distribution. You can integrate your GreptimeCloud instance as data sinks of Alloy. ## Prometheus Remote Write Configure GreptimeDB as remote write target. ``` // config.alloy prometheus.remote_write "greptimedb" { endpoint { url = "https:///v1/prometheus/write?db=" basic_auth { username = "" password = "" } } } ``` ## OpenTelemetry GreptimeDB can also be configured as OpenTelemetry collector. ``` // config.alloy otelcol.exporter.otlphttp "greptimedb" { client { endpoint = "https:///v1/otlp/" headers = { "X-Greptime-DB-Name" = "", } auth = otelcol.auth.basic.credentials.handler } } otelcol.auth.basic "credentials" { username = "" password = "" } ``` --- ## DBeaver(Integrations) [DBeaver](https://dbeaver.io/) is a free, open-source, and cross-platform database tool that supports all popular databases. It is a popular choice among developers and database administrators for its ease of use and extensive feature set. You can use DBeaver to connect to GreptimeDB via MySQL database drivers. Click the "New Database Connection" button in the DBeaver toolbar to create a new connection to GreptimeDB. Select MySQL and click "Next" to configure the connection settings. Install the MySQL driver if you haven't already. Input the following connection details: - Connect by Host - Host: `` - Port: `4002` - Database: `` - Enter the `` and `` Click "Test Connection" to verify the connection settings and click "Finish" to save the connection. For more information on interacting with GreptimeDB using MySQL, refer to the [MySQL protocol documentation](https://docs.greptime.com/user-guide/protocols/mysql). --- ## EMQX Platform [EMQX Platform](https://www.emqx.io/) is an MQTT Gateway, designed to handle massive amounts of IoT device connections and message traffic, making it a popular choice for building large-scale IoT applications. It has built-in support for GreptimeDB as a data integration. By adding GreptimeDB as a Data Persistent sink, you can ingest EMQX messages into GreptimeDB automatically. You will need to follow these steps for your complete IoT data link, from MQTT to database: - Sign up your account on [EMQX Platform](https://www.emqx.io/) - Create a **Dedicated Instance** and wait for it's up and running - Setup Private Link or NAT Gateway for your deployment so it has internet access - Go to **Data Integrations** and find **GreptimeDB** - Configure your **GreptimeDB** connector using following information - Server host: `:4001` - Database: `` - Username: `` - Password: `` Then you are all set. Start from using EMQX's debugging tools to generate data and check GreptimeDB Dashboard for the data ingested. --- ## Fluent Bit(3) Fluent Bit is a lightweight and fast log processor and forwarder that can collect, parse, filter, and forward logs and metrics. Fluent Bit is part of the Fluentd project ecosystem and is written in C language. It is designed to be memory-efficient and performant, making it suitable for use in resource-constrained environments. ## HTTP Fluent Bit can be configured to send logs to GreptimeCloud using the HTTP protocol. This allows you to collect logs from various sources and send them to GreptimeCloud for storage, analysis, and visualization. ``` [OUTPUT] Name http Match * Host Port 443 Uri /v1/ingest?db=&table=&pipeline_name= Format json Json_date_key scrape_timestamp Json_date_format iso8601 Tls On compress gzip http_User http_Passwd ``` In this example, the `http` output plugin is used to send logs to GreptimeCloud. For more information, and extra options, refer to the [Logs HTTP API](https://docs.greptime.com/reference/pipeline/write-log-api/#http-api) guide. ## Prometheus Remote Write Fluent Bit can be configured to send metrics to GreptimeCloud using the Prometheus Remote Write protocol. This allows you to collect metrics from various sources and send them to GreptimeCloud for storage, analysis, and visualization. ``` [OUTPUT] Name prometheus_remote_write Match internal_metrics Host Port 443 Uri /v1/prometheus/write?db= Tls On http_user http_passwd ``` In this example, the `prometheus_remote_write` output plugin is used to send metrics to GreptimeCloud. For more information, and extra options, refer to the [Prometheus Remote Write](https://docs.greptime.com/user-guide/integrations/prometheus) guide. ## OpenTelemetry Fluent Bit can be configured to send logs and metrics to GreptimeCloud using the OpenTelemetry protocol. This allows you to collect logs and metrics from various sources and send them to GreptimeCloud for storage, analysis, and visualization. ``` # Only for metrics [OUTPUT] Name opentelemetry Alias opentelemetry_metrics Match *_metrics Host Port 443 Metrics_uri /v1/otlp/v1/metrics http_User http_Passwd Log_response_payload True Tls On compress gzip # Only for logs [OUTPUT] Name opentelemetry Alias opentelemetry_logs Match *_logs Host Port 443 Logs_uri /v1/otlp/v1/logs http_User http_Passwd Log_response_payload True Tls On compress gzip Header X-Greptime-Log-Table-Name "" Header X-Greptime-Log-Pipeline-Name "" Header X-Greptime-DB-Name "" ``` In this example, the [OpenTelemetry OTLP/HTTP API](https://docs.greptime.com/user-guide/ingest-data/for-observability/opentelemetry) interface is used. For more information, and extra options, refer to the [OpenTelemetry](https://docs.greptime.com/user-guide/ingest-data/for-observability/opentelemetry) guide. --- ## Grafana(Integrations) GreptimeDB can be configured as a [Grafana data source](https://grafana.com/docs/grafana/latest/datasources/add-a-data-source/). You have the option to connect GreptimeDB with Grafana using one of three data sources: GreptimeDB, Prometheus, or MySQL. ## GreptimeDB data source plugin Before using the GreptimeDB data source, it is necessary to manually install the GreptimeDB data source plugin. For more information, please refer to the [GreptimeDB data source plugin](https://docs.greptime.com/user-guide/integrations/grafana##greptimedb-data-source-plugin) document. Click the Add data source button and select GreptimeDB as the type. Fill in the following URL in the GreptimeDB server URL: ```txt https:// ``` Then do the following configuration: - Database Name:``, leave it blank to use the default database `public` - In the Auth section, click basic auth, and fill in the username and password for GreptimeDB in the Basic Auth Details section (not set by default, no need to fill in). - User: `` - Password: `` Then click the Save & Test button to test the connection. ## Prometheus data source Click the Add data source button and select Prometheus as the type. Fill in Prometheus server URL in HTTP: ```txt https:///v1/prometheus ``` Click basic auth in the Auth section and fill in your GreptimeDB username and password in Basic Auth Details: - User: `` - Password: `` Click Custom HTTP Headers and add one header: - Header: `x-greptime-db-name` - Value: `` Then click Save & Test button to test the connection. ## MySQL data source Click the Add data source button and select MySQL as the type. Fill in the following information in MySQL Connection: - Host: `:4002` - Database: `` - User: `` - Password: `` - Session timezone: `UTC` Then click Save & Test button to test the connection. Note that you need to use raw SQL editor for panel creation. SQL Builder is not supported due to timestamp data type difference between GreptimeDB and vanilla MySQL. --- ## InfluxDB and Telegraf GreptimeCloud provides [Influxdb line protocol](https://docs.influxdata.com/influxdb/cloud/reference/syntax/line-protocol/) ingestion API over http. The API and authentication is compatible with [InfluxDB write protocol 1.x](https://docs.influxdata.com/influxdb/v1.8/guides/write_data/#write-data-using-the-influxdb-api). Please refer to [InfluxDB line protocol](https://docs.greptime.com/user-guide/ingest-data/for-iot/influxdb-line-protocol) of GreptimeDB for more information. - URL: `https:///v1/influxdb/write?db=` - Username: `` - Password: `` ## Telegraf To use Telegraf to ingest data, add following configuration. ``` [[outputs.influxdb_v2]] urls = ["https:///v1/influxdb"] token = ":" bucket = "" ## Leave empty organization = "" ``` ## InfluxDB Client Library The following Java example code demonstrates how to configure the [InfluxDB client](https://github.com/influxdata/influxdb-java) when connecting to GreptimeCloud: ```java final String serverURL = "https:///v1/influxdb/", username = "", password = ""; final InfluxDB influxDB = InfluxDBFactory.connect(serverURL, username, password); influxDB.setDatabase(""); ``` --- ## Kafka(3) If you are using Kafka or Kafka-compatible message queue for observability data transporting, it's possible to ingest data into GreptimeDB directly. Here we are using Vector as the tool to transport data from Kafka to GreptimeDB. ## Logs A sample configuration. Note that you will need to [create your pipeline](https://docs.greptime.com/user-guide/logs/use-custom-pipelines/) for log parsing. ```toml # sample.toml [sources.log_mq] type = "kafka" group_id = "vector0" topics = ["test_log_topic"] bootstrap_servers = "kafka:9092" [sinks.sink_greptime_logs] type = "greptimedb_logs" inputs = [ "log_mq" ] compression = "gzip" endpoint = "https://" dbname = "" username = "" password = "" compression = "gzip" ## customize to your own table and pipeline name table = "demo_logs" pipeline_name = "demo_pipeline" ``` ## Metrics If you are using Kafka to transport metrics data in InfluxDB line protocol format, you can also ingest it directly. ```toml # sample.toml [sources.metrics_mq] type = "kafka" group_id = "vector0" topics = ["test_metric_topic"] bootstrap_servers = "kafka:9092" decoding.codec = "influxdb" [sinks.metrics_in] inputs = ["metrics_mq"] type = "greptimedb" endpoint = ":5001" dbname = "" username = "" password = "" tls = {} ``` ## Reference For detailed information on the data ingestion process, please refer to the [Ingest Data via Kafka](https://docs.greptime.com/user-guide/ingest-data/for-observability/kafka) guide. --- ## Metabase(Integrations) [Metabase](https://github.com/metabase/metabase) is an open source BI tool that written in Clojure. You can configure GreptimeDB as a metabase data source from a community driver plugin. See [our docs](https://docs.greptime.com/user-guide/integrations/metabase) for the instructions of plugin installation. ## Connection information - Database type: `GreptimeDB` - Host: `` - Port: `4003` - Database name: `` - User: `` - Password: `` --- ## MindsDB(Integrations) [MindsDB](https://mindsdb.com/) is an open-source machine learning platform that enables developers to easily incorporate advanced machine learning capabilities with existing databases. Your GreptimeDB instance work out of box as using GreptimeDB extension with MindsDB. To configure GreptimeDB database, run the following SQL: ```sql CREATE DATABASE greptime_datasource WITH ENGINE = 'greptimedb', PARAMETERS = { "host": "", "port": 4002, "database": "", "user": "", "password": "", "ssl": True }; ``` MindsDB is a great gateway for many machine learning features, including time-series forecasting, for your time series data stored in our instance. See [MindsDB docs](https://docs.mindsdb.com/what-is-mindsdb) for more information. --- ## MySQL(Integrations) GreptimeCloud exposes GreptimeDB access in MySQL server-client protocol. Most standard clients and drivers are compatible and the connection is encrypted with TLS. Refer to [MySQL client](https://docs.greptime.com/user-guide/protocols/mysql) of GreptimeDB for more information. To connect to GreptimeCloud in MySQL protocol, using information below: - Host: `` - Port: `4002` - Database: `` - Username: `` - Password: `` ## MySQL CLI Connect to GreptimeCloud service instance using `mysql` CLI. ```shell mysql --ssl-mode=REQUIRED -u -p -h -P 4002 -A ``` ## MariaDB CLI MariaDB's CLI has slightly different `ssl` option with original MySQL ```shell mysql --ssl -u -p -h -P 4002 -A ``` ## URL Use following connect string for your JDBC client. ```text jdbc:mysql://:4002/?user=&password= ``` And if you are using client like Python, use following url to connect to your instance. ```text mysql://:@:4002/ ``` --- ## OpenTelemetry GreptimeDB serves as an observability backend that natively consumes OpenTelemetry Metrics, Logs and Traces via the [OTLP](https://opentelemetry.io/docs/specs/otlp/) protocol. Please use the following endpoint and include the required headers: - URL: `https:///v1/otlp/` - Protocol: `HTTP/protobuf` - Headers: - `X-Greptime-DB-Name`: `` - `Authentication`: ``, For more information, please refer to [Authentication](https://docs.greptime.com/user-guide/protocols/http#authentication) in HTTP API. ## OpenTelemetry Collector OpenTelemetry Collector is a vendor-agnostic implementation of OpenTelemetry, below is a sample configuration for exporting to GreptimeDB. You can use the [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/) to send metrics, logs, and traces to GreptimeDB. ```yaml extensions: basicauth/client: client_auth: username: password: receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 http: endpoint: 0.0.0.0:4318 exporters: otlphttp/traces: endpoint: 'https:///v1/otlp' auth: authenticator: basicauth/client headers: x-greptime-db-name: '' x-greptime-pipeline-name: 'greptime_trace_v1' otlphttp/logs: endpoint: 'https:///v1/otlp' auth: authenticator: basicauth/client headers: x-greptime-db-name: '' # x-greptime-log-table-name: "" otlphttp/metrics: endpoint: 'https:///v1/otlp' auth: authenticator: basicauth/client headers: x-greptime-db-name: '' service: extensions: [basicauth/client] pipelines: traces: receivers: [otlp] exporters: [otlphttp/traces] logs: receivers: [otlp] exporters: [otlphttp/logs] metrics: receivers: [otlp] exporters: [otlphttp/metrics] ``` ## Grafana Alloy If you prefer to use [Grafana Alloy](https://grafana.com/docs/alloy/latest/)'s OpenTelemetry exporter, you can use the following configuration to send your data. A sample configuration for exporting to GreptimeDB: ``` otelcol.exporter.otlphttp "greptimedb" { client { endpoint = "https:///v1/otlp/" headers = { "X-Greptime-DB-Name" = "", } auth = otelcol.auth.basic.credentials.handler } } otelcol.auth.basic "credentials" { username = "" password = "" } ``` ## References For more information on using GreptimeDB with OpenTelemetry, please refer to the [OpenTelemetry Protocol documentation](https://docs.greptime.com/user-guide/ingest-data/for-observability/opentelemetry/) in the GreptimeDB user guide. --- ## PostgreSQL(Integrations) GreptimeCloud exposes GreptimeDB access in PostgreSQL v3 wire protocol. Most standard clients and drivers are compatible at wire protocol level, and the connection is encrypted with TLS. Note that we don't use Postgres' SQL dialect in GreptimeDB, so there can be some statements that are unsupported. For more information, please refer to [Postgresql documentation](https://docs.greptime.com/user-guide/protocols/postgresql) of GreptimeDB. To connect to GreptimeCloud in Postgres wire protocol, using information below: - Host: `` - Port: `4003` - Database: `` - Username: `` - Password: `` ## `psql` The default cli tool bundled with PostgreSQL. ```text psql -h -p 4003 -U -d -W ``` ## Postgres Connection String Using the connection string below for compatible client libraries like psycopg, rust-postgres and more. ```text host= port=4003 dbname= user= password= ``` ## URL Using the URL below with your Postgres JDBC client. ```text jdbc:postgresql://:4003/?user=&password=&ssl=true ``` If you are using clients from Python, you might be able to use following URL ```text postgresql://:@:4003/ ``` ## Postgres Foreign Data Wrapper Configure your GreptimeCloud instance as Postgres FDW. Change server name and username to your own. ```sql CREATE SERVER greptimedb FOREIGN DATA WRAPPER postgres_fdw OPTIONS (host '', dbname '', port '4003'); CREATE USER MAPPING FOR postgres SERVER greptimedb OPTIONS (user '', password ''); ``` --- ## Prometheus(3) GreptimeCloud with GreptimeDB is fully compatible with Prometheus. This ensures a seamless transition, allowing you to use GreptimeCloud as a direct replacement for Prometheus. For more details, please refer to the [Prometheus documentation](https://docs.greptime.com/user-guide/integrations/prometheus) in the GreptimeDB user guide. ## Prometheus Remote Write GreptimeCloud instance can be configured as a Prometheus [remote write endpoint](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#remote_write). Append the following section to your Prometheus configuration. ```yaml remote_write: - url: https:///v1/prometheus/write?db= basic_auth: username: password: ``` ## Prometheus HTTP API and PromQL Directly access this database through Prometheus API endpoint: - URL root: `https:///v1/prometheus` - Database name: include HTTP header `x-greptime-db-name` with value `` - Authentication: utilize Basic authentication using the instance's username and password This is an example of invoking the Prometheus HTTP API to ping: ```shell curl -X GET \ -H "x-greptime-db-name: " \ -u ":" \ "https:///v1/prometheus/api/v1/query?query=1" ``` GreptimeDB supports PromQL (Prometheus Query Language). This means that you can use GreptimeDB as a drop-in replacement for Prometheus, with Grafana or any other tools. Please refer to [PromQL](https://docs.greptime.com/user-guide/integrations/prometheus#prometheus-query-language) for more details. --- ## Go SDK The GreptimeDB Go ingester library utilizes gRPC for writing data to the database. For how to use the library, please refer to the [Go library documentation](https://docs.greptime.com/user-guide/ingest-data/for-iot/grpc-sdks/go). To connect to GreptimeCloud, using information below: - Host: `` - Port: `5001` - Database: `` - Username: `` - Password: `` The following code shows how to create a `client`. ```go cfg := greptime.NewConfig(""). WithDatabase(""). WithPort(5001). WithInsecure(false). WithAuth("", "") cli, err := greptime.NewClient(cfg) if err != nil { panic("failed to init client") } ``` --- ## Java SDK The GreptimeDB Java ingester library utilizes gRPC for writing data to the database. For how to use the library, please refer to the [Java library documentation](https://docs.greptime.com/user-guide/ingest-data/for-iot/grpc-sdks/java). To connect to GreptimeCloud, using information below: - Host: `` - Port: `5001` - Database: `` - Username: `` - Password: `` The following code snippet shows how to connect to database: ```java String database = ""; String[] endpoints = {":5001"}; AuthInfo authInfo = new AuthInfo("", ""); GreptimeOptions opts = GreptimeOptions.newBuilder(endpoints, database) .authInfo(authInfo) .tlsOptions(new TlsOptions()) .build(); GreptimeDB client = GreptimeDB.create(opts); ``` --- ## Streamlit(Integrations) Streamlit is a faster way to build and share data apps. It's possible to build streamlit based data apps based on GreptimeDB. To use GreptimeDB data in your application, you will need to create a SQL connection. Thanks to GreptimeDB's MySQL protocol compatibility, you can treat GreptimeDB as MySQL when connecting to it. ```python st.title('GreptimeDB Streamlit Demo') conn = st.connection("greptimedb", type="sql", url="mysql://:@:4002/") df = conn.query("SELECT * FROM ...") ``` Once you have created the connection, you can run SQL query against your GreptimeDB instance. The resultset is automatically converted to Pandas dataframe just like normal data source in streamlit. --- ## Superset(Integrations) [Superset](https://superset.apache.org) is an open source BI tool that written in Python. You can configure GreptimeDB as a metabase data source from python package. See [our docs](https://docs.greptime.com/user-guide/integrations/superset) for the instructions of plugin installation. ## Connection information Select `GreptimeDB` from database list. Use following SQlAlchemy URL for connection: ``` greptimedb://:@:4003/ ``` --- ## Vector(3) Vector is [a high performance observability data pipeline](https://vector.dev). It has native support for GreptimeDB as data sink. With vector, you can ingest metrics and log data from various sources. To use Vector with GreptimeCloud, we recommend version `0.41` and above. A minimal configuration of when using your GreptimeCloud instance can be: ```toml # sample.toml ## metrics [sources.metrics_in] type = "host_metrics" [sinks.metrics_out] inputs = ["metrics_in"] type = "greptimedb" endpoint = ":5001" dbname = "" username = "" password = "" tls = {} new_naming = true ## logs [sources.logs_in] type = "demo_logs" format = "json" [transforms.logs_json] type = "remap" inputs = ["logs_in"] source = ''' . = parse_json!(.message) ''' [sinks.logs_out] inputs = ["logs_json"] type = "greptimedb_logs" endpoint = "https://" compression = "gzip" dbname = "" username = "" password = "" table = "demo_logs" pipeline_name = "greptime_identity" healthcheck.enabled = false ``` Execute Vector with: ``` vector -c sample.toml ``` For more configuration options, see [Vector GreptimeDB Configuration](https://vector.dev/docs/reference/sinks/greptimedb/). --- ## Migrate from InfluxDB(Migrate-to-greptimecloud) Navigate to the [GreptimeCloud console](https://greptime.cloud) and click the `Connection Information` section under `Manage Your Data`. You can find the GreptimeDB URL, database name, as well as the username and password associated with the token. ```shell curl -X POST 'https:///v1/influxdb/api/v2/write?bucket=' \ -H 'authorization: token ' \ -d 'census,location=klamath,scientist=anderson bees=23 1566086400000000000' ``` ```shell curl 'https:///v1/influxdb/write?db=&u=&p=' \ -d 'census,location=klamath,scientist=anderson bees=23 1566086400000000000' ``` ```toml [[outputs.influxdb_v2]] urls = ["https:///v1/influxdb"] token = ":" bucket = "" ## Leave empty organization = "" ``` ```toml [[outputs.influxdb]] urls = ["https:///v1/influxdb"] database = "" username = "" password = "" ``` ```js 'use strict' /** @module write **/ /** Environment variables **/ const url = 'https:///v1/influxdb' const token = ':' const org = '' const bucket = '' const influxDB = new InfluxDB({ url, token }) const writeApi = influxDB.getWriteApi(org, bucket) writeApi.useDefaultTags({ region: 'west' }) const point1 = new Point('temperature') .tag('sensor_id', 'TLM01') .floatField('value', 24.0) writeApi.writePoint(point1) ``` ```python from influxdb_client.client.write_api import SYNCHRONOUS bucket = "" org = "" token = ":" url="https:///v1/influxdb" client = influxdb_client.InfluxDBClient( url=url, token=token, org=org ) # Write script write_api = client.write_api(write_options=SYNCHRONOUS) p = influxdb_client.Point("my_measurement").tag("location", "Prague").field("temperature", 25.3) write_api.write(bucket=bucket, org=org, record=p) ``` ```go bucket := "" org := "" token := ":" url := "https:///v1/influxdb" client := influxdb2.NewClient(url, token) writeAPI := client.WriteAPIBlocking(org, bucket) p := influxdb2.NewPoint("stat", map[string]string{"unit": "temperature"}, map[string]interface{}{"avg": 24.5, "max": 45}, time.Now()) writeAPI.WritePoint(context.Background(), p) client.Close() ``` ```java private static String url = "https:///v1/influxdb"; private static String org = ""; private static String bucket = ""; private static char[] token = ":".toCharArray(); public static void main(final String[] args) { InfluxDBClient influxDBClient = InfluxDBClientFactory.create(url, token, org, bucket); WriteApiBlocking writeApi = influxDBClient.getWriteApiBlocking(); Point point = Point.measurement("temperature") .addTag("location", "west") .addField("value", 55D) .time(Instant.now().toEpochMilli(), WritePrecision.MS); writeApi.writePoint(point); influxDBClient.close(); } ``` ```php $client = new Client([ "url" => "https:///v1/influxdb", "token" => ":", "bucket" => "", "org" => "", "precision" => InfluxDB2\Model\WritePrecision::S ]); $writeApi = $client->createWriteApi(); $dateTimeNow = new DateTime('NOW'); $point = Point::measurement("weather") ->addTag("location", "Denver") ->addField("temperature", rand(0, 20)) ->time($dateTimeNow->getTimestamp()); $writeApi->write($point); ``` The GreptimeCloud console provides a Workbench for data visualization. To use it, open the [Greptime console](https://greptime.cloud), select `Web Dashboard` under `Manage Your Data`, then create a new Workbench file and add panels as your needs. ```shell for file in data.*; do curl -i --retry 3 \ -X POST "https://${GREPTIME_HOST}/v1/influxdb/write?db=${GREPTIME_DB}&u=${GREPTIME_USERNAME}&p=${GREPTIME_PASSWORD}" \ --data-binary @${file} sleep 1 done ``` --- ## Migrate from Prometheus(Migrate-to-greptimecloud) For information on configuring Prometheus to write data to GreptimeDB, please refer to the [remote write](/greptimecloud/integrations/prometheus.md#prometheus-remote-write) documentation. For detailed information on querying data in GreptimeDB using Prometheus query language, please refer to the [HTTP API](/greptimecloud/integrations/prometheus.md#prometheus-http-api-and-promql) section in the PromQL documentation. To add GreptimeDB as a Prometheus data source in Grafana, please refer to the [Grafana](/greptimecloud/integrations/grafana.md#prometheus-data-source) documentation. --- ## GreptimeCloud GreptimeCloud is a cloud service that is powered by fully-managed serverless GreptimeDB, providing a scalable and efficient solution for time-series data platform and Prometheus backend. --- ## Billing ## Invoice Every service in GreptimeCloud belongs to a team. You can add Payment Methods for the team in the [billing](https://console.greptime.cloud/settings/team#billing) dashboard under the team settings. GreptimeCloud charges and generates invoices on a calendar monthly basis. ## Usage tracking A detailed usage report for the current billing cycle can be found in the [billing](https://console.greptime.cloud/settings/team#billing) dashboard, which includes the following items: - Serverless plan: - The sum of request capacity units (RCU and WCU) set by all Serverless services. - The sum of storage capacity used by all Serverless services. - Dedicated plan: - The number of dedicated instances according to the configuration. - The sum of storage capacity used by all dedicated instances. - The network traffic of the load balancers for all dedicated instances. The usage tracking items are updated daily by summing up the usage from the previous days of the current month. For example, if you have Service A in the Serverless plan with 10 RCU set, and Service B with 20 RCU set, the usage tracking item "Serverless RCU" is calculated as 720 (10 * 24 hours + 20 * 24 hours) on the second day of the month and 1440 (720 + 720) on the third day. ## Costs Please refer to [Serverless Plan](serverless.md#costs) and [Dedicated Plan](dedicated.md#costs) for cost calculation logics. --- ## Dedicated Plan The dedicated plan allows you to purchase dedicated CPUs and storage to host GreptimeDB. It provides unlimited data storage and retention, complete isolation of resources and network, and includes support from Greptime's SRE team. If you require absolute isolation from other users or need to exceed the maximum usage limits of the serverless plan, then the dedicated plan is your choice. ## Costs Please see [Pricing](https://greptime.com/pricing) for the latest pricing information. ### Computing nodes When setting up a service under the Dedicated Plan, you'll need to configure the service mode, which determine the size of computing nodes. Greptime calculates costs based on the computing nodes specified in your chosen plan every hour and bills monthly. Cost Calculation Formula: - Hourly Costs: (Chosen Plan's Node Size * Number of Nodes * Node Hour Price) - Daily Costs: Sum of Hourly Costs - Monthly Costs: Sum of Daily Costs ### Network traffic The cost of network traffic will be included in your monthly bill. Pricing is determined by the cloud server provider (such as AWS). Greptime does not charge any additional fees for traffic costs. --- ## Hobby Plan ## Introduction GreptimeCloud offers a free tier Hobby Plan for users to try the service. Each team can create up to three services in the Hobby Plan. The Hobby Plan has the following limitations: - RCU (Read Capacity Units): 40 RCU/s per service. - WCU (Write Capacity Units): 20 WCU/s per service. - Storage capacity: 5GB per service. - Data retention policy: 3 months. :::tip NOTE The plan may change in the future. If you have any questions about it, please contact [feedback@greptime.cloud](mailto:feedback@greptime.cloud). ::: --- ## Usage and Billing These documents will help you understand the usage and billing of Greptime Cloud. - [Request Capacity Unit](request-capacity-unit.md) - [Hobby Plan](hobby.md) - [Serverless Plan](serverless.md) - [Dedicated Plan](dedicated.md) --- ## Request Capacity Unit This document introduces the calculation algorithms for request capacity units. To monitor your service usage, you can visit the [GreptimeCloud Console](https://console.greptime.cloud/). All requests to GreptimeCloud are measured in capacity units, which reflect the size and complexity of the request. The measurement methods of write capacity unit and read capacity unit are different, see following for details. ### Write capacity unit (WCU) Each API call to write data to your table is a write request. WCU is calculated based on the total size of the insert rows in one request. A standard write capacity unit can write rows up to 1KB. For rows larger than 1KB, additional write capacity units are required. :::tip NOTE The capacity unit may be subject to change in the future. ::: The following steps are used to determine the size of each request: 1. Get the size of the data type of each column in the table schema. You can find details about the size of each data type in the [Data Types](/reference/sql/data-types.md) documentation. 2. Sum up the sizes of all columns in the request. If a column is not present in the request, its size depends on the column's default value. If the default value is null, the size is 0; otherwise, it is the size of the data type. 3. Multiply the sum by the number of rows to be written. Here's an example of how to calculate the WCU for a table with the following schema: ```shell +-------------+----------------------+------+------+---------------------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +-------------+----------------------+------+------+---------------------+---------------+ | host | String | PRI | YES | | TAG | | idc | String | PRI | YES | | TAG | | cpu_util | Float64 | | YES | | FIELD | | memory_util | Float64 | | YES | | FIELD | | disk_util | Float64 | | YES | | FIELD | | ts | TimestampMillisecond | PRI | NO | current_timestamp() | TIMESTAMP | +-------------+----------------------+------+------+---------------------+---------------+ ``` You have a write request as following: ```shell INSERT INTO system_metrics VALUES ("host1", "a", 11.8, 10.3, 10.3, 1667446797450); ``` Based on the size of the data types in your table schema, the size of each row is 38 bytes (5+1+8+8+8+8), and the WCU of this request is 1 according to the calculation algorithm. To reduce the WCU usage, use batched `INSERT` statements to insert multiple rows in a single statement, rather than sending a separate statement per row. For example: ```shell INSERT INTO system_metrics VALUES ("host1", "idc_a", 11.8, 10.3, 10.3, 1667446797450), ("host1", "idc_a", 80.1, 70.3, 90.0, 1667446797550), # ...... 22 rows ("host1", "idc_b", 90.0, 39.9, 60.6, 1667446798250); ``` The size of the request is 950 bytes (38 x 25). The WCU of this request is 1. If you insert 40 rows in a single statement, the size is 1520 bytes (38 x 40), and the WCU of this request is 2. ### Read capacity unit (RCU) Each API call to read data from your table is a read request. RCU is the data size scanned and loaded into server's memory in one request. A standard read capacity unit can scan up to 1MB data. For scanned data larger than 1MB, additional read capacity units are required. :::tip NOTE The capacity unit may be subject to change in the future. ::: Suppose there is a read request scanning 2.5MB data. The RCU of this request is 3 according to calculation algorithm. To lower the RCU, you can design the table schema and queries carefully. Here are some tips: - Use indexes to support the efficient execution of queries in GreptimeDB. Without indexes, GreptimeDB must scan the entire table to process the query. If an index matches the query, GreptimeDB can use the index to limit the data scanned. Consider using a column with high cardinality as the primary key and use it in the `WHERE` clause. - Use queries that match a smaller percentage of data for better selectivity. For instance, an equality match on the time index field and a high cardinality tag field can efficiently limit the data scanned. Note that the inequality operator `!=` is not efficient because it always scans all data. ## Monitoring CU Usage via HTTP Response GreptimeCloud provides information on CU (Capacity Unit) usage through HTTP response headers. This enhancement allows you to conveniently track CU consumption for requests. For instance, when making a write request like following: ```bash curl -s -i -XPOST -w '\n' \ "https:///v1/influxdb/api/v2/write?db=&precision=ms&u=&p=" \ --data-binary \ 'monitor,host=127.0.0.1 cpu=0.1,memory=0.4 1667446797450 monitor,host=127.0.0.2 cpu=0.2,memory=0.3 1667446798450 monitor,host=127.0.0.1 cpu=0.5,memory=0.2 1667446798450' ``` The response headers will include information such as: ``` HTTP/2 204 date: Wed, 10 Apr 2024 03:29:36 GMT x-greptime-metrics: {"greptime_cloud_wcu":1} strict-transport-security: max-age=15724800; includeSubDomains access-control-allow-origin: * access-control-allow-credentials: true access-control-allow-methods: OPTIONS access-control-allow-headers: DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization access-control-max-age: 1728000 ``` Here, the `x-greptime-metrics` header includes the value of `greptime_cloud_wcu`, indicating the consumed WCU for the particular write request. Similarly, for read requests, you can inspect `greptime_cloud_rcu`. This capability provides valuable insights into CU utilization, facilitating better resource management and optimization efforts. ## Usage metrics You can view the usage at the [GreptimeCloud Console](https://console.greptime.cloud/). The maximum WCU and RCU utilized are aggregated by time range and presented in the usage charts. --- ## Serverless Plan The serverless plan allows you to purchase request capacities according to your needs and provides support from the SRE team. This solution offers unlimited data storage and configurable retention, making it suitable for production environments and scalable with your business growth. When setting up a service under the Serverless Plan or upgrading from the Hobby Plan, you'll need to configure the capacity units for the service plan, which include: - The Maximum WCU (Write Capacity Unit) per second, upper limit of 5000 - The Maximum RCU (Read Capacity Unit) per second, upper limit of 5000 :::tip NOTE For the concepts of WCU and RCU, see [Request Capacity Unit](request-capacity-unit.md). ::: ## Costs Please see [Pricing](https://greptime.com/pricing) for the latest pricing information. ### WCU and RCU Greptime calculates costs based on the capacity units specified in your chosen plan on a hour-by-hour basis and bills you monthly for the services used. Cost Calculation Formula: - Hourly Costs: (Chosen Plan's WCU * (WCU Minute Price * 60 minutes)) + (Chosen Plan's RCU * (RCU Minute Price * 60 minutes)) - Daily Costs: Sum of Hourly Costs - Monthly Costs: Sum of Daily Costs --- ## Shared Storage Capacity ### Storage Capacity GreptimeCloud stores your data in object storage, such as S3, and calculates storage costs based on your total data size in the database. You'll be billed monthly for the services used. --- ## Monitor Kubernetes Metrics with Prometheus and GreptimeDB This guide demonstrates how to set up a complete Kubernetes monitoring solution using Prometheus for metrics collection and GreptimeDB as the long-term storage backend. ## What is Kubernetes Monitoring Kubernetes monitoring is the practice of collecting, analyzing, and acting on metrics and logs from a Kubernetes cluster. It provides visibility into the health, performance, and resource utilization of your containerized applications and infrastructure. Key aspects of Kubernetes monitoring include: - **Resource Metrics**: CPU, memory, disk, and network usage for nodes, pods, and containers - **Cluster Health**: Status of cluster components like kube-apiserver, etcd, and controller-manager - **Application Metrics**: Custom metrics from your applications running in the cluster - **Events and Logs**: Kubernetes events and container logs for troubleshooting Effective monitoring helps you: - Detect and diagnose issues before they impact users - Optimize resource utilization and reduce costs - Plan capacity based on historical trends - Ensure SLA compliance - Troubleshoot performance bottlenecks ## Architecture Overview The monitoring architecture consists of the following components: ![Kubernetes Monitoring Architecture](/k8s-metrics-monitor-architecture.drawio.svg) **Components:** - **kube-state-metrics**: Exports cluster-level metrics about Kubernetes objects (deployments, pods, services, etc.) - **Node Exporter**: Exports hardware and OS-level metrics from each Kubernetes node - **Prometheus Operator**: Automates Prometheus deployment and configuration using Kubernetes custom resources - **GreptimeDB**: Acts as the long-term storage backend for Prometheus metrics with high compression and query performance - **Grafana**: Provides dashboards and visualizations for metrics stored in GreptimeDB ## Prerequisites Before starting, ensure you have: - A running Kubernetes cluster (version >= 1.18) - `kubectl` configured to access your cluster - [Helm](https://helm.sh/docs/intro/install/) v3.0.0 or higher installed - Sufficient cluster resources (at least 2 CPU cores and 4GB memory available) ## Install GreptimeDB GreptimeDB serves as the long-term storage backend for Prometheus metrics. For detailed installation steps, please refer to the [Deploy GreptimeDB Cluster](/user-guide/deployments-administration/deploy-on-kubernetes/deploy-greptimedb-cluster.md) documentation. ### Verify the GreptimeDB Installation After deploying GreptimeDB, verify that the cluster is running. In this guide we assume the GreptimeDB cluster is deployed in the `greptime-cluster` namespace and named `greptimedb`. ```bash kubectl -n greptime-cluster get greptimedbclusters.greptime.io greptimedb ``` ```bash NAME FRONTEND DATANODE META FLOWNODE PHASE VERSION AGE greptimedb 1 2 1 1 Running v1.0.1 33s ``` Check the pods: ```bash kubectl get pods -n greptime-cluster ``` ```bash NAME READY STATUS RESTARTS AGE greptimedb-datanode-0 1/1 Running 0 71s greptimedb-datanode-1 1/1 Running 0 97s greptimedb-flownode-0 1/1 Running 0 64s greptimedb-frontend-8bf9f558c-7wdmk 1/1 Running 0 90s greptimedb-meta-fc4ddb78b-nv944 1/1 Running 0 87s ``` ### Access GreptimeDB To interact with GreptimeDB directly, you can port-forward the frontend service to your local machine. GreptimeDB supports multiple protocols, with MySQL protocol available on port `4002` by default. ```bash kubectl port-forward -n greptime-cluster svc/greptimedb-frontend 4002:4002 ``` Connect using any MySQL-compatible client: ```bash mysql -h 127.0.0.1 -P 4002 ``` ### Storage Partitioning To improve query performance and reduce storage costs, GreptimeDB automatically creates columns based on Prometheus metric labels and stores metrics in a physical table. The default table name is `greptime_physical_table`. Since we deployed a GreptimeDB cluster with [multiple datanodes](#verify-the-greptimedb-installation), you can partition the table to distribute data across datanodes for better scalability and performance. In this Kubernetes monitoring scenario, we can use the `namespace` label as the partition key. For example, with namespaces like `kube-public`, `kube-system`, `monitoring`, `default`, `greptime-cluster`, and `etcd-cluster`, you can create a partitioning scheme based on the first letter of the namespace: ```sql CREATE TABLE greptime_physical_table ( greptime_value DOUBLE NULL, namespace STRING PRIMARY KEY, greptime_timestamp TIMESTAMP TIME INDEX, ) PARTITION ON COLUMNS (namespace) ( namespace < 'f', namespace >= 'f' AND namespace < 'g', namespace >= 'g' AND namespace < 'k', namespace >= 'k' ) ENGINE = metric WITH ( "physical_metric_table" = "" ); ``` For more information about Prometheus metrics storage and query performance optimization, refer to the [Improve efficiency by using metric engine](/user-guide/ingest-data/for-observability/prometheus.md#improve-efficiency-by-using-metric-engine) guide. ### Prometheus URLs in GreptimeDB GreptimeDB provides [Prometheus-compatible APIs](/user-guide/query-data/promql.md#prometheus-http-api) under the HTTP context `/v1/prometheus/`, enabling seamless integration with existing Prometheus workflows. To integrate Prometheus with GreptimeDB, you need the GreptimeDB service address. Since GreptimeDB runs inside the Kubernetes cluster, use the internal cluster address. The GreptimeDB frontend service address follows this pattern: ``` -frontend..svc.cluster.local: ``` In this guide: - GreptimeDB cluster name: `greptimedb` - Namespace: `greptime-cluster` - Frontend port: `4000` So the service address is: ```bash greptimedb-frontend.greptime-cluster.svc.cluster.local:4000 ``` The complete [Remote Write URL](/user-guide/ingest-data/for-observability/prometheus.md#remote-write-configuration) for Prometheus is: ```bash http://greptimedb-frontend.greptime-cluster.svc.cluster.local:4000/v1/prometheus/write ``` This URL consists of: - **Service endpoint**: `greptimedb-frontend.greptime-cluster.svc.cluster.local:4000` - **API path**: `/v1/prometheus/write` ## Install Prometheus Now that GreptimeDB is running, we'll install Prometheus to collect metrics and send them to GreptimeDB for long-term storage. ### Add the Prometheus Community Helm Repository ```bash helm repo add prometheus-community https://prometheus-community.github.io/helm-charts helm repo update ``` ### Install the kube-prometheus-stack The [`kube-prometheus-stack`](https://github.com/prometheus-operator/kube-prometheus) is a comprehensive monitoring solution that includes Prometheus, Grafana, kube-state-metrics, and node-exporter components. This stack automatically discovers and monitors all Kubernetes namespaces, collecting metrics from cluster components, nodes, and workloads. In this deployment, we'll configure Prometheus to use GreptimeDB as the remote write destination for long-term metric storage and configure Grafana's default Prometheus data source to use GreptimeDB. Create a `kube-prometheus-values.yaml` file with the following configuration: ```yaml # Configure Prometheus remote write to GreptimeDB prometheus: prometheusSpec: remoteWrite: - url: http://greptimedb-frontend.greptime-cluster.svc.cluster.local:4000/v1/prometheus/write # Configure Grafana to use GreptimeDB as the default Prometheus data source grafana: datasources: datasources.yaml: apiVersion: 1 datasources: - name: Prometheus type: prometheus url: http://greptimedb-frontend.greptime-cluster.svc.cluster.local:4000/v1/prometheus access: proxy editable: true ``` This configuration file specifies [the GreptimeDB service address](#prometheus-urls-in-greptimedb) for: - **Prometheus remote write**: Sends collected metrics to GreptimeDB for long-term storage - **Grafana data source**: Configures GreptimeDB as the default Prometheus data source for dashboard queries Install the `kube-prometheus-stack` using Helm with the custom values file: ```bash helm install kube-prometheus prometheus-community/kube-prometheus-stack \ --namespace monitoring \ --create-namespace \ --values kube-prometheus-values.yaml ``` ### Verify the Installation Check that all Prometheus components are running: ```bash kubectl get pods -n monitoring ``` ```bash NAME READY STATUS RESTARTS AGE alertmanager-kube-prometheus-kube-prome-alertmanager-0 2/2 Running 0 60s kube-prometheus-grafana-78ccf96696-sghx4 3/3 Running 0 78s kube-prometheus-kube-prome-operator-775fdbfd75-w88n7 1/1 Running 0 78s kube-prometheus-kube-state-metrics-5bd5747f46-d2sxs 1/1 Running 0 78s kube-prometheus-prometheus-node-exporter-ts9nn 1/1 Running 0 78s prometheus-kube-prometheus-kube-prome-prometheus-0 2/2 Running 0 60s ``` ### Verify the Monitoring Status Use [MySQL protocol](#access-greptimedb) to query GreptimeDB and verify that Prometheus metrics are being written. ```sql SHOW TABLES; ``` You should see tables created for various Prometheus metrics. ```sql +---------------------------------------------------------------------------------+ | Tables | +---------------------------------------------------------------------------------+ | :node_memory_MemAvailable_bytes:sum | | ALERTS | | ALERTS_FOR_STATE | | aggregator_discovery_aggregation_count_total | | aggregator_unavailable_apiservice | | alertmanager_alerts | | alertmanager_alerts_invalid_total | | alertmanager_alerts_received_total | | alertmanager_build_info | | ...... | +---------------------------------------------------------------------------------+ 1553 rows in set (0.18 sec) ``` ## Use Grafana for Visualization Grafana is included in the kube-prometheus-stack and comes pre-configured with dashboards for comprehensive Kubernetes monitoring. ### Access Grafana Port-forward the Grafana service to access the web interface: ```bash kubectl port-forward -n monitoring svc/kube-prometheus-grafana 3000:80 ``` ### Get Admin Credentials Retrieve the admin password using kubectl: ```bash kubectl get secret --namespace monitoring kube-prometheus-grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo ``` ### Login Grafana 1. Open your browser and navigate to [http://localhost:3000](http://localhost:3000) 2. Login with: - **Username**: `admin` - **Password**: The password retrieved from the previous step ### Explore Pre-configured Dashboards After logging in, navigate to **Dashboards** to explore the pre-configured Kubernetes monitoring dashboards: - **Kubernetes / Compute Resources / Cluster**: Overview of cluster-wide resource utilization - **Kubernetes / Compute Resources / Namespace (Pods)**: Resource usage breakdown by namespace - **Kubernetes / Compute Resources / Node (Pods)**: Node-level resource monitoring - **Node Exporter / Nodes**: Detailed node hardware and OS metrics ![Grafana Dashboard](/k8s-prom-monitor-grafana.jpg) ## Conclusion You now have a complete Kubernetes monitoring solution with Prometheus collecting metrics and GreptimeDB providing efficient long-term storage. This setup enables you to: - Monitor cluster and application health in real-time - Store metrics for historical analysis and capacity planning - Create rich visualizations and dashboards with Grafana - Query metrics using both PromQL and SQL For more information about GreptimeDB and Prometheus integration, see: - [Prometheus Integration](/user-guide/ingest-data/for-observability/prometheus.md) - [Query Data in GreptimeDB](/user-guide/query-data/overview.md)