Is there any way to make it faster?
Oh yes, much faster. (Updated 2021.)
Basic assessment
If you need this often and fast, and writes to the table are either few or predictable (like: new rows always have current time), a materialized view would be fastest, like @Roger suggested. But you still need a query to implement it. And the queries I am going to suggest are so fast that you might skip the MV ...
In related cases there is often a look-up table with candidate values allowing for a much faster query:
Assumptions for this case:
- Postgres 9.4 or later.
- creation_dateis data type- timestamp(works for- dateor- timestamptztoo).
- Actual range of timestamps is unknown.
- There is a btree index on acs_objects(creation_date).
Emulate loose index scan with rCTE
If you neither have a look-up table nor a derived table with candidate values, there is still a very fast alternative. Basically, you need to emulate an "index skip scan", a.k. a."loose index scan". This query works in any case:
WITH RECURSIVE cte AS (
   SELECT date_trunc('year', max(creation_date)) AS y
   FROM   acs_objects
   UNION ALL
   SELECT (SELECT date_trunc('year', max(creation_date))
           FROM   acs_objects
           WHERE  creation_date < cte.y)
   FROM   cte
   WHERE  cte.y IS NOT NULL
   )
SELECT to_char(y, 'YYYY') AS year
FROM   cte
WHERE  cte.y IS NOT NULL;
Probably fastest: top-down, and truncate each timestamp to the start of the year, then find the latest of the earlier rows; repeat.
Details for this technique:
Based on generate_series()
valex's idea can be implemented more efficiently with generate_series() producing timestamp values based on the actual range of existing years:
SELECT to_char(y, 'YYYY') AS year
FROM  (
   SELECT generate_series(date_trunc('year', min(creation_date))
                        , max(creation_date)
                        , interval  '1 year')
   FROM   acs_objects
   ) t(y)
WHERE  EXISTS (
   SELECT FROM acs_objects 
   WHERE creation_date >= y
   AND   creation_date <  y + interval '1 year'
   );
db<>fiddle here demonstrating both.
Old slfiddle
If there are few gaps in the range of years, this may be faster, yet. But either should only take a few milliseconds or less, regardless of the table size.
Related: