perf(2meet-data-optimizer): let flat-first sorts use a (column, id) index
- a group index may end with the entity ID column (post_id, ...) - flat-first rewrites the posts.ID tie-breaks once, in the sort's direction: with a (column, post_id) index MySQL returns rows in order instead of sorting the whole match. dev36 (1.3M listings), price range sorted by price: 850 ms filesort -> 2 ms. Ties are ordered by ID the same way as the column (natively ID DESC); pagination stays stable, result sets are unchanged - Verify: EntityRegistryIndexesTest, PostQueryRouterFoundRowsTest (ASC tie-break, single tie-break), unit 704, integration 589, phpcs, stan; dev36 with the HivePress indexes (PR-119) - PR: PR-118
This commit is contained in:
@@ -159,9 +159,12 @@ final class TMDO_Entity_Registry {
|
||||
self::$scopes[ $entity_type ][ $group_name ] = $post_types;
|
||||
}
|
||||
$keys = array_column( $normalized, 'key' );
|
||||
// A sort index may end with the entity ID (flat-first tie-break, 2.4 PR-118).
|
||||
$id_col = (string) self::$adapters[ $entity_type ]->get_entity_id_column();
|
||||
foreach ( (array) ( $args['indexes'] ?? array() ) as $index_name => $columns ) {
|
||||
$columns = array_values( array_map( 'strval', (array) $columns ) );
|
||||
if ( $columns && ! array_diff( $columns, $keys ) ) {
|
||||
$fields = '' !== $id_col && end( $columns ) === $id_col ? array_slice( $columns, 0, -1 ) : $columns;
|
||||
if ( $fields && ! array_diff( $fields, $keys ) ) {
|
||||
self::$indexes[ $entity_type ][ $group_name ][ (string) $index_name ] = $columns;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -797,10 +797,17 @@ class TMDO_Post_Query_Router {
|
||||
if ( 1 === preg_match_all( '/\bJOIN\b/i', (string) $flat_first ) ) {
|
||||
$flat_first = preg_replace( '/\s+GROUP BY\s+`?' . preg_quote( $wpdb->posts, '/' ) . '`?\.`?ID`?(?=\s)/', ' ', (string) $flat_first, 1 );
|
||||
}
|
||||
// Tie-breaks on posts.ID (ours, and any a plugin appended) read the flat post_id.
|
||||
// Tie-breaks on posts.ID (ours, and any a plugin appended) read the flat
|
||||
// post_id, once, in the sort's direction: a (column, post_id) index then
|
||||
// returns rows in order with no filesort. Ties are ordered by ID the same
|
||||
// way as the column (natively ID DESC); pagination stays stable.
|
||||
$tie = "`{$alias}`.`post_id` " . ( 'ASC' === strtoupper( (string) $sort['order'] ) ? 'ASC' : 'DESC' );
|
||||
$flat_first = preg_replace_callback(
|
||||
'/\bORDER BY\b(?!.*\bORDER BY\b).*$/s',
|
||||
static fn( $m ) => preg_replace( '/`?' . preg_quote( $wpdb->posts, '/' ) . '`?\.`?ID`?(?!\w)/', "`{$alias}`.`post_id`", $m[0] ),
|
||||
static function ( $m ) use ( $wpdb, $tie ) {
|
||||
$order = (string) preg_replace( '/`?' . preg_quote( $wpdb->posts, '/' ) . '`?\.`?ID`?(?!\w)(\s+(ASC|DESC)\b)?/i', $tie, $m[0] );
|
||||
return (string) preg_replace( '/(,\s*' . preg_quote( $tie, '/' ) . ')(\s*,\s*' . preg_quote( $tie, '/' ) . ')+/', '$1', $order );
|
||||
},
|
||||
(string) $flat_first
|
||||
);
|
||||
return (string) preg_replace( '/^\s*SELECT\s/', 'SELECT STRAIGHT_JOIN ', (string) $flat_first, 1 );
|
||||
|
||||
Reference in New Issue
Block a user