How to make PG query faster even when it is using indices
One odd thing is that the filter Filter: (school_year = 2018) doesn't remove any rows.  So either the entire table has school_year = 2018, or all the rows which meet the criteria classes in ('1st','2nd','3rd') have school_year = 2018. Either way, it seems a bit odd.  Is this how your real problem is, or is it an artefact of creating a smaller demonstration problem?

The slowness probably comes from the IO needed to read a large amount of the table.  Doing the EXPLAIN (ANALYZE, BUFFERS), especially with "track_io_timing" turned on, would be especially helpful to figure that out.

If so, creating an index that includes all of the columns, like:

create index on mytable (classes, school_year, score);


should make this much faster.  It will allow an index-only scan, instead of an scan which still needs to visit the table for each row.  But for this to be effective, the table must be kept well-vacuumed.  The default settings of autovac will probably not be enough.