KingbaseES迁移推荐:MySQL数据库、Schema、用户对比

2026-06-09阅读 0热度 0
其他

在KingbaseES中,将连接目标、对象位置和用户身份视为三个独立维度,能避免大量误操作。

先创建一个普通用户 app_user 和一个数据库 app_db。如果沿用MySQL的习惯,常被误认为:连上 app_db 后,表自然就建在该库下。逻辑上看似成立,实际编写SQL时,各种问题会接踵而至。

KingbaseES里,连接目标、对象命名空间、执行用户是三个独立概念:

database 决定连接入口;schema 划分表、视图、函数等对象的逻辑归属;user/role 决定当前操作的执行身份。

MySQL中常把 database 直接当作命名空间,db_name.table_name 写法很普遍。而KingbaseES需要优先理解 schema.table 的层级关系。不厘清这点,极易出现表存在但查不到、同名表数据不一致、切换用户后对象看不全等典型问题。

这并非理论洁癖。实际开发中,大部分初级错误并非SQL函数不会写,而是连错了库、表建错了位置、查错了对象。MySQL里执行 use app_db; 后,show tables; 的结果,直觉上就是“当前库的全部表”。但到了KingbaseES,连接上 app_db 后,还需主动确认:当前schema是什么?默认的对象搜索顺序如何?

只操作单表时,差异不明显。一旦涉及数据迁移、按模块拆分schema、或为不同用户分配对象,差异就立刻凸显。一个数据库里完全可能同时存在 public.t_orderarchive.t_orderreport.t_order。不带schema前缀的 select * from t_order 到底指向哪张表,无法单凭表名判断。

下面实验仅用两个核心对象:普通用户 app_user 和一个数据库 app_db。特意复用表名 t_schema_demo,将其分别创建在 publicapp_schema 下。这样能最小化变量:相同database、相同user、相同表名,仅因schema和 search_path 不同,查询结果就产生差异。

当前连接不仅包含数据库名

用普通用户连接数据库:

ksql -h 127.0.0.1 -p 54321 -U app_user -d app_db

进入 ksql 后查询三个关键值:

select current_database(), current_user, current_schema();show search_path;

查询结果清晰显示:当前数据库为 app_db,当前用户为 app_user,当前schema为 publicsearch_path 值为 "$user", public

查看当前 database user schema查看当前 database user schema

这组结果印证了三个概念是分离的。连接命令的 -d app_db 仅决定当前database;登录参数的 -U app_user 决定当前用户;不写前缀建表时,最终落点则取决于当前schema和 search_path

"$user", public 的查找顺序是:优先查找与当前用户同名的schema,若不存在,则使用 public。当前环境中没有 app_user 这个schema,因此 current_schema() 返回 public

这一步对MySQL用户至关重要。连上 app_db 并不意味着后续所有对象都直接挂在该库下,表最终会归属于某个特定的schema。

可以将这组信息提炼为一句话:app_user 以指定用户身份连接到 app_db,当前默认的创建和查找对象位置是 public schema。三个值分别回答了三个核心问题:

  • current_database():当前连接的数据库
  • current_user:当前执行操作的用户
  • current_schema():当前默认使用的schema

show search_path; 则回答了另一个问题:不带schema前缀时,数据库按什么顺序查找对象。该配置不仅是状态显示,它直接决定了建表和查表的行为。

不指定schema,表会落入默认位置

直接创建一张表:

drop table if exists t_schema_demo;create table t_schema_demo(id int, name varchar(50));insert into t_schema_demo values (1, 'from default schema');

dtd 查看对象:

dt
d t_schema_demo

同时查询系统视图:

select schemaname, tablename, tableowner
from sys_tables
where tablename = 't_schema_demo';

结果直接证明 t_schema_demo 位于 public 下,所有者是 app_user

默认 schema 下建表默认 schema 下建表

这正是 search_path 生效的结果。建表语句未指定 public.t_schema_demo,但当前默认schema是 public,表自然落入其中。

用MySQL思维理解时,容易产生错觉:已连接 app_db,表应直接在库里。更准确的说法是:当前连接处于 app_db,表对象属于该库内的 public schema。

这意味着,database是外层连接边界,schema才是真正的对象命名空间。后续执行 select * from t_schema_demo 时,若不带schema前缀,数据库会依据当前搜索路径进行查找。

这里的 dt 输出也能看出门道。它不仅列出表名,还附带schema信息。当前结果中,已有的 t_ksql_conn_demo 和新创建的 t_schema_demo 都在 public 下,所有者均为 app_user。这说明“谁创建”和“建在哪个schema”是两码事:当前用户是 app_user,对象所有者为 app_user,但对象所在的schema是 public

编写DDL前,最好先确认这三要素。仅知道“当前连的是 app_db”远远不够,至少还要清楚默认schema是什么。否则后续清理对象时,可能会发现同一个库里存在多个schema,表名也不唯一。

再创建一个 app_schema

接着创建一个新的schema:

create schema app_schema authorization app_user;

再次查询当前数据库中的相关schema:

select schema_name
from information_schema.schemata
where schema_name in ('public', 'app_schema');

结果中可以看到 publicapp_schema

创建 app_schema创建 app_schema

app_schema 并非新数据库,它只是 app_db 内的一个命名空间。authorization app_user 表示该schema归 app_user 所有。

这一步无需深入展开权限体系。只需记住一点:同一个database下可以容纳多个schema。表名、视图名、函数名等对象,都在schema这一层进行组织。

authorization app_user 并非可有可无的修饰。它让 app_schema 这个命名空间属 app_user 所有。后续在该schema下建表时,逻辑更贴近日常开发:普通用户连接自己的数据库,在自己的schema中放置对象。完整的权限控制还可以继续细化,这里先打通对象层级。

在实际项目中,schema常用于隔离。例如,一个库里可以分业务表、报表表、中间表,或迁移时将旧系统对象放入独立schema。这样既无需为每个模块拆成独立数据库,也能有效避免对象名冲突。

同一个 database 内允许存在同名表

现在显式将表创建到 app_schema 下:

create table app_schema.t_schema_demo(id int,name varchar(50));
insert into app_schema.t_schema_demo values (2, 'from app_schema');

再查询 information_schema.tables

select table_schema, table_name
from information_schema.tables
where table_name = 't_schema_demo'
order by table_schema;

结果中出现了两行:app_schema | t_schema_demopublic | t_schema_demo

不同 schema 下的同名表不同 schema 下的同名表

这清晰展示了schema的作用。同一个 app_db 内,public.t_schema_demoapp_schema.t_schema_demo 可以共存。它们表名相同,但完整对象名不同。

这与MySQL中 database.table 的直觉不同。在KingbaseES中,提及对象时,更常见的规范是 schema_name.table_name。如果仅写表名,数据库无法自动判断你要查询哪个schema下的表,它会按照 search_path 的顺序进行查找。

同名表实验有助于打破MySQL的一个惯性:同一个“库”中表名必须唯一。这里并不是同一个schema里允许同名表,而是同一个database内不同schema允许同名对象。完整对象名分别为 public.t_schema_demoapp_schema.t_schema_demo。写出完整名称后,它们自然不冲突。后续进行SQL排查时,如果只看到一个裸表名,不要立刻认为它指向唯一对象。应先查对象归属,再看搜索路径。

加上 schema 前缀,查询目标更明确

分别查询两张同名表:

select * from public.t_schema_demo;
select * from app_schema.t_schema_demo;

前一张表返回 1 | from default schema,后一张表返回 2 | from app_schema

使用 schema 前缀查询同名表使用 schema 前缀查询同名表

加上 schema.table 前缀后,查询目标十分明确,不受当前 search_path 顺序影响。

日常编写业务SQL时,不一定每条都要带schema前缀。很多项目通过默认schema或连接参数固定环境。但在排查问题、编写迁移脚本、执行跨schema查询时,显式写出schema能极大减少歧义。

以下几种场景最好写出全名:迁移脚本、初始化脚本、定时任务、跨schema查询、临时排查SQL。这些SQL通常在不同账号、不同终端、不同工具中执行,不能假设每次会话的 search_path 都相同。写成 app_schema.t_schema_demo 虽然稍长,但能确保上下文清晰。

尤其在多人共用测试库时,写明schema能避免大量无意义的来回确认,也有助于后续的对象清理和问题复盘。

这也是迁移时容易踩的坑。MySQL里从 db1.table1 迁移到KingbaseES,不能机械地改为 database.table。更常见的做法是:连接到目标database,将对象放入指定schema,然后用 schema.table 进行访问。具体设计要依据项目是否需要多schema、是否要保留原库名、是否需要隔离临时迁移对象。

search_path 影响无前缀查询

现在不带schema前缀,直接查询:

select * from t_schema_demo;

这条SQL查询哪张表,完全取决于当前 search_path

先将 app_schema 置于路径首位:

set search_path to app_schema, public;
show search_path;
select * from t_schema_demo;

返回的是 app_schema.t_schema_demo 的数据:2 | from app_schema

再将 public 置于路径首位:

set search_path to public, app_schema;
show search_path;
select * from t_schema_demo;

返回结果变为 public.t_schema_demo 的数据:1 | from default schema

search_path 影响未加前缀查询search_path 影响未加前缀查询

这能解释很多看似奇怪的问题。表存在,查询也没报错,但结果并非预期表的数据,原因可能不是SQL写错,而是无前缀表名被 search_path 解析到了另一个schema。

开发阶段如果只有一个schema,问题不明显。一旦出现多schema、迁移临时schema、按用户隔离schema,search_path 就会成为关键因素。

这个实验中,两次查询的SQL都是 select * from t_schema_demo;,SQL文本未变,结果却不同。变化来自前面的 set search_path 命令。这类问题在日志中不易一眼看出。只看业务SQL,会以为查的是同一张表;只有补上当时会话的 search_path,才能解释结果为何不同。因此,排查“查错表”时,show search_path; 应与 current_database()current_user 一同查看。

换成 system 用户,查看同一个 app_db

退出 app_user 后,以 system 用户连接同一个数据库:

ksql -h 127.0.0.1 -p 54321 -U system -d app_db

再查询当前位置:

select current_database(), current_user, current_schema();

结果变为 app_db | system | public

继续查看 t_schema_demo 的归属:

select table_schema, table_name
from information_schema.tables
where table_name = 't_schema_demo'
order by table_schema;

仍然能看到 app_schema | t_schema_demopublic | t_schema_demo

system 查看同一数据库对象system 查看同一数据库对象

切换用户不等于切换数据库,也不等于将对象搬移到别的schema。system 仅改变了当前执行SQL的身份,连接目标仍是 app_db,对象仍在 publicapp_schema 下。

这里先不细讲权限授权。仅看这组结果,已足够说明:database、schema、user 是三个不同的概念。

换成 system 后,current_user 变了,但 current_database() 仍是 app_db,对象归属也未变。这清晰划分了user和database的边界。用户不是数据库,数据库也不是用户。用户只是当前会话执行SQL的身份,它影响能否查看、修改、以及默认schema的解析,但不会因为换用户而将同一数据库内的对象改名或搬移。

这也是为什么不建议长期使用管理员用户进行日常实验。管理员用户能查看更多内容,也能绕过部分权限限制。用它排查问题可以,但模拟普通应用连接时会产生偏差。准备 app_userapp_db,就是为了让这些实验更贴近日常开发账号。

与 MySQL 习惯对照

若从MySQL迁移过来,可用下表调整直觉:

MySQL 常见理解 KingbaseES 需要拆分理解
database 常被当作命名空间 database 是连接目标
database.table schema.table 更为主流
use db ksql 中用 \c 切换连接
show tables \dt 或 information_schema.tables
当前库 current_database()
当前用户 current_user
默认 schema current_schema()
对象查找路径 search_path

这并非否定MySQL的方式,而是两种系统的对象层级不同。MySQL中看到“库”,通常直接联想到一组表;KingbaseES中连接到database后,还需追问:当前schema是哪个?表实际在哪个schema下?当前用户是否有权限访问它?

前面实验的结果可以串联理解:

  • app_db:当前连接的database
  • app_user / system:当前执行SQL的user
  • public / app_schema:表所在的具体schema
  • t_schema_demo:两个schema下均可存在的表名
  • search_path:不写schema前缀时的查找顺序

今后遇到“表不存在”“查询结果不符预期”“切换用户后对象看不见”等问题,不要只盯着表名。先查 current_database()current_usercurrent_schema(),再看 search_path 和对象的实际归属,很多问题会迎刃而解。

建议固定排查顺序:

select current_database(), current_user, current_schema();
show search_path;
select table_schema, table_name
from information_schema.tables
where table_name = '<表名>';

如果对象确实存在,再检查权限;如果对象在另一个schema,则需决定是修改SQL加前缀,还是调整当前会话的 search_path。切勿一上来就怀疑表丢失,或直接重建同名表。schema未看清时,重建对象反而会使现场更混乱。

例如,应用报“表不存在”,不要急着执行 create table。如果表在 app_schema,而连接进来默认搜索的是 public,裸写 select * from t_schema_demo 就可能找不到目标。此时有两个解决方案:SQL中写成 app_schema.t_schema_demo,或在该连接会话中将 app_schema 加入 search_path。两种方式都能解决问题,但含义不同。前者目标最明确,后者更依赖会话配置。

再比如查询结果不对,也不一定是数据被改坏。同名表同时存在时,public.t_schema_demoapp_schema.t_schema_demo 都能正常查询,只是数据来源不同。SQL不带schema前缀时,结果随 search_path 变化。该问题在测试库里不显眼,但到了迁移验证、报表库、临时表整理时,会非常令人头疼。

免责声明

本网站新闻资讯均来自公开渠道,力求准确但不保证绝对无误,内容观点仅代表作者本人,与本站无关。若涉及侵权,请联系我们处理。本站保留对声明的修改权,最终解释权归本站所有。

相关阅读

更多
欢迎回来 登录或注册后,可保存提示词和历史记录
登录后可同步收藏、历史记录和常用模板
注册即表示同意服务条款与隐私政策