Well, all the row counts in expected and actual are pretty close. I'm
guessing it's as optimized as it's likely to get. you could try
mucking about with random_page_cost to force index usage, but indexes
are not always a win in pgsql, hence the seq scans etc... If the
number of rows returned represents a large percentage of the total
number of rows in the table, then a seq scan is generally a win. Note
that most all the time being spent in this query is on the Hash Join,
not on the seq scans.
Also, you should really update to 8.2.6 the latest 8.2 version. Check
the release notes for the bugs that were fixed between 8.2.1 and 8.2.6