Split CALC_FOUND_ROW query into seperate count query for better performance (#35468)
Co-authored-by: Néstor Soriano <konamiman@konamiman.com>
This commit is contained in:
parent
e66d335542
commit
7187c8dff0
|
@ -0,0 +1,4 @@
|
||||||
|
Significance: patch
|
||||||
|
Type: performance
|
||||||
|
|
||||||
|
Split CALC_FOUND_ROW query into seperate count query for better performance.
|
|
@ -115,6 +115,13 @@ class OrdersTableQuery {
|
||||||
*/
|
*/
|
||||||
private $sql = '';
|
private $sql = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Final SQL query to count results after processing of args.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $count_sql = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The number of pages (when pagination is enabled).
|
* The number of pages (when pagination is enabled).
|
||||||
*
|
*
|
||||||
|
@ -586,11 +593,7 @@ class OrdersTableQuery {
|
||||||
$fields = $this->fields;
|
$fields = $this->fields;
|
||||||
|
|
||||||
// SQL_CALC_FOUND_ROWS.
|
// SQL_CALC_FOUND_ROWS.
|
||||||
if ( ( ! $this->arg_isset( 'no_found_rows' ) || ! $this->args['no_found_rows'] ) && $this->limits ) {
|
|
||||||
$found_rows = 'SQL_CALC_FOUND_ROWS';
|
|
||||||
} else {
|
|
||||||
$found_rows = '';
|
$found_rows = '';
|
||||||
}
|
|
||||||
|
|
||||||
// JOIN.
|
// JOIN.
|
||||||
$join = implode( ' ', array_unique( array_filter( array_map( 'trim', $this->join ) ) ) );
|
$join = implode( ' ', array_unique( array_filter( array_map( 'trim', $this->join ) ) ) );
|
||||||
|
@ -617,6 +620,23 @@ class OrdersTableQuery {
|
||||||
$groupby = $this->groupby ? 'GROUP BY ' . implode( ', ', (array) $this->groupby ) : '';
|
$groupby = $this->groupby ? 'GROUP BY ' . implode( ', ', (array) $this->groupby ) : '';
|
||||||
|
|
||||||
$this->sql = "SELECT $found_rows DISTINCT $fields FROM $orders_table $join WHERE $where $groupby $orderby $limits";
|
$this->sql = "SELECT $found_rows DISTINCT $fields FROM $orders_table $join WHERE $where $groupby $orderby $limits";
|
||||||
|
$this->build_count_query( $fields, $join, $where, $groupby );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build SQL query for counting total number of results.
|
||||||
|
*
|
||||||
|
* @param string $fields Prepared fields for SELECT clause.
|
||||||
|
* @param string $join Prepared JOIN clause.
|
||||||
|
* @param string $where Prepared WHERE clause.
|
||||||
|
* @param string $groupby Prepared GROUP BY clause.
|
||||||
|
*/
|
||||||
|
private function build_count_query( $fields, $join, $where, $groupby ) {
|
||||||
|
if ( ! isset( $this->sql ) || '' === $this->sql ) {
|
||||||
|
wc_doing_it_wrong( __FUNCTION__, 'Count query can only be build after main query is built.', '7.3.0' );
|
||||||
|
}
|
||||||
|
$orders_table = $this->tables['orders'];
|
||||||
|
$this->count_sql = "SELECT COUNT(DISTINCT $fields) FROM $orders_table $join WHERE $where $groupby";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1014,7 +1034,7 @@ class OrdersTableQuery {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $this->limits ) {
|
if ( $this->limits ) {
|
||||||
$this->found_orders = absint( $wpdb->get_var( 'SELECT FOUND_ROWS()' ) );
|
$this->found_orders = absint( $wpdb->get_var( $this->count_sql ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
||||||
$this->max_num_pages = (int) ceil( $this->found_orders / $this->args['limit'] );
|
$this->max_num_pages = (int) ceil( $this->found_orders / $this->args['limit'] );
|
||||||
} else {
|
} else {
|
||||||
$this->found_orders = count( $this->orders );
|
$this->found_orders = count( $this->orders );
|
||||||
|
|
|
@ -1003,6 +1003,48 @@ class OrdersTableDataStoreTests extends WC_Unit_Test_Case {
|
||||||
$this->assertEquals( array_slice( $test_orders, 5, 5 ), $query->orders, 'The expected dataset is supplied when paginating through orders.' );
|
$this->assertEquals( array_slice( $test_orders, 5, 5 ), $query->orders, 'The expected dataset is supplied when paginating through orders.' );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @testdox Test that the query counts works as expected.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function test_cot_query_count() {
|
||||||
|
$this->assertEquals( 0, ( new OrdersTableQuery() )->found_orders, 'We initially have zero orders within our custom order tables.' );
|
||||||
|
|
||||||
|
for ( $i = 0; $i < 30; $i ++ ) {
|
||||||
|
$order = new WC_Order();
|
||||||
|
$this->switch_data_store( $order, $this->sut );
|
||||||
|
if ( 0 === $i % 2 ) {
|
||||||
|
$order->set_billing_address_2( 'Test' );
|
||||||
|
}
|
||||||
|
$order->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = new OrdersTableQuery( array( 'limit' => 5 ) );
|
||||||
|
$this->assertEquals( 30, $query->found_orders, 'Specifying limits still calculate all found orders.' );
|
||||||
|
|
||||||
|
// Count does not change based on the fields that we are fetching.
|
||||||
|
$query = new OrdersTableQuery(
|
||||||
|
array(
|
||||||
|
'fields' => 'ids',
|
||||||
|
'limit' => 5,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$this->assertEquals( 30, $query->found_orders, 'Fetching specific field does not change query count.' );
|
||||||
|
|
||||||
|
$query = new OrdersTableQuery(
|
||||||
|
array(
|
||||||
|
'field_query' => array(
|
||||||
|
array(
|
||||||
|
'field' => 'billing_address_2',
|
||||||
|
'value' => 'Test',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$this->assertEquals( 15, $query->found_orders, 'Counting orders with a field query works.' );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @testDox Test the `get_order_count()` method.
|
* @testDox Test the `get_order_count()` method.
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue