MySQL和KingbaseES中連接、對象命名空間及用戶權(quán)限的區(qū)別
先準(zhǔn)備一個(gè)普通用戶 app_user 和一個(gè)數(shù)據(jù)庫 app_db。如果按 MySQL 的習(xí)慣看,很容易把事情理解成:連上 app_db,表就建在 app_db 下面。
這個(gè)理解在日??陬^表達(dá)里問題不大,但繼續(xù)寫 SQL 時(shí)會很快遇到麻煩。KingbaseES 里,連接目標(biāo)、對象命名空間、登錄用戶是三件事:
database:連接到哪個(gè)數(shù)據(jù)庫 schema:表、視圖、函數(shù)這些對象放在哪個(gè)命名空間 user/role:當(dāng)前是誰在執(zhí)行操作
MySQL 里經(jīng)常把 database 當(dāng)作命名空間使用,寫 db_name.table_name 很常見。KingbaseES 這里更需要先適應(yīng) schema.table 這層關(guān)系。不把這件事分清楚,后面很容易出現(xiàn)表明明存在卻查不到、同一個(gè)表名查到的不是預(yù)期數(shù)據(jù)、換個(gè)用戶以后對象顯示不一樣這些問題。
這不是概念潔癖。開發(fā)時(shí)最常見的低級問題,往往不是 SQL 函數(shù)不會用,而是連錯(cuò)庫、建錯(cuò)位置、查錯(cuò)對象。MySQL 里執(zhí)行 use app_db; 以后,再 show tables;,心里通常會默認(rèn)“當(dāng)前庫里的表就在這里”。到了 KingbaseES,連接到 app_db 以后,還要多看一層:當(dāng)前 schema 是誰,默認(rèn)對象查找順序是什么。
如果只做一個(gè)簡單表,這個(gè)差別不明顯。一旦開始做遷移、按模塊拆 schema、給不同用戶分配對象,差別就會變得很具體。一個(gè)庫里可能有 public.t_order,也可能有 archive.t_order、report.t_order。不帶 schema 前綴的 select * from t_order 到底查哪張表,不能只靠表名判斷。
下面的實(shí)驗(yàn)只用兩個(gè)對象名:一個(gè)普通用戶 app_user,一個(gè)數(shù)據(jù)庫 app_db。表名也故意復(fù)用 t_schema_demo,讓它分別出現(xiàn)在 public 和 app_schema 下面。這樣能把問題壓到最?。和粋€(gè) database、同一個(gè) user、同一個(gè)表名,只因?yàn)?schema 和 search_path 不同,查詢結(jié)果就會變。
當(dāng)前連接里不只有數(shù)據(jù)庫名
先用普通用戶連接數(shù)據(jù)庫:
ksql -h 127.0.0.1 -p 54321 -U app_user -d app_db
進(jìn)入 ksql 后查三個(gè)值:
select current_database(), current_user, current_schema(); show search_path;
返回結(jié)果里,當(dāng)前數(shù)據(jù)庫是 app_db,當(dāng)前用戶是 app_user,當(dāng)前 schema 是 public。search_path 是:
"$user", public

這里已經(jīng)能看到幾個(gè)概念被拆開了。連接命令里的 -d app_db 只決定當(dāng)前 database;登錄命令里的 -U app_user 決定當(dāng)前用戶;真正不寫前綴建表時(shí)會落到哪里,還要看當(dāng)前 schema 和 search_path。
"$user", public 的意思是:先嘗試找和當(dāng)前用戶同名的 schema,再找 public。當(dāng)前環(huán)境里沒有 app_user 這個(gè) schema,所以 current_schema() 返回的是 public。
這一步對 MySQL 用戶很關(guān)鍵。連到 app_db 不等于后面所有對象都直接掛在 app_db 這一層,表還會屬于某個(gè) schema。
可以把這組信息拆成一句話:app_user 以某個(gè)用戶身份連接到了 app_db,當(dāng)前默認(rèn)會在 public schema 里創(chuàng)建和查找對象。三個(gè)值分別回答三個(gè)問題:
current_database() 當(dāng)前連接哪個(gè)數(shù)據(jù)庫 current_user 當(dāng)前用哪個(gè)用戶執(zhí)行 current_schema() 當(dāng)前默認(rèn)使用哪個(gè) schema
show search_path; 則回答另一個(gè)問題:沒寫 schema 前綴時(shí),數(shù)據(jù)庫按什么順序找對象。這個(gè)配置不只是顯示信息,它會直接影響建表和查表。
不寫 schema,表會落到默認(rèn)位置
直接建一張表:
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');
再用 \dt 和 \d 看對象:
\dt \d t_schema_demo
同時(shí)查系統(tǒng)視圖:
select schemaname, tablename, tableowner from sys_tables where tablename = 't_schema_demo';
結(jié)果很直接,t_schema_demo 在 public 下,owner 是 app_user。

這就是 search_path 生效后的結(jié)果。建表語句沒有寫 public.t_schema_demo,但當(dāng)前默認(rèn) schema 是 public,所以表落到了 public。
換成 MySQL 習(xí)慣時(shí),這里最容易想當(dāng)然:已經(jīng)連上 app_db,所以表就在 app_db 里。更準(zhǔn)確的說法應(yīng)該是:當(dāng)前連接在 app_db,表對象屬于 app_db 里的 public schema。
也就是說,database 是更外層的連接邊界,schema 才是對象命名空間。后面寫 select * from t_schema_demo 時(shí),如果不帶 schema 前綴,數(shù)據(jù)庫會按當(dāng)前搜索路徑去找。
這里的 \dt 也能看出問題。它列出來的不只是表名,還有 schema。當(dāng)前結(jié)果里,已有的 t_ksql_conn_demo 和這次新建的 t_schema_demo 都在 public 下,owner 都是 app_user。這說明“誰創(chuàng)建”和“建在哪個(gè) schema”也是兩回事:當(dāng)前用戶是 app_user,對象 owner 是 app_user,但對象所在 schema 是 public。
寫 DDL 時(shí)最好先確認(rèn)這三件事。只知道“當(dāng)前連的是 app_db”還不夠,至少還要知道默認(rèn) schema 是什么。否則以后清理對象時(shí),可能會發(fā)現(xiàn)同一個(gè)庫里散著多個(gè) schema,表名也不一定唯一。
再建一個(gè) app_schema
接著創(chuàng)建一個(gè)新的 schema:
create schema app_schema authorization app_user;
再查當(dāng)前數(shù)據(jù)庫里關(guān)心的 schema:
select schema_name
from information_schema.schemata
where schema_name in ('public', 'app_schema');
結(jié)果里能看到 public 和 app_schema。

app_schema 不是新數(shù)據(jù)庫,它只是 app_db 里的一個(gè)命名空間。authorization app_user 表示這個(gè) schema 歸 app_user 所有。
這一步不用先展開權(quán)限體系。先抓住一點(diǎn)就行:同一個(gè) database 里可以有多個(gè) schema。表名、視圖名、函數(shù)名這些對象名,都是在 schema 這一層組織的。
authorization app_user 也不是隨手加的裝飾。它讓 app_schema 這個(gè)命名空間歸 app_user 所有。后面在這個(gè) schema 下建表時(shí),邏輯就更接近日常開發(fā):普通用戶連接自己的數(shù)據(jù)庫,在自己的 schema 里放對象。完整權(quán)限還可以繼續(xù)細(xì)分,這里先把對象層級跑通。
在真實(shí)項(xiàng)目里,schema 常用來做隔離。比如一個(gè)庫里放業(yè)務(wù)表、報(bào)表表、中間表,或者遷移時(shí)先把舊系統(tǒng)對象放到單獨(dú) schema。這樣不需要每個(gè)模塊都拆成一個(gè)獨(dú)立數(shù)據(jù)庫,也能避免對象名互相撞在一起。
同一個(gè) database 里可以有同名表
現(xiàn)在顯式把表建到 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;
結(jié)果里出現(xiàn)了兩行:
app_schema | t_schema_demo public | t_schema_demo

這就是 schema 的作用。同一個(gè) app_db 里,public.t_schema_demo 和 app_schema.t_schema_demo 可以同時(shí)存在。它們名字一樣,但完整對象名不一樣。
這和 MySQL 里常見的 database.table 直覺不一樣。在 KingbaseES 里,寫到對象層面時(shí),更常見的是:
schema_name.table_name
如果只寫表名,數(shù)據(jù)庫不會憑空知道想查哪一個(gè) schema 下的表,它會按 search_path 的順序找。
同名表實(shí)驗(yàn)很適合用來打斷 MySQL 里的一個(gè)慣性:同一個(gè)“庫”里表名必須唯一。這里并不是同一個(gè) schema 里允許同名表,而是同一個(gè) database 里不同 schema 允許同名對象。完整對象名分別是:
public.t_schema_demo app_schema.t_schema_demo
這兩個(gè)名字完整寫出來以后,就不沖突了。后面做 SQL 排查時(shí),如果只看到一個(gè)裸表名,不要馬上以為它指向唯一對象。先查對象歸屬,再看搜索路徑。
加上 schema 前綴,目標(biāo)就明確了
分別查詢兩張同名表:
select * from public.t_schema_demo; select * from app_schema.t_schema_demo;
前一張表里是:
1 | from default schema
后一張表里是:
2 | from app_schema

加上 schema.table 前綴以后,查詢目標(biāo)很明確,不受當(dāng)前 search_path 順序影響。
平時(shí)寫業(yè)務(wù) SQL 時(shí),不一定每條都要帶 schema 前綴。很多項(xiàng)目會通過默認(rèn) schema 或連接參數(shù)把環(huán)境固定下來。但在排查問題、寫遷移腳本、做跨 schema 查詢時(shí),顯式寫出 schema 能少很多歧義。
有幾種場景最好直接寫全名:遷移腳本、初始化腳本、定時(shí)任務(wù)、跨 schema 查詢、臨時(shí)排查 SQL。這些 SQL 往往會在不同賬號、不同終端、不同工具里執(zhí)行,不能假設(shè)每次會話的 search_path 都一樣。寫成 app_schema.t_schema_demo 雖然長一點(diǎn),但現(xiàn)場更清楚。
尤其是多人共用測試庫時(shí),寫清 schema 能避免很多無意義的來回確認(rèn),也方便后面清理對象和復(fù)盤問題。
這也是遷移時(shí)很容易踩的點(diǎn)。MySQL 里從 db1.table1 改到 KingbaseES,不一定能機(jī)械改成 database.table。更常見的處理是:連接到目標(biāo) database,然后把對象放進(jìn)指定 schema,再用 schema.table 來訪問。具體怎么設(shè)計(jì),要看項(xiàng)目是否需要多 schema、是否要保留原庫名、是否要隔離臨時(shí)遷移對象。
search_path 會影響未加前綴的查詢
現(xiàn)在不帶 schema 前綴,直接查:
select * from t_schema_demo;
這條 SQL 查哪張表,取決于當(dāng)前 search_path。
先把 app_schema 放到前面:
set search_path to app_schema, public; show search_path; select * from t_schema_demo;
返回的是 app_schema.t_schema_demo 里的數(shù)據(jù):
2 | from app_schema
再把 public 放到前面:
set search_path to public, app_schema; show search_path; select * from t_schema_demo;
返回變成 public.t_schema_demo 里的數(shù)據(jù):
1 | from default schema

這一步能解釋很多看起來很怪的問題。表存在,查詢也沒報(bào)錯(cuò),但結(jié)果不是預(yù)期那張表的數(shù)據(jù),原因可能不是 SQL 寫錯(cuò),而是未加前綴的表名被 search_path 解析到了另一個(gè) schema。
開發(fā)階段如果只有一個(gè) schema,問題不明顯。一旦出現(xiàn)多 schema、遷移臨時(shí) schema、按用戶隔離 schema,search_path 就會變得很重要。
這個(gè)實(shí)驗(yàn)里,兩次查詢的 SQL 都是:
select * from t_schema_demo;
SQL 文本沒有變化,結(jié)果卻變了。變化來自前面的:
set search_path to app_schema, public; set search_path to public, app_schema;
這類問題在日志里也不好一眼看出來。只看業(yè)務(wù) SQL,會以為查的是同一張表;把當(dāng)時(shí)會話里的 search_path 補(bǔ)上,才能解釋結(jié)果為什么不同。所以排查“查錯(cuò)表”時(shí),show search_path; 應(yīng)該和 current_database()、current_user 一起看。
換成 system,再看同一個(gè) app_db
退出 app_user 后,換 system 連接同一個(gè)數(shù)據(jù)庫:
ksql -h 127.0.0.1 -p 54321 -U system -d app_db
再查當(dāng)前位置:
select current_database(), current_user, current_schema();
結(jié)果變成:
app_db | system | public
繼續(xù)查 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_demo public | t_schema_demo

換用戶不等于換數(shù)據(jù)庫,也不等于把對象搬到別的 schema。system 只是換了當(dāng)前執(zhí)行 SQL 的身份,連接目標(biāo)仍然是 app_db,對象仍然在 public 和 app_schema 下面。
這里先不展開授權(quán)。只看這一組結(jié)果已經(jīng)足夠說明:database、schema、user 不是一個(gè)概念。
換成 system 后,current_user 變了,但 current_database() 仍然是 app_db,對象歸屬也沒變。這能把 user 和 database 的邊界講清楚。用戶不是數(shù)據(jù)庫,數(shù)據(jù)庫也不是用戶。用戶只是當(dāng)前會話執(zhí)行 SQL 的身份,它會影響能不能看、能不能改、默認(rèn) schema 怎么解析,但不會因?yàn)閾Q用戶就把同一個(gè)數(shù)據(jù)庫里的對象改名或搬走。
這也是為什么不建議長期拿管理員用戶做日常實(shí)驗(yàn)。管理員用戶能看到更多東西,也能繞過一些權(quán)限限制。用它排查問題可以,拿它模擬普通應(yīng)用連接就不準(zhǔn)確。準(zhǔn)備 app_user 和 app_db,就是為了讓這些實(shí)驗(yàn)更接近日常開發(fā)賬號。
和 MySQL 的習(xí)慣對一下
如果從 MySQL 過來,可以先用下面這張對照表調(diào)整直覺:
MySQL 常見理解 KingbaseES 里要拆開看 database 常當(dāng)命名空間 database 是連接目標(biāo) database.table schema.table 更常見 use db ksql 里用 \c 切換連接數(shù)據(jù)庫 show tables \dt 或 information_schema.tables 當(dāng)前庫 current_database() 當(dāng)前用戶 current_user 默認(rèn) schema current_schema() 對象查找路徑 search_path
這不是說 MySQL 的方式不好,而是兩套對象層級不一樣。MySQL 里很多時(shí)候看到“庫”,腦子里會自動(dòng)想到一組表;KingbaseES 這里連到 database 以后,還要繼續(xù)問:當(dāng)前 schema 是哪個(gè),表實(shí)際在哪個(gè) schema 下,當(dāng)前用戶有沒有權(quán)限訪問它。
前面實(shí)驗(yàn)里的幾個(gè)結(jié)果可以串起來看:
app_db 當(dāng)前連接的 database app_user / system 當(dāng)前執(zhí)行 SQL 的 user public / app_schema 表所在的 schema t_schema_demo 兩個(gè) schema 下都可以存在的表名 search_path 不寫 schema 前綴時(shí)的查找順序
后面如果遇到“表不存在”“查到的不是預(yù)期數(shù)據(jù)”“換用戶以后看不到對象”,不要只盯著表名。先查 current_database()、current_user、current_schema(),再看 search_path 和對象實(shí)際歸屬,很多問題會直接變清楚。
可以把排查順序固定下來:
select current_database(), current_user, current_schema(); show search_path; select table_schema, table_name from information_schema.tables where table_name = '<表名>';
如果對象確實(shí)存在,再看權(quán)限;如果對象在另一個(gè) schema,先決定是改 SQL 加前綴,還是調(diào)整當(dāng)前會話的 search_path。不要一上來就懷疑表丟了,也不要直接重建同名表。schema 沒看清時(shí),重建對象反而可能把現(xiàn)場弄得更亂。
比如應(yīng)用報(bào)“表不存在”,先不要急著執(zhí)行 create table。如果表在 app_schema,而連接進(jìn)來以后默認(rèn)搜索的是 public,裸寫 select * from t_schema_demo 就可能找不到目標(biāo)對象。這個(gè)時(shí)候有兩種處理方式:SQL 里寫成 app_schema.t_schema_demo,或者在連接會話里把 app_schema 放進(jìn) search_path。兩種方式都能解決問題,但含義不一樣。前者目標(biāo)最明確,后者更依賴會話配置。
再比如查出來的數(shù)據(jù)不對,也不一定是數(shù)據(jù)被改壞了。同名表同時(shí)存在時(shí),public.t_schema_demo 和 app_schema.t_schema_demo 都能正常查詢,只是數(shù)據(jù)來源不同。SQL 不帶 schema 前綴時(shí),結(jié)果跟著 search_path 走。這個(gè)問題在測試庫里不顯眼,到了遷移驗(yàn)證、報(bào)表庫、臨時(shí)表整理時(shí)就會很煩。
到此這篇關(guān)于MySQL和KingbaseES中連接、對象命名空間及用戶權(quán)限的區(qū)別的文章就介紹到這了,更多相關(guān)MySQL和KingbaseES的區(qū)別內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- KingbaseES中SQL高級性能優(yōu)化與執(zhí)行計(jì)劃深度解析
- mysql切到國產(chǎn)數(shù)據(jù)庫KingbaseES后的SQL區(qū)別
- Oracle遷移到KingbaseES實(shí)戰(zhàn)指南:語法差異、函數(shù)映射與避坑指南
- KingbaseES金倉數(shù)據(jù)庫:ksql?命令行從建表到刪表實(shí)戰(zhàn)(含增刪改查)
- 國產(chǎn)數(shù)據(jù)庫KingbaseES安裝與使用方法詳解
- KingbaseES數(shù)據(jù)庫開發(fā)運(yùn)維:部署、安全、備份與監(jiān)控實(shí)戰(zhàn)
相關(guān)文章
Mysql Error 1826:Duplicate foreign key&n
MySQL1826錯(cuò)誤是由于在創(chuàng)建表時(shí),外鍵索引名重復(fù)導(dǎo)致的,解決辦法是在創(chuàng)建外鍵時(shí)指定不同的索引名,或修改ForeignKeyName,此問題需注意索引和外鍵名稱的唯一性2026-05-05
MySQL 4G內(nèi)存服務(wù)器配置優(yōu)化
MySQL對于web架構(gòu)性能的影響最大,也是關(guān)鍵的核心部分。下面我們了解一下MySQL優(yōu)化的一些基礎(chǔ),MySQL自身(my.cnf)的優(yōu)化2017-07-07
MySQL Workbench工具導(dǎo)出導(dǎo)入數(shù)據(jù)庫方式
這篇文章主要介紹了MySQL Workbench工具導(dǎo)出導(dǎo)入數(shù)據(jù)庫方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-05-05
MySQL數(shù)據(jù)庫10秒內(nèi)插入百萬條數(shù)據(jù)的實(shí)現(xiàn)
假設(shè)現(xiàn)在我們要向mysql插入500萬條數(shù)據(jù),如何實(shí)現(xiàn)高效快速的插入進(jìn)去?本文就詳細(xì)的介紹一下,感興趣的可以了解一下2021-10-10

