• 金仓数据库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 只支持会话级执行计划共享。

  • 相关阅读:
    今日AI:GPT-4.5意外曝光可能6月发布、UP主借AI识别情绪播放量186万、全球首个AI程序员诞生
    Linux操作文档——Linux运维面试掌握
    【SpringBoot+MP】实现简单购物车并集成用户下单功能
    [算法沉淀记录] 排序算法 —— 希尔排序
    filament沙盒传参数到shader
    中秋征文 | 【云原生之Docker】使用docker部署内网穿透工具FRP
    unity3d 布娃娃系统插件 PuppetMaster 木偶师
    AI: 2021 年人工智能前沿科技报告(更新中……)
    美容院圣诞节促销活动方案
    动漫新闻查询易语言代码
  • 原文地址:https://blog.csdn.net/arthemis_14/article/details/128135419