To improve the ability of the In-Memory Column Index (IMCI) to handle complex queries, the IMCI optimizer combines query transformation rules with statistics from table columns and uses cost-based optimization to generate efficient execution plans. This topic describes how the IMCI query optimization feature works, its usage, and its limitations.
How it works
SQL is a declarative language, which means it specifies what result to return but not how to compute it. For any given SQL statement, multiple valid query plans can produce the correct result. For example:
SELECT * FROM t0, t1, t2, t3 WHERE t0.a = t1.a AND t1.a = t2.a AND t2.a = t3.a AND t3.b = t1.b;
For the preceding SQL statement, both of the following query plans can return the correct result.
Plan A and Plan B are known as equivalent query plans. The optimizer explores equivalent query plans for an SQL statement by applying transformations. For example, t1 INNER JOIN t2 and t2 INNER JOIN t1 are a pair of equivalent query plans. The optimizer can generate t2 INNER JOIN t1 from t1 INNER JOIN t2. This type of transformation is called a query transformation rule.
The query optimizer follows this workflow:
-
The optimizer receives an initial query plan that the database generates by parsing an SQL statement.
-
It then applies query transformation rules to the initial plan to generate equivalent query plans.
-
Using statistics and a cost model, the optimizer selects the plan with the lowest estimated execution cost and passes it to the execution engine as the final execution plan.
The query optimization feature relies on statistics to perform cardinality estimation and cost calculation to determine the best query plan. In IMCI, table statistics include the following:
-
A histogram describes the value distribution of a column and is mainly used to estimate the selectivity of value ranges and equality predicates on a single table.
-
The number of distinct values in a column is mainly used to estimate the number of groups in a
Group Byclause and can also help estimate the selectivity of equality predicates. -
Other constraints, such as whether the column has a unique index or a foreign key constraint.
The query optimizer calculates the cost of each operator in a query plan based on two factors:
-
The total number of rows processed by the operator, which can be estimated from statistics.
-
The algorithmic complexity of each operator used in the query plan.
The total number of rows processed by an operator is a parameter in its complexity function. The total execution cost of a query plan is the sum of the costs of all its operators. For the two query plans in the preceding figure, if we assume a hash join algorithm is used, the cost formula is:
Costjoin=Cardinner+Cardouter
The costs of the two execution plans are as follows:
CostA==10000+1+1000+100+10000+10=21111
CostB==10000+1+100+10+1000+10=11121
The calculation shows that Plan B has a lower execution cost. Therefore, the optimizer selects Plan B as the final execution plan.
Prerequisites
Your PolarDB cluster must meet one of the following version requirements:
-
PolarDB for MySQL 8.0.1 with revision 8.0.1.1.31 or later.
-
PolarDB for MySQL 8.0.2 with revision 8.0.2.2.12 or later.
You can view your cluster version number to confirm your cluster version.
Limitations
The following scenarios can cause significant errors in cardinality estimation, which may lead the optimizer to choose a suboptimal query plan. You can use HINT syntax to guide the optimizer toward a better query plan.
-
A query with a predicate that uses a comparison operator on different columns of the same table, such as
t1.c1>t1.c2. -
A query with a predicate that uses an operator that cannot be estimated using statistics, such as
t1.c1 MOD 2=1ort1.c2 LIKE '%ABC%'. -
A query with a predicate that contains an expression that cannot be computed during optimization, such as
t1.c1+t1.c3>100. -
A query where columns involved in an operator lack the statistics needed to estimate predicate selectivity, such as
SELECT a, SUM(b) FROM t1 HAVING SUM(b) > 10. -
Multiple predicates are connected by an
ANDoperator, such ast1.c1>10 AND t1.c3<5. -
The query has too many nested layers.
-
The query joins too many tables. You can adjust the number of joins the IMCI optimizer searches by modifying the
loose_imci_max_enum_join_pairsparameter.
Parameters
You can configure the following parameters in the console to enable and use the IMCI query optimization feature. For instructions on how to set parameters, see Specify cluster and node parameters.
|
Parameter |
Description |
|
loose_imci_optimizer_switch |
Controls the IMCI query optimization feature. It consists of the following flags:
|
|
loose_imci_auto_update_statistic |
Specifies whether the IMCI optimizer automatically recollects statistics when they are stale. Valid values:
|
|
loose_imci_max_enum_join_pairs |
Specifies the maximum number of equivalent query plans the IMCI optimizer searches when join reorder is enabled. Valid values: 0 to 4294967295. Default value: 2000. |
Procedure
To use the IMCI optimization feature, you must first collect statistics based on your chosen strategy. After collecting statistics, enable the feature and then run your queries.
-
Collect statistics.
You can use one of the following two strategies to collect statistics:
-
Periodically run the
ANALYZE TABLEcommand on tables that require IMCI optimization to collect the latest statistics. -
(Recommended) For tables where IMCI has been newly enabled, run the
ANALYZE TABLEcommand on a read-only node to build initial statistics. Then, set theloose_imci_auto_update_statisticparameter to ASYNC to automatically update statistics.
-
-
Enable the IMCI query optimization feature.
You can enable the IMCI query optimization feature by setting the
loose_imci_optimizer_switchparameter in the console. -
Run your queries.
Performance comparison
The following example uses TPC-H Q8, which is a multi-table query that includes aggregate functions.
SELECT
o_year,
SUM(
CASE
WHEN nation = 'BRAZIL' THEN volume
ELSE 0
END
) / SUM(volume) AS mkt_share
FROM
(
SELECT
EXTRACT(
year
FROM
o_orderdate
) AS o_year,
l_extendedprice * (1 - l_discount) AS volume,
n2.n_name AS nation
FROM
lineitem,
orders,
part,
supplier,
customer,
nation n1,
nation n2,
region
WHERE
p_partkey = l_partkey
AND s_suppkey = l_suppkey
AND l_orderkey = o_orderkey
AND o_custkey = c_custkey
AND c_nationkey = n1.n_nationkey
AND n1.n_regionkey = r_regionkey
AND r_name = 'AMERICA'
AND s_nationkey = n2.n_nationkey
AND o_orderdate BETWEEN DATE '1995-01-01'
AND DATE '1996-12-31'
AND p_type = 'ECONOMY ANODIZED STEEL'
) AS all_nations
GROUP By
o_year
ORDER BY
o_year;
-
The query plan with IMCI optimization disabled is as follows:
In this plan, numerous joins generate large intermediate result sets, which increases the amount of data and the processing cost for subsequent operators, leading to longer query latency. On a 32-core machine with a TPC-H SF100 dataset, this query took 7,017 ms to complete. -
The query plan with IMCI optimization enabled is as follows:
The IMCI optimizer reorders the joins, reducing the output size of most join operators to millions of rows. This effectively reduces the processing cost for subsequent operators. On the same 32-core machine with the TPC-H SF100 dataset, this query took 1,900 ms to complete, a 73% reduction in query time.