Skip to content

exists? shouldn't remove the order_by clause #4691

@DaemonSnake

Description

@DaemonSnake

Elixir version

1.19.4

Database and Version

Postgresql 17.5

Ecto Versions

3.13.5

Database Adapter and Versions (postgrex, myxql, etc)

ecto_sql 3.13.3 (postgresql)

Current behavior

the exists? function currently makes changes to the give query.
All these changes are expected but one:

      |> Query.exclude(:order_by)

While it's logical to not care about ordering when looking if a record exists,
order_by has an impact on the query plan and the performance of the query in postgres
where limit: 1 is provided

Here is a small example:

explain
SELECT
	TRUE
FROM
	"permission_targets" AS p0
WHERE
	(p0."removed_at" IS NULL)
	AND (p0."workspace_id" = '...')
LIMIT
	1
;
-- produces the following query plan:
-- Limit  (cost=0.00..0.44 rows=1 width=1)
--  ->  Seq Scan on permission_targets p0  (cost=0.00..51834.21 rows=118618 width=1)
--"        Filter: ((removed_at IS NULL) AND (workspace_id = '...'::uuid))"

Same query with an order_by on workspace_id, id with the right index

explain
SELECT
	TRUE
FROM
	"permission_targets" AS p0
WHERE
	(p0."removed_at" IS NULL)
	AND (p0."workspace_id" = '...')
order by p0.id
LIMIT
	1
;

-- produces the following query plan:
-- Limit  (cost=0.05..0.54 rows=1 width=33)
-- "  ->  Index Only Scan using ""permission_targets_workspace_id_id"" on permission_targets p0  (cost=0.05..57654.03 rows=118618 width=33)"
-- "        Index Cond: (workspace_id = '...'::uuid)"

The above query is a simplified version of a hot-path query that can spike to 9s in avg and 2.74 Load by Waits for just 0.1 calls/sec

Temporary fix will be to use .one instead

Expected behavior

exists? shouldn't alter the order_by clause of the query as:

  • it doesn't affect the exists? logic
  • changes the query plan of the query
  • doesn't trigger a sort because the query has a select(1) clause

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