I am observing behavior I cannot explain in Postgres v9.6.
A table exists, let's call it 'orders' with a schema of
create table orders(
id uuid primary key,
created_at timestamp with time zone not null,
modified_at timestamp with time zone not null,
entity jsonb not null);
I need to create an index based on a function that uses the id and the modified_at values to create the index value. Therefore, I have
-- We put the 'A' on the front because if the beginning of the string looks like a date, it triggers
-- a postgres bug that causes sorting to skip some rows. The 'A' makes the value not look like a date.
create function sortable_timestamp_and_uuid(timestamp with time zone, uuid) returns text as
$$ select 'A' || to_char($1, 'YYYY-MM-DD HH24:MI:SS.US') || '/' || $2::text; $$
language sql immutable;
create function paging_func(timestamp with time zone, uuid) returns text as
$$ select sortable_timestamp_and_uuid($1, $2); $$
language sql immutable;
create index my_paging_idx on orders( paging_func(modified_at, id) );
This works as expected. I can create an index on the orders table and when I run a query with a WHERE clause of paging_func(modified_at, id) < pagine_func(some_specfic_timestamp, some_specific_uuid) it returns the results that I would expect.
HOWEVER this only works for data that already existed in the table when I created the index. If I insert data into the table, INSERT id, created_at, modified_at, entity VALUES(?,now(),now(),?), my previous where clause does not work for the newly inserted data. The data appears at the top (least in value) of the index.
For example, if I have two rows with values:
id | modified_at
--------------------------------------------------------------------
199967e2-0987-2987-11c7-bbca1348467e | 2020-01-14 20:14:25.799287
298bc22a-6eaa-5ec3-d962-ad2d206a4dca | 2020-01-14 20:14:25.799287
If I create the index with the rows already existing the database and query with
WHERE paging_func(modified_at, id) < paging_func(to_timestamp('2020-01-14 20:14:25.799287',
'YYYY/MM/DD HH24:MI:SS.US'),
uuid_in('298bc22a-6eaa-5ec3-d962-ad2d206a4dca'))
The result set will only contain the first row. If however, only the first row exists when the index is created and I insert the second row into the table, and run the same exact query both rows are returned.
If I delete the index and re-create the index, the index behaves as expected for the data in the table, but all new values inserted into the table are not indexed correctly. I would appreciate any help explaining what I am doing incorrectly and why I am observing this behavior.
(id, the modified_at)?IMMUTABLE indicates that the function cannot modify the database and always returns the same result when given the same argument values; that is, it does not do database lookups or otherwise use information not directly present in its argument list. If this option is given, any call of the function with all-constant arguments can be immediately replaced with the function value.