Таблица wp_postmeta в WordPress является универсальным хранилищем ключ-значение, прикрепленным к каждому посту. Именно так хранятся post_title, post_content и custom_field_x. Схема выглядит так:
«sql CREATE TABLE wp_postmeta ( meta_id BIGINT(20) PRIMARY KEY, post_id BIGINT(20), meta_key VARCHAR(255), meta_value LONGTEXT, INDEX (post_id), INDEX (meta_key(191)) ); «
Просто. Гибко. Работает для любой пары ключ-значение. И на типичном сайте WordPress с множеством плагинов она огромна — легко достигает миллионов строк на 5-летнем сайте электронной коммерции с множеством заказов и метаданных продуктов.
Вот что происходит, когда вы загружаете страницу архива с 20 постами, каждый из которых имеет 10 пользовательских полей:
«`sql — Запрос 1: Получить посты SELECT * FROM wp_posts WHERE post_type = ‘post’ LIMIT 20;
— Запросы 2-201: Для каждого поста получить каждое поле SELECT meta_value FROM wp_postmeta WHERE post_id = 1 AND meta_key = ‘field_a’; SELECT meta_value FROM wp_postmeta WHERE post_id = 1 AND meta_key = ‘field_b’; — … 198 дополнительных запросов «`
200 отдельных запросов. Каждый запрос выполняется быстро, но накладные расходы на обратные поездки накапливаются. На сайтах, обращающихся к базе данных через сеть (что часто бывает при управляемом хостинге), это может добавить 500 мс+ к каждому просмотру страницы. Кумулятивный сдвиг макета увеличивается. Основные показатели веба падают. SEO страдает.
Поля повторителей в ACF хранятся с одной строкой метаданных на подполе на строку. Повторитель с 5 подполями и 10 строками создает 50 записей метаданных на пост. Добавьте 20 постов в архив, и вы получите более 1,000 мета-запросов на одном просмотре страницы. Вот почему сайты с большим количеством ACF известны тем, что замедляются после определенного масштаба.
Field Forge хранит значения полей в выделенной таблице wp_fieldforge_values:
«sql CREATE TABLE wp_fieldforge_values ( id BIGINT(20) PRIMARY KEY, post_id BIGINT(20) NOT NULL, field_group_id BIGINT(20) NOT NULL, field_name VARCHAR(255) NOT NULL, parent_id BIGINT(20) NULL, -- для вложенных значений (повторитель/группа/гибкий) row_index INT NULL, -- для позиции строки повторителя value LONGTEXT, INDEX (post_id, field_name), INDEX (post_id, field_group_id), INDEX (parent_id, row_index) ); «
Ключевые отличия от wp_postmeta:
parent_id, row_index) — вложенные значения (повторитель, группа, гибкий) структурированы, а не соединены в строкуwp_postmeta, не загрязняют данные полейwp_postmeta нетМы провели контролируемые бенчмарки на тестовом сайте с 10,000 постами, каждый из которых имел группу полей, содержащую 15 полей (3 текстовых, 2 WYSIWYG, 1 изображение, 1 повторитель с 5 подполями, 1 гибкое содержимое с 3 типами макетов).
| wp_postmeta (ACF / SCF) | Пользовательская таблица Field Forge | |
|---|---|---|
| SQL запросы | 302 | 1 (batch_load) |
| Время запроса (локальная БД) | 840ms | 95ms |
| Время запроса (сетевая БД, +20ms RTT) | 6,880ms | 115ms |
| Первый контентный рендеринг | 2,100ms | 340ms |
| wp_postmeta | Field Forge | |
|---|---|---|
| SQL запросы | 16 | 1 |
| Время запроса (локальная БД) | 45ms | 12ms |
| Время запроса (сетевая БД, +20ms RTT) | 365ms | 32ms |
| wp_postmeta | Field Forge | |
|---|---|---|
| SQL запросы | 1,000 INSERTs | 1 многострочный INSERT |
| Время (локальная БД) | 1,240ms | 48ms |
| Время (сетевая БД) | 21,240ms | 68ms |
На базах данных, подключенных к сети (что является стандартом для почти всех управляемых хостингов WordPress — Kinsta, WP Engine, Cloudways, SiteGround Cloud и т.д.), разница драматична. Задержка обратной поездки является доминирующей стоимостью, и Field Forge делает меньше обратных поездок.
API для разработчиков для явной пакетной загрузки, когда автоматическая предварительная загрузка Field Forge недостаточна:
«`php // Загрузить поля для конкретного набора постов за один запрос $post_ids = [1, 2, 3, 4, 5]; FieldForge::batch_load($post_ids);
// Теперь любой вызов get_field() для этих постов обращается к кэшу foreach ($post_ids as $id) { $hero = get_field(‘hero_title’, $id); // Без запроса к БД } «`
Вызов batch_load() выполняет один запрос WHERE post_id IN (...) и заполняет кэш Field Forge в памяти для всех запрашиваемых постов. Последующие вызовы get_field() являются попаданиями в кэш.
Field Forge подключается к фильтру the_posts в WordPress для автоматической предварительной загрузки полей для основного запроса. Страницы архива, результаты поиска и списки категорий автоматически получают данные полей пакетной загрузки — без необходимости изменения кода.
Field Forge уважает API wp_cache_* WordPress:
fieldforge), чтобы не конфликтовать с другими плагинами или основными операциями кэша.Недействительность кэша происходит автоматически при обновлении или удалении значения поля через хуки действий.
Быстрее страницы архива, быстрее результаты поиска, быстрее динамические шаблоны. Основные показатели веба улучшаются. Удержание клиентов улучшается, потому что сайт «ощущается отзывчивым».
Страницы со списками продуктов с 30+ продуктами и сложными пользовательскими полями отрисовываются за то же время, что и более простые сайты. Взаимодействия с корзиной покупок быстрее, потому что загрузки метаданных продуктов обрабатываются пакетами.
Ответы REST API и WPGraphQL быстрее. Генераторы статических сайтов (Next.js ISR, Astro, Nuxt) выполняют меньше запросов к базе данных на сборку. Время сборки улучшается.
Совместимость Field Forge с ACF означает, что вызовы get_field() в вашей теме возвращают те же значения — но они поступают из пользовательской таблицы, а не из wp_postmeta. Улучшение производительности происходит прозрачно после миграции.
Чтобы быть честным: если на вашем сайте менее 500 постов и простые пользовательские поля (без глубоких повторителей, без гибкого содержимого), подход wp_postmeta работает. Вы не заметите разницы в скорости. Преимущество производительности Field Forge становится значимым в масштабе — 1,000+ постов, сложные повторители или сайты на сетевых базах данных.
Получите Field Forge — от $35 в год →
Хранение пользовательских таблиц включено в каждую версию Field Forge, включая бесплатную.