одно из простых решений:
задаем диапазоны допустимых значений для фильтров
отбираем строки в рамках этих диапазонов
сортируем их либо по абсолютному отклонению от значений фильтров, либо по некоей "формуле" совокупного отклонения (например корень квадратный из суммы квадратов отклонений)
Громоздкость - это не критерий. Главное чтобы оптимизатору-планировщику было понятно как выполнять запрос.
Вот если запрос выполняется медленно - тогда думать надо.
Можно убрать констрэйн, но это чревато нарушением консистентности.
Можно в проекциях объектов (таблицах) делать условно избыточность в виде нескольких полей-ссылок и поле типа.
Естественно и то и то не идеал. Но так или иначе приходится искать компромисс между многомерностью (ООП) и ее проекциями (реляционные БД). Отсюда и различные вариант нереляционных БД
Без глубокого понимания стоит задать себе непреложное правило "у каждой таблицы должен быть primary key". В дальнейшем, когда-нибудь можно будет достичь нирваны ситуации когда pk не должно быть.
Представляю картину: ходит человек с мобилкой в роуминге, открывает сайтик, а ему вываливается сотня гигов данных, дабы потом жабаскрипт поискал там и нашел нужную сотню байт....
select
article_id,
count(distinct user_article_likes.article_id),
count(distinct subscribed_user_articles.article_id)
from articles
left join лайки
left join подписки
group by article