Skip to content

[ES|QL] WHERE Command filtering can be significantly slower than DSL #128529

@BenB196

Description

@BenB196

Elasticsearch Version

8.18.1

Installed Plugins

No response

Java Version

bundled

OS Version

Container

Problem Description

I recently came across a problem a relatively simple query/agg was performing extremely slow in ES|QL (~62000ms), but was fairly fast with DSL (~150ms). I was able to track it down to a single WHERE filter in the ES|QL query. Removing the offending WHERE clause, caused the ES|QL query to perform on-par with the DSL one.

Steps to Reproduce

  1. Run the following query and observe poor performance.
POST /_query
{
  "query": "FROM logs-istio.access_logs-*\r\n| WHERE istio.access.upstream.cluster != \"outbound|8200||apm.apm.svc.cluster.local\"\r\n| STATS COUNT()\r\n",
  "locale": "en",
  "include_ccs_metadata": true,
  "filter": {
    "bool": {
      "must": [],
      "filter": [
        {
          "range": {
            "@timestamp": {
              "format": "strict_date_optional_time",
              "gte": "2025-05-27T16:00:00.000Z",
              "lte": "2025-05-27T17:00:00.000Z"
            }
          }
        }
      ]
    }
  }
}

(ES|QL query)

FROM logs-istio.access_logs-*
| WHERE istio.access.upstream.cluster != "outbound|8200||apm.apm.svc.cluster.local"
| STATS COUNT()

(Is the query I noticed the issue with)

{
  "rawResponse": {
    "is_running": false,
    "took": 61944,
    "is_partial": false,
    "all_columns": [
      {
        "name": "COUNT()",
        "type": "long"
      }
    ],
    "columns": [
      {
        "name": "COUNT()",
        "type": "long"
      }
    ],
    "values": [
      [
        835129
      ]
    ]
  }
}
  1. Run the same query, but without the WHERE clause
POST /_query
{
  "query": "FROM logs-istio.access_logs-*\r\n| STATS COUNT()\r\n",
  "locale": "en",
  "include_ccs_metadata": true,
  "filter": {
    "bool": {
      "must": [],
      "filter": [
        {
          "range": {
            "@timestamp": {
              "format": "strict_date_optional_time",
              "gte": "2025-05-27T16:00:00.000Z",
              "lte": "2025-05-27T17:00:00.000Z"
            }
          }
        }
      ]
    }
  }
}

(ESQL query)

FROM logs-istio.access_logs-*
| STATS COUNT()

Response:

{
  "rawResponse": {
    "is_running": false,
    "took": 121,
    "is_partial": false,
    "all_columns": [
      {
        "name": "COUNT()",
        "type": "long"
      }
    ],
    "columns": [
      {
        "name": "COUNT()",
        "type": "long"
      }
    ],
    "values": [
      [
        1121299
      ]
    ]
  }
}
  1. Run the same query with DSL
POST /logs-istio.access_logs-*/_async_search?batched_reduce_size=64&ccs_minimize_roundtrips=true&wait_for_completion_timeout=200ms&keep_on_completion=true&keep_alive=60000ms&ignore_unavailable=true&preference=1748371077976
{
  "aggs": {},
  "size": 0,
  "query": {
    "bool": {
      "filter": [
        {
          "range": {
            "@timestamp": {
              "format": "strict_date_optional_time",
              "gte": "2025-05-27T16:00:00.000Z",
              "lte": "2025-05-27T17:00:00.000Z"
            }
          }
        }
      ],
      "must_not": [
        {
          "match_phrase": {
            "istio.access.upstream.cluster": "outbound|8200||apm.apm.svc.cluster.local"
          }
        }
      ]
    }
  }
}

Response:

{
  "id": "FjRJX19mdF9iUVNTZGtyd0ZJQVExTXcgYU1Lang5Y1NTYmU2N3h6VE92OHdWdzoyMzUxMzUyMjU=",
  "rawResponse": {
    "took": 130,
    "timed_out": false,
    "_shards": {
      "total": 132,
      "successful": 132,
      "skipped": 128,
      "failed": 0
    },
    "hits": {
      "total": 838731,
      "max_score": null,
      "hits": []
    }
  },
  "isPartial": false,
  "isRunning": false,
  "total": 132,
  "loaded": 132,
  "isRestored": false
}

Observe that both queries 2 & 3 perform about the same.

Logs (if relevant)

I've attached 2 profiles, 1 for the query executed in step 1 and another for the query executed in step 2.

esql-profile-query-step-1.json
esql-profile-query-step-2.json

Metadata

Metadata

Assignees

Labels

:Analytics/ES|QLAKA ESQLTeam:AnalyticsMeta label for analytical engine team (ESQL/Aggs/Geo)

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions