



前情回顾
前面我们介绍了金仓数据库的版本发展脉络,如何安装金仓数据库 KES。在本文中,我们将继续阐述如何使用 KES 数据库的 Docker 镜像,同时分享几个实用的性能优化案例。
金仓数据库 Docker 镜像
从电科金仓官网的下载中心可以直接下载到最新的 Docker 镜像。这里我们选择 x86_64 架构的镜像。

下载完成后上传到服务器,并导入镜像。
[shawnyan@rl9 ~]$ ll -h kdb_x86_64_V009R001C002B0014.tar
-rw-r--r-- 1 shawnyan shawnyan 711M Jan 30 22:01 kdb_x86_64_V009R001C002B0014.tar
[shawnyan@rl9 ~]$ podman load -i kdb_x86_64_V009R001C002B0014.tar
Getting image source signatures
...
Loaded image: localhost/kingbase_v009r001c002b0014_single_x86:v1
[shawnyan@rl9 ~]$ podman images
REPOSITORY TAG IMAGE ID CREATED SIZE
localhost/kingbase_v009r001c002b0014_single_x86 v1 a12899877a42 3 months ago 744 MB
接下来,我们可以运行该镜像。
podman run -dit --name kingbase a12899877a42
需要注意的是,系统存在以下默认配置:
- 系统用户默认密码:
123 - 数据库默认用户名:
system - 数据库默认密码:
12345678ab - 数据库默认数据目录:
/home/kingbase/userdata/data
容器启动后,数据库会自动运行。我们可以通过以下命令确认数据库的运行状态。
[shawnyan@rl9 ~]$ podman exec -it kingbase sys_ctl status -D /home/kingbase/userdata/data/
sys_ctl: server is running (PID: 100)
/home/kingbase/install/kingbase/bin/kingbase "-D" "/home/kingbase/userdata/data"
最后,我们可以使用客户端 ksql 连接数据库。
[shawnyan@rl9 ~]$ podman exec -it kingbase ksql -Usystem -dkingbase
Type "help" for help.
kingbase=# \l
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges
-----------+--------+----------+-------------+-------------+-------------------
kingbase | system | UTF8 | en_US.UTF-8 | en_US.UTF-8 |
security | system | UTF8 | en_US.UTF-8 | en_US.UTF-8 |
template0 | system | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/system +
| | | | | system=CTc/system
template1 | system | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/system +
| | | | | system=CTc/system
test | system | UTF8 | en_US.UTF-8 | en_US.UTF-8 |
(5 rows)
kingbase=# \du
List of roles
Role name | Attributes | Member of
------------+------------------------------------------------------------+-----------
kcluster | Cannot login | {}
sao | No inheritance, Create role | {}
sao_oper | No inheritance, Cannot login | {}
sao_public | No inheritance, Cannot login | {}
sso | No inheritance, Create role | {}
sso_oper | No inheritance, Cannot login | {}
sso_public | No inheritance, Cannot login | {}
system | Superuser, Create role, Create DB, Replication, Bypass RLS | {}
kingbase=# select version();
version
----------------------------------------------------------------------------------------------------------------------
KingbaseES V009R001C002B0014 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-28), 64-bit
(1 row)
kingbase=# show database_mode;
database_mode
---------------
oracle
(1 row)
kingbase=#
SQL 优化之 Hint
KingbaseES 使用的是基于成本的优化器。该优化器会对 SQL 语句的每个可能的执行计划的成本,然后选择成本最低的执行计划来执行。因为优化器不计算数据的某些属性,比如列之间的相关性,优化器有时选择的计划并不一定是最优的。
Hint 的作用就是通过使用特殊形式的注释中的 Hint 短语来指定执行 SQL 语句所用的执行计划。Hint 为用户提供了直接影响执行计划生成的手段,用户可以通过指定 join 顺序,join、scan 方法,指定结果行数等多个手段来进行执行计划的调优,以提升查询的性能。
需要注意的是,KES 默认禁用了 Hint 特性,需要手动开启,具体操作如下。
kingbase=# show enable_hint ;
enable_hint
-------------
off
(1 row)
kingbase=# select sys_reload_conf();
sys_reload_conf
-----------------
t
(1 row)
kingbase=# show enable_hint ;
enable_hint
-------------
on
(1 row)
KES V9R1C1B3 对 Hint 功能进行了增强,增加以下 4 种 Hint 类型。
- 并行执行 ParallelAppend(workers)
- 聚集 ParallelHashagg 和 ParallelGroupagg
- 参数化路径行数更正 PRows(table_list table #|+|-|* const)
并行执行 ParallelAppend(workers)
并行执行类型的 Hint,针对 union all 的并行执行,需要在 union all 的外层进行指定,该 Hint 指定查询中的 append 节点强制并行执行。
使用以下脚本创建测试数据。
create table t2(id int, val int);
create table t3(id int, val int);
create index t2_idx on t2(id);
create index t3_idx on t3(id);
insert into t2 select i, i%5000 from generate_series(1,1000000) as x(i);
insert into t3 select i, i%5 from generate_series(1,100) as x(i);
analyze t2;
analyze t3;
这是一个并行测试用例,需要将并行打开。
set max_parallel_workers_per_gather to 2;
查看实际执行计划,确认使用到了 Parallel Append。
kingbase=# explain analyze select /*+ParallelAppend(2)*/ * from (select * from t2 union all select * from t3) a;
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------
Gather (cost=0.00..23594.88 rows=1000100 width=8) (actual time=0.543..127.860 rows=1000100 loops=1)
Workers Planned: 2
Workers Launched: 2
-> Parallel Append (cost=0.00..23594.88 rows=1000042 width=8) (actual time=0.013..56.308 rows=333367 loops=3)
-> Seq Scan on t3 (cost=0.00..2.00 rows=100 width=8) (actual time=0.018..0.024 rows=100 loops=1)
-> Parallel Seq Scan on t2 (cost=0.00..8591.67 rows=416667 width=8) (actual time=0.009..30.558 rows=333333 loops=3)
Planning Time: 0.240 ms
Execution Time: 172.673 ms
(8 rows)
聚集 ParallelHashagg 和 ParallelGroupagg
测试聚集 Hint,符合预期。
kingbase=# explain select/*+parallelhashagg*/t2.id, count(t3.val) from t2,t3 where t2.id=t3.val group by t2.id;
QUERY PLAN
----------------------------------------------------------------------------------------------------------------
Finalize HashAggregate (cost=1017.56..1018.56 rows=100 width=12)
Group Key: t2.id
-> Gather Merge (cost=1006.07..1017.14 rows=84 width=12)
Workers Planned: 2
-> Partial GroupAggregate (cost=6.05..7.42 rows=42 width=12)
Group Key: t2.id
-> Merge Join (cost=6.05..6.79 rows=42 width=8)
Merge Cond: (t2.id = t3.val)
-> Parallel Index Only Scan using t2_idx on t2 (cost=0.42..24635.09 rows=416667 width=4)
-> Sort (cost=5.32..5.57 rows=100 width=4)
Sort Key: t3.val
-> Seq Scan on t3 (cost=0.00..2.00 rows=100 width=4)
(12 rows)
性能优化
在性能优化方面,金仓数据库提供分区表 LIKE 剪枝,以及 UPDATE/DELETE 语句执行时的剪枝优化功能,能够在多级分区表分区数量多、高并发场景下显著提升 SQL 语句查询性能。
同时,系统完善了 DBTime 模型。该模型可以帮助用户衡量数据库负载,精准定位性能瓶颈,从而为性能调优决策提供有力支持,为用户解决问题和分析问题提供了有效的帮助。
分区表执行计划优化
分区表支持范围分区、列表分区、HASH 分区的分区方式以及二级子分区。单表分区个数原则上不建议超过 500 个,全库不超过 10 万个分区。对象过多时,会造成数据字典庞大,数据库整体运行效率明显下降。
分区表执行计划优化,旨在解决高并发场景下分区表子表数量较多时,SELECT/UPDATE/DELETE 计划生成过程中出现的锁问题。
该功能由 GUC 参数 partition_table_limit 控制,0 表示不启用,默认值为 20。
kingbase=# show partition_table_limit ;
partition_table_limit
-----------------------
20
(1 row)
当经过剪枝后的分区表子表数量超过该参数的值时,将启用该功能快速生成执行计划。否则将按原有逻辑生成执行计划。
分区表执行计划优化适用于以下场景:分区表子表数量较多;分区表上索引数量较多;分区表查询语句中等价类条件较多。
参数 enable_partition_pruning 意为:允许或者禁止查询规划器从查询计划中消除一个分区表的分区。这也控制着规划器产生允许执行器在查询执行期间移除(忽略)分区的查询计划的能力。默认值是 on。
shawnyan=# show enable_partition_pruning ;
enable_partition_pruning
--------------------------
on
(1 row)
测试用例如下。
首先,创建一个分区表,及三个子分区,生产测试数据。
create table pt(col1 INT, col2 INT) PARTITION BY RANGE (col1);
create table pt_1 partition of pt for values from (0) to (10);
create table pt_2 partition of pt for values from (10) to (20);
insert into pt select i, i from generate_series(1,19) as x(i);
进行点查,查看执行计划是扫描全部分区。
kingbase=# explain analyze select * from pt where col1 = 11;
QUERY PLAN
----------------------------------------------------------------------------------------------------
Append (cost=0.00..1.00 rows=1 width=8) (actual time=0.020..0.022 rows=1 loops=1)
-> Seq Scan on pt_1 (cost=0.00..0.50 rows=0 width=8) (actual time=0.016..0.016 rows=0 loops=1)
Filter: (col1 = 11)
Rows Removed by Filter: 9
-> Seq Scan on pt_2 (cost=0.00..0.50 rows=0 width=8) (actual time=0.003..0.004 rows=1 loops=1)
Filter: (col1 = 11)
Rows Removed by Filter: 9
Planning Time: 0.049 ms
Execution Time: 0.041 ms
(9 rows)
开启分区裁剪后,再次查看执行计划,可以发现这次只扫描 pt_2 分区。
kingbase=# show enable_partition_pruning;
enable_partition_pruning
--------------------------
on
(1 row)
kingbase=# explain analyze select * from pt where col1 = 11;
QUERY PLAN
----------------------------------------------------------------------------------------------
Seq Scan on pt_2 (cost=0.00..1.00 rows=1 width=8) (actual time=0.021..0.022 rows=1 loops=1)
Filter: (col1 = 11)
Rows Removed by Filter: 9
Planning Time: 0.064 ms
Execution Time: 0.041 ms
(5 rows)
结语
本节内容就到这里。感谢大家的阅读,欢迎点点关注,我们下期再见。




