【KWDB创作者计划】实战指南:KWDB 2.2.0数据分析与性能调优深度对比

作者:ShunWah

在运维管理领域,我拥有多年深厚的专业积累,兼具坚实的理论基础与广泛的实践经验。精通运维自动化流程,对于OceanBase、MySQL等多种数据库的部署与运维,具备从初始部署到后期维护的全链条管理能力。拥有OceanBase的OBCA和OBCP认证、OpenGauss社区认证结业证书,以及崖山DBCA、亚信AntDBCA、翰高HDCA、GBase 8a | 8c | 8s、Galaxybase的GBCA、Neo4j的Graph Data Science Certification、NebulaGraph的NGCI & NGCP、东方通TongTech TCPE等多项权威认证。

在OceanBase & 墨天轮的技术征文大赛中,多次荣获一、二、三等奖。同时,在OpenGauss第五届、第六届、第七届技术征文大赛,TiDB社区专栏征文大赛,金仓数据库有奖征文活动,以及YashanDB「产品体验官」征文等活动中,我也屡获殊荣。此外,我还活跃于墨天轮、CSDN、ITPUB等技术平台,经常发布原创技术文章,并多次被首页推荐。

modbkwdb.png

引言

浪潮数据库KWDB2.2.0:数据分析与性能调优深度对比实战指南

随着开源社区的蓬勃发展,越来越多的优秀项目涌现出来,为开发者们提供了丰富的工具和资源。其中,KWDB 作为一款面向AIoT场景的分布式多模数据库,自2024年开源以来,凭借其强大的功能和灵活的架构,吸引了众多开发者的关注。【KWDB创作者计划】更是为KWDB带来了全新的玩法和可能性。
在本文中,我们将详细介绍如何使用KWDB 2.2.0,并通过一系列实操命令,展示如何解锁KWDB的新玩法。

KWDB 2.2.0的新功能概览

KWDB 2.2.0版本带来了许多新功能和改进,以下是其中一些亮点:
多模数据支持增强
支持更多数据类型,包括JSON、图像、视频和音频,适用于复杂的AIoT场景。
分布式性能优化
提高了分布式环境下的数据同步和查询性能,适合大规模部署。
新增API接口
提供了更多便捷的API,简化了数据库操作流程。
用户界面改进
新增了一个更直观的控制台界面,方便用户管理数据库。

一、安装KWDB 2.2.0

首先,我们需要安装KWDB 2.2.0版本。以下是安装步骤:

1. 环境准备

确保你的开发环境满足KWDB的运行要求。KWDB支持多种操作系统,包括Linux、macOS和Windows。
本文以 x86 架构的 CentOS Linux 7.4 镜像作为环境介绍如何使用 docker容器化部署 KWDB2.2.0 数据库。

[root@worker3 kaiwudb]# cat /etc/redhat-release 
CentOS Linux release 7.9.2009 (Core)
[root@worker3 kaiwudb]# free -h
              total        used        free      shared  buff/cache   available
Mem:            27G        1.8G         10G        313M         15G         24G
Swap:          8.0G          0B        8.0G
[root@worker3 kaiwudb]# 

image.png

2. 安装命令

由于我已提前完成安装,这里不再重复演示。如需详细安装步骤,请参考我的上一篇文章:
【KWDB创作者计划】容器赋能KaiwuDB:探索浪潮数据库KWDB2.2.0 实战指南

3. 验证安装

安装完成后,在终端中运行以下命令验证安装是否成功:

[root@worker3 kwdb]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                              NAMES
40305e626095        kwdb/kwdb:2.2.0     "/bin/bash -c '/kaiw…"   9 days ago          Up 9 days           0.0.0.0:8080->8080/tcp, 0.0.0.0:26257->26257/tcp   kaiwudb-experience
[root@worker3 kwdb]# docker exec -it kaiwudb-experience bash
root@kaiwudb-experience:/kaiwudb/bin# ./kwbase sql --insecure --host=127.0.0.1
#
# Welcome to the KWDB SQL shell.
# All statements must be terminated by a semicolon.
# To exit, type: \q.
#
# Server version: KaiwuDB 2.2.0 (x86_64-linux-gnu, built 2025/03/31 07:20:02, go1.16.15, gcc 11.4.0) (same version as client)
# Cluster ID: b565096e-c243-4399-8aa0-6ec3ea6b77a5
#
# Enter \? for a brief introduction.
#
root@127.0.0.1:26257/defaultdb> 

image.png

首先,确保你已经成功部署了 KWDB 2.2.0。或你可以从 Gitee 上下载最新版的 KWDB 2.2.0 安装包,并按照官方文档进行安装和配置。安装完成后,启动 KWDB 服务,并确保其正常运行。

二、KWDB 联合查询数据分析

现在,我们将用 KWDB 进行创建数据库和表。

1、创建数据库
root@127.0.0.1:26257/example_db> CREATE DATABASE testdb; CREATE DATABASE Time: 6.130957ms root@127.0.0.1:26257/example_db> 

切换到新创建的数据库

root@127.0.0.1:26257/example_db> USE testdb; SET Time: 1.416482ms root@127.0.0.1:26257/testdb> 

2、创建数据库表
2.1 创建时序表,用于存储设备指标数据
root@127.0.0.1:26257/testdb> CREATE TABLE device_metrics ( temperature FLOAT, humidity FLOAT, -> time TIMESTAMP NOT NULL, -> device_id STRING NOT NULL, PRIMARY KEY (time, device_id) ); -> temperature FLOAT, -> humidity FLOAT, -> PRIMARY KEY (time, device_id) -> ); CREATE TABLE Time: 5.415833ms root@127.0.0.1:26257/testdb> 

2.2 创建用户信息表,用于存储用户基本信息
root@127.0.0.1:26257/testdb> CREATE TABLE user_info ( username STRING NOT NULL, email STRING, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -> user_id INT PRIMARY KEY, -> username STRING NOT NULL, -> email STRING, -> created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP -> ); CREATE TABLE Time: 5.662591ms root@127.0.0.1:26257/testdb> 

3. 插入测试数据

创建好数据库和表后,我们插入一些测试数据,以便后续进行查询和优化操作。

root@127.0.0.1:26257/testdb> INSERT INTO device_metrics VALUES ('2021-09-15 12:30:00', 'device2', 26.1, 44.8), ('2022-03-20 15:45:00', 'device3', 27.0, 43.5), ('2023-07-10 08:15:00', 'device1', 25.7, 44.9), ('2024-01-25 11:00:00', 'device2', 26.3, 44.6), ('2024-08-05 14:20:00', 'device3', 27.2, 43.3), -> ('2020-06-01 10:00:00', 'device1', 25.3, 45.2), ('2025-02-14 09:40:00', 'device1', 25.9, 44.7), ('2025-05-30 16:50:00', 'device2', 26.5, 44.4), ('2025-09-12 13:10:00', 'device3', 27.4, 43.1), ('2025-12-25 18:35:00', 'device1', 26.0, 44.0); -> ('2021-09-15 12:30:00', 'device2', 26.1, 44.8), -> ('2022-03-20 15:45:00', 'device3', 27.0, 43.5), -> ('2023-07-10 08:15:00', 'device1', 25.7, 44.9), -> ('2024-01-25 11:00:00', 'device2', 26.3, 44.6), -> ('2024-08-05 14:20:00', 'device3', 27.2, 43.3), -> ('2025-02-14 09:40:00', 'device1', 25.9, 44.7), -> ('2025-05-30 16:50:00', 'device2', 26.5, 44.4), -> ('2025-09-12 13:10:00', 'device3', 27.4, 43.1), -> ('2025-12-25 18:35:00', 'device1', 26.0, 44.0); INSERT 10 Time: 1.498235ms root@127.0.0.1:26257/testdb> 

4、查看全部数据
root@127.0.0.1:26257/testdb> SELECT * FROM device_metrics; time | device_id | temperature | humidity ----------------------------+-----------+-------------+----------- 2020-06-01 10:00:00+00:00 | device1 | 25.3 | 45.2 2021-09-15 12:30:00+00:00 | device2 | 26.1 | 44.8 2022-03-20 15:45:00+00:00 | device3 | 27 | 43.5 2023-07-10 08:15:00+00:00 | device1 | 25.7 | 44.9 2024-01-25 11:00:00+00:00 | device2 | 26.3 | 44.6 2024-08-05 14:20:00+00:00 | device3 | 27.2 | 43.3 2025-02-14 09:40:00+00:00 | device1 | 25.9 | 44.7 2025-05-30 16:50:00+00:00 | device2 | 26.5 | 44.4 2025-09-12 13:10:00+00:00 | device3 | 27.4 | 43.1 2025-12-25 18:35:00+00:00 | device1 | 26 | 44 (10 rows) Time: 1.628286ms root@127.0.0.1:26257/testdb> 

5、插入用户信息数据
root@127.0.0.1:26257/testdb> root@127.0.0.1:26257/testdb> INSERT INTO user_info (user_id, username, email) VALUES (1, 'alice', 'alice@example.com'), -> (1, 'alice', 'alice@example.com'), (2, 'bob', 'bob@example.com'), (3, 'charlie', 'charlie@example.com'); -> (2, 'bob', 'bob@example.com'), -> (3, 'charlie', 'charlie@example.com'); INSERT 3 Time: 1.800617ms root@127.0.0.1:26257/testdb> 

6、数据查询与优化

创建好数据库和表,并插入测试数据后,我们可以通过 MCP Server 执行查询操作,并尝试对查询进行优化。

6.1 简单查询设备指标数据
root@127.0.0.1:26257/testdb> SELECT * FROM device_metrics WHERE device_id = 'device1'; time | device_id | temperature | humidity ----------------------------+-----------+-------------+----------- 2020-06-01 10:00:00+00:00 | device1 | 25.3 | 45.2 2023-07-10 08:15:00+00:00 | device1 | 25.7 | 44.9 2025-02-14 09:40:00+00:00 | device1 | 25.9 | 44.7 2025-12-25 18:35:00+00:00 | device1 | 26 | 44 (4 rows) Time: 2.05378ms root@127.0.0.1:26257/testdb> 

6.2 时间范围查询设备指标数据
root@127.0.0.1:26257/testdb> SELECT * FROM device_metrics WHERE time > '2025-01-01 09:00:00' AND time < '2025-12-30 10:15:00'; time | device_id | temperature | humidity ----------------------------+-----------+-------------+----------- 2025-02-14 09:40:00+00:00 | device1 | 25.9 | 44.7 2025-05-30 16:50:00+00:00 | device2 | 26.5 | 44.4 2025-09-12 13:10:00+00:00 | device3 | 27.4 | 43.1 2025-12-25 18:35:00+00:00 | device1 | 26 | 44 (4 rows) Time: 1.635945ms root@127.0.0.1:26257/testdb> 

6.3 聚合查询设备平均温度
root@127.0.0.1:26257/testdb> SELECT device_id, AVG(temperature) AS avg_temp WHERE time > NOW() - INTERVAL '1 hour' GROUP BY device_id; -> FROM device_metrics -> WHERE time > NOW() - INTERVAL '1 hour' -> GROUP BY device_id; device_id | avg_temp ------------+----------- device1 | 26 device2 | 26.5 device3 | 27.4 (3 rows) Time: 2.286525ms root@127.0.0.1:26257/testdb> 

6.4 查询用户信息
root@127.0.0.1:26257/testdb> SELECT * FROM user_info; user_id | username | email | created_at ----------+----------+---------------------+----------------------------------- 1 | alice | alice@example.com | 2025-04-18 06:51:45.654229+00:00 2 | bob | bob@example.com | 2025-04-18 06:51:45.654229+00:00 3 | charlie | charlie@example.com | 2025-04-18 06:51:45.654229+00:00 (3 rows) Time: 1.465467ms root@127.0.0.1:26257/testdb> 

6.5 优化查询:为 device_metrics 表的 device_id 列创建索引
root@127.0.0.1:26257/testdb> CREATE INDEX idx_device_id ON device_metrics (device_id); CREATE INDEX Time: 173.51779ms root@127.0.0.1:26257/testdb> 

6.6 再次执行简单查询,观察性能变化
root@127.0.0.1:26257/testdb> SELECT * FROM device_metrics WHERE device_id = 'device1'; time | device_id | temperature | humidity ----------------------------+-----------+-------------+----------- 2020-06-01 10:00:00+00:00 | device1 | 25.3 | 45.2 2023-07-10 08:15:00+00:00 | device1 | 25.7 | 44.9 2025-02-14 09:40:00+00:00 | device1 | 25.9 | 44.7 2025-12-25 18:35:00+00:00 | device1 | 26 | 44 (4 rows) Time: 1.805047ms root@127.0.0.1:26257/testdb> 

在查询过程中,我们可能会发现某些查询的性能不够理想。这时,我们可以尝试对 KWDB 进行优化,比如调整索引、分区策略等。在上述示例中,我们为 device_metrics 表的 device_id 列创建了索引,以加速基于 device_id 的查询操作。

7. 高级查询与数据分析

除了基本的查询操作外,我们还可以利用 KWDB 进行更高级的数据分析和处理。在实际业务场景中,数据库系统通常需要处理复杂的关联查询和数据分析任务。例如:
用户(user_info 表)与设备(device_metrics 表)之间的关联。每个用户可能绑定一个或多个设备,并且需要根据设备的最新数据进行统计和分析。本案例通过以下步骤展示了如何利用 KWDB 进行高级查询和数据分析:

创建用户设备关联表(user_device_mapping),用于存储用户与设备的绑定关系。
插入示例数据,模拟用户与设备的实际关联。
使用多表联合查询(JOIN)获取每个用户的最新设备数据,并按用户名排序。

7.1 首先,创建用户设备关联表
root@127.0.0.1:26257/testdb> CREATE TABLE user_device_mapping ( user_id INT, device_id STRING, PRIMARY KEY (user_id) ); -> user_id INT, -> device_id STRING, -> PRIMARY KEY (user_id) -> ); CREATE TABLE Time: 6.371418ms root@127.0.0.1:26257/testdb> 

目的:建立用户与设备的映射关系。
字段说明:
user_id:用户 ID,主键,确保每个用户只能绑定一个设备。
device_id:设备 ID,表示用户绑定的设备。

7.2 插入一些示例数据
root@127.0.0.1:26257/testdb> INSERT INTO user_device_mapping (user_id, device_id) VALUES (3, 'device3'); -> (1, 'device1'), -> (2, 'device2'), -> (3, 'device3'); INSERT 3 Time: 1.261248ms root@127.0.0.1:26257/testdb> 

数据解释:
用户 1 绑定设备 device1。
用户 2 绑定设备 device2。
用户 3 绑定设备 device3。

7.3 然后,进行复杂关联查询

以下是核心查询语句,用于获取每个用户的最新设备数据:
查询逻辑解析
用户信息表(user_info)包含用户的基本信息,如用户名(username)。通过 user_id 与用户设备关联表(user_device_mapping)连接。
用户设备关联表(user_device_mapping)存储用户与设备的绑定关系。通过 device_id 与设备指标表(device_metrics)连接。
设备指标表(device_metrics)存储设备的时间序列数据,如温度(temperature)、湿度(humidity)等。需要提取每个设备的最新数据。
子查询(latest)从 device_metrics 表中提取每个设备的最新时间戳(MAX(time))。通过 GROUP BY device_id 确保每个设备只返回一条记录。
最终联合查询将所有表连接起来,筛选出每个设备的最新数据。
按用户名(u.username)排序,便于阅读和分析。

root@127.0.0.1:26257/testdb> SELECT dm.humidity FROM user_info u JOIN user_device_mapping udm ON u.user_id = udm.user_id JOIN device_metrics dm ON udm.device_id = dm.device_id JOIN ( SELECT device_id, MAX(time) AS m -> ax_time u.username, GROUP BY device_id ) latest ON dm.device_id = latest.device_id AND dm.time = latest.max_time ORDER BY u.username; -> dm.time, -> dm.temperature, -> dm.humidity -> FROM -> user_info u -> JOIN user_device_mapping udm ON u.user_id = udm.user_id -> JOIN device_metrics dm ON udm.device_id = dm.device_id -> JOIN ( -> SELECT -> device_id, -> MAX(time) AS max_time -> FROM -> device_metrics -> GROUP BY -> device_id -> ) latest ON dm.device_id = latest.device_id AND dm.time = latest.max_time -> ORDER BY -> u.username; username | time | temperature | humidity -----------+---------------------------+-------------+----------- alice | 2025-12-25 18:35:00+00:00 | 26 | 44 bob | 2025-05-30 16:50:00+00:00 | 26.5 | 44.4 charlie | 2025-09-12 13:10:00+00:00 | 27.4 | 43.1 (3 rows) Time: 3.899709ms root@127.0.0.1:26257/testdb> 

结果解释:
用户 alice 的设备 device3 在 2025-12-25 18:35:00 的最新数据显示温度为 26℃,湿度为 44%。
用户 bob 的设备 device1 在 2025-05-30 16:50:00 的最新数据显示温度为 26.5℃,湿度为 44.4%。
用户 charlie 的设备 device2 在 2025-09-12 13:10:00 的最新数据显示温度为 27.4℃,湿度为 43.1%。

多表联合查询(JOIN)
通过 JOIN 将多个表(user_info、user_device_mapping、device_metrics)连接起来,实现复杂的数据关联。使用子查询提取每个设备的最新时间戳,确保查询结果的准确性。聚合函数(GROUP BY 和 MAX)使用 GROUP BY 和 MAX 提取每个设备的最新数据。这是时间序列数据分析中的常见模式。排序(ORDER BY)按用户名排序,使结果更具可读性。

三、KWDB 优化和性能对比

1. 连接到 KWDB

启动 KWDB 的 SQL Shell,进入交互式命令行。

root@kaiwudb-experience:/kaiwudb/bin# ./kwbase sql --insecure --host=127.0.0.1 # # Welcome to the KWDB SQL shell. # All statements must be terminated by a semicolon. # To exit, type: \q. # # Server version: KaiwuDB 2.2.0 (x86_64-linux-gnu, built 2025/03/31 07:20:02, go1.16.15, gcc 11.4.0) (same version as client) # Cluster ID: b565096e-c243-4399-8aa0-6ec3ea6b77a5 # # Enter \? for a brief introduction. # root@127.0.0.1:26257/defaultdb> 

2. 创建数据库
2.1 创建一个新的数据库 example_db
root@127.0.0.1:26257/defaultdb> CREATE DATABASE example_db; CREATE DATABASE Time: 5.737184ms root@127.0.0.1:26257/defaultdb> 

2.2 使用 USE example_db; 切换到新创建的数据库。
root@127.0.0.1:26257/defaultdb> USE example_db; SET Time: 682.48µs root@127.0.0.1:26257/example_db> 

3. 创建用户信息表

创建一个用户信息表,用于存储用户的基本信息。
字段说明:
id:主键,自增序列(SERIAL 类型)。
username:用户名,长度限制为 50 字符,不能为空。
email:邮箱地址,长度限制为 100 字符。
age:用户年龄,整数类型。
created_at:记录创建时间,默认值为当前时间戳。

root@127.0.0.1:26257/example_db> CREATE TABLE users ( age INT, -> id SERIAL PRIMARY KEY, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -> username VARCHAR(50) NOT NULL, -> email VARCHAR(100), -> age INT, -> created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP -> ); CREATE TABLE Time: 6.163336ms root@127.0.0.1:26257/example_db> 

4、新插入数据

批量插入 9001 条用户数据。
关键点:
generate_series(1000, 10000)
生成一系列整数(从 1000 到 10000),用作临时 ID。
动态生成用户名和邮箱
‘user_’ || id::TEXT || ‘’ || (floor(random() * 1000))::TEXT:构造随机用户名。
'user
’ || id::TEXT || ‘@test.com’:构造唯一的邮箱地址。
随机生成年龄
floor(25 + random() * 20)::int:生成范围在 25 到 44 之间的随机整数。
批量插入
使用 INSERT INTO … SELECT 语法高效地插入大量数据。

root@127.0.0.1:26257/example_db> INSERT INTO users (username, email, age) 'user_' || id::TEXT || '@test.com', floor(25 + random() * 20)::int FROM generate_series(1000, 10000) AS id; -> SELECT -> 'user_' || id::TEXT || '_' || (floor(random() * 1000))::TEXT, -> 'user_' || id::TEXT || '@test.com', -> floor(25 + random() * 20)::int -> FROM generate_series(1000, 10000) AS id; INSERT 9001 Time: 257.076009ms root@127.0.0.1:26257/example_db> 

image.png

5、查询验证数据

查询表中的前 50 条记录,验证数据插入是否成功。

root@127.0.0.1:26257/example_db> SELECT * FROM users LIMIT 50;
          id          |     username     |         email         | age |            created_at
----------------------+------------------+-----------------------+-----+-----------------------------------
  1064580450243248129 | john_doe         | john@example.com      |  28 | 2025-04-18 05:36:10.606017+00:00
  1064580450243346433 | jane_doe         | jane@example.com      |  32 | 2025-04-18 05:36:10.606017+00:00
  1064580450243379201 | alice_smith      | alice@example.com     |  25 | 2025-04-18 05:36:10.606017+00:00
  1064580450243411969 | bob_jones        | bob@example.com       |  40 | 2025-04-18 05:36:10.606017+00:00
  1064580450243444737 | charlie_brown    | charlie@example.com   |  35 | 2025-04-18 05:36:10.606017+00:00
  1065191668815233025 | john_doe_1       | john1@example.com     |  28 | 2025-04-20 09:24:59.710609+00:00
  1065191668815396865 | jane_doe_2       | jane2@example.com     |  32 | 2025-04-20 09:24:59.710609+00:00
  1065191668815462401 | alice_smith_3    | alice3@example.com    |  25 | 2025-04-20 09:24:59.710609+00:00
  1065191668815527937 | bob_jones_4      | bob4@example.com      |  40 | 2025-04-20 09:24:59.710609+00:00
  1065191668815560705 | charlie_brown_5  | charlie5@example.com  |  35 | 2025-04-20 09:24:59.710609+00:00
  1065191668815593473 | john_doe_6       | john6@example.com     |  29 | 2025-04-20 09:24:59.710609+00:00
  1065191668815659009 | jane_doe_7       | jane7@example.com     |  33 | 2025-04-20 09:24:59.710609+00:00
  1065191668815724545 | alice_smith_8    | alice8@example.com    |  26 | 2025-04-20 09:24:59.710609+00:00
  1065191668815757313 | bob_jones_9      | bob9@example.com      |  41 | 2025-04-20 09:24:59.710609+00:00
  1065191668815790081 | charlie_brown_10 | charlie10@example.com |  36 | 2025-04-20 09:24:59.710609+00:00
  1065191668815822849 | john_doe_11      | john11@example.com    |  30 | 2025-04-20 09:24:59.710609+00:00
  1065191668815888385 | jane_doe_12      | jane12@example.com    |  34 | 2025-04-20 09:24:59.710609+00:00
  1065191668815986689 | alice_smith_13   | alice13@example.com   |  27 | 2025-04-20 09:24:59.710609+00:00
  1065191668816052225 | bob_jones_14     | bob14@example.com     |  42 | 2025-04-20 09:24:59.710609+00:00
  1065191668816084993 | charlie_brown_15 | charlie15@example.com |  37 | 2025-04-20 09:24:59.710609+00:00
  1065191668816117761 | john_doe_16      | john16@example.com    |  28 | 2025-04-20 09:24:59.710609+00:00
  1065191668816183297 | jane_doe_17      | jane17@example.com    |  32 | 2025-04-20 09:24:59.710609+00:00
  1065191668816216065 | alice_smith_18   | alice18@example.com   |  25 | 2025-04-20 09:24:59.710609+00:00
  1065191668816248833 | bob_jones_19     | bob19@example.com     |  40 | 2025-04-20 09:24:59.710609+00:00
  1065191668816314369 | charlie_brown_20 | charlie20@example.com |  35 | 2025-04-20 09:24:59.710609+00:00
  1065191668816347137 | john_doe_21      | john21@example.com    |  29 | 2025-04-20 09:24:59.710609+00:00
  1065191668816379905 | jane_doe_22      | jane22@example.com    |  33 | 2025-04-20 09:24:59.710609+00:00
  1065191668816445441 | alice_smith_23   | alice23@example.com   |  26 | 2025-04-20 09:24:59.710609+00:00
  1065191668816478209 | bob_jones_24     | bob24@example.com     |  41 | 2025-04-20 09:24:59.710609+00:00
  1065191668816510977 | charlie_brown_25 | charlie25@example.com |  36 | 2025-04-20 09:24:59.710609+00:00
  1065191668816576513 | john_doe_26      | john26@example.com    |  30 | 2025-04-20 09:24:59.710609+00:00
  1065191668816609281 | jane_doe_27      | jane27@example.com    |  34 | 2025-04-20 09:24:59.710609+00:00
  1065191668816674817 | alice_smith_28   | alice28@example.com   |  27 | 2025-04-20 09:24:59.710609+00:00
  1065191668816707585 | bob_jones_29     | bob29@example.com     |  42 | 2025-04-20 09:24:59.710609+00:00
  1065191668816740353 | charlie_brown_30 | charlie30@example.com |  37 | 2025-04-20 09:24:59.710609+00:00
  1065191668816773121 | john_doe_31      | john31@example.com    |  28 | 2025-04-20 09:24:59.710609+00:00
  1065191668816838657 | jane_doe_32      | jane32@example.com    |  32 | 2025-04-20 09:24:59.710609+00:00
  1065191668816871425 | alice_smith_33   | alice33@example.com   |  25 | 2025-04-20 09:24:59.710609+00:00
  1065191668816904193 | bob_jones_34     | bob34@example.com     |  40 | 2025-04-20 09:24:59.710609+00:00
  1065191668816936961 | charlie_brown_35 | charlie35@example.com |  35 | 2025-04-20 09:24:59.710609+00:00
  1065191668816969729 | john_doe_36      | john36@example.com    |  29 | 2025-04-20 09:24:59.710609+00:00
  1065191668817002497 | jane_doe_37      | jane37@example.com    |  33 | 2025-04-20 09:24:59.710609+00:00
  1065191668817068033 | alice_smith_38   | alice38@example.com   |  26 | 2025-04-20 09:24:59.710609+00:00
  1065191668817100801 | bob_jones_39     | bob39@example.com     |  41 | 2025-04-20 09:24:59.710609+00:00
  1065191668817133569 | charlie_brown_40 | charlie40@example.com |  36 | 2025-04-20 09:24:59.710609+00:00
  1065191668817166337 | john_doe_41      | john41@example.com    |  30 | 2025-04-20 09:24:59.710609+00:00
  1065191668817199105 | jane_doe_42      | jane42@example.com    |  34 | 2025-04-20 09:24:59.710609+00:00
  1065191668817264641 | alice_smith_43   | alice43@example.com   |  27 | 2025-04-20 09:24:59.710609+00:00
  1065191668817297409 | bob_jones_44     | bob44@example.com     |  42 | 2025-04-20 09:24:59.710609+00:00
  1065191668817330177 | charlie_brown_45 | charlie45@example.com |  37 | 2025-04-20 09:24:59.710609+00:00
(50 rows)

Time: 3.046443ms

root@127.0.0.1:26257/example_db> 

image.png


查询结果:
显示了每条记录的 id、username、email、age 和 created_at 字段。
数据按插入顺序排列,created_at 字段显示了记录的创建时间。

6、数据库优化

在数据库系统中,查询效率是影响性能的关键因素。通过索引优化和统计信息分析,可以显著提升查询速度,尤其是在处理大规模数据时。本案例展示了如何对用户表(users)进行索引优化、统计信息分析以及执行计划查看,以验证优化效果。
为了提高查询效率,我们可以对表进行索引优化。创建索引会增加写入(INSERT/UPDATE/DELETE)的开销,但能大幅提高读取(SELECT)性能。

6.1 为用户名字段添加索引

为 username 和 age 字段创建索引,加速基于这些字段的查询。
username:通常用于精确匹配查询(如 WHERE username = ‘john_doe’)。

root@127.0.0.1:26257/example_db> 
root@127.0.0.1:26257/example_db> CREATE INDEX idx_users_username ON users(username);
CREATE INDEX

Time: 167.695363ms

root@127.0.0.1:26257/example_db> 

image.png

6.1 为年龄字段添加索引

age:常用于范围查询(如 WHERE age > 30)

root@127.0.0.1:26257/example_db> CREATE INDEX idx_users_age ON users(age);
CREATE INDEX

Time: 181.634007ms

root@127.0.0.1:26257/example_db> 

image.png

6.2 分析表结构以获取统计信息

查看表的统计信息,帮助数据库优化器选择最佳查询计划

root@127.0.0.1:26257/example_db> SHOW STATISTICS FOR TABLE users;
  statistics_name | column_names |             created              | row_count | distinct_count | null_count |    histogram_id
------------------+--------------+----------------------------------+-----------+----------------+------------+----------------------
  __auto__        | {id}         | 2025-04-20 12:43:48.429957+00:00 |      9056 |           9016 |          0 | 1065230756859936769
  __auto__        | {username}   | 2025-04-20 12:43:48.429957+00:00 |      9056 |           9045 |          0 | 1065230756879499265
  __auto__        | {age}        | 2025-04-20 12:43:48.429957+00:00 |      9056 |             20 |          0 | 1065230756894179329
  __auto__        | {email}      | 2025-04-20 12:43:48.429957+00:00 |      9056 |           9033 |          0 |                NULL
  __auto__        | {created_at} | 2025-04-20 12:43:48.429957+00:00 |      9056 |              3 |          0 |                NULL
  __auto__        | {id}         | 2025-04-20 13:15:48.569988+00:00 |      9056 |           9016 |          0 | 1065237048780324865
  __auto__        | {username}   | 2025-04-20 13:15:48.569988+00:00 |      9056 |           9045 |          0 | 1065237048801624065
  __auto__        | {email}      | 2025-04-20 13:15:48.569988+00:00 |      9056 |           9033 |          0 |                NULL
  __auto__        | {age}        | 2025-04-20 13:15:48.569988+00:00 |      9056 |             20 |          0 |                NULL
  __auto__        | {created_at} | 2025-04-20 13:15:48.569988+00:00 |      9056 |              3 |          0 |                NULL
  __auto__        | {created_at} | 2025-04-20 13:17:48.654422+00:00 |      9056 |              3 |          0 |                NULL
  __auto__        | {username}   | 2025-04-20 13:17:48.654422+00:00 |      9056 |           9045 |          0 |                NULL
  __auto__        | {id}         | 2025-04-20 13:17:48.654422+00:00 |      9056 |           9016 |          0 | 1065237442265612289
  __auto__        | {age}        | 2025-04-20 13:17:48.654422+00:00 |      9056 |             20 |          0 |                NULL
  __auto__        | {email}      | 2025-04-20 13:17:48.654422+00:00 |      9056 |           9033 |          0 |                NULL
  __auto__        | {id}         | 2025-04-20 13:18:48.747856+00:00 |      9056 |           9016 |          0 | 1065237639201554433
  __auto__        | {username}   | 2025-04-20 13:18:48.747856+00:00 |      9056 |           9045 |          0 | 1065237639226916865
  __auto__        | {email}      | 2025-04-20 13:18:48.747856+00:00 |      9056 |           9033 |          0 |                NULL
  __auto__        | {age}        | 2025-04-20 13:18:48.747856+00:00 |      9056 |             20 |          0 |                NULL
  __auto__        | {created_at} | 2025-04-20 13:18:48.747856+00:00 |      9056 |              3 |          0 |                NULL
  __auto__        | {id}         | 2025-04-20 13:20:48.858779+00:00 |      9056 |           9016 |          0 | 1065238032765943809
  __auto__        | {username}   | 2025-04-20 13:20:48.858779+00:00 |      9056 |           9045 |          0 | 1065238032789766145
  __auto__        | {age}        | 2025-04-20 13:20:48.858779+00:00 |      9056 |             20 |          0 | 1065238032805953537
  __auto__        | {email}      | 2025-04-20 13:20:48.858779+00:00 |      9056 |           9033 |          0 |                NULL
  __auto__        | {created_at} | 2025-04-20 13:20:48.858779+00:00 |      9056 |              3 |          0 |                NULL
(25 rows)

Time: 3.58239ms

root@127.0.0.1:26257/example_db> 

image.png

row_count:表中的总行数(9056 行)。
distinct_count:字段值的唯一性(如 username 的唯一值为 9045,age 的唯一值为 20)。
null_count:字段中 NULL 值的数量(均为 0)。
统计信息的作用:
数据库优化器根据统计信息决定是否使用索引或全表扫描。

6.3 查看执行计划

root@127.0.0.1:26257/example_db> EXPLAIN ANALYZE SELECT * FROM users WHERE username = 'john_doe';
  automatic |                                                                                                                                                                                                                                                                                  json
------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    false   | {
            |
            |   "sql": "EXPLAIN ANALYZE (DISTSQL) SELECT * FROM users WHERE username = 'john_doe'",
            |
            |   "nodeNames": [
            |
            |     "1"
            |
            |   ],
            |
            |   "processors": [
            |
            |     {
            |
            |       "nodeIdx": 0,
            |
            |       "inputs": [],
            |
            |       "core": {
            |
            |         "title": "TableReader/0",
            |
            |         "details": [
            |
            |           "users@idx_users_username",
            |
            |           "Spans: /\"john_doe\"-/\"john_doe\"/PrefixEnd",
            |
            |           "Out: @1",
            |
            |           "rows read: 1",
            |
            |           "stall time: 782µs",
            |
            |           "bytes read: 46 B"
            |
            |         ]
            |
            |       },
            |
            |       "outputs": [],
            |
            |       "stage": 1
            |
            |     },
            |
            |     {
            |
            |       "nodeIdx": 0,
            |
            |       "inputs": [],
            |
            |       "core": {
            |
            |         "title": "JoinReader/1",
            |
            |         "details": [
            |
            |           "users@primary",
            |
            |           "Out: @1,@2,@3,@4,@5",
            |
            |           "rows read: 1",
            |
            |           "stall time: 990µs",
            |
            |           "index rows read: 1",
            |
            |           "index stall time: 509µs"
            |
            |         ]
            |
            |       },
            |
            |       "outputs": [],
            |
            |       "stage": 2
            |
            |     },
            |
            |     {
            |
            |       "nodeIdx": 0,
            |
            |       "inputs": [],
            |
            |       "core": {
            |
            |         "title": "Response",
            |
            |         "details": [
            |
            |           "rows read: 1",
            |
            |           "stall time: 1.651ms"
            |
            |         ]
            |
            |       },
            |
            |       "outputs": [],
            |
            |       "stage": 0
            |
            |     }
            |
            |   ],
            |
            |   "edges": [
            |
            |     {
            |
            |       "sourceProc": 0,
            |
            |       "sourceOutput": 0,
            |
            |       "destProc": 1,
            |
            |       "destInput": 0
            |
            |     },
            |
            |     {
            |
            |       "sourceProc": 1,
            |
            |       "sourceOutput": 0,
            |
            |       "destProc": 2,
            |
            |       "destInput": 0
            |
            |     }
            |
            |   ],
            |
            |   "encodePlan": "eJyUktuO0zAQhu95itHcLKCBJmW7UEtIKRBEUWlLW4nTRpW3HhajxA62I7qq8li8AE-GklDtQWzF3nnG_598n-Qd-h85Ckw_ziej8RRG09Hk0-cU7r8aL1fL95MHsEwn6csVPITXi9k7qDw7Dx_epIu0PRtZMDyHo-_2m1kry0dIaKziqSzYo_iCMWaEpbMb9t66ZrVrA2O1RRERalNWoVlnhBvrGMUOgw45o8CVPMt5wVKx60VIqDhInbefbTkSrbbr9rTesyDhspTGC-id4h7qFB9dm3pzx1_1NjUKCWdVEJDESOjsTw-OpRLQjD7IPIegCxbw9Fn_9y-PhGcXgfeh4xN4gVlNaKtwKeGDPGcUcU3_L_rWavPXM_6XZ-l0Id3FJS0lfUqeUHJMyeAw-XAYdeTaKN7CjWS3vJofRMMmf5tW_y5aC_alNZ6vKx2AjR-fDOLi9r9HdUbI6py7d-Rt5TY8d3bTonTjrO21C8U-dLdxN4xNd9VIXC3HB8v9G-WsvvcnAAD__zF0C4A="
            |
            | }
(1 row)

Time: 4.726964ms

root@127.0.0.1:26257/example_db> 

image.png

image.png

索引使用情况:
查询使用了 idx_users_username 索引,直接定位到目标记录。避免了全表扫描,显著提高了查询效率。
性能指标:
Rows read: 1 行。
Stall time: 索引查找时间(782µs)和主表读取时间(990µs)均较短。
Bytes read: 仅读取了 46 字节的数据。
索引有效减少了 I/O 操作,提升了查询速度。

root@127.0.0.1:26257/example_db> EXPLAIN ANALYZE SELECT * FROM users WHERE age > 30;
  automatic |                                                                                                                                                                                                                                      json
------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    true    | {
            |
            |   "sql": "EXPLAIN ANALYZE (DISTSQL) SELECT * FROM users WHERE age \u003e 30",
            |
            |   "nodeNames": [
            |
            |     "1"
            |
            |   ],
            |
            |   "processors": [
            |
            |     {
            |
            |       "nodeIdx": 0,
            |
            |       "inputs": [],
            |
            |       "core": {
            |
            |         "title": "TableReader/0",
            |
            |         "details": [
            |
            |           "users@primary",
            |
            |           "Spans: -",
            |
            |           "Filter: @4 \u003e 30:::INT8",
            |
            |           "rows read: 9056",
            |
            |           "stall time: 12.132ms",
            |
            |           "bytes read: 733 KiB"
            |
            |         ]
            |
            |       },
            |
            |       "outputs": [],
            |
            |       "stage": 1
            |
            |     },
            |
            |     {
            |
            |       "nodeIdx": 0,
            |
            |       "inputs": [],
            |
            |       "core": {
            |
            |         "title": "Response",
            |
            |         "details": [
            |
            |           "rows read: 6285",
            |
            |           "stall time: 23.208ms"
            |
            |         ]
            |
            |       },
            |
            |       "outputs": [],
            |
            |       "stage": 0
            |
            |     }
            |
            |   ],
            |
            |   "edges": [
            |
            |     {
            |
            |       "sourceProc": 0,
            |
            |       "sourceOutput": 0,
            |
            |       "destProc": 1,
            |
            |       "destInput": 0
            |
            |     }
            |
            |   ],
            |
            |   "encodePlan": "eJyMkE9vm0AQxe_9FKM5tdXW5U_tunuy22IVlWIXkPon4bCGkYUELNlZlFgW3z0yKHISKVKO8-bt29-bE_JNjRKDv7toHcawjtfRv_8BvP0epln6O3oHaRAF3zJ4D5tk-wt6JsPw50eQBKAOBNe94_gEvoMCW11SrBpilFfoYi6wM7ogZm3O0mk0hOUdSkdg1Xa9Pcu5wEIbQnlCW9maUGKm9jUlpEoyH8_BJVlV1WPs-P-qM1WjzBEFpp1qWcIHFLipaktGwurThUpKGcbZEgUafctgSJUSvjjzBQpkq-oabNWQBNebub7XMArcHy09OD_7PvysvmI-CNS9vRCzVQdC6Q7i9a0S4k63TE8LPeJaeMv5My7Pn3nOsuEXCZwhF0jlgaYLs-5NQTujixFnGrfju1Eoie20dachbKfVkA9v7gMAAP__ZG2jlw=="
            |
            | }
(1 row)

Time: 25.207949ms

root@127.0.0.1:26257/example_db> 

image.png

image.png


索引使用情况:
查询使用了 idx_users_age 索引,快速定位符合条件的记录。范围查询的效率依赖于字段的分布情况(如唯一值数量)。
性能指标:
Rows read: 返回多行数据(具体数量取决于条件匹配的记录数)。
Stall time: 时间开销较大,可能与范围查询涉及的记录数较多有关。
索引在范围查询中仍然有效,但性能受字段分布影响较大。

7、性能对比

为了更好地理解 KWDB 的性能优势,我们可以进行一些简单的性能测试。这里我们将比较有无索引情况下的查询性能差异,并结合大数据量进行测试。

7.1 清除现有索引
root@127.0.0.1:26257/example_db> DROP INDEX idx_users_username;
NOTICE: the data for dropped indexes is reclaimed asynchronously
HINT: The reclamation delay can be customized in the zone configuration for the table.
DROP INDEX

Time: 94.822581ms

root@127.0.0.1:26257/example_db> 

image.png

root@127.0.0.1:26257/example_db> DROP INDEX idx_users_age;
NOTICE: the data for dropped indexes is reclaimed asynchronously
HINT: The reclamation delay can be customized in the zone configuration for the table.
DROP INDEX

Time: 92.224639ms

root@127.0.0.1:26257/example_db> 

image.png

7.2 执行查询并记录时间
root@127.0.0.1:26257/example_db> EXPLAIN ANALYZE SELECT * FROM users WHERE username = 'john_doe';
  automatic |                                                                                                                                                                                                                                        json
------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    true    | {
            |
            |   "sql": "EXPLAIN ANALYZE (DISTSQL) SELECT * FROM users WHERE username = 'john_doe'",
            |
            |   "nodeNames": [
            |
            |     "1"
            |
            |   ],
            |
            |   "processors": [
            |
            |     {
            |
            |       "nodeIdx": 0,
            |
            |       "inputs": [],
            |
            |       "core": {
            |
            |         "title": "TableReader/0",
            |
            |         "details": [
            |
            |           "users@primary",
            |
            |           "Spans: -",
            |
            |           "Filter: @2 = 'john_doe':::STRING",
            |
            |           "rows read: 9056",
            |
            |           "stall time: 9.658ms",
            |
            |           "bytes read: 733 KiB"
            |
            |         ]
            |
            |       },
            |
            |       "outputs": [],
            |
            |       "stage": 1
            |
            |     },
            |
            |     {
            |
            |       "nodeIdx": 0,
            |
            |       "inputs": [],
            |
            |       "core": {
            |
            |         "title": "Response",
            |
            |         "details": [
            |
            |           "rows read: 1",
            |
            |           "stall time: 13.062ms"
            |
            |         ]
            |
            |       },
            |
            |       "outputs": [],
            |
            |       "stage": 0
            |
            |     }
            |
            |   ],
            |
            |   "edges": [
            |
            |     {
            |
            |       "sourceProc": 0,
            |
            |       "sourceOutput": 0,
            |
            |       "destProc": 1,
            |
            |       "destInput": 0
            |
            |     }
            |
            |   ],
            |
            |   "encodePlan": "eJyMkF9r1UAQxd_9FMN5qcpak156tQtCr5pqMKY1CfiPINvsUCNJNu5s0HLJd5cmiFYQ-rZzztnd35k95HsHjeTDRbZLc9rlu-zjp4Tuv0zLqnyXPaAyyZIXFT2ks-L8LU3CXuj966RIlvNgeqZndPDNfR2-WMcHUBic5dz0LNCfEaNWGL1rWMT5G2m_BFL7EzpSaIdxCjdyrdA4z9B7hDZ0DI3KXHZcsLHsH0dQsBxM2y3PLhyno29746-hUI5mEE2PoHDWdoG9ptOjW2Ba67Iq0vwVFLz7IeTZWE0n0fEWChJM11Foe9Z0crg9ftoLFC6vA_8OPtls6E37HPWs4Kbwh1qCuWLoeFZ3b1awjG4Qvl3qL6z4H6Z4cxhtj3r57_fRXCuwveJ1xeIm3_CFd83Cso7ny71FsCxhdeN1SIfVmuv53q8AAAD__9JdqQI="
            |
            | }
(1 row)

Time: 14.958257ms

root@127.0.0.1:26257/example_db> 

image.png

image.png

root@127.0.0.1:26257/example_db> EXPLAIN ANALYZE SELECT * FROM users WHERE age > 30;
  automatic |                                                                                                                                                                                                                              json
------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    false   | {
            |
            |   "sql": "EXPLAIN ANALYZE (DISTSQL) SELECT * FROM users WHERE age \u003e 30",
            |
            |   "nodeNames": [
            |
            |     "1"
            |
            |   ],
            |
            |   "processors": [
            |
            |     {
            |
            |       "nodeIdx": 0,
            |
            |       "inputs": [],
            |
            |       "core": {
            |
            |         "title": "TableReader/0",
            |
            |         "details": [
            |
            |           "users@idx_users_age_covering",
            |
            |           "Spans: /31-",
            |
            |           "rows read: 6285",
            |
            |           "stall time: 13.034ms",
            |
            |           "bytes read: 503 KiB"
            |
            |         ]
            |
            |       },
            |
            |       "outputs": [],
            |
            |       "stage": 1
            |
            |     },
            |
            |     {
            |
            |       "nodeIdx": 0,
            |
            |       "inputs": [],
            |
            |       "core": {
            |
            |         "title": "Response",
            |
            |         "details": [
            |
            |           "rows read: 6285",
            |
            |           "stall time: 22.803ms"
            |
            |         ]
            |
            |       },
            |
            |       "outputs": [],
            |
            |       "stage": 0
            |
            |     }
            |
            |   ],
            |
            |   "edges": [
            |
            |     {
            |
            |       "sourceProc": 0,
            |
            |       "sourceOutput": 0,
            |
            |       "destProc": 1,
            |
            |       "destInput": 0
            |
            |     }
            |
            |   ],
            |
            |   "encodePlan": "eJyMkF9r2zAUxd_3KS73aRtaIsfLCHpatnnMzEsyO7C_JijWxRhsy9WV25Tg715iU0ofWvqme-7R0e_ojHxVo8Lo9y5ZxxtYb9bJn78RvP4SZ_vsZ_IGsiiJPu_hLXxNtz-gZ3IMv75FaQS6JPjfSxkShBIFttbQRjfEqP5hgLnAztmCmK27SOfREJsTKimwarveX-RcYGEdoTqjr3xNqHCvjzWlpA25-SXYkNdVPcaO73-szOkwng66pENhr8lVbYkCs063rGAeBu9QoLM3DI60UfBhsVqiQPa6rsFXDSkIwpkM3zeMAo-3nu6dSxnC9-oT5oNA2_sHSva6JFTBIF7eJCXubMv0uMTzXIvFbCXDhp8kkEMukExJ06-y7V1BO2eLEWcat-O9UTDEftoG0xC302rIh1d3AQAA___0mKJh"
            |
            | }
(1 row)

Time: 24.651309ms

root@127.0.0.1:26257/example_db> 

image.png

image.png

7.3 重新添加索引

添加覆盖索引(username)
通过 STORING 子句将查询所需字段直接包含在索引中,避免回表:

root@127.0.0.1:26257/example_db> CREATE INDEX idx_users_username_covering ON users(username)
                              ->   STORING (email, age, created_at);
CREATE INDEX

Time: 342.749645ms

root@127.0.0.1:26257/example_db> 

image.png

添加覆盖索引(age)
将查询所需的所有字段包含在索引中,避免回表操作:

root@127.0.0.1:26257/example_db> CREATE INDEX idx_users_age_covering ON users (age)   STORING (username, email, created_at);
CREATE INDEX

Time: 309.510184ms

root@127.0.0.1:26257/example_db> 

image.png

● 作用:索引直接包含 username, email, created_at,无需回表。
● 适用场景:频繁的 SELECT * + WHERE age 查询。

7.4 再次执行查询并记录时间

验证执行计划
检查优化器是否选择新索引:

root@127.0.0.1:26257/example_db> EXPLAIN ANALYZE SELECT * FROM users WHERE username = 'john_doe';
  automatic |                                                                                                                                                                                                                                        json
------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    false   | {
            |
            |   "sql": "EXPLAIN ANALYZE (DISTSQL) SELECT * FROM users WHERE username = 'john_doe'",
            |
            |   "nodeNames": [
            |
            |     "1"
            |
            |   ],
            |
            |   "processors": [
            |
            |     {
            |
            |       "nodeIdx": 0,
            |
            |       "inputs": [],
            |
            |       "core": {
            |
            |         "title": "TableReader/0",
            |
            |         "details": [
            |
            |           "users@idx_users_username_covering",
            |
            |           "Spans: /\"john_doe\"-/\"john_doe\"/PrefixEnd",
            |
            |           "rows read: 1",
            |
            |           "stall time: 382µs",
            |
            |           "bytes read: 77 B"
            |
            |         ]
            |
            |       },
            |
            |       "outputs": [],
            |
            |       "stage": 1
            |
            |     },
            |
            |     {
            |
            |       "nodeIdx": 0,
            |
            |       "inputs": [],
            |
            |       "core": {
            |
            |         "title": "Response",
            |
            |         "details": [
            |
            |           "rows read: 1",
            |
            |           "stall time: 463µs"
            |
            |         ]
            |
            |       },
            |
            |       "outputs": [],
            |
            |       "stage": 0
            |
            |     }
            |
            |   ],
            |
            |   "edges": [
            |
            |     {
            |
            |       "sourceProc": 0,
            |
            |       "sourceOutput": 0,
            |
            |       "destProc": 1,
            |
            |       "destInput": 0
            |
            |     }
            |
            |   ],
            |
            |   "encodePlan": "eJyMkN2O0zAUhO95CmtuCsioDUUUWUKiQBCRQluSSvw1itz4UIJSO9gOFFV5rH2BfbJVHVWrXuxq787MGdvf-Aj3p4FA_HWVzpMFmy_m6bfvMXv8PsnX-ef0CcvjNH63Zk_Zh2z5iXWOrGNfPsZZHGYt98Res9Fv80uXytAIHNooWsg9OYgfiFBwtNZU5JyxJ-sYAok6QEw4at12_mQXHJWxBHGEr31DEFjLbUMZSUV2PAGHIi_rJlwbON7U6lCGqTyzlJX5S7bWO3DkrdROsPEGZ7oNnl2o8crSz_oQawUOa_45ZkkqwSJwOC-bhvl6T4JNXz2_vnLg2P73dA7NZuwtip7DdP62g_NyRxBRzx_eMyPXGu3osuI9PC9eTk88dz0-6QsOUjsavtuZzla0sqYKJINchnPBUOT8sI0Gkehh1Rf9o5sAAAD__6z_s0E="
            |
            | }
(1 row)

Time: 1.61164ms

root@127.0.0.1:26257/example_db> 

image.png

image.png

root@127.0.0.1:26257/example_db> EXPLAIN ANALYZE SELECT * FROM users WHERE age > 30;
  automatic |                                                                                                                                                                                                                              json
------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    false   | {
            |
            |   "sql": "EXPLAIN ANALYZE (DISTSQL) SELECT * FROM users WHERE age \u003e 30",
            |
            |   "nodeNames": [
            |
            |     "1"
            |
            |   ],
            |
            |   "processors": [
            |
            |     {
            |
            |       "nodeIdx": 0,
            |
            |       "inputs": [],
            |
            |       "core": {
            |
            |         "title": "TableReader/0",
            |
            |         "details": [
            |
            |           "users@idx_users_age_covering",
            |
            |           "Spans: /31-",
            |
            |           "rows read: 6285",
            |
            |           "stall time: 4.412ms",
            |
            |           "bytes read: 503 KiB"
            |
            |         ]
            |
            |       },
            |
            |       "outputs": [],
            |
            |       "stage": 1
            |
            |     },
            |
            |     {
            |
            |       "nodeIdx": 0,
            |
            |       "inputs": [],
            |
            |       "core": {
            |
            |         "title": "Response",
            |
            |         "details": [
            |
            |           "rows read: 6285",
            |
            |           "stall time: 8.107ms"
            |
            |         ]
            |
            |       },
            |
            |       "outputs": [],
            |
            |       "stage": 0
            |
            |     }
            |
            |   ],
            |
            |   "edges": [
            |
            |     {
            |
            |       "sourceProc": 0,
            |
            |       "sourceOutput": 0,
            |
            |       "destProc": 1,
            |
            |       "destInput": 0
            |
            |     }
            |
            |   ],
            |
            |   "encodePlan": "eJyMkF9vmzAUxd_3Ka7u0zZ5CYRki_y0bGMaGksyiLT1D4ocfIWQAFNf06aK-O5VQFXVh1Z98z33-Ph3fEK-qVBi-H8br6I1rNar-OIyhPc_onSX_o0_QBrG4fcdfISfyeYPdEyW4d-vMAlBFQTXnecFBIGHAhujaa1qYpRX6GMmsLUmJ2Zjz9JpMET6iNITWDZt585yJjA3llCe0JWuIpS4U4eKElKa7PQcrMmpshpih_e_lvq4H057VdA-N7dky6ZAgWmrGpYwDfxPKNCaOwZLSkv4PFsuUCA7VVXgypokzCdzf1YzCjzcO3o0LrwAfpffMOsFms49QbJTBaH0e_H2Iglxaxqm5x1ex1pOfO9LzS8CeH0mkHRB45-y6WxOW2vygWYcN8O9QdDEbtz64xA146rP-ncPAQAA___iiKIC"
            |
            | }
(1 row)

Time: 9.135709ms

image.png

image.png

性能对比分析:
● 在没有索引的情况下,查询需要扫描整个表,性能较差。
● 添加索引后,查询速度显著提升,特别是对于大数据量的场景。

7.5 统计不同年龄段的用户数量
root@127.0.0.1:26257/example_db> SELECT 
        WHEN age BETWEEN 18 AND 25 THEN '18-25'
        WHEN age BETWEEN 26 AND 35 THEN '26-35'
        WHEN age BETWEEN 36 AND 45 THEN '36-45'
        ELSE '46+'
    END AS age_group,
                              ->     CASE 
    COUNT(*) AS user_count
FROM users
GROUP BY age_group;
                              ->         WHEN age BETWEEN 18 AND 25 THEN '18-25'
                              ->         WHEN age BETWEEN 26 AND 35 THEN '26-35'
                              ->         WHEN age BETWEEN 36 AND 45 THEN '36-45'
                              ->         ELSE '46+'
                              ->     END AS age_group,
                              ->     COUNT(*) AS user_count
                              -> FROM users
                              -> GROUP BY age_group;
  age_group | user_count
------------+-------------
  36-45     |       4100
  18-25     |        479
  26-35     |       4477
(3 rows)

Time: 11.981512ms

root@127.0.0.1:26257/example_db> 

image.png

  • 结果
    • 36-45 岁:4100 人
    • 26-35 岁:4477 人
    • 18-25 岁:479 人
  • 性能11.98ms,依赖全表扫描或索引覆盖。
7.6 统计每个用户的平均年龄
root@127.0.0.1:26257/example_db> SELECT AVG(age) AS average_age FROM users;
       average_age
-------------------------
  34.480675795053003534
(1 row)

Time: 8.359482ms

image.png

  • 结果:34.48 岁
  • 性能8.36ms,快速聚合无需复杂过滤。
7.7 统计每个用户的注册时间分布
root@127.0.0.1:26257/example_db> SELECT 
    COUNT(*) AS user_count
FROM users
                              ->     created_at,
GROUP BY created_at
ORDER BY created_at;
                              ->     COUNT(*) AS user_count
                              -> FROM users
                              -> GROUP BY created_at
                              -> ORDER BY created_at;
             created_at            | user_count
-----------------------------------+-------------
  2025-04-18 05:36:10.606017+00:00 |          5
  2025-04-20 09:24:59.710609+00:00 |         50
  2025-04-20 12:43:10.985752+00:00 |       9001
(3 rows)

Time: 8.570607ms

root@127.0.0.1:26257/example_db> 

image.png

  • 结果:数据集中在 3 个时间点(2025-04-18、2025-04-20)。
  • 性能8.57ms,分组效率高。
8、KWDB 优化与性能对比总结分析
8.1 索引优化效果对比
查询类型无索引耗时普通索引耗时覆盖索引耗时优化效果
WHERE username=~14.96ms~3.28ms~1.61ms覆盖索引提升 89%(对比无索引)
WHERE age > 30~3.08ms~16.86ms~9.14ms覆盖索引提升 46%(对比普通索引)
8.2 关键优化分析

a. WHERE username= 精确查询

  • 普通索引:通过 idx_users_username 直接定位记录,减少全表扫描,耗时从 14.96ms 降至 3.28ms
  • 覆盖索引:进一步消除回表操作(STORING email, age, created_at),耗时降至 1.61ms,性能提升 89%
  • 执行计划:明确使用 users@idx_users_username_covering,仅读取索引数据(77 B),无需回表。

b. WHERE age > 30 范围查询

  • 普通索引问题
    • 数据分布广泛(年龄>30 占比约 70%),优化器认为全表扫描更高效。
    • 普通索引需回表,耗时 16.86ms,性能甚至差于无索引场景(3.08ms)。
  • 覆盖索引优势
    • 包含所有查询字段(STORING username, email, created_at),避免回表,耗时降至 9.14ms
    • 数据读取量从 733 KiB(全表)减少至 503 KiB(索引内直接读取)。
8.3 优化结论

a. 覆盖索引的核心价值

  • 消除回表操作,减少 IO 开销,尤其适用于高频的 SELECT * 查询。
  • 示例:WHERE username= 查询性能提升至 1.61msWHERE age > 30 提升至 9.14ms

b. 普通索引的局限性

  • 当查询覆盖大量数据时(如范围覆盖 70% 行),可能被优化器忽略。
  • 需结合 ANALYZE 更新统计信息,确保优化器决策准确。

c. 数据分布影响

  • 年龄字段唯一值少(20 个),范围查询需谨慎选择索引策略。
  • 高频查询建议使用覆盖索引,低频查询可保留普通索引。
8.4 建议与扩展

a. 定期更新统计信息
– 确保优化器基于最新数据分布决策

b. 冷热数据分离

  • 按时间分区(如 created_at),减少活跃数据集大小。

c. 业务逻辑优化

  • 避免 SELECT *,仅请求必要字段,降低 IO 压力。

d. 分布式特性探索

  • 若 KWDB 为分布式架构,可研究数据分片对查询性能的影响。
8.5 最终性能对比图
查询场景 | 无索引 | 普通索引 | 覆盖索引 ------------------------------------------------ WHERE username= | 14.96ms | 3.28ms | 1.61ms WHERE age > 30 | 3.08ms | 16.86ms | 9.14ms 

通过覆盖索引和统计信息优化,KWDB 在关键查询场景中展现了显著的性能提升,尤其在高频精确匹配和大范围扫描场景下表现优异。

结论

本文详细介绍了如何在 CentOS 7 环境下安装和配置 KWDB 2.2.0,并通过一系列实际操作展示了其强大的功能和灵活性。无论是创建库、表,还是进行数据库优化和性能对比,KWDB 都展现出了卓越的性能和灵活性。希望这篇文档能够帮助读者更好地理解和应用 KWDB,同时也期待更多开发者加入我们的社区,共同探索分布式多模数据库的未来。
通过本文的学习,你已经掌握了从基础安装到高级优化的全过程。让我们一起“码”上出发,用键盘构建通向技术与创新的桥梁!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

shunwahma

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值