What the author of the article posted, as I read it, is suggesting you do is something like this:
$cats = array(1,2,3,4);
$q = new WP_Query(
array(
'category__not_in' => $cats
)
);
var_dump($q->request);
You should see the complex default query in that dump.
$ids = array_unique(get_objects_in_term($cats,'category'));
var_dump($ids);
Now you have an array of post IDs for listed categories.
$q2 = new WP_Query(
array(
'post__not_in' => $ids
)
);
var_dump($q2->request);
Now you should see the more simple query that the author suggests.
If you look at the source for get_objects_in_term()
you will about the same SQL as in the subquery of the first complex query:
$object_ids = $wpdb->get_col("SELECT tr.object_id FROM $wpdb->term_relationships AS tr INNER JOIN $wpdb->term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy IN ($taxonomies) AND tt.term_id IN ($term_ids) ORDER BY tr.object_id $order");
https://core.trac.wordpress.org/browser/tags/4.2.1/src//wp-includes/taxonomy.php#L608
To get any gain from this you will have to cache $ids
. There are two ways to do this: 1) is to use the Transient API, which will give you time based caching, 2) the other is to set/update options on, say, post save so that you update $ids
on the backend and your front end code never has to worry about the freshness of the cache.
I do not have time to write more of that code, but the caching part shouldn’t be too hard given the Core code available and the Codex.