drop table hits_user_daily_count; create table hits_user_daily_count ( userid integer not null, date date not null, num_hits integer default 0, num_cover_page_hits integer default 0, num_additional_files_hits integer default 0, primary key (userid, date)); create index hits_user_daily_count_date on hits_user_daily_count(date); create or replace function fill_for_date(d date, n int) returns void language plpgsql as $$ begin insert into hits_user_daily_count select uid, d, random()*10, random()*10 from generate_series(1,n) uid order by random(); end $$; select fill_for_date('today'::date - 5, 100000); select fill_for_date('today'::date - 4, 100000); select fill_for_date('today'::date - 3, 100000); select fill_for_date('today'::date - 2, 100000); select fill_for_date('today'::date - 1, 100000); analyze hits_user_daily_count; -- If you include this step, the query for today actually takes a long time; -- but you risk auto-analyze changing the stats and making the problem go away. -- select fill_for_date('today'::date - 0, 20000); explain analyze select 1 from hits_user_daily_count where userid = 15901 and date = 'yesterday'::date; explain analyze select 1 from hits_user_daily_count where userid = 15901 and date = 'today'::date;