The scope of this comparison
This is an architectural comparison rather than a benchmark league table. Results change with storage volume and cache state. Retention and query selectivity also matter. Borrowed numbers are therefore not useful. We compare the work each design performs during ingestion and querying. We also examine its infrastructure and the experience it gives engineers.
The Grafana stack here means Grafana with Mimir plus Loki and Tempo. SigNoz and OpenObserve are integrated applications with their own interfaces. PulsusDB provides OpenTelemetry ingestion over purpose-built ClickHouse® models. It exposes PromQL plus LogQL and TraceQL for frontends such as Grafana and Perses.
Four different architectures
SigNoz and PulsusDB both use the ClickHouse database but build different products around it. SigNoz provides an integrated collector and backend with its own interface. PulsusDB keeps the application tier stateless. It concentrates on ingestion and signal-specific storage. Its query-language compilers are designed for teams that retain their existing frontends.
OpenObserve makes Parquet and object storage its normal data path. The Grafana stack uses three specialised backends. Mimir plus Loki and Tempo can scale independently. Both approaches can handle large deployments. Their production topologies introduce more services than the two-tier PulsusDB model.
| Platform | Primary storage | Query language | Application layer | Scaling model |
|---|---|---|---|---|
| PulsusDB | Separate ClickHouse tables for each signal. Active data uses local storage and older data can move to an S3-compatible tier | PromQL plus LogQL and TraceQL compile into bounded ClickHouse work. Exact engine evaluation runs where required | Stateless API and ingestion processes with separate compiler services. Visualisation remains external | Scale stateless PulsusDB processes independently while ClickHouse owns state, replication and distributed execution |
| SigNoz | ClickHouse on persistent block volumes. S3 or GCS can provide optional cold storage | PromQL for metrics. A unified query builder and ClickHouse SQL support other exploration | An integrated backend and query experience with dashboards and alerting | Scale the application and collector tier together with the selected ClickHouse topology |
| OpenObserve | Parquet files on local disk or object storage. Metadata uses a separate store | PromQL for metrics and SQL-oriented exploration for logs and traces | An integrated interface with query services plus dashboards and alerting | Single node for a compact start; multiple specialised node types in high-availability mode |
| Grafana stack | Separate Mimir blocks and Loki chunks plus Tempo blocks. Retained data normally lives in object storage | Native PromQL plus LogQL and TraceQL in their respective backends | Grafana interface over three separately operated signal backends | Scale Mimir, Loki and Tempo component groups independently for each signal |
Query languages and compliance
Compare the languages each platform supports, its compatibility level and the difficulty of authoring production queries rather than basic filters.
| Platform | Metrics | Logs | Traces |
|---|---|---|---|
| PulsusDB | PromQL · Fully compliant. Available through the standard Prometheus HTTP API Easy to moderate | LogQL · Fully compliant. Includes pipelines and parsers. Supports range and vector aggregation plus unwrap and binary operations Easy to moderate | TraceQL · Fully compliant. Includes search and structural operators. Supports aggregation and TraceQL metrics Easy to moderate |
| SigNoz | PromQL · Partially compliant. Query builder and ClickHouse SQL are also available Easy to moderate with PromQL High when PromQL cannot be used | SQL-like filter expressions. ClickHouse SQL is available in dashboards High difficulty | SQL-like filter expressions. ClickHouse SQL is available in dashboards High difficulty |
| OpenObserve | PromQL · Partially compliant. SQL is also available over metric streams Easy to moderate with PromQL High when PromQL cannot be used | SQL with full-text and regular-expression functions High difficulty | SQL over trace streams High difficulty |
| Grafana stack | PromQL in Mimir · Fully compliant Easy to moderate | LogQL in Loki · Fully compliant Easy to moderate | TraceQL in Tempo · Fully compliant Easy to moderate |
Storage efficiency and retention
PulsusDB selects codecs for the type of data in each column. Metric timestamps use DoubleDelta before ZSTD. DoubleDelta records the change between adjacent timestamp deltas. A regular collection interval makes that second delta zero or very small. Metric values use Gorilla before ZSTD. Gorilla stores compact XOR differences between neighbouring floating-point samples. These encodings remove huge amounts of repetition across billions of samples. Metric rollups can reduce the stored data further.
SigNoz uses the same DoubleDelta and Gorilla combination in its current ClickHouse metric sample schema. All four approaches store traces efficiently through different implementations. PulsusDB and SigNoz use typed ClickHouse columns. Their codecs suit timestamps and integers as well as repeated strings and attributes. OpenObserve uses Parquet column encodings with ZSTD. Tempo uses Parquet encodings with Snappy. Each approach avoids an uncompressed generic span document. Queries can read only the columns they require.
| Platform | Timestamp columns | Metric values | Log data | Trace data | Retention storage |
|---|---|---|---|---|---|
| PulsusDB | Most efficientDoubleDelta then ZSTD. Regular collection intervals collapse into tiny second-order deltas | Most efficientGorilla then ZSTD. Compact XOR differences avoid repeatedly storing full Float64 values | Most efficientZSTD compresses each column. Compact whole-word indexes support targeted search without creating a full inverted copy | Most efficientA trace-specific model stores typed span and attribute columns under ZSTD. Repeated values compress together by column. This includes service names and operation names as well as statuses and attribute keys. A generic span document would duplicate them | Active ClickHouse parts on local block storage, with older parts moved to S3-compatible storage through the same tables and APIs |
| SigNoz | Most efficientCurrent metric sample schema uses DoubleDelta then ZSTD(1) | Most efficientCurrent metric sample schema uses Gorilla then ZSTD(1) | Most efficientLog timestamps use DoubleDelta with LZ4. The string body uses ZSTD(2). The JSON body and promoted fields use ZSTD(1). IDs plus attributes and resource or scope columns also use ZSTD(1). Token and n-gram Bloom indexes cover body and attribute search | Most efficientSpan timestamps and time buckets use DoubleDelta with LZ4. Duration plus kind and status use T64 with ZSTD(1). The same applies to flags. Repeated names and common service or HTTP fields use LowCardinality with ZSTD(1). Events use ZSTD(2). IDs plus attribute maps and JSON attributes use ZSTD(1). Several compact indexes cover the common trace filters | Persistent block volumes, with optional ClickHouse S3 or GCS cold storage |
| OpenObserve | Parquet column encodings followed by ZSTD file compression | Parquet column encodings followed by ZSTD file compression | ZSTD-compressed Parquet. Optional inverted indexes improve search but add ingestion and storage work | Most efficientZSTD-compressed Parquet with column pruning | Object storage is the durable layer in high-availability deployments; local disk buffers writes and caches query files |
| Grafana stack | Most efficientMimir TSDB uses delta-of-delta timestamp encoding. Tempo delta-encodes time and duration columns | Most efficientMimir uses Prometheus TSDB XOR or XOR2 chunks. Both specialise in floating-point samples | Most efficientLoki stores a TSDB label index and compressed chunks. Gzip is the default; Snappy is a common performance setting | Most efficientTempo Parquet uses Snappy. String columns use dictionary encoding. Time and duration use delta encoding. Sparse fields use RLE | Separate object-storage blocks or chunks and retention processes for Mimir, Loki and Tempo |
Query response time across large datasets
Exact response times depend on the query and dataset. Hardware and cache state also matter. PulsusDB and SigNoz belong in the same low-latency class for hot data because both query compressed ClickHouse parts on block storage. PulsusDB may have an edge when its signal-specific models reduce the scan. Their ordering keys and indexes follow PromQL plus LogQL and TraceQL workloads. Eligible metric queries can also use the most efficient rollup. The larger architectural difference is between these ClickHouse hot paths and systems that must first fetch data from object storage.
| Platform | Expected response time | Hot data queries | Cold or uncached queries | How scan time is reduced |
|---|---|---|---|---|
| PulsusDB | Lowest latency pathThe same low-latency class as SigNoz on equivalent ClickHouse infrastructure. Query-optimised signal models may give PulsusDB an edge. Its ordering keys and indexes can reduce the data scanned. Automatic metric rollup routing can reduce it further | Lowest latency pathClickHouse scans compressed columnar MergeTree parts on dedicated block storage. It uses vectorised execution and distributes processing across the cluster | ClickHouse reads only the required cold parts from the S3-compatible tier through the same tables. First access includes object-storage latency. Later reads can benefit from caching | Lowest latency pathThe compiler pushes filters into ClickHouse along with aggregation and column selection. Ordering keys plus skip indexes and rollup routing reduce the number of rows and bytes scanned |
| SigNoz | Lower latency pathLow expected response time for large hot datasets. It should be broadly similar to PulsusDB on equivalent ClickHouse infrastructure. Results still depend on the query layer and schema as well as the selected indexes | Lower latency pathSignal-specific ClickHouse tables use column pruning and vectorised execution against active parts on persistent block volumes | Optional ClickHouse S3 or GCS cold storage adds remote-read and cache-fill time when the required parts are no longer local | Lower latency pathOrdering keys, skip indexes and application-specific materialised views can reduce the data read by ClickHouse |
| OpenObserve | Narrow or cached queries can have low response times. The baseline differs from PulsusDB and SigNoz because hot data does not follow the same block-storage path. Broad uncached queries must retrieve Parquet data from object storage before scanning it. This makes response time more variable | Memory and local-disk caches can avoid remote fetches when the required data is already present on query nodes | Required Parquet files are downloaded from object storage into the query tier. Response time then includes object requests and network transfer before the scan begins | Stream metadata and time partitions reduce the files fetched. File lists plus optional indexes and Parquet pruning reduce them further |
| Grafana stack | Response time is more variable across Mimir plus Loki and Tempo. Recent or cached data can be quick. Broad uncached queries depend on object retrieval in each backend | Recent data may remain in ingesters or caches. Each signal backend has its own query frontend. Sharding and caching also follow separate paths | Store gateways or queriers download uncached blocks and chunks from object storage before scanning them. Broad log and trace searches may touch many remote objects | Indexes and query splitting reduce remote reads. Sharding and caches help as well. Each mechanism is configured and operated separately for every signal |
Text search and indexing
The important distinction is what an index can exclude. Some indexes locate matching rows. Others reject storage blocks that cannot match. A platform may index no log content at all. Tantivy maps full words to matching rows. ClickHouse Bloom filters reject granules before scanning the remaining candidates. Loki indexes stream labels and then brute-force scans every selected chunk.
| Platform | Relative search speed | Log-body search path | Indexing mechanism | When a full scan is required | Index storage cost |
|---|---|---|---|---|---|
| PulsusDB | Fastest tier. LogQL labels narrow the streams. Token and n-gram filters then cover word and substring searches on ClickHouse | Time range and LogQL label selectors narrow the search to matching streams first. Bloom filters then reject non-matching ClickHouse granules before the remaining rows are scanned to verify exact matches | tokenbf_v1 for whole words and ngrambf_v1 for substrings. Both are compact probabilistic skip indexes | A full scan is required only when a filter cannot produce a usable token or n-gram. Even then the time range and label selectors restrict it to matching streams | Negligible. Bloom filters store compact bitsets rather than term-to-row posting lists |
| SigNoz | Fast tier. Attribute filtering and n-gram Bloom pruning reduce the ClickHouse data scanned for text searches | The time range and resource or log-attribute filters narrow the ClickHouse read first. Bloom filters then reject granules that cannot match before the remaining log-body rows are scanned and evaluated | An n-gram Bloom skip index covers the log body. Token Bloom indexes cover selected attribute data | When a query cannot use the body n-gram index or an indexed attribute. Time and attribute filters can still restrict the data scanned | Low. ClickHouse skip indexes are much smaller than a full inverted index |
| OpenObserve | Fast for full words because Tantivy locates indexed tokens directly. Substring and regular-expression searches can fall back to scanning object-backed Parquet data | OpenObserve has no Loki-style log labels. Stream selection and time narrow the dataset first. Partition keys and field predicates can remove unrelated Parquet files before text search | A Tantivy inverted index locates full-word matches in configured fields. Other fields can use partitioning or secondary indexes. Bloom filters are another option | Substring and regular-expression searches scan the remaining Parquet data when they cannot use indexed words. Stream and time filters can still reduce that scan. Field filters can reduce it further | Material. OpenObserve documents approximately 25% storage overhead for an indexed stream, varying with data entropy |
| Grafana stack | Slowest tier. Labels narrow the streams. Log-body searches still download and brute-force scan every selected chunk | Loki resolves matching streams from labels. It downloads their chunks and brute-force scans every selected log line for body filters | A stream-label index. Optional experimental Bloom blocks cover structured metadata but not general log-body text | Every log-body search scans the selected chunks. This applies to words as well as substrings and regular expressions | Small for the standard label index. Optional Bloom acceleration adds separate blocks and operating components |
The PulsusDB approach
PulsusDB combines fast ClickHouse queries with data models built for observability. Automatic rollups reduce long-range metric scans. Compact token and n-gram Bloom indexes accelerate text search without the storage cost of a large inverted index. Active data stays on block storage for low-latency queries. Older data moves to an object-storage tier while remaining available through the same tables and query APIs.
Teams can keep the Grafana UI and query through familiar languages that are easy to use. PromQL handles metrics. LogQL handles logs. TraceQL handles traces. Engineers do not need to write ClickHouse SQL for routine investigations or learn a proprietary query language. Perses is supported as another frontend. OpenTelemetry ingestion keeps collection portable. The PulsusDB tier remains stateless while ClickHouse owns durable data. ClickHouse provides replication and horizontal scale. PulsusDB brings these capabilities together without requiring three separate telemetry backends or another observability interface.