У меня есть серверная служба node js, которая в настоящее время извлекает данные непосредственно из базы данных postgres, и я работаю над внедрением среднего уровня кэширования.
Я впервые использую Redis, и я столкнулся с некоторыми проблемами, связанными с тем, как эффективно использовать его для своих сложных запросов. Меня здесь смущает две вещи: как сопоставить запрос с ключом в кеше Redis. Как следует обновлять кеш Redis после вызова функций обновления/создания.
У меня есть, например. следующая функция для объединения нескольких таблиц (здесь для краткости показаны только две)
async findAll(query: PaginateQuery, user: User): Promise<Paginated<any>> {
const limit = query.limit && query.limit < MAX_LIMIT ? query.limit : MAX_LIMIT
const page = query.page ?? DEFAULT_PAGE
const skip = (page - 1) * limit
const queryBuilder = getConnection().getRepository(tableEntryX).createQueryBuilder('tableX').leftJoin('tableX.fk1', 'fk1').addSelect(['fk1.id', 'fk1.gender']).leftJoin('tableX.fk2', 'fk2').addSelect(['fk2.id', 'fk2.weigth'])
if (query.filter?.createdAt) {
/// udpate query based on this filter
}
// filter 2
// filter 3
// fetch
const [data, count] = await Promise.all([queryBuilder.skip(skip).take(limit).getMany(), queryBuilderCount.getCount()])
const res = EMPTY_PAGINATED_DATA
res.data = data
res.meta.itemsPerPage = limit
res.meta.currentPage = page
res.meta.totalItems = count
res.meta.totalPages = Math.ceil(count / limit)
res.meta.sortBy = sorting
return res
}
Одна и та же функция проверяет наличие нескольких фильтров, и на основе этих фильтров мы изменяем запрос с помощью функций и/илиWhere.
Как нам следует это кэшировать, принимая во внимание, что сохранение новой записи в таблице может или не может подразумевать изменение кэшированных данных.
Поэтому моей первоначальной задачей было просто хешировать запрос и кэшировать его. Это может быть довольно простое решение и, вероятно, не так уж плохо с потреблением памяти (признавая, что такой подход может привести к дублированию записей в кэше, поскольку некоторые запросы могут частично перекрывать друг друга)
Однако я считаю, что более острая проблема с этим подходом — это когда происходит обновление/новая запись. Вот что нам делать со всеми нашими кэшами. Кажется пустой тратой просто удалять все кеши и начинать с нуля. Особенно, если учесть, что обновление/создание записей происходит довольно регулярно.





Любой кеш — это всегда компромисс. Таким образом, правильный ответ будет зависеть от многих факторов (сколько чтений, сколько записей, сколько параметров, какие индексы и т. д.; вы поняли). Рассмотрим пару самых простых подходов.
Вы можете сохранить копию полных данных запроса таблицы в кеше (в вашем случае Redis), а затем реализовать фильтрацию в своем коде, избегая фильтрации на основе SQL. Этот подход переместит нагрузку из вашей базы данных в кеш. В этом случае аннулирование кэша выполняется просто: вы просто обновляете кэш при изменении данных.
Другой вариант — хранить строки таблицы в кеше, где ключом является идентификатор, а значением — необработанная целая строка (объект). Затем вы можете фильтровать строки на стороне SQL, но вместо полных строк возвращается только список отфильтрованных/отсортированных идентификаторов. После этого вы можете обогатить идентификаторы данными из кэша. Этот подход сэкономит пропускную способность вашей сети или позволит вам записывать закрытые индексы, а также сэкономит дисковый ввод-вывод.
Моя личная рекомендация — проанализировать ваши данные и запрос. Возможно, вам не понадобится сложное решение для кэширования, а кэширование запроса с параметрами по умолчанию может сэкономить 95 % ресурсов.