• 金仓数据库KingbaseES 绑定变量窥探机制


    目录

    窥探机制

    构建例子

    1、构建测试数据

    2、测试窥探机制

    3、窥探机制问题

    对于数据严重倾斜的,极端如以下例子,不同的传入值,可能执行计划不同,制定执行计划时,就要求知道变量的值。

    对于绑定变量的情况,我们知道Oracle 有optim_peek_user_binds 参数,控制是否启用变量窥探。KingbaseES 也有类似参数,控制是否启用变量窥探。

    窥探机制

    KingbaseES 采用以下判断机制,决定是否固定执行计划:

    • 前5次执行时,每次都会根据实际传入的实际绑定变量新生成执行计划进行执行,即每次都是硬解析,同时会记录这5次的执行计划;

    • 当第6次开始执行时,会生成一个通用的执行计划(generic plan),同时与前5次的执行计划进行比较,如果比较的结果是通用执行计划不比前5次的执行计划差,以后就会把这个通用的执行计划固定下来,这之后即使传入的值发生变化后,执行计划也不再变化。这就相当于Oracle打开了绑定变量窥视的功能。

    • 当然,当第6次开始执行时,如果通用的执行计划(generic plan)比前5次的某一个执行计划差,则以后则每次都重新生成执行计划,即以后永远都是硬解析了。

    构建例子

    1、构建测试数据

    1. create table t1(id integer,name text);
    2. insert into t1 select 1,repeat('a',100) from generate_series(1,1000000);
    3. insert into t1 select 2,repeat('b',100) ;
    4. create index ind_t1_id on t1(id);
    5. analyze t1;
    6. prepare t1_plan(integer) AS select count(*) from t1 where id=$1;

    2、测试窥探机制

    测试一:

    1. test=# prepare t1_plan(integer) AS select * from t1 where id=$1;
    2. PREPARE
    3. test=#
    4. test=# explain execute t1_plan(1);
    5. QUERY PLAN
    6. --------------------------------------------------------------
    7. Seq Scan on t1 (cost=0.00..29742.01 rows=1000001 width=105)
    8. Filter: (id = 1)
    9. (2 rows)
    10. test=# explain execute t1_plan(1);
    11. QUERY PLAN
    12. --------------------------------------------------------------
    13. Seq Scan on t1 (cost=0.00..29742.01 rows=1000001 width=105)
    14. Filter: (id = 1)
    15. (2 rows)
    16. test=# explain execute t1_plan(1);
    17. QUERY PLAN
    18. --------------------------------------------------------------
    19. Seq Scan on t1 (cost=0.00..29742.01 rows=1000001 width=105)
    20. Filter: (id = 1)
    21. (2 rows)
    22. test=# explain execute t1_plan(1);
    23. QUERY PLAN
    24. --------------------------------------------------------------
    25. Seq Scan on t1 (cost=0.00..29742.01 rows=1000001 width=105)
    26. Filter: (id = 1)
    27. (2 rows)
    28. test=# explain execute t1_plan(1);
    29. QUERY PLAN
    30. --------------------------------------------------------------
    31. Seq Scan on t1 (cost=0.00..29742.01 rows=1000001 width=105)
    32. Filter: (id = 1)
    33. (2 rows)
    34. test=# explain execute t1_plan(1);
    35. QUERY PLAN
    36. --------------------------------------------------------------
    37. Seq Scan on t1 (cost=0.00..29742.01 rows=1000001 width=105)
    38. Filter: (id = $1)
    39. (2 rows)
    40. test=# explain execute t1_plan(2);
    41. QUERY PLAN
    42. --------------------------------------------------------------
    43. Seq Scan on t1 (cost=0.00..29742.01 rows=1000001 width=105)
    44. Filter: (id = $1)
    45. (2 rows)
    46. test=# explain execute t1_plan(2);
    47. QUERY PLAN
    48. --------------------------------------------------------------
    49. Seq Scan on t1 (cost=0.00..29742.01 rows=1000001 width=105)
    50. Filter: (id = $1)
    51. (2 rows)

    结论:可以看到,第6次执行时,变为 id=$1,说明执行计划变成通用执行计划了。后续,即使传入的 值是 2,也不会走索引。

    测试二:

    1. test=# prepare t1_plan(integer) AS select * from t1 where id=$1;
    2. PREPARE
    3. test=# explain execute t1_plan(2);
    4. QUERY PLAN
    5. ----------------------------------------------------------------------
    6. Index Scan using ind_t1_id on t1 (cost=0.42..4.44 rows=1 width=105)
    7. Index Cond: (id = 2)
    8. (2 rows)
    9. test=# explain execute t1_plan(2);
    10. QUERY PLAN
    11. ----------------------------------------------------------------------
    12. Index Scan using ind_t1_id on t1 (cost=0.42..4.44 rows=1 width=105)
    13. Index Cond: (id = 2)
    14. (2 rows)
    15. test=# explain execute t1_plan(2);
    16. QUERY PLAN
    17. ----------------------------------------------------------------------
    18. Index Scan using ind_t1_id on t1 (cost=0.42..4.44 rows=1 width=105)
    19. Index Cond: (id = 2)
    20. (2 rows)
    21. test=# explain execute t1_plan(2);
    22. QUERY PLAN
    23. ----------------------------------------------------------------------
    24. Index Scan using ind_t1_id on t1 (cost=0.42..4.44 rows=1 width=105)
    25. Index Cond: (id = 2)
    26. (2 rows)
    27. test=# explain execute t1_plan(2);
    28. QUERY PLAN
    29. ----------------------------------------------------------------------
    30. Index Scan using ind_t1_id on t1 (cost=0.42..4.44 rows=1 width=105)
    31. Index Cond: (id = 2)
    32. (2 rows)
    33. test=# explain execute t1_plan(1);
    34. QUERY PLAN
    35. --------------------------------------------------------------
    36. Seq Scan on t1 (cost=0.00..29742.01 rows=1000001 width=105)
    37. Filter: (id = 1)
    38. (2 rows)
    39. test=# explain execute t1_plan(1);
    40. QUERY PLAN
    41. --------------------------------------------------------------
    42. Seq Scan on t1 (cost=0.00..29742.01 rows=1000001 width=105)
    43. Filter: (id = 1)
    44. (2 rows)
    45. test=# explain execute t1_plan(1);
    46. QUERY PLAN
    47. --------------------------------------------------------------
    48. Seq Scan on t1 (cost=0.00..29742.01 rows=1000001 width=105)
    49. Filter: (id = 1)
    50. (2 rows)
    51. test=# explain execute t1_plan(1);
    52. QUERY PLAN
    53. --------------------------------------------------------------
    54. Seq Scan on t1 (cost=0.00..29742.01 rows=1000001 width=105)
    55. Filter: (id = 1)
    56. (2 rows)
    57. test=# explain execute t1_plan(1);
    58. QUERY PLAN
    59. --------------------------------------------------------------
    60. Seq Scan on t1 (cost=0.00..29742.01 rows=1000001 width=105)
    61. Filter: (id = 1)
    62. (2 rows)
    63. test=# explain execute t1_plan(1);
    64. QUERY PLAN
    65. --------------------------------------------------------------
    66. Seq Scan on t1 (cost=0.00..29742.01 rows=1000001 width=105)
    67. Filter: (id = 1)
    68. (2 rows)
    69. test=# explain execute t1_plan(1);
    70. QUERY PLAN
    71. --------------------------------------------------------------
    72. Seq Scan on t1 (cost=0.00..29742.01 rows=1000001 width=105)
    73. Filter: (id = 1)
    74. (2 rows)
    75. test=# explain execute t1_plan(1);
    76. QUERY PLAN
    77. --------------------------------------------------------------
    78. Seq Scan on t1 (cost=0.00..29742.01 rows=1000001 width=105)
    79. Filter: (id = 1)
    80. (2 rows)

    结论:如果第6次与前5次执行计划是不一致的,后续都不会走通用的执行计划。本例中,哪怕后续连续超过 5次 传入同一值,都不会固定执行计划。

    3、窥探机制问题

    与Oracle 相比,KES需要前 5 次执行绑定变量的SQL,都会窥探变量值,只有在执行计划都一致时,第6次执行时才会固定执行计划。

    可以看到,这种机制相比于Oracle,出现执行计划错误的概率更低,但是还是有一定的几率。

    为了解决该问题,KingbaseES提供参数,可以关闭变量窥探机制。

    plan_cache_mode 参数控制是否固定执行计划(执行计划共享),还是永远进行硬解析。可以取以下三个值:

    • auto: 默认值,即根据以上的机制选择是否固定执行计划。
    • force_custom_plan: 关闭绑定变量窥视,永远进行硬解析。
    • force_generic_plan: 走通用的固定执行计划(generic plan)。比如:是否走索引是根据distinct 值的数量,而不是第一个传入的变量值。

    注意:与Oracle 实例级的执行计划共享不同,KingbaseES 只支持会话级执行计划共享。

  • 相关阅读:
    yolov5 v7.0自动标注
    【数字化转型】10大数字化转型能力成熟度模型01(IOMM)
    java遍历Map的方式
    C_C++在linux和windows下文件操作比较总结
    基础算法 - 常见算法模板题(最简洁写法)【下】
    Kafka 架构和原理机制 (图文全面详解)
    安装了 vue-cli,竟然提示 zsh: command not found: v
    C# 自定义控件
    基于口罩佩戴公开赛数据实践口罩佩戴识别
    微服务-gateway【服务网关入门】
  • 原文地址:https://blog.csdn.net/arthemis_14/article/details/128135419