更新时间:2026-07-28 GMT+08:00
分享

操作指导

前置条件

  • 数据库运行正常。
  • 反馈基数功能开启。
  • 数据库查询解析正常进入计划优化阶段。

使用指导

打开参数enable_adaptive_cost,其他参数使用默认设置即可开启本功能。

反馈基数功能需要先收集基数才能修正统计偏差,只有通过explain (analyze)执行或执行时间超过adaptive_cost_min_time的SQL才会收集基数信息。

当设置adaptive_cardest_strategy=auto(默认配置)时,同类型的SQL(按照sql id区分)第一次执行不会使用反馈基数。对重复执行的同类SQL,会按照过去的执行时间来判断是否可以使用反馈基数。如果出现了严重的计划劣化,即本次执行时间超过了不使用反馈基数平均执行时间的10倍再多5秒,则会将对应的SQL列入黑名单,不再使用反馈基数。例如,某sql不使用反馈基数的平均执行时间为1s,如果使用反馈基数后执行时间超过了1*10+5=15秒,则会列入黑名单。

示例

受环境、版本及部署形态差异影响,示例中的执行计划可能与实际不同。本示例仅作参考,具体优化效果请以实际执行计划为准。

  • 通过后台线程自动进行模型训练,调整执行计划。
  1. 启动数据库,查看enable_adaptive_cost参数是否开启,确保反馈基数估计功能的后台训练已正常开启。

    gaussdb=# SHOW enable_adaptive_cost;
     enable_adaptive_cost
    ----------------------
     on
    (1 row)

  2. 设置计划展示格式。

    gaussdb=# SET explain_perf_mode = pretty;

  3. 执行由于错误的基数估计导致次优计划的语句,如含有多种连接路径和连接类型的查询SQL,观察执行计划在多次执行中是否迭代出更优计划。以JOB数据集为例,首先导入JOB数据集,并运行查询语句01b.sql。

    gaussdb=# EXPLAIN (ANALYZE) 
    SELECT MIN(mc.note) AS production_note,
           MIN(t.title) AS movie_title,
           MIN(t.production_year) AS movie_year
    FROM company_type AS ct,
         info_type AS it,
         movie_companies AS mc,
         movie_info_idx AS mi_idx,
         title AS t
    WHERE ct.kind = 'production companies'
      AND it.info = 'bottom 10 rank'
      AND mc.note NOT LIKE '%(as Metro-Goldwyn-Mayer Pictures)%'
      AND t.production_year BETWEEN 2003 AND 2010
      AND ct.id = mc.company_type_id
      AND t.id = mc.movie_id
      AND t.id = mi_idx.movie_id
      AND mc.movie_id = mi_idx.movie_id
      AND it.id = mi_idx.info_type_id;

  4. 观察执行计划可知,总执行时间为6763.152毫秒。重点关注A-rows(实际行数)与E-rows(估计行数)两列数据,可以发现当前计划生成过程中的基数估计存在显著偏差。例如,对于Hash Join(8, 11)算子,其实际行数仅为6行,而估计行数却高达407,582行。正是由于此类基数估计偏差,导致该执行计划并非当前最优选择。此时,因后台训练功能已开启,反馈基数估计模块的后台训练线程将被触发,自动执行模型训练任务。

    id |                                      operation                                       |  A-time  | A-rows  | E-rows  | Peak Memory | A-width | E-width |        E-costs
    ----+--------------------------------------------------------------------------------------+----------+---------+---------+-------------+---------+---------+------------------------
      1 | ->  Aggregate                                                                        | 6763.152 |       1 |       1 | 37KB        |         |     113 | 310093.406..310093.416
      2 |    ->  Hash Join (3,6)                                                               | 6763.081 |       4 |  519424 | 33KB        |         |      45 | 168520.603..306197.726
      3 |       ->  Nested Loop (4,5)                                                          | 1331.081 |  140904 | 1304518 | 14KB        |         |      28 | 0.000..55534.270
      4 |          ->  Seq Scan on company_type ct                                             | 0.057    |       1 |       1 | 40KB        |         |       4 | 0.000..1.050
      5 |          ->  Index Scan using company_type_id_movie_companies on movie_companies mc  | 1277.665 |  140904 | 1304518 | 99KB        |         |      32 | 0.000..42488.040
      6 |       ->  Hash                                                                       | 5338.253 |       6 |  407582 | 2101KB      |         |      29 | 153872.828..153872.828
      7 |          ->  Hash Join (8,11)                                                        | 5338.095 |       6 |  407582 | 25KB        |         |      29 | 4.452..153872.828
      8 |             ->  Merge Join (9,10)                                                    | 5218.758 |  453508 | 1293307 | 22KB        |         |      33 | 2.027..147395.782
      9 |                ->  Index Scan using title_pkey on title t                            | 3113.129 |  868454 |  867579 | 94KB        |         |      25 | 0.000..95529.890
     10 |                ->  Index Scan using movie_id_movie_info_idx on movie_info_idx mi_idx | 1347.430 | 1380035 | 1380035 | 85KB        |         |       8 | 0.000..33401.173
     11 |             ->  Hash                                                                 | 0.245    |       1 |       1 | 299KB       |         |       4 | 2.413..2.413
     12 |                ->  Seq Scan on info_type it                                          | 0.167    |       1 |       1 | 43KB        |         |       4 | 0.000..2.413
    (12 rows)
    

  5. 再次执行查询并观察执行计划,可见执行时间已优化(从6763.152毫秒降至5337.537毫秒)。分析基数估计情况,在反馈基数估计模型的预测下,多数算子的基数估计值得到了有效矫正,从而优化了执行计划的生成。然而,仍可观察到部分基数估计偏差存在。例如,Nested Loop (4, 10)算子的估计行数与实际行数之间仍存在显著误差。这是由于上一轮基数估计的矫正改变了计划选择,导致本次执行相同SQL时生成了包含新算子(即此Nested Loop)的不同执行计划。因此,在上一轮模型训练周期内,系统未能采集到该算子的相关数据用于训练。而在本轮执行中,该新算子的信息将被收集,并触发模型训练。待后续查询再次包含此算子时,系统即可加载对应的训练模型进行精准预测。

    gaussdb=# EXPLAIN (ANALYZE) 
    SELECT MIN(mc.note) AS production_note,
           MIN(t.title) AS movie_title,
           MIN(t.production_year) AS movie_year
    FROM company_type AS ct,
         info_type AS it,
         movie_companies AS mc,
         movie_info_idx AS mi_idx,
         title AS t
    WHERE ct.kind = 'production companies'
      AND it.info = 'bottom 10 rank'
      AND mc.note NOT LIKE '%(as Metro-Goldwyn-Mayer Pictures)%'
      AND t.production_year BETWEEN 2003 AND 2010
      AND ct.id = mc.company_type_id
      AND t.id = mc.movie_id
      AND t.id = mi_idx.movie_id
      AND mc.movie_id = mi_idx.movie_id
      AND it.id = mi_idx.info_type_id;
     id |                                      operation                                       |  A-time  | A-rows  | E-rows  | Peak Memory | A-width | E-width |        E-costs
    ----+--------------------------------------------------------------------------------------+----------+---------+---------+-------------+---------+---------+------------------------
      1 | ->  Aggregate                                                                        | 5337.527 |       1 |       1 | 37KB        |         |     113 | 154787.966..154787.976
      2 |    ->  Hash Join (3,11)                                                              | 5337.411 |       4 |   56104 | 25KB        |         |      45 | 5.514..154367.186
      3 |       ->  Nested Loop (4,10)                                                         | 5336.835 |      78 |  645521 | 14KB        |         |      49 | 4.452..149520.686
      4 |          ->  Hash Join (5,8)                                                         | 5335.656 |       6 |       6 | 25KB        |         |      29 | 4.452..149504.894
      5 |             ->  Merge Join (6,7)                                                     | 5214.316 |  453508 |  420811 | 22KB        |         |      33 | 2.027..147395.782
      6 |                ->  Index Scan using title_pkey on title t                            | 3136.195 |  868454 |  867579 | 94KB        |         |      25 | 0.000..95529.890
      7 |                ->  Index Scan using movie_id_movie_info_idx on movie_info_idx mi_idx | 1315.340 | 1380035 | 1380035 | 85KB        |         |       8 | 0.000..33401.173
      8 |             ->  Hash                                                                 | 0.128    |       1 |       1 | 299KB       |         |       4 | 2.413..2.413
      9 |                ->  Seq Scan on info_type it                                          | 0.070    |       1 |       1 | 43KB        |         |       4 | 0.000..2.413
     10 |          ->  Index Scan using movie_id_movie_companies on movie_companies mc         | 0.882    |      78 |       2 | 99KB        |         |      32 | 0.000..2.612
     11 |       ->  Hash                                                                       | 0.095    |       1 |       1 | 299KB       |         |       4 | 1.050..1.050
     12 |          ->  Seq Scan on company_type ct                                             | 0.030    |       1 |       1 | 43KB        |         |       4 | 0.000..1.050
    (12 rows)

  6. 再次执行查询并观察执行计划,可见上一轮基数估计未矫正的Nested Loop算子,其基数估计结果亦得到有效矫正

    gaussdb=# EXPLAIN (ANALYZE) 
    SELECT MIN(mc.note) AS production_note,
           MIN(t.title) AS movie_title,
           MIN(t.production_year) AS movie_year
    FROM company_type AS ct,
         info_type AS it,
         movie_companies AS mc,
         movie_info_idx AS mi_idx,
         title AS t
    WHERE ct.kind = 'production companies'
      AND it.info = 'bottom 10 rank'
      AND mc.note NOT LIKE '%(as Metro-Goldwyn-Mayer Pictures)%'
      AND t.production_year BETWEEN 2003 AND 2010
      AND ct.id = mc.company_type_id
      AND t.id = mc.movie_id
      AND t.id = mi_idx.movie_id
      AND mc.movie_id = mi_idx.movie_id
      AND it.id = mi_idx.info_type_id;
     id |                                      operation                                       |  A-time  | A-rows  | E-rows  | Peak Memory | A-width | E-width |        E-costs
    ----+--------------------------------------------------------------------------------------+----------+---------+---------+-------------+---------+---------+------------------------
      1 | ->  Aggregate                                                                        | 5239.744 |       1 |       1 | 37KB        |         |     113 | 149522.816..149522.826
      2 |    ->  Nested Loop (3,4)                                                             | 5239.688 |       4 |       4 | 18KB        |         |      45 | 4.452..149522.786
      3 |       ->  Seq Scan on company_type ct                                                | 0.031    |       1 |       1 | 40KB        |         |       4 | 0.000..1.050
      4 |       ->  Nested Loop (5,11)                                                         | 5239.539 |      78 |      84 | 14KB        |         |      49 | 4.452..149520.686
      5 |          ->  Hash Join (6,9)                                                         | 5238.656 |       6 |       6 | 25KB        |         |      29 | 4.452..149504.894
      6 |             ->  Merge Join (7,8)                                                     | 5122.325 |  453508 |  420811 | 22KB        |         |      33 | 2.027..147395.782
      7 |                ->  Index Scan using title_pkey on title t                            | 3063.495 |  868454 |  867579 | 21KB        |         |      25 | 0.000..95529.890
      8 |                ->  Index Scan using movie_id_movie_info_idx on movie_info_idx mi_idx | 1295.687 | 1380035 | 1380035 | 85KB        |         |       8 | 0.000..33401.173
      9 |             ->  Hash                                                                 | 0.095    |       1 |       1 | 299KB       |         |       4 | 2.413..2.413
     10 |                ->  Seq Scan on info_type it                                          | 0.071    |       1 |       1 | 43KB        |         |       4 | 0.000..2.413
     11 |          ->  Index Scan using movie_id_movie_companies on movie_companies mc         | 0.775    |      78 |       2 | 99KB        |         |      32 | 0.000..2.612

  • 通过EXPLAIN ADAPTCOST选项展示模型使用情况,沿用上一节的执行计划。
  1. 设置计划展示格式,展示模型使用情况仅支持normal模式。

    gaussdb=# SET explain_perf_mode = normal;

  2. 在EXPLAIN语句中加入ADAPTCOST选项,执行查询。

    gaussdb=# EXPLAIN (ANALYZE, ADAPTCOST) 
    SELECT MIN(mc.note) AS production_note,
           MIN(t.title) AS movie_title,
           MIN(t.production_year) AS movie_year
    FROM company_type AS ct,
         info_type AS it,
         movie_companies AS mc,
         movie_info_idx AS mi_idx,
         title AS t
    WHERE ct.kind = 'production companies'
      AND it.info = 'bottom 10 rank'
      AND mc.note NOT LIKE '%(as Metro-Goldwyn-Mayer Pictures)%'
      AND t.production_year BETWEEN 2003 AND 2010
      AND ct.id = mc.company_type_id
      AND t.id = mc.movie_id
      AND t.id = mi_idx.movie_id
      AND mc.movie_id = mi_idx.movie_id
      AND it.id = mi_idx.info_type_id;
    

  3. 观察执行计划输出,可见在算子详情中新增了cardest字段。当算子应用了反馈基数估计模型进行基数预测时,该字段会显示所加载的模型名称。如第二行的Nested Loop算子所示,其cardest字段值为UMM_S_3461496410,26633.5。这表明该算子使用了名为此标识符的UMM模型进行预测。模型名称即为该算子特征值(哈希值)

                                                                                                 QUERY PLAN
    -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    ---------------
     Aggregate  (cost=149522.82..149522.83 rows=1 cardest=default width=113) (actual time=5278.285..5278.286 rows=1 loops=1)
       ->  Nested Loop  (cost=4.45..149522.79 rows=4 cardest=trust UMM_S_3461496410,26633.5 width=45) (actual time=3421.652..5278.209 rows=4 loops=1)
             Join Filter: (mc.company_type_id = ct.id), (Expression Flatten Optimized)
             Rows Removed by Join Filter: 74
             ->  Seq Scan on company_type ct  (cost=0.00..1.05 rows=1 cardest=try default width=4) (actual time=0.022..0.033 rows=1 loops=1)
                   Filter: ((kind)::text = 'production companies'::text), (Expression Flatten Optimized)
                   Rows Removed by Filter: 3
             ->  Nested Loop  (cost=4.45..149520.69 rows=84 cardest=trust UMM_S_2994907757,26633.5(mixed) width=49) (actual time=3030.134..5278.040 rows=78 loops=1)
                   ->  Hash Join  (cost=4.45..149504.89 rows=6 cardest=trust UMM_S_3093839448,26633.5(mixed) width=29) (actual time=3029.979..5277.112 rows=6 loops=1)
                         Hash Cond: (mi_idx.info_type_id = it.id), (Expression Flatten Optimized)
                         ->  Merge Join  (cost=2.03..147395.78 rows=420811 cardest=trust UMM_S_1518054377,26633.5(mixed) width=33) (actual time=0.091..5158.858 rows=453508 loops=1)
                               Merge Cond: (t.id = mi_idx.movie_id)
                               ->  Index Scan using title_pkey on title t  (cost=0.00..95529.89 rows=867579 cardest=try default width=25) (actual time=0.043..3081.927 rows=868454 loops=1)
                                     Filter: ((production_year >= 2003) AND (production_year <= 2010)), (Expression Flatten Optimized)
                                     Rows Removed by Filter: 1657356
                               ->  Index Scan using movie_id_movie_info_idx on movie_info_idx mi_idx  (cost=0.00..33401.17 rows=1380035 cardest=default width=8) (actual time=0.037..1309.014 rows=13
    80035 loops=1)
                         ->  Hash  (cost=2.41..2.41 rows=1 cardest=default width=4) (actual time=0.088..0.088 rows=1 loops=1)
                                Buckets: 32768  Batches: 1  Memory Usage: 1kB
                               ->  Seq Scan on info_type it  (cost=0.00..2.41 rows=1 cardest=try default width=4) (actual time=0.069..0.072 rows=1 loops=1)
                                     Filter: ((info)::text = 'bottom 10 rank'::text), (Expression Flatten Optimized)
                                     Rows Removed by Filter: 112
                   ->  Index Scan using movie_id_movie_companies on movie_companies mc  (cost=0.00..2.61 rows=2 cardest=try default width=32) (actual time=0.599..0.836 rows=78 loops=6)
                         Index Cond: (movie_id = t.id)
                         Filter: (note !~~ '%(as Metro-Goldwyn-Mayer Pictures)%'::text)
                         Rows Removed by Filter: 15
     Total runtime: 5279.630 ms

相关文档