Have you done a "vacuum analyze"?
Prefix your query with "Explain" and you will see the query plan it decided upon. From the looks of it, it will generate an **incredible** amount of data before moving on to GROUP and then HAVING. Particularly with 2.1M rows.
I don't know your data model, but I can't help but wonder if the query couldn't be simplified. Do you have indices created on functions? See CREATE INDEX documentation, see the ON phrase.