Вопрос или проблема
Я сохраняю посты, которые пользователь подписывает в нестандартной таблице, содержащей столбцы id
, post_id
и user_id
. Чтобы получить посты, которые пользователь подписывает, я расширил WP_Query следующим образом:
class WP_Query_Posts_User_Follows extends WP_Query {
function __construct($args=array()) {
if ( !empty($args['followed_by']) ) {
$this->followed_by = $args['followed_by'];
add_filter('posts_where', array($this, 'posts_where'));
}
parent::query($args);
}
function posts_where($where) {
global $wpdb;
$table = $wpdb->prefix . 'post_followed_by';
$where .= $wpdb->prepare(" AND ID IN (SELECT post_id FROM $table WHERE user_id = %d)", $this->followed_by);
return $where;
}
}
Если вы заметите, в условии WHERE
используется подзапрос. Мое понимание таково, что подзапросы нежелательны, так как они ухудшают производительность, особенно в этом случае, когда подзапрос может потенциально вернуть сотни или тысячи post_ids
, на которые подписан пользователь. Какие у меня есть альтернативы, учитывая, что мне нужно работать с WP_Query и я не могу выполнять пользовательский SQL непосредственно с использованием wpdb
?
Вот идея, хотя она потребует возможности выполнения пользовательских SQL-запросов – с $wpdb.
Поскольку вы хотите получить посты, на которые подписан пользователь, вы можете создать представление со следующей структурой:
id user_id post_id post_title post_content ... (все другие поля постов)
не беспокойтесь о дублировании постов.
Когда вы выбираете, вам просто нужно выполнять простой select * from the_view where...
.
Позже вы можете кэшировать результаты этого представления, используя memcache или другую технику кэширования объектов для ускорения.
Вы используете лучший способ:) Может быть, если вы хотите оптимизировать ваш запрос, вы можете использовать плагин posts 2 posts. Вам не нужно будет фильтровать запрос. Ссылка – https://github.com/scribu/wp-posts-to-posts/wiki
Ответ или решение
Оптимизация SQL-запросов является важной задачей при работе с базами данных, особенно когда речь идет о большом объеме данных и высоких требованиях к производительности. В вашем случае, где вы расширяете WP_Query для получения постов, на которые подписан пользователь, использование подзапросов в секции WHERE действительно может негативно сказаться на производительности, особенно если подзапрос возвращает сотни или тысячи идентификаторов постов. Давайте рассмотрим возможные альтернативы и оптимизации для вашего сценария.
Проблема
Вы храните информацию о подписках пользователей в кастомной таблице с колонками id
, post_id
, user_id
и используете подзапрос для получения постов подписок:
function posts_where($where) {
global $wpdb;
$table = $wpdb->prefix . 'post_followed_by';
$where .= $wpdb->prepare(" AND ID IN (SELECT post_id FROM $table WHERE user_id = %d)", $this->followed_by);
return $where;
}
Возможные альтернативы
-
Использование JOIN: Вместо подзапроса, вы можете использовать соединение (JOIN), что обычно более эффективно для баз данных. Вам понадобится написать свой собственный метод для соединения таблиц, например:
function posts_join($join) { global $wpdb; $table = $wpdb->prefix . 'post_followed_by'; $join .= " INNER JOIN $table ON $wpdb->posts.ID = $table.post_id "; return $join; } function posts_where($where) { global $wpdb; $where .= $wpdb->prepare(" AND $table.user_id = %d", $this->followed_by); return $where; }
Однако при этом нет возможности напрямую реализовать такой подход в WP_Query без использования фильтров
posts_join
иposts_where
. -
Создание индексов: Убедитесь, что в вашей кастомной таблице созданы индексы по
user_id
иpost_id
. Это значительно увеличит скорость выборки при выполнении запросов. -
Предварительная загрузка данных: Иногда проще и быстрее заранее загрузить все
post_id
, на которые подписан пользователь, и использовать их в несложном WHERE IN() запросе. Этот подход может быть реалистичнее, если общая информация о подписках сравнительно невелика. -
Кэширование результатов: Используйте возможности кэширования, такие как объектное-кэширование или Memcached, для уменьшения реального количества запросов к базе данных. Это поможет сохранить производительность на уровне при повторных запросах одних и тех же данных.
Другие подходы
Если у вас есть возможность использовать более кастомный подход, например, в виде плагина "Posts 2 Posts" или реализации собственных виджетов, это может также оптимизировать процесс за счет уменьшения логики на уровне SQL-запросов.
Заключение
Каждый из предложенных методов имеет свои плюсы и минусы, и выбор зависит от специфики вашего проекта и объема данных. Применение комбинации этих методов может значительно улучшить производительность ваших запросов в WordPress. Концентрируйтесь на оптимизации за счет уменьшения нагрузки на базу данных и использования кэширования для уменьшения задержек в работе приложений.