Note: we’re talking here about the difference between permalinks /%ID%/%name%/
and %/name/%
. It would be a whole different story if we were to compare /%ID%/%name%/
and %/ID/%
.
Now, there are two use cases that affect performance:
One. You have a permalink and WP needs to resolve it in order to serve the page requested.
This means setting up the WP class. The main function is at the bottom of the code. After init this involves calling parse_request
. This checks whether rewrite rules exist for this particular page and checks query variables for validity. In this case we’d like to know whether processing example.com/123/slug
takes more time than example.com/slug
. For that to matter you would have to assume that the PHP string function that needs to handle a few bytes more has a significant impact on performance.
Once the requested url has been chopped into workable chunks, the action moves to parse_query
, which in this case will be passed a query object either containing name
or both name
and ID
(confusingly in the query object the ID is called p
). A lot of handling is done, but nothing extra for including the ID in the query.
Next follow two hooks in (pre_get_posts
and posts_selection
) that are plugin territory, so impact on performance is unknown.
Now comes the main issue: will it take more time to query the database with one variable or with two? Both ID
and name
are stored in the wp_posts
table in the database. So, there is no difference in the size of the table that will be queried. Also, both are unique, because when a post is stored this is checked (OP’s assumption that including ID in the url will get rid of the -2
in posts is wrong, unless you hack the saving procedure). As a result, it doesn’t really matter whether you have to query all database rows for the unique ID
or the unique name
. The only difference in performance when providing both is that after the row with the ID
has been found it will check if the name
matches. That really is negligible.
Two. You need to generate a permalink on a page.
This is done by the get_permalink
function. For standard post types the procedure only adds some lengthy calculations if you are using %category%
. For ID
and name
it is just a matter of search and replace in this line of code:
$permalink = home_url( str_replace( $rewritecode, $rewritereplace, $permalink ) );
The efficiency of str_replace
depends on the size of the parameters that are passed to it, but since all possible rewriting parameters are passed, not just the one or two that are actually used, this does not affect performance.
For custom post types get_permalink
refers to get_post_permalink
, which involves more calculations anyway, but essentially winds down to the same search and replace.