Исходя из плана EXPLAIN, ваш стол большой. Около 2 строк на странице. Либо он очень раздутый, либо сами строки очень широкие.
Ключ к хорошей производительности, вероятно, состоит в том, чтобы заставить его использовать сканирование только по индексу, создав индекс, который содержит все 4 столбца, на которые есть ссылки в Ваш запрос. Столбец, проверенный на равенство, должен стоять первым. После этого вам придется выбирать между двумя столбцами, для которых задан диапазон или неравенство («last_active» или «rating»), в зависимости от того, что, по вашему мнению, будет более избирательным. Затем вы добавляете другой диапазон или неравенство и столбец id в конец, чтобы можно было использовать сканирование только по индексу. Так что, может быть, create index on app_user (country, last_active, rating, id)
. Это, вероятно, будет достаточно.
Вы также можете попробовать индекс GiST для тех же столбцов. Это имеет теоретическое преимущество, заключающееся в том, что два ограничения диапазона или неравенства можно использовать вместе при определении того, какие индексные страницы следует просматривать. Но на практике индексы GiST имеют очень высокие издержки, и эти издержки, вероятно, превысят теоретическое преимущество.
Если вышеприведенное не достаточно хорошо, вы можете попробовать разделить. Но как именно вы это делаете, должно основываться на целостном c представлении вашего приложения, а не на одном запросе.