Use the proper table definition, including natural key on (story_id, ztimestamp)
.
BTW timestamp
is a data type, better not use it as a column name.
BTW2: you probably want story_id
to be an integer field in stead of a text field, and since it is a key field you may also want it to be NOT NULL.
-- DDL
DROP TABLE story CASCADE;
CREATE TABLE story
( id serial not null primary key
, story_id text NOT NULL
, ztimestamp timestamp not null
, zvalue integer not null default 0
, UNIQUE (story_id, ztimestamp) -- the natural key
);
\d+ story
EXPLAIN
SELECT * FROM story st
WHERE story_id IN('1','2','3')
AND NOT EXISTS(
SELECT *
FROM story nx
WHERE nx.story_id = st.story_id
AND nx.ztimestamp > st.ztimestamp
);
DROP TABLE
CREATE TABLE
Table "tmp.story"
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
------------+-----------------------------+-----------+----------+-----------------------------------+----------+--------------+-------------
id | integer | | not null | nextval('story_id_seq'::regclass) | plain | |
story_id | text | | not null | | extended | |
ztimestamp | timestamp without time zone | | not null | | plain | |
zvalue | integer | | not null | 0 | plain | |
Indexes:
"story_pkey" PRIMARY KEY, btree (id)
"story_story_id_ztimestamp_key" UNIQUE CONSTRAINT, btree (story_id, ztimestamp)
QUERY PLAN
----------------------------------------------------------------------------------------------------------
Nested Loop Anti Join (cost=1.83..18.97 rows=13 width=48)
-> Bitmap Heap Scan on story st (cost=1.67..10.94 rows=16 width=48)
Recheck Cond: (story_id = ANY ('{1,2,3}'::text[]))
-> Bitmap Index Scan on story_story_id_ztimestamp_key (cost=0.00..1.67 rows=16 width=0)
Index Cond: (story_id = ANY ('{1,2,3}'::text[]))
-> Index Only Scan using story_story_id_ztimestamp_key on story nx (cost=0.15..0.95 rows=2 width=40)
Index Cond: ((story_id = st.story_id) AND (ztimestamp > st.ztimestamp))
(7 rows)