Если речь о десятках и более тысяч документов, то это поможет: habrahabr.ru/post/253737/
Вариант хороший. На первый взгляд, даже идеальный:
а) никакие join'ы не требуются
б) каждое поле индивидуально типизировано и проиндексировано — как следствие, сортировка и фильтрация будут выполняться максимально быстро и корректно (для строковых значений сравнение строковое, для числовых — числовое)
в) данные занимают меньше места за счёт индивидуальной типизации (верно, только если оригинальные значения TV-параметров из стандартной таблицы с TV будут удаляться)
Но этот вариант не всегда реализуем. Как, например, в моём случае.
У меня более десяти типов ресурсов, у каждого — по 15-20 TV. Итого — сотни TV. Сортировка и фильтрация выполняется по большинству из них. Да, можно все эти TV (по которым выполняется сортировка и фильтрация) автоматом закинуть в (site_content) и индивидуально типизировать на основе характеристик TV. И сделать всё это программно (имя поля = tv_{id}). В mySQL допускается 4 тысячи полей в таблице. Этого с головой хватит и на текущий, и на будущий функционал. Но проблема в том, что работать с этими полями без индексов не имеет смысла, а максимально допустимое число индексов в таблице mySQL — 64. Вот это ограничение и является определяющим. Даже если для некоторых полей создавать составные индексы, всё равно индексов понадобится более 100. К тому же со временем функционал будет только расширяться, добавляться новые типы ресурсов и новые TV-поля.
Сейчас у меня реализован следующий вариант:
а) все TV-поля дублируются в поле (properties) таблицы ресурсов (в формате json) — это поле используется для выборки TV
б) при фильтрации и сортировках подключаются через JOIN только те TV, которые участвуют в этих фильтрах/сортировках (как правило, их не более 3 за раз, а 3 JOIN'а выполняются вполне себе быстро)
в) в случаях, когда ресурс имеет большое количество TV, а в конечной выборке необходимо получить 2-3 TV-ки, эти TV join'ятся (так быстрее: на json-декодирование большого числа TV нужно время), в остальных случаях для выборки использую поле (properties) с последующим json-декодированием