В базе SQlite имеются таблицы (упрощенно): posts(to_id, from_id, text), users (id, name), groups (id, name).
Для того чтобы вывести posts в удобочитаемом виде, нужно заменить to_id и from_id на имена.
Оба идентификатора to_id и from_id могут указывать как на юзера, так и на группу, причем в posts у юзеров положительные id, а у групп отрицательные (так сделано к примеру в соцсети vk).
Провел эксперимент с таким запросом (LEFT JOIN потому что не все to_id, from_id существуют в таблицах users и groups, а записи все равно нужны):
SELECT
CASE WHEN posts.to_id > 0 THEN u_to.name ELSE g_to.name END AS to_name,
CASE WHEN posts.from_id > 0 THEN u_from.name ELSE g_from.name END AS from_name,
posts.to_id,
posts.from_id,
posts.text
FROM posts
LEFT JOIN users AS u_to ON posts.to_id = u_to.id
LEFT JOIN groups AS g_to ON posts.to_id = -g_to.id
LEFT JOIN users AS u_from ON posts.from_id = u_from.id
LEFT JOIN groups AS g_from ON posts.from_id = -g_from.id
WHERE ... ORDER BY ... LIMIT ... OFFSET ...
и оказалось, что на последних страницах пагинации все это достаточно заметно подтормаживает (хотя данных пока не много — 5000 постов, 300000 юзеров и 4000 групп).
Далее попытался выяснить что именно подтормаживает. Убрал условный JOIN, приняв для эксперимента что to_id всегда группа а from_id всегда юзер (т.е. осталось 2 джойна вместо 4). Не помогло, задержки остались. А вот если принять, что to_id и from_id всегда юзеры, и убрать группы из запроса вообще (опять же 2 джойна вместо 4), то скорость становится нормальной. Получается, что дополнительные джойны даже при небольшом размере таблицы существенно замедляет работу запроса.
Прав ли я в своих рассуждениях? Все ли я правильно делаю? Есть ли альтернативные решения этой задачи в целом?
Думаю о варианте вообще объединить юзеров и группы в одну таблицу — у них значительная часть полей общая, в 99% случаев только она и нужна, а отличающиеся поля оставить в добавочных таблицах, связанных "один к одному" с главной.