Как правило, вы должны использовать идентификатор сеанса вместе с базой данных для хранения продукта (ов). Это сохраняет информацию о сеансе минимальной (только идентификатор) и предоставляет вам максимальную гибкость. IMO - это плохая идея поместить такую структуру данных в хранилище сеансов: что, если вы решите изменить структуру данных позже? Вам придется поддерживать как старые, так и новые версии структуры данных.
Как вы заметили, проблема с решением на основе БД заключается в том, что в какой-то момент вам нужно убрать непокупаемые предметы из базы данных. Обычно это делается периодически (например, тележки старше X дней очищаются), где временные рамки могут быть основаны на размере базы данных (насколько большой он увеличивается, если тележки очищаются через 3 месяца? 6 месяцев) и от может вернуться в какой-то момент в будущем (они вернутся через 3 месяца? через 6 месяцев?).
Если вы решите сохранить информацию в сеансе, то вам, вероятно, понадобится выполнить простой сериализацию, например:
Session_id | Items
892jsls098s | sku1:3,sku2:4,sku3:2
Единственным ограничением здесь является продолжительность данных сеанса (обязательно добавьте проверку длины).