ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

人大金仓数据库库、模式、表空间关系与实操指南

人大金仓数据库库、模式、表空间关系与实操指南 刚开始用人大金仓数据库的时候我也被“库、模式、表空间”这三个词绕晕过连接串里写的是库名建表时又要选模式存储路径又和表空间有关出了问题到底该查哪一层后来在几个课程设计和生产项目里反复踩坑我才把这三者拆成一句话库是逻辑隔离的大房间模式是房间里按业务划分的隔间表空间是决定这些隔间里的家具到底放在哪块硬盘上的仓库。人大金仓数据库因为同时兼容 PostgreSQL 和 Oracle 的使用习惯所以初学时特别容易把“用户等于模式”“建库就自动建表空间”这些经验混在一起。这篇文章就从连接、建库、建模式、建表空间、建表、迁移、排错一路讲下去适合刚接触人大金仓的开发者、做数据库课程设计的学生也适合从 Oracle、MySQL 转过来的运维和开发。你不需要先把所有系统表背下来只要跟着实操把三层关系跑通后面遇到表空间满、模式找不到、权限不足这些问题基本都能定位。1. 先理清三层关系实例、库、模式、表空间到底谁管谁1.1 从一条连接串和建表语句反推层级先把一条最普通的连接串拆开看ksql -h 127.0.0.1 -p 54321 -U app_user -d appdb。这里-h和-p指向的是数据库实例-U是登录角色-d才是你要进入的数据库。也就是说实例是底座数据库是实例内部的一个逻辑隔离单元。你连上实例之后还要选择进入哪个库不同库之间默认不能直接跨库访问对象这一点和 MySQL 里db.table随处可写的感觉不一样。人大金仓在 PostgreSQL 兼容风格下跨库访问需要额外配置普通 SQL 里通常只操作当前库内的对象。再看建表语句CREATE TABLE app.user_info (...)。这里的app是模式user_info是表完整对象名是“模式.表”。如果没有写模式名数据库会按照search_path去找找错了就可能建到别的模式或者直接报“关系不存在”。表建完以后物理文件放在哪里由表空间决定。你可以在建表时写TABLESPACE tbs_app也可以不写让它落到数据库默认表空间。所以一条建表语句其实同时牵涉了库、模式、表空间三个层次库决定你在哪个逻辑房间里模式决定你进哪个隔间表空间决定家具放进哪个仓库。这个层级关系可以记成实例 数据库 模式 表/索引/序列等对象而表空间是横切在实例级别的物理存储映射不属于某个数据库独有。一个表空间可以被多个数据库共用一个数据库也可以使用多个表空间模式则必须属于某个数据库不能跨库存在。你把这条主线记住后面很多报错就能对上位置。1.2 库、模式、表空间的职责边界很多人把“库”和“模式”当成同一种东西觉得建库就是建模式建模式就是建库。实际上它们的职责完全不同。数据库主要负责连接入口、权限边界、备份恢复边界和一部分参数边界模式主要负责对象命名空间、权限收纳和业务模块隔离表空间主要负责物理文件落盘位置、磁盘容量和 IO 分布。下面这张表可以帮你快速对照。概念所在层级主要作用典型操作影响范围数据库实例内逻辑单元连接入口、对象隔离、备份恢复边界CREATE DATABASE影响当前库内所有模式和对象模式数据库内命名空间业务模块隔离、对象命名、权限管理CREATE SCHEMA影响模式内所有表、索引、视图等表空间实例级物理映射指定文件目录、容量规划、冷热分离CREATE TABLESPACE可能影响多个数据库中的对象表/索引模式内对象实际存数据、支撑查询CREATE TABLE、CREATE INDEX受所属库、模式、表空间共同影响从影响范围看表空间最“危险”。你删一个模式只影响这个模式里的对象你删一个数据库影响这个库里的所有模式你删一个表空间只要还有对象在使用它数据库通常会阻止你删除但如果强行把底层目录清掉可能直接导致多个库里的对象不可读。所以表空间不是普通的“文件夹”它是数据库元数据和文件系统之间的映射关系操作时要比建库建模式更谨慎。模式则是最容易被忽略的一层。很多应用连接上来之后不设置search_path直接执行SELECT * FROM user_info开发环境能用生产环境却报错原因就是生产库把表建在了app模式而默认搜索路径是public或用户同名模式。库决定你进哪个房间模式决定你开哪个抽屉表空间决定抽屉里的东西放在哪块硬盘上这三层各管一段不能互相替代。1.3 为什么人大金仓里容易混淆 Oracle 和 PostgreSQL 两套习惯人大金仓数据库常见的一个特点是兼容 PostgreSQL 和 Oracle 两套使用习惯。在 PostgreSQL 风格里用户和模式不是一回事你可以先创建角色app_user再创建模式app然后把模式权限授予角色。模式和用户名字可以不同一个用户也可以访问多个模式。建表时如果不指定模式对象会落到search_path第一个有效模式里。表空间是独立对象创建表、索引时可以单独指定。在 Oracle 风格里用户和模式通常同名创建用户app_user时数据库会自动创建一个同名模式用户登录后默认操作的就是这个模式。用户还可以有默认表空间建表不指定表空间时就往用户的默认表空间里放。很多从 Oracle 转过来的人会习惯性认为“建用户就等于建模式”“用户默认表空间就是模式默认表空间”但在人大金仓的 PostgreSQL 兼容风格下这个对应关系并不完全成立。所以你在人大金仓里操作前最好先确认当前库的兼容模式。不同版本、不同初始化参数下CREATE USER、CREATE ROLE、CREATE SCHEMA的行为可能有差异。最简单的方法是在 SQL 窗口里查当前用户、当前模式、默认表空间和搜索路径再结合建库时的兼容选项判断。如果你们项目用的是 Oracle 兼容模式就按“用户即模式、默认表空间随用户走”的思路理解如果用的是 PostgreSQL 兼容模式就牢牢记住“模式是命名空间用户是权限主体表空间是物理位置”。把这两套习惯分清楚后面写 SQL 和排错会省很多时间。2. 动手之前先把环境、连接和现有信息摸清楚2.1 连接方式ksql、图形工具和 Docker 环境人大金仓常见的命令行工具是ksql用法和 PostgreSQL 的psql很接近。假设实例端口是54321管理员账号以安装时设置为准下面用kingbase作为示例账号ksql -h 127.0.0.1 -p 54321 -U kingbase -d testdb进入之后你可以用元命令快速查看数据库列表、模式列表和表空间列表。不同版本可能对元命令支持略有差异但常见的有\l查看数据库\dn查看模式\db查看表空间。图形工具方面Navicat、DBeaver、dbx 数据库工具都可以连人大金仓本质上也是通过驱动执行 SQL。图形界面适合日常查看建表空间、改默认表空间这类操作建议还是保留 SQL 窗口方便记录和复现。如果是在 Docker 里跑人大金仓数据库要特别小心路径问题。容器里的数据库进程只能看到容器内文件系统你在客户端机器上建一个目录然后在 SQL 里写LOCATION /data/kingbase/tbs_app它找的是容器内路径不是你的笔记本路径。正确做法是通过 volume 把宿主机目录挂载到容器内再让 SQL 里的LOCATION指向容器内挂载点。否则你会遇到“目录不存在”或者数据库启动后表空间失效的问题。2.2 查看当前库、模式、搜索路径、表空间连接上之后先别急着建对象。先把当前环境摸清楚后面出问题才知道从哪一层查。下面这几条 SQL 很实用SELECT current_database() AS current_db, current_user AS current_user, current_schema() AS current_schema; SHOW search_path; SELECT spcname, pg_catalog.pg_tablespace_location(oid) AS location FROM pg_catalog.pg_tablespace; SELECT datname, pg_catalog.pg_get_userbyid(datdba) AS owner, dattablespace::regclass AS default_tablespace FROM pg_database ORDER BY datname; SELECT nspname, pg_catalog.pg_get_userbyid(nspowner) AS owner FROM pg_namespace WHERE nspname NOT LIKE pg_% AND nspname information_schema ORDER BY nspname;如果当前版本对系统表做了sys_前缀封装也可以尝试SELECT * FROM sys_tablespace;或者通过图形工具的表空间节点查看。重点看三个结果当前数据库是谁当前模式是谁默认表空间是谁。很多“表建错地方”“索引找不到”的问题根源就是这三项和预期不一致。search_path尤其重要。它决定你不写模式名时数据库按什么顺序找对象。典型值可能是$user, public意思是先找和当前用户同名的模式再找public。如果你的业务表建在app模式但search_path里没有app那你不加模式前缀就会报错。解决方式可以是会话级SET search_path TO app, public;也可以是角色级或数据库级设置后面会细讲。2.3 建库前必须确认的字符集、兼容模式和表空间目录建库不是只有一句CREATE DATABASE。模板、字符集、排序规则、兼容模式、连接限制、默认表空间这些都会影响后续使用。字符集推荐统一用UTF8避免后期导入中文乱码。排序规则如果不确定就跟现有系统保持一致不要一个实例里混用多套规则。兼容模式要根据项目技术栈决定Oracle 迁移项目通常选 Oracle 兼容原生 PostgreSQL 风格项目则选 PostgreSQL 兼容。表空间目录规划更要提前做。假设你计划把业务数据、索引、历史数据分开可以设计三个表空间tbs_app_data、tbs_app_idx、tbs_app_hist对应服务器目录/data/kingbase/tbs_app_data、/data/kingbase/tbs_app_idx、/data/kingbase/tbs_app_hist。这些目录必须在数据库服务器上创建属主是运行数据库进程的操作系统用户权限通常要求0700。目录必须为空不能和数据库数据目录重叠也不要随手挂在临时目录下。容量估算可以按这个思路来先估算业务表年增量再给索引留出约表大小的 30% 到 60%最后乘以 1.5 到 2 的膨胀系数。比如预计一年表数据 200GB索引 80GB再考虑更新膨胀、临时排序和后续增长单表空间至少准备 500GB 以上。如果热数据查询频繁把热表空间放在 SSD历史归档查询少可以放普通磁盘。表空间不是备份备份策略还要单独做不要以为把数据放到不同目录就等于有了冗余。3. 从零建一套可复现的库、模式、表空间3.1 创建表空间目录、属主、权限和 LOCATION创建表空间之前先在数据库服务器上做操作系统层准备。以 Linux 为例假设数据库进程属主是kingbasemkdir -p /data/kingbase/tbs_app_data mkdir -p /data/kingbase/tbs_app_idx chown kingbase:kingbase /data/kingbase/tbs_app_data chown kingbase:kingbase /data/kingbase/tbs_app_idx chmod 700 /data/kingbase/tbs_app_data chmod 700 /data/kingbase/tbs_app_idx然后进入ksql用有权限的账号执行CREATE TABLESPACE tbs_app_data OWNER kingbase LOCATION /data/kingbase/tbs_app_data; CREATE TABLESPACE tbs_app_idx OWNER kingbase LOCATION /data/kingbase/tbs_app_idx;这里有几个关键点。第一LOCATION是数据库服务器上的路径不是客户端路径。第二目录必须为空如果里面有文件通常会被拒绝。第三目录权限和属主必须正确否则数据库进程无法读写。第四创建表空间通常需要较高权限普通业务账号不要授予这个能力。第五表空间一旦创建就是实例级对象其他数据库也可能使用所以命名要带业务前缀不要叫tbs1、test这种无法辨认的名字。创建完成后可以查一下SELECT spcname, pg_catalog.pg_tablespace_location(oid) AS location FROM pg_catalog.pg_tablespace WHERE spcname IN (tbs_app_data, tbs_app_idx);如果查不到先确认当前连接的是不是同一个实例。表空间是实例级的不是某个库私有的这一点和模式完全不同。你在 A 库创建的表空间B 库也能看到并使用前提是有权限。也正因为如此删表空间时要确认没有其他库的对象还在用。3.2 创建数据库并指定默认表空间有了表空间之后可以创建业务库。下面这条语句在 PostgreSQL 兼容风格里比较典型CREATE DATABASE appdb WITH OWNER kingbase ENCODING UTF8 TABLESPACE tbs_app_data CONNECTION LIMIT 100 TEMPLATE template0;TABLESPACE tbs_app_data表示这个数据库的默认表空间。以后在这个库里建表、建索引如果没有单独指定表空间默认就往tbs_app_data放。TEMPLATE template0常用于配合指定编码避免模板库已有对象干扰。CONNECTION LIMIT可以限制连接数生产环境按应用连接池规模设置不要随便设得过大。创建完数据库后退出当前库重新连接到新库ksql -h 127.0.0.1 -p 54321 -U kingbase -d appdb如果你需要修改数据库默认表空间可以用ALTER DATABASE appdb SET TABLESPACE tbs_app_data2;这个操作会把数据库默认表空间里的对象移动到新表空间可能涉及大量文件复制和锁生产环境要选低峰期做并提前确认磁盘空间足够。对于普通业务表更常见的做法是单独对表或索引执行SET TABLESPACE而不是整体改数据库默认表空间。数据库默认表空间影响的是“没有显式指定表空间”的新对象已有对象不会因为你改了默认值就自动搬家。3.3 创建模式、用户与权限绑定接下来创建业务模式和业务用户。在 PostgreSQL 兼容风格下用户和模式是分开的CREATE ROLE app_user LOGIN PASSWORD ReplaceWithStrongPassword; CREATE SCHEMA app AUTHORIZATION app_user; GRANT CONNECT ON DATABASE appdb TO app_user; GRANT USAGE, CREATE ON SCHEMA app TO app_user;这里CREATE ROLE ... LOGIN创建的是可以登录的角色CREATE SCHEMA app AUTHORIZATION app_user创建模式并指定属主。GRANT USAGE允许用户进入这个模式GRANT CREATE允许用户在模式里创建对象。如果只给USAGE不给CREATE用户能查已有表但不能自己建表。如果只给CREATE不给USAGE通常也没法正常使用两个权限要配合。如果你使用的是 Oracle 兼容风格可能会用到类似下面的语句CREATE USER app_user IDENTIFIED BY ReplaceWithStrongPassword DEFAULT TABLESPACE tbs_app_data;在 Oracle 兼容模式下创建用户可能会自动创建同名模式用户默认表空间也会影响建表落点。但你要记住这只是兼容行为不代表所有人大金仓环境都完全一样。最稳妥的办法是创建完用户后用SELECT current_user, current_schema;和SHOW search_path;验证一下看看实际进入的是哪个模式默认表空间是否符合预期。权限方面生产环境不要直接给业务用户超级用户权限。建表空间、建库这类操作交给 DBA 或初始化脚本业务用户只拿连接、模式使用、表增删改查权限。可以配合ALTER DEFAULT PRIVILEGES提前设置未来对象的默认权限ALTER DEFAULT PRIVILEGES IN SCHEMA app GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO app_user; ALTER DEFAULT PRIVILEGES IN SCHEMA app GRANT USAGE, SELECT ON SEQUENCES TO app_user;3.4 在指定模式下建表并落到指定表空间模式、用户、表空间都准备好之后就可以建表了。建议在会话里先设置搜索路径再建表SET search_path TO app, public; CREATE TABLE app.user_info ( id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, user_name varchar(64) NOT NULL, created_at timestamp DEFAULT now() ) TABLESPACE tbs_app_data;这条语句把表建在app模式数据文件放到tbs_app_data表空间。注意主键索引的表空间。很多情况下表指定了表空间但主键或唯一约束对应的索引不一定自动落到你想要的索引表空间。为了把索引也分开放可以显式指定CREATE TABLE app.user_info ( id bigint GENERATED BY DEFAULT AS IDENTITY, user_name varchar(64) NOT NULL, created_at timestamp DEFAULT now(), CONSTRAINT pk_user_info PRIMARY KEY (id) USING INDEX TABLESPACE tbs_app_idx ) TABLESPACE tbs_app_data; CREATE INDEX idx_user_info_name ON app.user_info(user_name) TABLESPACE tbs_app_idx;这里把主键索引和普通索引都放到了tbs_app_idx表数据放在tbs_app_data。这样做的好处是数据和索引可以分别规划磁盘、分别监控容量备份恢复时也能更清楚哪些文件属于哪类对象。缺点是多了一层管理如果表空间目录权限或磁盘出问题索引查询会直接受影响。对于课程设计可以简单一点全部放一个表空间对于生产系统建议至少把表和索引分开。如果你不想每条建表语句都写表空间可以在数据库、角色或会话级别设置默认值ALTER DATABASE appdb SET default_tablespace tbs_app_data; ALTER ROLE app_user SET default_tablespace tbs_app_data; SET default_tablespace TO tbs_app_data;优先级通常是会话级高于角色级角色级高于数据库级。实际项目里不要把默认表空间设得太随意尤其是多个业务共用同一个库时很容易出现“明明想放索引表空间结果忘了指定全落到默认表空间”的情况。3.5 验证表、索引、模式、表空间对应关系建完之后一定要验证不要只看“创建成功”就结束。下面这条查询可以列出模式和对象对应的表空间SELECT n.nspname AS schema_name, c.relname AS object_name, CASE c.relkind WHEN r THEN table WHEN i THEN index WHEN S THEN sequence WHEN v THEN view ELSE c.relkind::text END AS object_type, COALESCE(t.spcname, database_default) AS tablespace_name FROM pg_class c JOIN pg_namespace n ON n.oid c.relnamespace LEFT JOIN pg_tablespace t ON t.oid c.reltablespace WHERE n.nspname app AND c.relkind IN (r, i, S) ORDER BY object_type, object_name;还可以查看具体表的数据文件路径SELECT pg_relation_filepath(app.user_info);返回结果里通常会带pg_tblspc和表空间 OID 的痕迹。你可以通过这个路径确认表到底有没有落到目标表空间。如果看到database_default说明这个对象没有显式指定表空间用的是数据库默认表空间。很多“我明明建了索引表空间为什么没生效”的问题都是因为创建索引时忘了写TABLESPACE或者用了约束自动建索引但没有指定USING INDEX TABLESPACE。验证时还要看模式属主和权限SELECT nspname, pg_catalog.pg_get_userbyid(nspowner) AS owner FROM pg_namespace WHERE nspname app; SELECT grantee, privilege_type FROM information_schema.role_schema_grants WHERE schema_name app;确认业务用户有USAGE需要建表的用户有CREATE不需要的用户不要乱给权限。模式权限和表空间权限是两套东西给了模式权限不代表能给表空间写文件反过来也一样。把这几项查清楚后面应用连接上来才不会出现“库能连、模式进不去、表看不见”的连锁问题。4. 迁移、日常维护与工具链里的坑4.1 把已有表和索引迁到新表空间表空间规划不是一次定终身的。业务增长后你可能需要把热表迁到 SSD 表空间或者把历史表迁到便宜磁盘。单表迁移通常用ALTER TABLE app.user_info SET TABLESPACE tbs_app_data_new; ALTER INDEX app.idx_user_info_name SET TABLESPACE tbs_app_idx_new; ALTER INDEX app.pk_user_info SET TABLESPACE tbs_app_idx_new;注意表迁移不会自动带走它的索引。主键索引、唯一索引、普通索引都要单独迁移否则你会看到表数据已经到了新表空间索引还留在老表空间。迁移大表时数据库通常会持有较强的锁期间可能阻塞读写并且会在底层复制文件磁盘空间要预留双份。最好在业务低峰期做先在小表上验证流程再上大表。迁移后可以查一下还有哪些对象留在旧表空间SELECT n.nspname AS schema_name, c.relname AS object_name, t.spcname AS tablespace_name FROM pg_class c JOIN pg_namespace n ON n.oid c.relnamespace JOIN pg_tablespace t ON t.oid c.reltablespace WHERE t.spcname tbs_app_data_old AND c.relkind IN (r, i, S);如果确认旧表空间没有对象了也不要直接删目录。先通过 SQL 删除表空间再检查目录残留。不同版本对底层目录清理行为可能不同生产环境一定要先备份元数据和确认没有对象引用。4.2 模式搜索路径与跨模式访问模式这一层最常见的维护就是search_path。你可以按会话设置SET search_path TO app, public;也可以按角色设置让这个用户每次登录都自动生效ALTER ROLE app_user SET search_path TO app, public;还可以按数据库设置ALTER DATABASE appdb SET search_path TO app, public;优先级上会话设置只影响当前连接角色设置影响该角色后续连接数据库设置影响连到这个库的所有角色但角色级通常能覆盖数据库级。实际项目里建议应用连接池初始化时显式执行SET search_path不要完全依赖数据库默认值。因为一旦有人改了数据库级配置所有应用都可能受影响。跨模式访问要写完整对象名比如report.user_info、audit.login_log。如果两个模式有同名表搜索路径顺序决定你不写模式名时访问哪一个。更稳妥的做法是业务 SQL 里始终带模式名尤其是建表、改表、删表这种 DDL。public模式要特别小心默认情况下很多数据库允许普通用户在public建对象容易造成权限混乱和对象覆盖。生产库可以执行REVOKE CREATE ON SCHEMA public FROM PUBLIC;然后把必要的权限单独授予业务角色。这样能减少“不知道谁在 public 里建了表”的问题。4.3 备份恢复、数据库同步和 Docker 环境备份恢复时库和模式是逻辑边界表空间是物理边界。逻辑备份通常按库导出比如使用人大金仓的sys_dump工具导出某个库sys_dump -h 127.0.0.1 -p 54321 -U kingbase -Fc -f appdb.dmp appdb恢复时可以用sys_restore。逻辑备份一般会包含模式、表、索引等对象定义但表空间定义和物理路径不一定会原样恢复。如果你在目标库提前建好了同名表空间恢复脚本就可能把对象放进去如果没有可能落到默认表空间或直接报错。做数据库同步软件选型时也要注意结构同步可能包含表空间语句目标端没有对应表空间就会失败数据同步通常不关心表空间但大批量写入会集中落到默认表空间可能把默认表空间打满。Docker 环境下的坑更集中。表空间的LOCATION必须写容器内路径并且这个路径要通过 volume 持久化。比如启动容器时挂载docker run -d \ --name kingbase-test \ -p 54321:54321 \ -v /data/kingbase/tbs_app_data:/data/kingbase/tbs_app_data \ -v /data/kingbase/tbs_app_idx:/data/kingbase/tbs_app_idx \ your-kingbase-image然后在 SQL 里创建表空间LOCATION写容器内路径/data/kingbase/tbs_app_data。不要写宿主机路径也不要挂载临时目录。容器重建后如果挂载点没变表空间还能继续用如果路径变了数据库元数据里记录的还是旧路径启动或访问时就会报错。做课程设计时如果只是本地练习可以用默认表空间少碰 Docker 路径问题但一旦要模拟生产最好把表空间和 volume 规划清楚。4.4 删除顺序、权限与误删风险删除顺序必须从逻辑对象到物理映射先删表、索引、序列等对象再删模式再删数据库最后删表空间。示例DROP SCHEMA app CASCADE; SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname appdb AND pid pg_backend_pid(); DROP DATABASE appdb; DROP TABLESPACE tbs_app_data;DROP SCHEMA app CASCADE会连带删除模式内所有对象生产环境执行前一定要确认。删除数据库前要断开其他连接否则会报“数据库正在被其他用户访问”。删除表空间前要确认没有任何数据库对象还在使用它可以用前面的查询检查。表空间有对象时DROP TABLESPACE通常会失败这是保护机制不要想办法绕过它。还要注意权限。普通业务用户不应该有CREATE TABLESPACE、DROP TABLESPACE权限也不应该拥有超级用户权限。表空间是实例级资源一旦误删或底层目录损坏影响的不只是一个库可能是多个库里的多个模式。把建表空间、改数据库默认表空间、迁移大表这些操作收敛到 DBA 或初始化脚本应用账号只做日常增删改查。这不是流程繁琐而是血泪教训换来的边界。5. 常见问题与排查技巧速查5.1 表空间相关报错表空间问题通常集中在路径、权限、占用和存在性上。下面这张速查表可以贴在工位上报错或现象常见原因排查与解决tablespace tbs_app does not exist表空间建在了别的实例或名称拼错查pg_tablespace确认实例和名称could not set permissions on directory目录属主或权限不对改成数据库进程属主权限0700directory is not emptyLOCATION目录已有文件换空目录不要手工塞文件permission denied for tablespace当前用户没有表空间权限用高权限账号创建或授予必要权限tablespace is not empty还有表、索引等对象在使用查询pg_class.reltablespace迁移或删除对象表空间目录磁盘满容量规划不足或日志误放扩容、迁移对象、监控pg_tablespace_size容器重启后表空间失效容器内路径或挂载点变化检查 volume 映射保持容器内路径一致其中最容易误判的是“表空间不存在”。很多人在一个实例里建了表空间却连到另一个实例执行建表自然找不到。人大金仓的实例、数据库、模式、表空间四层信息最好在项目初始化文档里写清楚不要只记库名。5.2 模式与对象不可见模式问题最典型的报错是schema app does not exist、relation user_info does not exist、permission denied for schema app。第一种是模式没建或没连对库第二种通常是搜索路径不对或者表建到了别的模式第三种是用户没有USAGE权限。排查时按顺序执行SELECT current_database(), current_user, current_schema(); SHOW search_path; SELECT nspname FROM pg_namespace WHERE nspname app; SELECT schemaname, tablename, tableowner FROM pg_tables WHERE tablename user_info;如果表存在但你不写模式名查不到就显式写SELECT * FROM app.user_info;。如果这样能查到说明就是search_path的问题。解决方式可以临时SET search_path也可以永久ALTER ROLE。如果是权限问题用属主账号执行GRANT USAGE ON SCHEMA app TO app_user;。不要图省事直接给超级用户权限越大误操作破坏范围越大。5.3 空间与性能默认表空间、临时表空间和冷热分离表空间除了管路径还能参与性能规划。比如把高频表放 SSD 表空间把历史表放普通磁盘表空间把索引放独立表空间减少数据和索引争抢 IO。临时排序、哈希连接产生的临时文件也可以单独放SET temp_tablespaces TO tbs_app_tmp;也可以按数据库或角色设置。临时表空间不要和业务数据表空间混在一起否则一个大查询可能把业务表空间打满。监控表空间大小可以用SELECT spcname, pg_catalog.pg_tablespace_size(oid) AS size_bytes FROM pg_catalog.pg_tablespace ORDER BY size_bytes DESC;需要提醒的是表空间分离不等于性能一定提升。如果所有表空间都在同一块物理盘上逻辑上分开只是方便管理IO 还是互相影响。真正要提升性能得结合磁盘类型、RAID、文件系统、内存和 SQL 优化一起看。表空间规划是手段不是目的。5.4 Navicat、DBeaver、dbx 等工具建表空间的差异图形工具建表空间时本质上还是在执行CREATE TABLESPACE。以 Navicat 为例连接实例后左侧对象树里通常能找到“表空间”节点右键新建填写名称、属主和路径。这里的路径仍然必须是数据库服务器路径。如果工具界面没有表空间节点或者版本不支持图形化创建就直接开 SQL 窗口执行语句。dbx 数据库工具、DBeaver 等也是类似思路能图形化就图形化不能就写 SQL不要以为换个工具就能绕开底层规则。用图形工具最容易踩的坑有三个。第一把客户端路径填进LOCATION服务端当然找不到。第二工具连接的是 A 实例表空间却建在 B 实例建表时又连回 A 实例。第三工具自动提交了建表空间语句但目录权限没准备好于是报错信息被弹窗简化看不到底层原因。遇到这种情况切回ksql或用工具的 SQL 窗口重试通常能看到更完整的错误。6. 课程设计与生产环境的规划建议6.1 命名与分层库、模式、表空间怎么摆做数据库课程设计时最容易犯的错是把所有表堆在一个模式里表空间也懒得建最后文档里说不清库、模式、表空间的关系。一个简单可复现的规划是一个实例一个业务库appdb三个模式app、report、audit两个表空间tbs_app_data、tbs_app_idx。app放业务表report放报表视图或汇总表audit放日志表。表数据放tbs_app_data索引放tbs_app_idx。这样既能让老师看到你对三层关系的理解也不会把环境搞得太复杂。生产环境则要按系统边界和租户边界来分。多个互不相干的系统可以分库减少权限和备份恢复的相互影响同一系统内按业务模块分模式方便授权和对象管理表空间按存储类型分比如数据、索引、大对象、历史归档、临时文件。命名上建议带上业务前缀例如tbs_order_data、tbs_order_idx、tbs_order_hist。不要用tbs1、test、new这种名字过两个月你自己都不记得它是干什么的。6.2 权限最小化与审计权限最小化是库、模式、表空间三层都要落实的。库级别控制CONNECT模式级别控制USAGE和CREATE表空间级别控制使用权限。应用账号只拿业务模式下的增删改查权限不要给建库、建表空间、删模式的权限。对于报表账号只给只读权限对于批处理账号可以给特定表的写入权限。默认权限也要管起来REVOKE CREATE ON SCHEMA public FROM PUBLIC; ALTER DEFAULT PRIVILEGES IN SCHEMA app GRANT SELECT ON TABLES TO report_user; ALTER DEFAULT PRIVILEGES IN SCHEMA app GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO app_user;审计方面至少记录谁在什么时间建了模式、建了表空间、改了默认表空间。表空间变更影响范围大最好纳入变更流程。课程设计可以不搞复杂审计但生产环境如果连表空间被谁改过都不知道出问题时很难追溯。6.3 从单机到多库多模式的可扩展路径一开始可以单实例、单库、多模式等业务增长后再考虑多实例、多库、多表空间。扩展时库和模式通常跟着应用走表空间跟着存储走。比如订单系统从单库拆成订单库和库存库模式仍然可以保留order、stock表空间可以从一块盘扩展到 SSD 热数据、HDD 冷数据、临时表空间。数据库同步软件做结构同步时要把表空间映射关系写清楚做数据同步时要确认目标端默认表空间容量足够。影响范围分析可以这样看改search_path影响应用 SQL 解析改默认表空间影响新对象落点迁移表空间影响磁盘和锁删表空间影响多个库。每次变更前先把“这个操作会影响哪个库、哪个模式、哪些表、哪些索引”写清楚。人大金仓的库、模式、表空间并不难难的是它们交叉在一起时很多人只看了其中一层。把这三层关系画在纸上再对着系统表查一遍很多问题就不用靠猜了。我印象最深的一次是课程设计有人把表空间目录建在客户端机器上服务端一直报目录不存在后来才发现LOCATION认的是数据库服务器文件系统。另一个坑是主键索引没跟着表迁移表空间看起来腾空了检查索引还在老地方。把这些关系跑一遍比背系统表有用得多。
返回列表