You get an exception in your attempt to use now()
because the function is not IMMUTABLE
(obviously) and, I quote the manual here:
All functions and operators used in an index definition must be "immutable" ...
I see two ways to utilize a (much more effective) partial index here:
Partial index with condition using constant date:
CREATE INDEX queries_recent_idx ON queries_query (user_sid, created)
WHERE created > '2013-01-07 0:0'::timestamp
Drop and recreate that index at off hours with a cron job on a daily or weekly basis (or whatever is good enough for you). Creating an index is pretty fast, especially a partial index that is comparatively small. This solution also doesn't need to add anything to the table.
Automatic index recreation could be done with a function like this:
CREATE OR REPLACE FUNCTION f_index_recreate()
RETURNS void AS
$func$
BEGIN
DROP INDEX IF EXISTS queries_recent_idx;
EXECUTE format('CREATE INDEX queries_recent_idx
ON queries_query (user_sid, created)
WHERE created > %L::timestamp'
,to_char(now() - interval '30d', 'YYYYMMDD HH24:MI'));
END
$func$ LANGUAGE plpgsql;
Call:
SELECT f_index_recreate();
Tested with Postgres 9.2: ->sqlfiddle.
Partial index with condition on "archived" tag
Add an archived
tag to your table:
ALTER queries_query ADD COLUMN archived boolean NOT NULL DEFAULT FALSE;
UPDATE
the column at intervals of your choosing to "retire" older rows and create an index like:
CREATE INDEX some_index_name ON queries_query (user_sid, created)
WHERE NOT archived;
Add a matching condition to your queries (even if it seems redundant) to allow it to use the index. Check with EXPLAIN ANALYZE
whether the query planner catches on - it should be able to use the index for queries on an newer date. But it won't understand more complex conditions not matching exactly.
You don't have to drop and recreate the index, but the UPDATE
on the table may be more expensive than index recreation and the table gets slightly bigger.
I would go with the first option (index recreation). In fact, I am using this solution in several databases.
Both solutions retain their usefulness over time, performance slowly deteriorates as more outdated rows are included in the index.