在 KingbaseES 数据库中,表空间是用于存储数据库对象(如表、索引等)的物理位置,它实现了逻辑存储结构与物理文件路径的映射。合理的表空间规划对数据库的性能优化(如 I/O 负载均衡)、存储管理以及数据隔离至关重要。本文将深入解析 数据库 与 用户 这两个层面的默认表空间配置机制,并通过实战示例展示从创建到验证的完整操作流程。
一、数据库的默认表空间配置
1.1 默认创建行为
当使用 CREATE DATABASE 语句创建数据库且不显式指定表空间时,数据库将自动关联至系统默认表空间。
CREATE DATABASE shanjiatest1;

说明:此操作未使用 TABLESPACE 子句,因此数据库会采用默认配置。
1.2 默认存储位置
逻辑表空间:sys_default(系统预设的默认表空间)。
物理路径:位于数据库集群的数据目录(data_directory)下的 base/数据库OID 子目录中。
数据库OID是系统为每个数据库分配的唯一对象标识符,可通过 sys_database 系统目录查询。
1.3 查看数据库的默认表空间
方法一:使用 KSQL 元命令(快捷方式)
\l+ shanjiatest1

在输出结果中查找 Tablespace 字段,即可确认该数据库所属的表空间。当前默认表空间。
方法二:查询系统目录(详细信息)
language
SELECT
datname AS database_name,
dattablespace AS tablespace_oid,
(SELECT spcname FROM sys_tablespace WHERE oid = dattablespace) AS tablespace_name,
(SELECT setting FROM sys_settings WHERE name = 'data_directory') || '/base/' || oid AS physical_path
FROM sys_database
WHERE datname = 'shanjiatest1';
输出示例:

二、用户的默认表空间配置
2.1 默认创建行为
创建用户时若不指定表空间,其默认表空间将与当前连接数据库的默认表空间保持一致。
CREATE USER shanjiatestuser1 PASSWORD 'shanjiatestuser1';
执行示例:

2.2 关键配置项
默认表空间:决定了该用户创建数据库对象(如表、索引)时的存储位置。若未显式设置,将继承数据库的默认表空间(通常为 sys_default)。
临时表空间:用于存储临时对象(如排序、哈希生成的临时文件)。由系统参数 temp_tablespaces 决定,若该参数为空,则使用系统默认的临时文件位置。
2.3 查看用户的默认表空间配置
SELECT
usename AS username,
useconfig AS user_config,
(SELECT setting FROM sys_settings WHERE name = 'default_tablespace') AS default_tablespace,
(SELECT setting FROM sys_settings WHERE name = 'temp_tablespaces') AS temp_tablespaces
FROM sys_user
WHERE usename = 'shanjiatestuser1';
输出示例:

2.4 查询结果分析(示例)
| 字段 | 值 | 含义解释 |
|---|---|---|
| username | shanjiatestuser1 | 用户名 |
| user_config | 空 | 用户级别的自定义配置参数(未设置) |
| default_tablespace | 空 | 默认表空间参数为空,表示使用系统默认(即关联数据库的默认表空间,如 sys_default) |
| temp_tablespaces | 空 | 临时表空间参数为空,表示使用系统默认的临时存储位置 |
"为空"并不代表没有表空间,而是指未进行个性化覆盖,实际行为将遵循更高层次的默认规则。
这种设计提供了灵活性:可以在系统级(default_tablespace 参数)、数据库级或用户级逐层定义和覆盖存储策略。
2.5 综合验证用户的实际默认表空间
为了清晰展示最终生效的默认表空间,可执行以下关联查询:
SELECT
u.usename AS username,
d.datname AS database_name,
CASE
WHEN (SELECT setting FROM sys_settings WHERE name = 'default_tablespace') = ''
THEN 'sys_default'
ELSE (SELECT setting FROM sys_settings WHERE name = 'default_tablespace')
END AS user_default_tablespace,
ts.spcname AS database_default_tablespace,
(SELECT setting FROM sys_settings WHERE name = 'data_directory') || '/base/' || d.oid AS database_physical_path
FROM sys_user u, sys_database d, sys_tablespace ts
WHERE d.datname = current_database()
AND d.dattablespace = ts.oid
AND u.usename = 'shanjiatestuser1';
该查询将同时呈现用户关联的数据库、数据库的默认表空间及其物理存储路径,从而提供从用户到物理文件的完整映射视图。
输出示例:

三、系统参数的查询与管理
3.1 使用SQL检索关键的表空间关联参数
通过查阅 sys_settings 系统视图,用户可以精确地分析与表空间相关联的参数配置。
SELECT
name as parameter_name,
setting as current_value,
short_desc as description
FROM sys_settings
WHERE name IN ('default_tablespace', 'temp_tablespaces', 'data_directory');
此查询将返回以下核心参数的状态(结果示例):

default_tablespace :所有未显式指定表空间的对象(如表、索引)的默认存储位置。若值为空,将默认使用系统表空间 sys_default。
temp_tablespaces :用于指定排序、哈希等操作的临时表空间的列表。此参数也可为空,表示使用系统默认的临时文件路径。
data_directory:数据库集群的根数据目录,是计算对象物理绝对路径的基础
四、对象创建的默认表空间行为
当未指定表空间的情况下创建数据库对象时,其存储位置遵循一套默认的继承规则。了解此行为对于优化数据分布和磁盘I/O至关重要。
4.1 表创建的默认行为
场景:在不使用 TABLESPACE 子句的情况下创建表,表将自动存储到其所属数据库的默认表空间中。
CREATE TABLE shanjiatesttable1 (id SERIAL, name TEXT);

验证:通过查询系统目录,可以确认表的存储逻辑、物理位置和大小,输出示例:

输出关键词:
表空间 :若显示 sys_default,则验证了对象存储于数据库默认表空间。
绝对文件路径:揭示了表在操作系统文件系统中的确切位置。
4.2 索引创建的默认行为
场景:默认情况下,索引会与其父表存储在同一表空间。此行为可以用 CREATE INDEX 子句显式覆盖。
不指定表空间创建索引
CREATE INDEX idx_my_table_name ON shanjiatesttable1(name);

SELECT
i.indexname as "索引名称",
i.tablename as "所属表",
'sys_default(数据库默认表空间)' as "表空间名称",
'数据库默认表空间 (sys_default)' as "表空间说明",
sys_relation_filepath(i.indexname::regclass) as "相对文件路径",
(SELECT setting FROM sys_settings WHERE name = 'data_directory') || '/' ||
sys_relation_filepath(i.indexname::regclass) as "完整物理路径",
pg_size_pretty(pg_relation_size(i.indexname::regclass)) as "索引大小",
i.indexdef as "索引定义"
FROM sys_indexes i
WHERE i.indexname = 'idx_my_table_name';
验证:查询索引信息,确认其位置与默认策略一致。

五、实战案例:构建一个完整的用户及表空间配置
本案例提供一个从用户、表空间到数据库及对象的完整配置流程,适用于生产环境下的独立应用数据隔离与权限管理规划。
5.1 创建用户、表空间及关联数据库的完整流程
该流程遵循"先认证后授权"的安全原则。
5.1.1. 创建用户,并使用注释进行标记
CREATE USER shanjiatest2 WITH PASSWORD '46eCN+hHit3Ggidr7u/A';
COMMENT ON ROLE shanjiatest2 IS 'shanjia测试用户';
5.1.2. 授予该用户对Public模式的访问权
GRANT USAGE ON SCHEMA public TO shanjiatest2;
GRANT ALL PRIVILEGES ON ALL FUNCTIONS IN SCHEMA public TO shanjiatest2;
GRANT ALL PRIVILEGES ON ALL PROCEDURES IN SCHEMA public TO shanjiatest2;
5.1.3. 创建专用表空间,并指定物理目录
CREATE TABLESPACE shanjiatest2_tbs OWNER shanjiatest2
LOCATION '/home/kingbase/tablespaces/shanjiatest_tbs';
COMMENT ON TABLESPACE shanjiatest2_tbs IS '山佳应用专用表空间';
5.1.4. 授予用户对该表空间的完全控制权限
GRANT ALL PRIVILEGES ON TABLESPACE shanjiatest2_tbs TO shanjiatest2;
5.1.5. 创建数据库,明确指定使用新创建的表空间
CREATE DATABASE shanjia WITH ENCODING 'UTF8' OWNER shanjiatest2
TABLESPACE shanjiatest2_tbs ALLOW_CONNECTIONS TRUE;
COMMENT ON DATABASE shanjia IS 'shanjia测试数据库';
5.1.6. 切换至新数据库,创建专用模式并设置路径
\c shanjia
CREATE SCHEMA IF NOT EXISTS shanjia AUTHORIZATION shanjiatest2;
GRANT ALL PRIVILEGES ON SCHEMA shanjia TO shanjiatest2;
-- 设置数据库和用户的默认搜索路径,优化对象解析效率
ALTER DATABASE shanjia SET search_path TO shanjia, public;
ALTER ROLE shanjiatest2 SET search_path TO shanjia,public;
5.1.7. 在新模式下创建测试表和索引
CREATE TABLE shanjia.shanjiatesttable2 (id SERIAL, name TEXT);
ALTER TABLE shanjia.shanjiatesttable2 OWNER TO shanjiatest2;
CREATE INDEX idx_my_table_name ON shanjia.shanjiatesttable2(name);
ALTER INDEX shanjia.idx_my_table_name OWNER TO shanjiatest2;
完整的操作截图:

5.2 验证与审计
配置完成后,建议执行以下验证步骤,确保符合设计预期。
5.2.1 用户权限验证
SELECT
rolname as "用户名",
rolsuper as "超级用户",
rolcanlogin as "可登录",
rolconnlimit as "连接限制",
obj_description(oid, 'pg_authid') as "用户注释"
FROM sys_roles
WHERE rolname = 'shanjiatest2';
输出示例:

5.2.2 表空间信息查询
SELECT
spcname as "表空间名",
spcowner::regrole as "拥有者",
obj_description(oid, 'pg_tablespace') as "表空间注释",
sys_tablespace_location(oid) as "物理路径"
FROM sys_tablespace
WHERE spcname = 'shanjiatest2_tbs';
输出示例:

5.2.3 数据库配置查询
SELECT
datname as "数据库名",
datdba::regrole as "拥有者",
(SELECT spcname FROM sys_tablespace WHERE oid = dattablespace) as "默认表空间",
encoding as "字符编码"
FROM sys_database
WHERE datname = 'shanjia';
输出示例:

5.2.4 综合性权限审计报告
-- 检查用户对重点模式的具体权限
WITH privilege_check AS (
SELECT
nspname,
'USAGE' as privilege_type,
has_schema_privilege('shanjiatest2', oid, 'USAGE') as has_priv,
has_schema_privilege('shanjiatest2', oid, 'USAGE WITH GRANT OPTION') as has_grant
FROM sys_namespace
WHERE nspname IN ('shanjia', 'public')
UNION ALL
SELECT
nspname,
'CREATE' as privilege_type,
has_schema_privilege('shanjiatest2', oid, 'CREATE') as has_priv,
has_schema_privilege('shanjiatest2', oid, 'CREATE WITH GRANT OPTION') as has_grant
FROM sys_namespace
WHERE nspname IN ('shanjia', 'public')
)
SELECT
nspname as "模式名",
privilege_type as "权限类型",
CASE
WHEN has_priv THEN 'YES'
ELSE 'NO'
END as "是否有权限",
CASE
WHEN has_grant THEN 'YES'
ELSE 'NO'
END as "是否可转授",
CASE
WHEN has_priv AND has_grant THEN '完全权限(可转授)'
WHEN has_priv THEN '基础权限'
ELSE '无权限'
END as "权限状态"
FROM privilege_check
ORDER BY nspname, privilege_type;
输出示例:

5.3 [附]后期配置调整
在应用生命周期中,可能需要调整资源的存储位置。
5.3.1 修改数据库的默认表空间(注意:此操作可能涉及大规模数据迁移)
ALTER DATABASE shanjiadb SET TABLESPACE new_tablespace;
5.3.2 修改用户的默认表空间(仅影响此后创建的对象)
ALTER USER myuser SET DEFAULT_TABLESPACE = new_tablespace;
5.3.3 修改用户的临时表空间
ALTER USER myuser SET TEMPORARY_TABLESPACE = temp_tablespace;
5.4 综合验证脚本
DO $$
DECLARE
user_exists boolean;
tablespace_exists boolean;
database_exists boolean;
schema_exists boolean;
table_exists boolean;
index_exists boolean;
user_can_login boolean;
table_owner_correct boolean;
index_owner_correct boolean;
user_has_tablespace_priv boolean;
user_has_db_connect boolean;
user_has_schema_usage boolean;
user_has_table_select boolean;
BEGIN
-- 检查用户
SELECT EXISTS(SELECT 1 FROM sys_roles WHERE rolname = 'shanjiatest2') INTO user_exists;
SELECT rolcanlogin FROM sys_roles WHERE rolname = 'shanjiatest2' INTO user_can_login;
-- 检查表空间
SELECT EXISTS(SELECT 1 FROM sys_tablespace WHERE spcname = 'earchives_tbs') INTO tablespace_exists;
-- 检查表空间权限
SELECT has_tablespace_privilege('shanjiatest2', 'earchives_tbs', 'CREATE')
INTO user_has_tablespace_priv;
-- 检查数据库
SELECT EXISTS(SELECT 1 FROM sys_database WHERE datname = 'shanjia') INTO database_exists;
-- 检查数据库连接权限
SELECT has_database_privilege('shanjiatest2', 'shanjia', 'CONNECT')
INTO user_has_db_connect;
-- 检查schema
SELECT EXISTS(SELECT 1 FROM sys_namespace WHERE nspname = 'shanjia') INTO schema_exists;
-- 检查schema使用权限
SELECT has_schema_privilege('shanjiatest2', 'shanjia', 'USAGE')
INTO user_has_schema_usage;
-- 检查表
SELECT EXISTS(SELECT 1 FROM sys_tables WHERE schemaname = 'shanjia' AND tablename = 'shanjiatesttable2') INTO table_exists;
-- 检查表拥有者
SELECT tableowner = 'shanjiatest2'
FROM sys_tables
WHERE schemaname = 'shanjia' AND tablename = 'shanjiatesttable2'
INTO table_owner_correct;
-- 检查表查询权限
SELECT has_table_privilege('shanjiatest2', 'shanjia.shanjiatesttable2', 'SELECT')
INTO user_has_table_select;
-- 检查索引(使用sys_class视图)
SELECT EXISTS(
SELECT 1
FROM sys_class c
JOIN sys_namespace n ON c.relnamespace = n.oid
WHERE c.relname = 'idx_my_table_name'
AND n.nspname = 'shanjia'
AND c.relkind = 'i' -- 索引类型
) INTO index_exists;
-- 检查索引拥有者
SELECT EXISTS(
SELECT 1
FROM sys_class c
JOIN sys_roles r ON c.relowner = r.oid
JOIN sys_namespace n ON c.relnamespace = n.oid
WHERE c.relname = 'idx_my_table_name'
AND n.nspname = 'shanjia'
AND c.relkind = 'i'
AND r.rolname = 'shanjiatest2'
) INTO index_owner_correct;
RAISE NOTICE '=== KingbaseES 对象验证结果汇总 ===';
RAISE NOTICE '用户创建: %', CASE WHEN user_exists THEN '✓ 成功' ELSE '✗ 失败' END;
RAISE NOTICE '用户可登录: %', CASE WHEN user_can_login THEN '✓ 是' ELSE '✗ 否' END;
RAISE NOTICE '表空间创建: %', CASE WHEN tablespace_exists THEN '✓ 成功' ELSE '✗ 失败' END;
RAISE NOTICE '表空间权限: %', CASE WHEN user_has_tablespace_priv THEN '✓ 有CREATE权限' ELSE '✗ 无权限' END;
RAISE NOTICE '数据库创建: %', CASE WHEN database_exists THEN '✓ 成功' ELSE '✗ 失败' END;
RAISE NOTICE '数据库连接权限: %', CASE WHEN user_has_db_connect THEN '✓ 有权限' ELSE '✗ 无权限' END;
RAISE NOTICE 'Schema创建: %', CASE WHEN schema_exists THEN '✓ 成功' ELSE '✗ 失败' END;
RAISE NOTICE 'Schema使用权限: %', CASE WHEN user_has_schema_usage THEN '✓ 有权限' ELSE '✗ 无权限' END;
RAISE NOTICE '表创建: %', CASE WHEN table_exists THEN '✓ 成功' ELSE '✗ 失败' END;
RAISE NOTICE '表拥有者正确: %', CASE WHEN table_owner_correct THEN '✓ 是' ELSE '✗ 否' END;
RAISE NOTICE '表查询权限: %', CASE WHEN user_has_table_select THEN '✓ 有权限' ELSE '✗ 无权限' END;
RAISE NOTICE '索引创建: %', CASE WHEN index_exists THEN '✓ 成功' ELSE '✗ 失败' END;
RAISE NOTICE '索引拥有者正确: %', CASE WHEN index_owner_correct THEN '✓ 是' ELSE '✗ 否' END;
-- 综合评估
RAISE NOTICE '=== 综合评估 ===';
IF user_exists AND tablespace_exists AND database_exists AND schema_exists AND table_exists AND index_exists THEN
RAISE NOTICE '基础对象创建: ✓ 全部成功';
ELSE
RAISE NOTICE '基础对象创建: ✗ 存在失败项';
END IF;
IF user_has_tablespace_priv AND user_has_db_connect AND user_has_schema_usage AND user_has_table_select THEN
RAISE NOTICE '权限配置: ✓ 全部正确';
ELSE
RAISE NOTICE '权限配置: ✗ 存在权限问题';
END IF;
IF table_owner_correct AND index_owner_correct THEN
RAISE NOTICE '对象所有权: ✓ 全部正确';
ELSE
RAISE NOTICE '对象所有权: ✗ 存在所有权问题';
END IF;
END $$;
输出示例:

总结
通过本文的详细分析和实战案例,我们可以得出以下结论:
默认表空间机制:KingbaseES 具有清晰的默认表空间继承机制,从系统参数到数据库再到用户层级。
灵活配置:支持在数据库和用户级别分别设置默认表空间,满足不同应用场景需求。
完整权限体系:通过系统表查询可以全面了解表空间、权限和物理存储的关联关系。
最佳实践:建议为重要应用创建专用表空间,实现数据文件的物理隔离和管理优化。
合理的表空间规划和管理对于数据库性能、备份恢复和日常运维都具有重要意义,应根据实际业务需求制定相应的表空间策略。