概述
在 KingbaseES 数据库中,表空间是数据库对象的物理存储位置,合理的表空间配置对数据库性能和管理至关重要。本文将深入探讨数据库和用户的默认表空间配置,并通过实战案例展示完整的配置流程。
一、数据库默认表空间
1.1 创建数据库时不指定表空间
CREATE DATABASE shanjiatest1;
1.2 默认存放位置
表空间: sys_default
物理路径: <data>/base/数据库OID
1.3 查看数据库默认表空间
方法一:使用 \l+ 命令
\l+ shanjiatest1

方法二:查询系统表
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 查询结果分析
当前配置状态:
用户名: shanjiatestuser1
用户配置: 空(表示没有特殊配置)
默认表空间: 空(表示使用系统默认)
临时表空间: 空(表示使用系统默认)
详细解释:
默认表空间为空的意义
用户创建对象时使用数据库的默认表空间(sys_default)
等同于没有显式设置 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 查看关键系统参数
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');
四、创建对象得默认行为
4.1 表在默认表空间的创建
#不指定表空间创建表
CREATE TABLE shanjiatesttable1 (id SERIAL, name TEXT);
#验证表的表空间
SELECT
c.relname as "表名",
n.nspname as "模式名",
a.rolname as "表所有者",
CASE
WHEN c.reltablespace = 0 THEN 'sys_default(数据库默认表空间)'
ELSE (SELECT spcname FROM sys_tablespace WHERE oid = c.reltablespace)
END as "表空间",
c.relfilenode as "文件节点号",
sys_relation_filepath(c.oid) as "相对文件路径",
(SELECT setting FROM sys_settings WHERE name = 'data_directory') || '/' ||
sys_relation_filepath(c.oid) as "绝对文件路径",
pg_size_pretty(pg_relation_size(c.oid)) as "表大小"
FROM sys_class c
JOIN sys_namespace n ON c.relnamespace = n.oid
JOIN sys_authid a ON c.relowner = a.oid
WHERE c.relname = 'shanjiatesttable1'
AND c.relkind = 'r';

4.2 索引在默认表空间的创建
#不指定表空间创建索引
CREATE INDEX idx_my_table_name ON shanjiatesttable1(name);
#验证索引的表空间
SELECT
indexname as index_name,
tablespace as tablespace_name
FROM sys_indexes
WHERE indexname = 'idx_my_table_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 创建用户和表空间
-- 1、创建用户
CREATE USER shanjiatest2 WITH PASSWORD '46eCN+hHit3Ggidr7u/A';
COMMENT ON ROLE shanjiatest2 IS 'shanjia测试用户';
GRANT USAGE ON SCHEMA public TO shanjiatest2;
-- 2、授权共享用户访问public
GRANT ALL PRIVILEGES ON ALL FUNCTIONS IN SCHEMA public TO shanjiatest2;
GRANT ALL PRIVILEGES ON ALL PROCEDURES IN SCHEMA public TO shanjiatest2;
-- 3、创建表空间
CREATE TABLESPACE shanjiatest2_tbs OWNER shanjiatest2
LOCATION '/home/kingbase/tablespaces/shanjiatest_tbs';
COMMENT ON TABLESPACE shanjiatest2_tbs IS '山佳应用专用表空间';
-- 4、授予表空间上的所有权限
GRANT ALL PRIVILEGES ON TABLESPACE shanjiatest2_tbs TO shanjiatest2;
-- 5、创建数据库并指定默认表空间
CREATE DATABASE shanjia WITH ENCODING 'UTF8' OWNER shanjiatest2
TABLESPACE shanjiatest2_tbs ALLOW_CONNECTIONS TRUE;
COMMENT ON DATABASE shanjia IS 'shanjia测试数据库';
-- 6、创建Schema并授权以及设置search_path
\c shanjia
CREATE SCHEMA IF NOT EXISTS shanjia AUTHORIZATION shanjiatest2;
GRANT ALL PRIVILEGES ON SCHEMA shanjia TO shanjiatest2;
-- 设置整个数据库的默认search_path
ALTER DATABASE shanjia SET search_path TO shanjia, public;
-- 设置特定用户的search_path
ALTER ROLE shanjiatest2 SET search_path TO shanjia,public;
-- 7、授权public_to_user
GRANT USAGE ON SCHEMA public TO shanjiatest2;
-- 8、创建表
CREATE TABLE shanjia.shanjiatesttable2 (id SERIAL, name TEXT);
ALTER TABLE shanjia.shanjiatesttable2 OWNER TO shanjiatest2;
-- 9、创建索引
CREATE INDEX idx_my_table_name ON shanjia.shanjiatesttable2(name);
ALTER INDEX shanjia.idx_my_table_name OWNER TO shanjiatest2;
5.2 用户权限验证
SELECT
rolname as "用户名",
rolsuper as "超级用户",
rolinherit as "继承权限",
rolcreaterole as "可创建角色",
rolcreatedb as "可创建数据库",
rolcanlogin as "可登录",
rolconnlimit as "连接限制",
rolvaliduntil as "密码有效期",
rolconfig as "角色配置",
obj_description(oid, 'pg_authid') as "用户注释"
FROM sys_roles
WHERE rolname = 'shanjiatest2';

5.3 表空间信息查询
SELECT
spcname as "表空间名",
spcowner::regrole as "拥有者",
spcacl as "访问权限列表",
obj_description(oid, 'pg_tablespace') as "表空间注释",
sys_tablespace_location(oid) as "物理路径"
FROM sys_tablespace
WHERE spcname = 'shanjiatest2_tbs';

5.4 数据库配置查询
SELECT
datname as "数据库名",
datdba::regrole as "拥有者",
(SELECT spcname FROM sys_tablespace WHERE oid = dattablespace) as "默认表空间",
datconnlimit as "连接限制",
datacl as "访问权限列表",
obj_description(oid, 'pg_database') as "数据库注释",
encoding as "字符编码"
FROM sys_database
WHERE datname = 'shanjia';

5.5 权限汇总报告
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.6 PS:修改默认表空间配置
--修改数据库的默认表空间
ALTER DATABASE mydb SET TABLESPACE new_tablespace;
-- 注意:这会移动现有对象到新表空间
--修改用户的默认表空间
-- 修改用户的默认表空间
ALTER USER myuser SET DEFAULT_TABLESPACE = new_tablespace;
-- 修改用户的临时表空间
ALTER USER myuser SET TEMPORARY_TABLESPACE = temp_tablespace;
5.7 综合验证脚本
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 具有清晰的默认表空间继承机制,从系统参数到数据库再到用户层级。
灵活配置:支持在数据库和用户级别分别设置默认表空间,满足不同应用场景需求。
完整权限体系:通过系统表查询可以全面了解表空间、权限和物理存储的关联关系。
最佳实践:建议为重要应用创建专用表空间,实现数据文件的物理隔离和管理优化。
合理的表空间规划和管理对于数据库性能、备份恢复和日常运维都具有重要意义,应根据实际业务需求制定相应的表空间策略。