Skip to content

[receiver/sqlquery] tracking value is persistently saved on every row, causing poor performance and potential data loss #49629

Description

@vishalmore90

Component(s)

receiver/sqlquery

Describe the issue you're reporting

Description

In the sqlqueryreceiver's logs component, the tracking value (retrieved from the specified tracking_column) is persistently written to the configured storageClient on every single row processed within the collection loop.

This behavior:

  1. Causes significant performance degradation, high CPU overhead, and high disk/network I/O due to redundant serial writes to the storage backend, especially when querying large result sets (e.g., thousands of log records per collection cycle).
  2. Introduces a data loss risk under crash conditions. If the collector restarts or crashes after the storage client has been updated but before nextConsumer.ConsumeLogs successfully processes/exports the collected logs, the tracking value in persistent storage will have already been advanced. Upon restart, the receiver will query starting from the advanced tracking value, causing the failed/unexported logs to be permanently lost.

Steps to Reproduce

  1. Configure sqlqueryreceiver with a tracking_column and a persistent storage extension (e.g., filestorage or dbstorage).
  2. Run a query that returns a large number of rows (e.g., 10,000 logs).
  3. The receiver iterates through all 10,000 rows. For each row, it executes storageClient.Set to write the new tracking value to storage.
  4. Observe the performance degradation, high disk write throughput, or CPU wait times.
  5. Alternatively, simulate a failure in ConsumeLogs or crash the collector mid-collection; on restart, notice that the tracking value has advanced in the storage and the failed logs are skipped.

Expected Result

The receiver should only write the tracking value to persistent storage once per query collection cycle (e.g., at the end of the collection loop, or ideally, after the batch has been successfully consumed/exported by the pipeline). At minimum, writing to storage should happen once at the end of the collection loop rather than per row.

Actual Result

storageClient.Set is invoked synchronously on every single row inside the rows iteration, leading to thousands of redundant writes.

Version

v0.104.0 / main branch (commit 928d968ca2 or latest)

Environment Information

  • OS: All (Windows, Linux, macOS)
  • Compiler (if applicable): Go 1.22+

Repo Configuration

extensions:
  file_storage:
    directory: /tmp/otelcol/storage

receivers:
  sqlquery:
    driver: postgres
    datasource: "host=localhost user=postgres password=postgres dbname=postgres sslmode=disable"
    storage: file_storage
    collection_interval: 10s
    queries:
      - sql: "SELECT id, body, timestamp FROM logs_table WHERE id > $$1"
        tracking_column: id
        tracking_start_value: "0"
        logs:
          - body_column: body
            attribute_columns: [timestamp]

exporters:
  nop:

service:
  extensions: [file_storage]
  pipelines:
    logs:
      receivers: [sqlquery]
      processors: []
      exporters: [nop]

Log Output

Under normal operation, there is no explicit error, but significant latency and wait times are visible, potentially resulting in timeouts:

2026-07-13T17:25:13.000Z	warn	sqlqueryreceiver	problems encountered getting log rows	{"error": "context deadline exceeded"}

Additional Context

  • Root cause analysis:
    In logs_receiver.go, the loop that converts database rows to OTel logs calls queryReceiver.storeTrackingValue(ctx, row) for every row in rows when processing the first logs config (logsConfigIndex == 0).
    This method synchronously invokes the storage client's Set method (lines 359-371).

Tip

React with 👍 to help prioritize this issue. Please use comments to provide useful context, avoiding +1 or me too, to help us triage it. Learn more here.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions