You speak of "date", but `original_created_at` is type `timestamptz`. I assume you do not actually want *"values ​​from that date"*, but just for that timestamp.

A single multicolumn index can cover searches for either: `original_created_at` or for `original_created_at` + `user_id`. Just make sure to put `original_created_at` first:

    CREATE INDEX ON example_table (original_created_at, user_id);

See:

- https://dba.stackexchange.com/questions/27481/is-a-composite-index-also-good-for-queries-on-the-first-field/27493#27493

Also, I would rearrange table columns to save a couple of bytes per row and make your searches a tiny bit faster yet, with the two filter columns first:

~~~
CREATE TABLE IF NOT EXISTS example_table (
  original_created_at timestamptz NOT NULL DEFAULT now()
, user_id             uuid NOT NULL
, id                  serial  PRIMARY KEY  -- do you actually have use for this?
, external_id         text NOT NULL
, category            text NOT NULL
, data                jsonb NOT NULL DEFAULT '{}'::jsonb
, CONSTRAINT external_id_uq UNIQUE (external_id)
);
~~~

See:

- [Calculating and saving space in PostgreSQL][1]

Since `external_id_uq` is `UNIQUE NOT NULL` anyway, you may be able to drop the surrogate PK column `id`.

`bigint` is more efficient for `user_id` than `uuid`. Not least, it makes above index smaller. Only use the type `uuid` if you actually need it. See:

- [PostgreSQL using UUID vs Text as primary key][2]

If there are lots of rows for the same timestamp (or timestamp + id combo), and rows are physically sorted, a [BRIN index][3] may be an alternative due its small size.


  [1]: https://stackoverflow.com/a/7431468/939860
  [2]: https://stackoverflow.com/a/33838373/939860
  [3]: https://www.postgresql.org/docs/current/indexes-types.html#INDEXES-TYPES-BRIN