perf(2meet-data-optimizer): let the status/date copy route stop at the LIMIT

- Copy route: drop WordPress's GROUP BY when the flat row is the only join,
  and read posts.ID tie-breaks as the flat post_id (own direction, once)
- Post status sync: index (post_status, post_date, post_id) replaces the
  two-column idx_post_status_date (added / dropped by post-status-sync)
- dev36, 235k of 1.3M listings in a price range: main query 1.7 s -> 3 ms
- Verify: composer test (704), test:integration (597), phpcs, stan
- PR: PR-128
This commit is contained in:
2026-09-27 23:12:34 +08:00
parent 2aa9058ee9
commit 8ee3dce0fe
4 changed files with 141 additions and 15 deletions
@@ -29,7 +29,10 @@ final class TMDO_Post_Status_Sync {
public const OPTION = 'tmdo_post_status_columns';
private const INDEX = 'idx_post_status_date';
private const INDEX = 'idx_post_status_date_id';
/** The 2.2–2.3 (post_status, post_date) index, replaced by INDEX. */
private const LEGACY_INDEX = 'idx_post_status_date';
/**
* Hook the sync into WordPress.
@@ -203,7 +206,12 @@ final class TMDO_Post_Status_Sync {
$changes[] = 'ADD COLUMN `post_date` DATETIME DEFAULT NULL';
}
if ( ! in_array( self::INDEX, $indexes, true ) ) {
$changes[] = 'ADD INDEX `' . self::INDEX . '` (`post_status`, `post_date`)';
// Ends with post_id: the router reads the date route's ID tie-break
// from it, so MySQL walks the index and stops at the LIMIT (2.4 PR-128).
$changes[] = 'ADD INDEX `' . self::INDEX . '` (`post_status`, `post_date`, `post_id`)';
}
if ( in_array( self::LEGACY_INDEX, $indexes, true ) ) {
$changes[] = 'DROP INDEX `' . self::LEGACY_INDEX . '`';
}
if ( $changes && false === $wpdb->query( "ALTER TABLE `{$table}` " . implode( ', ', $changes ) ) ) { // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Fixed DDL on a registry table name.
return false;