Is it true $wpdb->get_results is faster than WP_Query in most cases?

How can I prepare() my wpdb query? I tried but couldn’t manage because
of the second parameter.

The prepare() works is explained in Codex, you need to have a query with placeholders and additional arguments to replace that placeholders. If you have no placeholders (so no variable parts in the query) then you can use esc_sql to avoid SQL injections, but that only makes sense when the query is built using user input.
The query in OP, is completely hardcoded, so there is no need to prepare() nor to esc_sql().

After using prepare, am I right in assuming that in terms of security
and performance, wpdb is indeed a better solution?

Short answer: no. WP_Query is just an higher level approach to queries, it builds a query string and then use $wpdb to run that sql query in the database.

If you look at 2 queries in OP their are different, just for example, the query ran using $wpdb doesn’t take into account post status, post date or post password, so if you have deleted, scheduled or private posts, using first query they are shown to users.
Also the query doesn’t take into account results ordering and some other stuff.
Sure you can build a complex query string that takes into account everything and then run it using $wpdb, you have two possibilities:

  1. write a complex hardcoded query string everytime you need a loop: this is really overwhelming and error prone
  2. write some code that handles query in a flexible way: it will be very hard and you should write a lot of code that is already handled by core in WP_Query: that makes no sense.

There is another important factor to consider: WP_Query fires quite a lot filter and action hooks, and thousands of plugins and themes rely on them: by running a manual $wpdb query for loops you will break a lot of things.

So, if you need to query posts use WP_Query: few milliseconds don’t worth hours and hours of code and frustrations. Use $wpdb only when you need to perform queries not handled by core.

It worth adding @TomJNowell comment here:

It should also be kept in mind that WP_Query would allow you to take advantage of a lot of the internal caches WordPress holds, such as retrieving a post once if it’s queried a second time etc. If you have 50 thousand posts to query all at once, you should probably be using a job queue or a CLI script to do your work (unless you have only tens of users and a lot of money to spend on a server)

Leave a Comment