CREATE TABLE IF NOT EXISTS events
(
id UUID NOT NULL,
type_id UUID,
occurred_at TIMESTAMP WITH TIME ZONE NOT NULL,
PRIMARY KEY (id)
);
jood code:
val queryDsl = dslContext.select(EventFields).from(EVENTS)
.where(
(EVENTS.TYPE_ID.isNull)
.or(EVENTS.TYPE_ID.eq(query.typeId.id))
)
model id code:
import java.util.UUID
data class TypeId(val id: UUID) {
constructor (id: String) : this(UUID.fromString(id))
override fun toString(): String = id.toString()
}
Query:
where ("public"."events"."type_id" = cast('d0c6a2a7-2032-4dd7-b2b1-77a554262af7' as uuid))
Why cast?
I tried to get rid of this casting as it affects my index performance
My index:
CREATE INDEX company_employee_occurred_at_idx
ON balance_state_event (id, type_id, occurred_at DESC);
In my explain query plain one of the line is:
Filter: ((type_id IS NULL) OR (type_id = '390caffd-9c3b-4ea4-b5e2-6ae342268141'::uuid))
why an explicit filter if the index is there?
Why cast?
There has been a relatively recent fix in jOOQ where all UUID
bind values are now cast to their type explicitly for SQLDialect.POSTGRES
:
The fix has been applied to versions:
It is necessary in a lot of edge cases and not-so-edge cases. jOOQ doesn't hard-code all of these cases to make a more specific decision based on the context, it just casts all UUID
typed bind values, just like it auto-casts all of these typed bind values:
And possibly more, in the future.
This answers the question you asked (the one from the title).
I tried to get rid of this casting as it affects my index performance
I don't think this cast affects your performance. The bind value is a constant, and casting it doesn't change anything. Without the cast, there would still be an implicit cast as types get promoted.
However, your OR
predicate is a more likely problem:
((type_id IS NULL) OR (type_id = '390caffd-9c3b-4ea4-b5e2-6ae342268141'::uuid))
Do check why in your case, no BitmapOr
operation appears in your execution plan. It is hard to say from the little information you provided. In a more minimal example, this works just fine:
create table t (i uuid);
create index i on t (i);
insert into t select uuid_generate_v4() from generate_series(1, 1000000) as t (i);
explain
select *
from t
where i is null or i = cast('390caffd-9c3b-4ea4-b5e2-6ae342268141' as uuid)
Producing:
|QUERY PLAN |
|-----------------------------------------------------------------------------------|
|Bitmap Heap Scan on t (cost=8.87..12.88 rows=1 width=16) |
| Recheck Cond: ((i IS NULL) OR (i = '390caffd-9c3b-4ea4-b5e2-6ae342268141'::uuid))|
| -> BitmapOr (cost=8.87..8.87 rows=1 width=0) |
| -> Bitmap Index Scan on i (cost=0.00..4.43 rows=1 width=0) |
| Index Cond: (i IS NULL) |
| -> Bitmap Index Scan on i (cost=0.00..4.43 rows=1 width=0) |
| Index Cond: (i = '390caffd-9c3b-4ea4-b5e2-6ae342268141'::uuid) |
This shows that you probably have another question to ask, best in a new question, as this one is about jOOQ and casting, not about your actual performance issue.