From b187c1c4d3f025ff766abd56488714d0840d6921 Mon Sep 17 00:00:00 2001 From: wpdev Date: Sun, 27 Sep 2026 16:19:11 +0800 Subject: [PATCH] perf(2meet-data-optimizer): count routed searches from a cached base count minus the excluded posts - a routed search with post__not_in (HivePress sends a random set per page) caches the COUNT without the exclusion and subtracts a live primary-key count of the excluded posts that match; the total stays exact - the excluded count drops STRAIGHT_JOIN so MySQL starts from posts.ID - Verify: PostQueryRouterFoundRowsTest, unit 698, integration 577, phpcs, stan; dev36 live router suite and keyword + price search - PR: PR-091 --- .../query/class-tmdo-post-query-router.php | 25 +++++++++++++++++-- .../PostQueryRouterFoundRowsTest.php | 25 +++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/includes/query/class-tmdo-post-query-router.php b/includes/query/class-tmdo-post-query-router.php index db90998..161b6b4 100644 --- a/includes/query/class-tmdo-post-query-router.php +++ b/includes/query/class-tmdo-post-query-router.php @@ -372,7 +372,23 @@ class TMDO_Post_Query_Router { if ( ! $counted ) { return $request; } - $matches = preg_replace( '/\s+LIMIT\s+\d+(\s*,\s*\d+)?\s*$/i', '', $request ); + global $wpdb; + $matches = (string) preg_replace( '/\s+LIMIT\s+\d+(\s*,\s*\d+)?\s*$/i', '', $request ); + $not_in = " AND {$wpdb->posts}.ID NOT IN ("; + // post__not_in (HivePress sends a random set per page) would give every + // search its own cache key: count without it (cached) minus the excluded + // posts that match (primary-key lookups, so no forced flat-first order). + if ( 1 === substr_count( $matches, $not_in ) && preg_match( '/' . preg_quote( $not_in, '/' ) . '([\d,]+)\)/', $matches, $m ) ) { + $excluded = str_replace( $m[0], " AND {$wpdb->posts}.ID IN ({$m[1]})", (string) preg_replace( '/^SELECT STRAIGHT_JOIN /', 'SELECT ', $matches ) ); + $query->set( + self::COUNT_VAR, + array( + 'SELECT COUNT(*) FROM ( ' . str_replace( $m[0], '', $matches ) . ' ) AS tmdo_found', + "SELECT COUNT(*) FROM ( {$excluded} ) AS tmdo_found", + ) + ); + return $request; + } $query->set( self::COUNT_VAR, "SELECT COUNT(*) FROM ( {$matches} ) AS tmdo_found" ); return $request; } @@ -414,13 +430,18 @@ class TMDO_Post_Query_Router { if ( empty( $count_sql ) ) { return (string) ( $sql ?? '' ); } + global $wpdb; + list( $count_sql, $excluded_sql ) = array_pad( (array) $count_sql, 2, '' ); + $key = md5( $count_sql ) . ':' . wp_cache_get_last_changed( 'posts' ); $total = wp_cache_get( $key, self::COUNT_CACHE_GROUP ); if ( false === $total ) { - global $wpdb; $total = (int) $wpdb->get_var( $count_sql ); wp_cache_set( $key, $total, self::COUNT_CACHE_GROUP, HOUR_IN_SECONDS ); } + if ( '' !== $excluded_sql ) { + $total = max( 0, (int) $total - (int) $wpdb->get_var( $excluded_sql ) ); + } return 'SELECT ' . (int) $total; } diff --git a/tests/integration/PostQueryRouterFoundRowsTest.php b/tests/integration/PostQueryRouterFoundRowsTest.php index 78e01eb..f66e4cc 100644 --- a/tests/integration/PostQueryRouterFoundRowsTest.php +++ b/tests/integration/PostQueryRouterFoundRowsTest.php @@ -121,6 +121,31 @@ class PostQueryRouterFoundRowsTest extends TestCase { $this->assertSame( '1', $wpdb->get_var( $router->found_posts_query( 'SELECT FOUND_ROWS()', $query ) ), 'recounted' ); } + /** + * HivePress excludes a different random set of posts on each search page; + * the total is the cached count without the exclusion minus a live count + * of the excluded posts that match (by primary key). + */ + public function test_excluded_posts_do_not_split_the_cached_total(): void { + global $wpdb; + $count = function ( string $not_in ) use ( $wpdb ): string { + list( $router, $query, $request ) = $this->routed(); + $request = str_replace( ' GROUP BY', " AND {$wpdb->posts}.ID NOT IN ({$not_in}) GROUP BY", $request ); + $router->posts_request( $request, $query ); + return (string) $wpdb->get_var( $router->found_posts_query( 'SELECT FOUND_ROWS()', $query ) ); + }; + + $this->assertSame( '1', $count( '3' ), 'prices 20, 30 match; 3 excluded' ); + $this->assertSame( '0', $count( '2,3' ) ); + + $wpdb->query( 'UPDATE `' . self::TABLE . '` SET fr_price = 5 WHERE post_id = 3' ); // Not seen until posts change. + $this->assertSame( '2', $count( '1' ), 'one cached count serves every exclusion list; 1 does not match' ); + $this->assertSame( '1', $count( '2' ) ); + + wp_cache_set_posts_last_changed(); + $this->assertSame( '0', $count( '2' ), 'recounted' ); + } + public function test_flat_writes_and_deletes_move_posts_last_changed(): void { $GLOBALS['_wp_current_filter'] = 'update_post_metadata'; $before = wp_cache_get_last_changed( 'posts' );