perf(2meet-data-optimizer): keep WordPress's split query on routed searches
- posts_request only drops SQL_CALC_FOUND_ROWS, but WordPress then treated the request as filtered and selected full post rows through a temporary table; split_the_query now keeps the ID-first split for routed searches when nothing else changed the request, and posts_request_ids drops SQL_CALC_FOUND_ROWS from the split ID query - Verify: tests/live/run.php router (12/12, IDs-first request, found_posts == native); dev36 fe.sh price 589→340 ms, price__asc 961→427 ms, rating__desc 1724→872 ms, hourly_rate__desc 855→884 ms (was 1206) - PR: PR-062b
This commit is contained in:
@@ -92,6 +92,8 @@ class TMDO_Post_Query_Router {
|
||||
add_filter( 'posts_where', array( $this, 'posts_where' ), 10, 2 );
|
||||
add_filter( 'posts_orderby', array( $this, 'posts_orderby' ), 10, 2 );
|
||||
add_filter( 'posts_request', array( $this, 'posts_request' ), 10, 2 );
|
||||
add_filter( 'split_the_query', array( $this, 'split_the_query' ), 10, 4 );
|
||||
add_filter( 'posts_request_ids', array( $this, 'posts_request' ), 10, 2 );
|
||||
add_filter( 'found_posts_query', array( $this, 'found_posts_query' ), 10, 2 );
|
||||
}
|
||||
|
||||
@@ -338,12 +340,37 @@ class TMDO_Post_Query_Router {
|
||||
if ( ! $routed || false === strpos( $request, 'SQL_CALC_FOUND_ROWS' ) ) {
|
||||
return $request;
|
||||
}
|
||||
$request = preg_replace( '/\bSQL_CALC_FOUND_ROWS\s+/', '', $request, 1 );
|
||||
$request = self::without_found_rows( $request );
|
||||
$matches = preg_replace( '/\s+LIMIT\s+\d+(\s*,\s*\d+)?\s*$/i', '', $request );
|
||||
$query->set( self::COUNT_VAR, "SELECT COUNT(*) FROM ( {$matches} ) AS tmdo_found" );
|
||||
return $request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Keep WordPress's split query (IDs first, then cached post objects) on a
|
||||
* routed search: posts_request only dropped SQL_CALC_FOUND_ROWS, yet
|
||||
* WordPress takes any change for a filtered request and selects full rows
|
||||
* (a temporary table sorting whole posts). The split ID request passes
|
||||
* through posts_request_ids, which drops SQL_CALC_FOUND_ROWS again.
|
||||
*
|
||||
* @param bool $split Core decision.
|
||||
* @param \WP_Query $query Current WP_Query.
|
||||
* @param string $old_request Request before posts_request.
|
||||
* @param array<string, string> $clauses Query clauses (fields, limits …).
|
||||
* @return bool
|
||||
*/
|
||||
public function split_the_query( $split, \WP_Query $query, $old_request = '', $clauses = array() ): bool {
|
||||
$routed = ! empty( $query->get( self::QUERY_VAR ) ) || ! empty( $query->get( self::SORT_VAR ) );
|
||||
if ( $split || ! $routed ) {
|
||||
return (bool) $split;
|
||||
}
|
||||
global $wpdb;
|
||||
// Core's other conditions: full rows, and a LIMIT under 500 or an external object cache.
|
||||
return "{$wpdb->posts}.*" === ( $clauses['fields'] ?? '' )
|
||||
&& self::without_found_rows( (string) $old_request ) === $query->request
|
||||
&& ( ( '' !== ( $clauses['limits'] ?? '' ) && (int) $query->get( 'posts_per_page' ) < 500 ) || wp_using_ext_object_cache() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Answer found rows from the cached COUNT of a routed search.
|
||||
*
|
||||
@@ -542,6 +569,16 @@ class TMDO_Post_Query_Router {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* A request without its SQL_CALC_FOUND_ROWS.
|
||||
*
|
||||
* @param string $request SELECT statement.
|
||||
* @return string
|
||||
*/
|
||||
private static function without_found_rows( string $request ): string {
|
||||
return (string) preg_replace( '/\bSQL_CALC_FOUND_ROWS\s+/', '', $request, 1 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a meta query type casts to a number (NUMERIC, SIGNED, DECIMAL(p,s) …).
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user