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

這里已經(jīng)能看到幾個概念被拆開了。連接命令里的 -d app_db 只決定當前 database;登錄命令里的 -U app_user 決定當前用戶;真正不寫前綴建表時會落到哪里,還要看當前 schema 和 search_path。
"$user", public 的意思是:先嘗試找和當前用戶同名的 schema,再找 public。當前環(huán)境里沒有 app_user 這個 schema,所以 current_schema() 返回的是 public。
這一步對 MySQL 用戶很關鍵。連到 app_db 不等于后面所有對象都直接掛在 app_db 這一層,表還會屬于某個 schema。
可以把這組信息拆成一句話:app_user 以某個用戶身份連接到了 app_db,當前默認會在 public schema 里創(chuàng)建和查找對象。三個值分別回答三個問題:
current_database() 當前連接哪個數(shù)據(jù)庫 current_user 當前用哪個用戶執(zhí)行 current_schema() 當前默認使用哪個 schema
show search_path; 則回答另一個問題:沒寫 schema 前綴時,數(shù)據(jù)庫按什么順序找對象。這個配置不只是顯示信息,它會直接影響建表和查表。
不寫 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');
再用 \dt 和 \d 看對象:
\dt \d t_schema_demo
同時查系統(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,但當前默認 schema 是 public,所以表落到了 public。
換成 MySQL 習慣時,這里最容易想當然:已經(jīng)連上 app_db,所以表就在 app_db 里。更準確的說法應該是:當前連接在 app_db,表對象屬于 app_db 里的 public schema。
也就是說,database 是更外層的連接邊界,schema 才是對象命名空間。后面寫 select * from t_schema_demo 時,如果不帶 schema 前綴,數(shù)據(jù)庫會按當前搜索路徑去找。
這里的 \dt 也能看出問題。它列出來的不只是表名,還有 schema。當前結(jié)果里,已有的 t_ksql_conn_demo 和這次新建的 t_schema_demo 都在 public 下,owner 都是 app_user。這說明“誰創(chuàng)建”和“建在哪個 schema”也是兩回事:當前用戶是 app_user,對象 owner 是 app_user,但對象所在 schema 是 public。
寫 DDL 時最好先確認這三件事。只知道“當前連的是 app_db”還不夠,至少還要知道默認 schema 是什么。否則以后清理對象時,可能會發(fā)現(xiàn)同一個庫里散著多個 schema,表名也不一定唯一。
再建一個 app_schema
接著創(chuàng)建一個新的 schema:
create schema app_schema authorization app_user;
再查當前數(shù)據(jù)庫里關心的 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 里的一個命名空間。authorization app_user 表示這個 schema 歸 app_user 所有。
這一步不用先展開權限體系。先抓住一點就行:同一個 database 里可以有多個 schema。表名、視圖名、函數(shù)名這些對象名,都是在 schema 這一層組織的。
authorization app_user 也不是隨手加的裝飾。它讓 app_schema 這個命名空間歸 app_user 所有。后面在這個 schema 下建表時,邏輯就更接近日常開發(fā):普通用戶連接自己的數(shù)據(jù)庫,在自己的 schema 里放對象。完整權限還可以繼續(xù)細分,這里先把對象層級跑通。
在真實項目里,schema 常用來做隔離。比如一個庫里放業(yè)務表、報表表、中間表,或者遷移時先把舊系統(tǒng)對象放到單獨 schema。這樣不需要每個模塊都拆成一個獨立數(shù)據(jù)庫,也能避免對象名互相撞在一起。
同一個 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 的作用。同一個 app_db 里,public.t_schema_demo 和 app_schema.t_schema_demo 可以同時存在。它們名字一樣,但完整對象名不一樣。
這和 MySQL 里常見的 database.table 直覺不一樣。在 KingbaseES 里,寫到對象層面時,更常見的是:
schema_name.table_name
如果只寫表名,數(shù)據(jù)庫不會憑空知道想查哪一個 schema 下的表,它會按 search_path 的順序找。
同名表實驗很適合用來打斷 MySQL 里的一個慣性:同一個“庫”里表名必須唯一。這里并不是同一個 schema 里允許同名表,而是同一個 database 里不同 schema 允許同名對象。完整對象名分別是:
public.t_schema_demo app_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.table 前綴以后,查詢目標很明確,不受當前 search_path 順序影響。
平時寫業(yè)務 SQL 時,不一定每條都要帶 schema 前綴。很多項目會通過默認 schema 或連接參數(shù)把環(huán)境固定下來。但在排查問題、寫遷移腳本、做跨 schema 查詢時,顯式寫出 schema 能少很多歧義。
有幾種場景最好直接寫全名:遷移腳本、初始化腳本、定時任務、跨 schema 查詢、臨時排查 SQL。這些 SQL 往往會在不同賬號、不同終端、不同工具里執(zhí)行,不能假設每次會話的 search_path 都一樣。寫成 app_schema.t_schema_demo 雖然長一點,但現(xiàn)場更清楚。
尤其是多人共用測試庫時,寫清 schema 能避免很多無意義的來回確認,也方便后面清理對象和復盤問題。
這也是遷移時很容易踩的點。MySQL 里從 db1.table1 改到 KingbaseES,不一定能機械改成 database.table。更常見的處理是:連接到目標 database,然后把對象放進指定 schema,再用 schema.table 來訪問。具體怎么設計,要看項目是否需要多 schema、是否要保留原庫名、是否要隔離臨時遷移對象。
search_path 會影響未加前綴的查詢
現(xiàn)在不帶 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 里的數(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

這一步能解釋很多看起來很怪的問題。表存在,查詢也沒報錯,但結(jié)果不是預期那張表的數(shù)據(jù),原因可能不是 SQL 寫錯,而是未加前綴的表名被 search_path 解析到了另一個 schema。
開發(fā)階段如果只有一個 schema,問題不明顯。一旦出現(xiàn)多 schema、遷移臨時 schema、按用戶隔離 schema,search_path 就會變得很重要。
這個實驗里,兩次查詢的 SQL 都是:
select * from t_schema_demo;
SQL 文本沒有變化,結(jié)果卻變了。變化來自前面的:
set search_path to app_schema, public; set search_path to public, app_schema;
這類問題在日志里也不好一眼看出來。只看業(yè)務 SQL,會以為查的是同一張表;把當時會話里的 search_path 補上,才能解釋結(jié)果為什么不同。所以排查“查錯表”時,show search_path; 應該和 current_database()、current_user 一起看。
換成 system,再看同一個 app_db
退出 app_user 后,換 system 連接同一個數(shù)據(jù)庫:
ksql -h 127.0.0.1 -p 54321 -U system -d app_db
再查當前位置:
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 只是換了當前執(zhí)行 SQL 的身份,連接目標仍然是 app_db,對象仍然在 public 和 app_schema 下面。
這里先不展開授權。只看這一組結(jié)果已經(jīng)足夠說明:database、schema、user 不是一個概念。
換成 system 后,current_user 變了,但 current_database() 仍然是 app_db,對象歸屬也沒變。這能把 user 和 database 的邊界講清楚。用戶不是數(shù)據(jù)庫,數(shù)據(jù)庫也不是用戶。用戶只是當前會話執(zhí)行 SQL 的身份,它會影響能不能看、能不能改、默認 schema 怎么解析,但不會因為換用戶就把同一個數(shù)據(jù)庫里的對象改名或搬走。
這也是為什么不建議長期拿管理員用戶做日常實驗。管理員用戶能看到更多東西,也能繞過一些權限限制。用它排查問題可以,拿它模擬普通應用連接就不準確。準備 app_user 和 app_db,就是為了讓這些實驗更接近日常開發(fā)賬號。
和 MySQL 的習慣對一下
如果從 MySQL 過來,可以先用下面這張對照表調(diào)整直覺:
MySQL 常見理解 KingbaseES 里要拆開看 database 常當命名空間 database 是連接目標 database.table schema.table 更常見 use db ksql 里用 \c 切換連接數(shù)據(jù)庫 show tables \dt 或 information_schema.tables 當前庫 current_database() 當前用戶 current_user 默認 schema current_schema() 對象查找路徑 search_path
這不是說 MySQL 的方式不好,而是兩套對象層級不一樣。MySQL 里很多時候看到“庫”,腦子里會自動想到一組表;KingbaseES 這里連到 database 以后,還要繼續(xù)問:當前 schema 是哪個,表實際在哪個 schema 下,當前用戶有沒有權限訪問它。
前面實驗里的幾個結(jié)果可以串起來看:
app_db 當前連接的 database app_user / system 當前執(zhí)行 SQL 的 user public / app_schema 表所在的 schema t_schema_demo 兩個 schema 下都可以存在的表名 search_path 不寫 schema 前綴時的查找順序
后面如果遇到“表不存在”“查到的不是預期數(shù)據(jù)”“換用戶以后看不到對象”,不要只盯著表名。先查 current_database()、current_user、current_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 加前綴,還是調(diào)整當前會話的 search_path。不要一上來就懷疑表丟了,也不要直接重建同名表。schema 沒看清時,重建對象反而可能把現(xiàn)場弄得更亂。
比如應用報“表不存在”,先不要急著執(zhí)行 create table。如果表在 app_schema,而連接進來以后默認搜索的是 public,裸寫 select * from t_schema_demo 就可能找不到目標對象。這個時候有兩種處理方式:SQL 里寫成 app_schema.t_schema_demo,或者在連接會話里把 app_schema 放進 search_path。兩種方式都能解決問題,但含義不一樣。前者目標最明確,后者更依賴會話配置。
再比如查出來的數(shù)據(jù)不對,也不一定是數(shù)據(jù)被改壞了。同名表同時存在時,public.t_schema_demo 和 app_schema.t_schema_demo 都能正常查詢,只是數(shù)據(jù)來源不同。SQL 不帶 schema 前綴時,結(jié)果跟著 search_path 走。這個問題在測試庫里不顯眼,到了遷移驗證、報表庫、臨時表整理時就會很煩。
到此這篇關于MySQL和KingbaseES中連接、對象命名空間及用戶權限的區(qū)別的文章就介紹到這了,更多相關MySQL和KingbaseES的區(qū)別內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Mysql Error 1826:Duplicate foreign key&n
MySQL1826錯誤是由于在創(chuàng)建表時,外鍵索引名重復導致的,解決辦法是在創(chuàng)建外鍵時指定不同的索引名,或修改ForeignKeyName,此問題需注意索引和外鍵名稱的唯一性2026-05-05
MySQL Workbench工具導出導入數(shù)據(jù)庫方式
這篇文章主要介紹了MySQL Workbench工具導出導入數(shù)據(jù)庫方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2025-05-05
MySQL數(shù)據(jù)庫10秒內(nèi)插入百萬條數(shù)據(jù)的實現(xiàn)
假設現(xiàn)在我們要向mysql插入500萬條數(shù)據(jù),如何實現(xiàn)高效快速的插入進去?本文就詳細的介紹一下,感興趣的可以了解一下2021-10-10

