Вероятно, возможное решение состоит в том, чтобы взять ваш второй пример и изменить его таким образом, чтобы обеспечить эффективные запросы для больших наборов. Один из способов, который приходит на ум, - это использовать несколько объектов базы данных для одного тега и группировать их так, чтобы вам редко приходилось получать больше нескольких групп. Если порядок сортировки по умолчанию (хорошо, давайте просто назовем его единственным разрешенным) по дате публикации, тогда заполните группы тегов в этом порядке.
class Tag(db.Model):
name = db.StringProperty(name="key")
posts = db.ListProperty(db.Key) # List of posts that marked with tag
firstpost = db.DateTimeProperty()
При добавлении или удалении тегов в группу проверьте, сколько сообщений в этой группе. Если добавляемый вами пост приведет к тому, что пост будет иметь более, скажем, 100 сообщений, разбейте его на две группы тегов. Если вы удаляете сообщение, чтобы в группе было менее 50 сообщений, украдите несколько сообщений из предыдущей или следующей группы. Если в одной из смежных групп также есть 50 сообщений, просто объедините их. При выводе сообщений по тегу (в порядке пост-даты) вам нужно получить только несколько групп.
Это на самом деле не решает проблему тегов с высоким спросом.
Думая об этом, было бы неплохо, чтобы вставки были немного более умозрительными. Получить последние записи группы тегов, объединить их и разместить новую группу тегов. Лаг в транзакциях может на самом деле не быть реальной проблемой.