范围与枚举与字符集与编码

共 45 题
📑 题目列表 45 题
#
★★★

1. MySQL 中 BLOB、TEXT、JSON 的差异?

请说明 MySQL 中 BLOB、TEXT、JSON 三种类型的差异?

  • BLOB 二进制、TEXT 文本
  • JSON 结构化与校验
  • 索引与查询

BLOB 存储二进制数据(字节流,无字符集),TEXT 存储文本字符串(有字符集,会按字符集转换),JSON 存储 JSON 文档并自动校验有效性、可优化存储。BLOB/TEXT 有 TINY/MEDIUM/LONG 等级别,JSON 有原生 JSON 类型与函数(JSON_EXTRACT、-> 等)。JSON 支持虚拟列生成索引,BLOB/TEXT 做前缀索引。用途上:BLOB 存图片/文件,TEXT 存长文本,JSON 存半结构化数据。

三者按"二进制/文本/结构化"区分,JSON 比 TEXT 多校验与查询能力,是半结构化数据首选。

#
★★★

2. MySQL 中 ENUM 与 SET 类型的内部存储(索引号 vs 字符串)?

请说明 MySQL 中 ENUM 与 SET 类型的内部存储方式(索引号 vs 字符串)?

  • ENUM 存索引号
  • SET 存位掩码
  • 字符串与索引

MySQL 的 ENUM 内部按枚举值在定义中的序号(从 1 起)存储为整数,占用 1-2 字节;SET 内部按位掩码存储(每个成员占一位),最多 64 个成员。存储时只存索引/位,而非字符串,但查询时返回字符串。ENUM 单值、SET 多值。因为存索引,排序默认按定义顺序而非字母序。

ENUM 存索引、SET 存位掩码,都是"用整数替代字符串"的空间优化,但语义不同。

#
★★★

3. PostgreSQL 中 BINARY BYTEA(大对象)的存储与编码(hex、escape)?

请说明 PostgreSQL 中 BYTEA 类型的存储与编码(hex、escape)?

  • BYTEA 二进制
  • hex/escape 编码
  • 存储与 TOAST

PostgreSQL 的 BYTEA 是二进制字节类型,数据库默认以 hex 编码显示(如 \x...),也可用 escape 格式(反斜杠转义)。bytea_output 参数控制输出格式:hex(PG 9.0+ 默认)或 escape。存储时大值会走 TOAST 压缩/外部存储。BYTEA 适合存小到中等二进制数据,超大文件应用 Large Object 或外部存储。

BYTEA 的 hex/escape 是输出编码格式,加上 TOAST 处理,是二进制存储的核心。

SET bytea_output = 'hex';
SELECT '\xDEADBEEF'::bytea; -- \xdeadbeef
#
★★★

4. ENUM 与 VARCHAR + CHECK 约束的取舍?

请说明 ENUM 与 VARCHAR + CHECK 约束之间的取舍?

  • ENUM 简洁 vs 灵活性
  • CHECK 约束可控
  • 迁移与扩展

ENUM 将合法值集合内建于类型,存储紧凑、语义清晰,但改值成本高(ALTER 加值受限、删值重建),且在不同数据库间可移植性差。VARCHAR + CHECK 约束把校验放在表级,增加新值只需改 CHECK,灵活性高、可移植性好,但存储空间略大。取舍:固定且极少变化的枚举用 ENUM;可能频繁扩展、需跨库或需保留未知值的用 VARCHAR+CHECK。

ENUM 的"内建集合"与"难扩展"是一体两面,VARCHAR+CHECK 用灵活性换可扩展性。

#
★★★

5. PostgreSQL 中 ENUM 类型的实现,枚举值的内部存储与索引?

请说明 PostgreSQL 中 ENUM 类型的内部存储与索引实现?

  • 枚举值内部排序法
  • 存储为 OID/排序号
  • 索引

PostgreSQL 的 ENUM 类型内部用一个排序 OID(sort order)标识每个枚举值,按定义顺序排列比较,存储时实际存的是枚举 OID 而非字符串。比较按定义顺序进行,而非字母序。ENUM 列可建普通 B-Tree 索引,索引按枚举排序 OID 排列。新增值只能追加到末尾(除非 ALTER TYPE 复杂操作),这影响已有数据的排序不变量。

ENUM 内部存排序号、比较按定义顺序,是理解其排序与索引行为的关键。

CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy');
CREATE TABLE t (m mood);
SELECT 'happy'::mood > 'sad'::mood; -- true(按定义顺序)
#
★★★

6. PostgreSQL 中 range 类型与 GiST 索引的应用(IP 范围、时间段)?

请说明 PostgreSQL 中 range 类型与 GiST 索引的应用(如 IP 范围、时间段)?

  • range 类型
  • GiST 索引
  • 重叠/包含查询

PostgreSQL 的 range 类型(int4range、tsrange、daterange、numrange 等)表示值的区间,专用于处理区间重叠、包含、前后等关系。配合 GiST 索引,可高效执行 @>、&&、<@ 等区间操作符,如"查询与某时间段重叠的所有记录"。典型的 IP 范围、会议时间段、价格区间等场景。GiST 能加速区间查询,避免全表扫描。

range + GiST 是处理区间数据的黄金搭档,GiST 索引利用区间边界加速重叠判断。

CREATE TABLE booking (period tsrange);
CREATE INDEX ON booking USING gist (period);
SELECT * FROM booking WHERE period && tsrange('2020-01-01', '2020-01-02');
#
★★★

7. 范围类型的索引,GiST 与 SP-GiST 的应用?

请说明范围类型索引中 GiST 与 SP-GiST 的应用差异?

  • GiST 与 SP-GiST
  • 适用场景
  • 选择

GiST 是通用搜索树,支持多种操作符(如 range 的 @>、&&),是 range 类型默认且最常用的索引;SP-GiST 是空间分区搜索树,适用于可"递归分区"的数据(如某些几何、网络),对 range 支持有限。GiST 对 range 的区间判定(重叠、包含)成熟高效,SP-GiST 主要用于四叉树、kd-tree 等分区场景。绝大多数 range 查询用 GiST 即可。

GiST 是 range 的通用选择,SP-GiST 是特定分区场景的替代,二者操作符支持不同。

#
★★★

8. JSONB 字段的 GIN 索引创建?

请说明 PostgreSQL 中如何在 JSONB 字段上创建 GIN 索引?

  • GIN 索引 JSONB
  • 默认与 jsonb_path_ops
  • 创建语法

在 JSONB 列上创建 GIN 索引可用 CREATE INDEX idx ON t USING gin (doc);(默认操作符类)或 USING gin (doc jsonb_path_ops);(路径操作符类)。默认类支持 @>、?、?&、?| 等操作符;jsonb_path_ops 更小更快,但只支持 @>(包含)操作符。GIN 索引能加速 JSONB 的包含与存在查询。

GIN 索引是 JSONB 查询加速的关键,jsonb_path_ops 是更精简的变体。

CREATE INDEX idx_gin ON products USING gin (attributes);
CREATE INDEX idx_gin2 ON products USING gin (attributes jsonb_path_ops);
#
★★★

9. JSONB 嵌套深度的限制?

请说明 PostgreSQL 中 JSONB 的嵌套深度限制?

  • 嵌套深度上限
  • 解析限制
  • 异常

PostgreSQL 的 json/jsonb 解析在 PG 16 及更早版本没有固定的嵌套深度上限(不存在 100 层或 1000 层的硬限制),超深 JSON 仅受通用栈深度保护(check_stack_depth,由 max_stack_depth 参数控制)约束;PG 17+ 的流式 JSON 解析器引入显式上限 6400 层(JSON_TD_MAX_STACK),超出报错 "JSON nested too deep, maximum permitted depth is 6400"。过深结构虽能解析,但会影响性能,深层 JSON 应考虑扁平化或拆表。

PG 的 JSONB 并无 100/1000 层的固定深度限制:PG 16 及以前仅受通用栈深度保护,PG 17+ 显式上限为 6400 层;超深结构影响性能,需注意设计。

#
★★★

10. JSONB 索引(jsonb_path_ops)的差异?

请说明 JSONB GIN 索引默认类与 jsonb_path_ops 的差异?

  • 操作符支持
  • 索引大小
  • 查询性能

jsonb_path_ops 相比默认 GIN 操作符类,索引更小(约 1/3 大小)、查询更快,但只支持 @>(包含)操作符,不支持 ?、?&、?|(存在性)操作符。默认类支持 @>、?、?&、?| 全部。若业务主要用 @> 查询,选 jsonb_path_ops 更优;若需存在性查询,用默认类。

两者是"小而快但功能少"与"功能全但较大"的取舍,取决于查询模式。

#
★★★

11. MySQL ENUM 的 ALTER TABLE 修改成本?

请说明 MySQL 中修改 ENUM 的 ALTER TABLE 成本?

  • 加值/删值
  • 表重建
  • 在线改表

MySQL 中修改 ENUM 类型(如增加枚举值)通常需要 ALTER TABLE,MySQL 8.0 对 ENUM 增加值可做 INPLACE 快速变更(在末尾追加),但仍然需要重建或修改表元数据、可能锁表。删除值或重排则需 COPY 重建全表,成本高。因此设计 ENUM 时预留扩展位或避免频繁改动。相比 VARCHAR+CHECK 改约束更简单。

ENUM 改值成本取决于"追加"还是"重排/删除",追加相对便宜但删除重建昂贵。

#
★★★

12. MySQL 中 BLOB 与 TEXT 的对比?

请对比 MySQL 中 BLOB 与 TEXT 的差异?

  • 二进制 vs 文本
  • 字符集
  • 排序与比较

MySQL 中 BLOB 存储二进制字节,无字符集,不做字符转换,比较按字节;TEXT 存储文本,有字符集,会按字符集解释与转换,比较按字符规则。两者都有 TINY/MEDIUM/LONG 等级别,最大长度不同。BLOB 适合图片、文件字节,TEXT 适合长文本。BLOB 不能有默认值,TEXT 排序用 collation。B/TEXT 做前缀索引。

BLOB 无字符集、TEXT 有字符集,是核心差异,决定排序与转换行为。

#
★★★

13. MySQL 中 MEDIUMBLOB、LONGBLOB 的大小?

请说明 MySQL 中 MEDIUMBLOB、LONGBLOB 的最大存储大小?

  • 各 BLOB 上限
  • 字节数
  • 应用

MySQL 中 BLOB 各等级的最大字节数:TINYBLOB 255 字节,BLOB 65535 字节(64KB),MEDIUMBLOB 16777215 字节(16MB),LONGBLOB 4294967295 字节(4GB)。同时受 max_allowed_packet 限制,实际可存储上限还受该参数影响。LONGBLOB 适合超大二进制,但大值会走外部存储影响性能。

MEDIUMBLOB 16MB、LONGBLOB 4GB,字节上限是选择 BLOB 等级的依据。

#
★★★

14. MySQL 中 TINYTEXT、TEXT、MEDIUMTEXT、LONGTEXT 的差异?

请说明 MySQL 中 TINYTEXT、TEXT、MEDIUMTEXT、LONGTEXT 的差异?

  • 各等级大小
  • 存储方式
  • 索引

MySQL 文本类型按最大字节数分级:TINYTEXT 255 字节,TEXT 64KB,MEDIUMTEXT 16MB,LONGTEXT 4GB。它们都受字符集影响(字节数按字符集换算)。TEXT 系列在行内存储指针,大值走外部存储。索引只能前缀。选择等级需匹配实际文本长度,过大浪费、过小截断。

四级 TEXT 按容量递增,选型依据是期望文本的最大字节数。

#
★★★

15. PostgreSQL 中 BYTEA 与 Large Object 的差异?

请说明 PostgreSQL 中 BYTEA 与 Large Object(大对象)的差异?

  • BYTEA 行内 vs Large Object 外部
  • 大小限制
  • 使用场景

BYTEA 是普通二进制类型,最大约 1GB,作为普通值存储,可参与常规查询与索引;Large Object(lo)是专门的大对象机制,存储于 pg_largeobject 表,支持流式读写(lo_open、lowrite),适合超大(>1GB)或流式访问的数据。BYTEA 简单、可索引、可参与事务;Large Object 需要 lo_manage 等管理,清理麻烦。存中小二进制用 BYTEA,超大/流式用 Large Object 或外部存储。

BYTEA 与 Large Object 是"行内常规值"与"外部流式对象"的取舍,BYTEA 更常用。

#
★★★

16. PostgreSQL 中 hstore 与 jsonb 的取舍?

请说明 PostgreSQL 中 hstore 与 jsonb 的取舍?

  • hstore 键值对
  • jsonb 通用 JSON
  • 嵌套与操作符

hstore 是键值对(key-value)类型,键和值都是纯文本,不支持嵌套与数组,操作符少(->、@> 等);jsonb 是通用 JSON,支持嵌套、数组、更多操作符(->、->>、@>、?、jsonb_path_ops 索引等)。jsonb 功能更强、更通用,几乎取代 hstore;hstore 更轻量、旧生态。新项目通常选 jsonb,除非只是简单两列键值对。

jsonb 是 hstore 的通用超集,嵌套与丰富操作符使 jsonb 成为默认选择。

#
★★

17. PostgreSQL 中数组的 GIN 索引?

请说明 PostgreSQL 中数组类型的 GIN 索引?

  • GIN 索引数组
  • 包含操作符
  • 查询加速

PostgreSQL 中可为数组列创建 GIN 索引,以加速 @>(包含)、<@(被包含)、&&(重叠)等数组操作符。GIN 索引把数组元素作为索引项,查询"包含某元素"的数组时快速定位。例如 CREATE INDEX ON t USING gin (tags); WHERE tags @> ARRAY['a']。GIN 适合数组包含/重叠查询,结合数组类型高效处理多值数据。

GIN 索引是基于"元素"的索引,天然适配数组的包含/重叠查询。

CREATE INDEX ON articles USING gin (tags);
SELECT * FROM articles WHERE tags @> ARRAY['postgres'];
#
★★

18. ENUM 与 VARCHAR 的存储对比?

请对比 ENUM 与 VARCHAR 的存储空间?

  • ENUM 存索引号
  • VARCHAR 存字符串
  • 空间差异

MySQL 中 ENUM 存储枚举值索引号(1-2 字节),即使字符串很长也很紧凑;VARCHAR 存储实际字符串(n 字节 + 长度前缀)。当枚举值字符串较长时,ENUM 明显省空间;当值很短时差异不大。PostgreSQL 中 ENUM 存 OID/排序号,也紧凑。但空间节省换来了扩展性与可移植性代价。

ENUM 用索引号压缩存储换取空间,但牺牲了灵活性与跨库兼容。

#
★★

19. ENUM 修改值的影响(依赖视图失效)?

请说明修改 ENUM 值对依赖视图的影响?

  • 依赖对象
  • 失败风险
  • 处理

修改(尤其删除或重排)ENUM 类型的值可能使依赖该类型的对象(视图、函数、默认值、约束)失效或报错,因为它们的依赖元数据引用了旧枚举值。PostgreSQL 中 ALTER TYPE ... ADD VALUE 在事务中有限制,而删除值需谨慎。MySQL 中删除枚举值可能导致依赖视图不可用。修改前应评估依赖对象,必要时重建。

ENUM 是"类型"而非"表约束",其变更影响依赖链,删除值风险高。

#
★★

20. ENUM 在 MySQL 中的实现(VARCHAR)?

请说明 MySQL 中 ENUM 的实现方式?

  • 内部索引号
  • 底层存储
  • 是否 VARCHAR

MySQL 的 ENUM 底层不是 VARCHAR,而是以紧凑的整数索引号存储(1 字节或 2 字节,取决于枚举数),每个枚举值对应一个序号,元数据中保存序号到字符串的映射。查询时把索引转回字符串。因此 ENUM 比 VARCHAR 省空间,但排序按索引号(定义顺序)而非字符串。它本质是"带字符串映射的整数类型"。

澄清"ENUM 是 VARCHAR"的误区——MySQL ENUM 底层是整数索引 + 字符串映射。

#
★★

21. 范围类型与 B-Tree 索引?

请说明范围类型能否使用 B-Tree 索引,及其适用场景?

  • B-Tree 对 range
  • 等值/排序
  • 与 GiST 对比

范围类型(range)可以建立 B-Tree 索引,但它只支持等值比较、排序和范围点的唯一性,无法高效表达"重叠""包含"等区间语义。若只需按范围值的整体排序或等值查找,B-Tree 可用;要做区间重叠/包含查询,必须用 GiST 索引。因此 range 的"区间查询"离不开 GiST,B-Tree 适用场景有限。

B-Tree 适合等值/排序,GiST 适合区间重叠,range 的区间查询需 GiST。

#
★★

22. 范围类型的 GIN 索引?

请说明范围类型能否使用 GIN 索引及其应用?

  • GIN 对 range
  • 元素包含
  • 适用

PostgreSQL 范围类型支持的索引为 GiST、SP-GiST、B-Tree 与 Hash(官方文档明确列出,GIN 不支持范围类型)。GiST/SP-GiST 用于区间重叠(&&)、包含(@>)等查询,B-Tree/Hash 只支持等值比较与排序。因此 range 的区间重叠/包含查询首选 GiST,GIN 不能用于 range 列。

range 的区间查询首选 GiST;GIN 不支持范围类型(官方文档所列 range 索引仅 GiST/SP-GiST/B-Tree/Hash),B-Tree/Hash 只能做等值比较。

#
★★

23. MySQL 中 character_set_server、character_set_client、character_set_connection 的差异?

请说明 MySQL 中 character_set_server、character_set_client、character_set_connection 的差异?

  • 服务器默认
  • 客户端声明
  • 连接转换

character_set_server 是服务器默认字符集(新建库/表未指定时的默认);character_set_client 是客户端发送语句所使用的字符集;character_set_connection 是连接层用于转换与参与运算的字符集。MySQL 在客户端、连接、结果集之间做字符集转换。设置 connection 字符集常通过 SET NAMES 同时设置三者。字符集不一致会导致乱码。

三者分别代表"服务器默认、客户端输入、连接运算"字符集,理解转换链避免乱码。

#
★★

24. 客户端编码(client_encoding)与服务端编码的自动转换,PostgreSQL 的 SET client_encoding?

请说明 PostgreSQL 中 client_encoding 与服务端编码的自动转换机制?

  • client_encoding
  • 服务端编码
  • 自动转换

PostgreSQL 的 client_encoding 指定客户端发送/接收数据的字符集,服务端编码是数据库存储编码。两者不同时,PostgreSQL 会自动做字符集转换,保证数据正确显示。可用 SET client_encoding TO 'UTF8' 或 SET NAMES 'UTF8' 设置。若字符集之间无法转换(如 Latin1 无法表示某个 UTF8 字符)会报错。JDBC 通常通过 characterEncoding 与 client_encoding 配合。

client_encoding 与服务端编码的自动转换是 PostgreSQL 的字符集处理核心,SET NAMES 可设置。

SET client_encoding TO 'UTF8';
#
★★

25. PostgreSQL 中 SHOW client_encoding 命令?

请说明 PostgreSQL 中 SHOW client_encoding 命令的用途?

  • 查看客户端字符集
  • 验证
  • 相关参数

SHOW client_encoding 显示当前会话的客户端字符集编码(如 UTF8)。用于确认客户端与服务器编码是否一致、排查乱码。改变编码用 SET client_encoding 或 SET NAMES。类似 SHOW server_encoding 显示服务端编码。JDBC 连接时可通过参数指定字符集。

SHOW client_encoding 是排查字符集乱码的快速检查命令。

SHOW client_encoding; -- UTF8
#
★★

26. JDBC 中 characterEncoding 参数?

请说明 JDBC 连接中 characterEncoding 参数的作用?

  • 客户端字符集
  • 与数据库编码
  • 乱码避免

JDBC 连接串中的 characterEncoding 参数指定客户端字符集(如 MySQL 的 characterEncoding=UTF-8),它控制应用与数据库之间传输的字符编码。MySQL 驱动会据此设置连接字符集,PostgreSQL 驱动通过 client_encoding 类似处理。字符集不匹配会导致乱码。通常设为 UTF-8 与数据库 UTF8 一致。

characterEncoding 是 JDBC 连接层字符集约定,与应用、数据库编码保持一致是关键。

jdbc:mysql://host/db?characterEncoding=UTF-8
#
★★

27. MySQL 中 SHOW VARIABLES LIKE 'character%' 查询?

请说明 MySQL 中 SHOW VARIABLES LIKE 'character%' 查询的用途?

  • 查看字符集变量
  • 排查乱码
  • 相关变量

SHOW VARIABLES LIKE 'character%' 列出所有以 character 开头的系统变量,包括 character_set_client、character_set_connection、character_set_server、character_set_database、character_set_results 等。用于排查字符集配置与乱码问题,确认各层字符集是否一致。修改可用 SET NAMES 或 SET character_set_xxx。

该查询是 MySQL 字符集排查的入口,展示各层字符集设置。

#
★★

28. MySQL 的 CONVERT 函数?

请说明 MySQL 中 CONVERT 函数的作用?

  • 字符集转换
  • 语法
  • 与 CAST 区别

MySQL 的 CONVERT(expr, charset) 用于把表达式转换为指定字符集,如 CONVERT('你好' USING utf8mb4) 或 CONVERT(name USING latin1)。它用于数据/列在字符集间转换,解决乱码与兼容问题。CONVERT 也可用于类型转换(CONVERT(x, TYPE)),但字符集转换是其主要用途。与 CAST 的区别:CAST 只做类型转换,CONVERT 可做字符集转换。

CONVERT 的核心是字符集转换,与 CAST 的类型转换形成对比。

SELECT CONVERT('你好' USING utf8mb4);
#
★★

29. PostgreSQL 中 ENCODING 'UTF8' 的设置?

请说明 PostgreSQL 中创建数据库时设置 ENCODING 'UTF8' 的作用?

  • 创建库编码
  • ENCODING 语法
  • 与 locale

PostgreSQL 中 CREATE DATABASE db ENCODING 'UTF8' 指定数据库的存储编码为 UTF8。数据库编码决定了该库内所有数据的字符集,创建后不可更改(除非重建)。UTF8 支持所有 Unicode 字符,是推荐选择。编码与 locale(排序规则)通常是 initdb 或 CREATE DATABASE 时一并确定的。SELECT pg_encoding_to_char(encoding) 可查看库编码。

ENCODING 在 CREATE DATABASE 时固化,UTF8 是默认且推荐的数据库编码。

CREATE DATABASE mydb ENCODING 'UTF8' TEMPLATE template0;
#
★★

30. PostgreSQL 中 pg_encoding_to_char 函数?

请说明 PostgreSQL 中 pg_encoding_to_char 函数的用途?

  • 编码编号转名称
  • 系统函数
  • 查询库编码

pg_encoding_to_char(encoding) 把数据库编码的整数编号转换为对应的字符集名称(如把 6 转成 'UTF8')。反向函数 pg_char_to_encoding('UTF8') 把名称转编号。常用于查询数据库编码:SELECT pg_encoding_to_char(encoding) FROM pg_database WHERE datname='mydb';。它方便查看与转换编码标识。

pg_encoding_to_char 是编码编号与名称的转换工具,用于查看库编码。

SELECT pg_encoding_to_char(encoding) FROM pg_database WHERE datname = current_database();
#
★★

31. PostgreSQL 中 server_encoding 默认值?

请说明 PostgreSQL 中 server_encoding 的默认值?

  • 默认编码
  • initdb 决定
  • 查看

PostgreSQL 的 server_encoding 默认值由 initdb 时的 --encoding 或 locale 决定,常见默认是 UTF8(在 initdb 使用较新 locale 时)。若未显式指定,initdb 会基于 locale 推断编码。可用 SHOW server_encoding 查看。UTF8 是广泛推荐的编码,支持全部 Unicode 字符。

server_encoding 是 initdb 决定的数据库编码,默认通常为 UTF8,可 SHOW 查看。

#
★★

32. ENUM 类型的修改成本,ALTER TYPE ADD VALUE 的限制?

请说明 PostgreSQL 中 ALTER TYPE ... ADD VALUE 的限制?

  • 事务限制
  • 追加位置
  • 版本差异

PostgreSQL 中 ALTER TYPE ... ADD VALUE 在事务中有限制:新值不能在同一事务内的后续语句中使用(直到提交),且 PG 12 之前不能与其他 DDL 在同一事务内(PG 12 起允许)。ADD VALUE 只能追加到末尾(PG 12+ 支持 BEFORE/AFTER 指定位置,但需重写)。删除值需更复杂操作。这些限制源于枚举的排序 OID 分配。

ADD VALUE 的"事务内不可立即可用"是常见坑,增大枚举值需注意版本与事务限制。

#
★★

33. array_agg 与 array_append 的差异?

请说明 PostgreSQL 中 array_agg 与 array_append 的差异?

  • 聚合 vs 标量
  • 用法
  • 结果

array_agg 是聚合函数,把多行某列的值聚合成一个数组(如 SELECT array_agg(tag) FROM ... GROUP BY);array_append 是标量函数,向已有数组末尾追加一个元素(如 array_append(ARRAY[1,2], 3))。一个是"多行→一数组",一个是"数组+元素→新数组"。用途不同,array_agg 用于分组聚合,array_append 用于数组操作。

array_agg 是聚合、array_append 是标量数组操作,区分"聚合"与"单元素操作"。

SELECT array_agg(tag) FROM post_tags;              -- 聚合到数组
SELECT array_append(ARRAY[1,2], 3);                -- => {1,2,3}
#
★★

34. int4range(1,10) 与 int4range(1,10,'[]') 的边界?

请说明 int4range(1,10) 与 int4range(1,10,'[]') 的边界差异?

  • 默认边界
  • 包含/排除
  • 边界语法

int4range(1,10) 默认使用 [) 边界(左闭右开),即包含 1 但不包含 10,范围是 [1,10);int4range(1,10,'[]') 显式指定双闭边界,包含 1 和 10,范围是 [1,10]。边界参数可选 '()'、'[]'、'[)'、'(]'。默认 [) 是 PostgreSQL 约定。边界选择影响包含性判断与范围语义。

默认 [) 左闭右开,'[]' 双闭,边界参数决定端点是否包含,是 range 语义的基础。

SELECT int4range(1,10) @> 10;        -- false(不包含 10)
SELECT int4range(1,10,'[]') @> 10;   -- true
#
★★

35. range 类型的包含 @>、<@ 操作符?

请说明 PostgreSQL 中 range 类型的 @> 与 <@ 包含操作符的语义?

  • @> 包含
  • <@ 被包含
  • 方向

@> 表示"左边包含右边"(left 包含 right):r1 @> r2 判断 r1 是否包含 r2(r2 是 r1 的子区间)。<@ 表示"左边被包含于右边"(left 是 right 的子集):r1 <@ r2 判断 r1 是否被 r2 包含。二者方向相反。也适用于元素与范围、数组等。@> 常用于"查询包含某时间点/区间"。

@> 与 <@ 是方向相反的包含操作符,@> 左包含右、<@ 左被右包含。

SELECT int4range(1,10) @> int4range(2,5);  -- true
SELECT int4range(2,5) <@ int4range(1,10);  -- true
#
★★

36. ALTER TYPE ... ADD VALUE 的位置限制?

请说明 PostgreSQL 中 ALTER TYPE ... ADD VALUE 的位置限制?

  • 追加位置
  • BEFORE/AFTER
  • 版本

PostgreSQL 中 ALTER TYPE ... ADD VALUE 默认把新值追加到枚举末尾(字符串末尾),PG 12+ 支持 BEFORE/AFTER 指定位置插入,但会重写枚举的排序 OID。由于排序 OID 分配,BEFORE/AFTER 插入会改变已有值的排序号,可能影响已有数据与索引。因此多数场景仍推荐追加到末尾以免重排。ADD VALUE 的位置影响排序与依赖。

追加到末尾是默认且最安全,BEFORE/AFTER 插入会重排枚举 OID,需谨慎。

#
★★

37. ENUM 与 SMALLINT 的应用对比?

请对比 ENUM 与 SMALLINT 在状态字段建模上的应用?

  • 可读性 vs 紧凑
  • ENUM 语义
  • 迁移

ENUM 用有意义的字符串表示状态,可读性好、数据库层校验合法值,但扩展难、跨库差;SMALLINT 用整数编码状态,紧凑、易扩展,但可读性差、需应用层维护映射、数据库不校验。取舍:状态少且稳定、希望可读性选 ENUM;状态多变、需灵活扩展或跨系统共享选 SMALLINT(配合代码表/常量)。现代实践更倾向 SMALLINT/INTEGER + 应用层枚举或 doc 表。

ENUM 把语义放数据库、SMALLINT 把语义放应用层,扩展性与可读性权衡。

#
★★

38. ENUM 与 master data 的取舍?

请说明 ENUM 与 master data(主数据/字典表)的取舍?

  • 内建校验 vs 可扩展
  • 外键代价
  • 场景

ENUM 把合法值内建于类型,简单、无需 join、数据库强校验,但值固定、扩展需改类型、跨系统共享差;master data(字典表)+ 外键引用把值保存在普通表,可自由增删、可携带字段(名称、排序、启用标记)、可跨系统共享,但需 join 查询、有外键开销。取舍:值极少变化且纯本地用 ENUM;值会扩展、需描述或共享用字典表。

字典表以 join 与可靠性换灵活性与可共享,ENUM 以灵活性换简单与强校验。

#
★★

39. ENUM 的 ORDER BY 排序行为?

请说明 ENUM 的 ORDER BY 排序行为?

  • 按定义顺序
  • 非字母序
  • 索引

MySQL 中 ENUM 的 ORDER BY 按枚举定义顺序(索引号)排序,而非字母序;PostgreSQL 中 ENUM 也按定义顺序(排序 OID)排序。若需要按字母序或其他顺序,需用 ORDER BY CAST(col AS CHAR) 或 EXPLICIT 排序。这一行为由底层整数索引/排序号决定。了解定义顺序能避免意外的排序结果。

ENUM 排序按定义顺序而非字母序,是常见的认知误区,需显式转换才能按字母排序。

SELECT x FROM t ORDER BY x;                      -- 按定义顺序
SELECT x FROM t ORDER BY CAST(x AS CHAR);        -- 按字母序
#
★★

40. BOM(Byte Order Mark)的处理,UTF-8 BOM 的去除?

请说明 UTF-8 BOM(字节序标记)的处理与去除?

  • BOM 概念
  • UTF-8 BOM
  • 去除方法

UTF-8 BOM 是文件开头 3 字节(EF BB BF),用于标识 UTF-8 编码。数据库导入时 BOM 可能被当作数据字符,导致首列出现不可见字符。处理方式:导入前先用工具去除 BOM(如 sed、iconv、文本编辑器),或导入后 SQL 去除(如 UPDATE t SET col = REPLACE(col, '\xEF\xBB\xBF', ''))。PostgreSQL COPY 导入时可用 COPY ... WITH (FORMAT csv) 配合处理。避免 BOM 的关键是导出/导入时统一编码。

UTF-8 BOM 是导入乱码的常见来源,去除 BOM 是数据清洗的常规步骤。

#
★★

41. Emoji 字符(4 字节)需要 utf8mb4 而非 utf8 的原因?

请说明 Emoji 字符(4 字节)为什么需要 utf8mb4 而非 utf8?

  • UTF-8 4 字节
  • MySQL utf8mb3 限制
  • 补充平面

Emoji 和部分补充平面字符在 UTF-8 中需要 4 字节编码。MySQL 的 utf8(utf8mb3)仅支持最多 3 字节的 UTF-8,无法表示 4 字节字符,因此存储 emoji 会报错或乱码。utf8mb4 是完整 4 字节 UTF-8,可存储全部 Unicode 字符。所以 MySQL 中存 emoji 必须用 utf8mb4。PostgreSQL 的 UTF8 是完整 4 字节,无此限制。

MySQL utf8mb3 是不完整 UTF-8(最多 3 字节),emoji 需 4 字节,故必须 utf8mb4。

#
★★

42. UTF-8、UTF-8MB4、UTF-16、Latin1 的字节长度差异?

请说明 UTF-8、UTF-8MB4、UTF-16、Latin1 的字节长度差异?

  • 各编码字节
  • 变长编码
  • 兼容性

Latin1 是单字节定长编码(每字符 1 字节),只能表示 256 个字符;UTF-8 是变长编码,ASCII 字符 1 字节、中文 3 字节、emoji 4 字节;UTF-8MB4 指 MySQL 的完整 4 字节 UTF-8(可含 4 字节字符);UTF-16 用 2 或 4 字节表示字符(BMP 2 字节、补充平面 4 字节)。Latin1 空间省但字符少,UTF-8 通用且兼容 ASCII,UTF-16 在 Windows 等环境常用。选择取决于字符集需求与兼容性。

各编码的字节数按字符范围变化,Latin1 定长 1 字节、UTF-8/UTF-16 变长、UTF-8MB4 支持 4 字节。

#

43. initdb 的 --encoding 与 --locale 选项?

请说明 PostgreSQL initdb 的 --encoding 与 --locale 选项?

  • 初始化编码
  • locale
  • 影响

initdb 的 --encoding 指定数据库集群的默认编码(如 --encoding=UTF8),--locale 指定默认排序规则/区域(如 --locale=C 或 --locale=en_US.UTF-8)。二者共同决定集群的默认字符集与排序行为。若不指定,--encoding 会从 --locale 推断。编码与 locale 在集群创建后难以更改,需在 initdb 时仔细选择。UTF8 编码 + 合适 locale 是推荐组合。

initdb 的编码与 locale 是集群级默认,创建后难改,需预先规划。

#

44. ENUM 在 ORM 框架的映射?

请说明 ENUM 在 ORM 框架(如 Hibernate、JPA)中的映射?

  • 字符串/序号映射
  • 枚举类型
  • 兼容性

ORM 框架(如 Hibernate)通常用 @Enumerated 注解映射 Java 枚举:EnumType.STRING 按枚举名存字符串,EnumType.ORDINAL 按序号存整数。当数据库是 ENUM 类型时,需让 ORM 以字符串形式与之匹配(避免 ORDINAL 因顺序变化而错位)。PostgreSQL 的 PG 类型与 MySQL ENUM 都可能被映射为字符串。枚举值顺序变化会导致 ORDINAL 错位,故推荐 STRING。ORM 对原生 ENUM 支持有限,常以 VARCHAR 模拟。

ORM 映射核心是"STRING vs ORDINAL",顺序变化风险使 STRING 更安全,且原生 ENUM 兼容性弱。

#

45. 多值范围(multirange)类型?

请说明 PostgreSQL 的多值范围(multirange)类型?

  • multirange 概念
  • 多个不连续区间
  • 操作

PostgreSQL 14+ 引入 multirange 类型,表示多个不连续范围的集合,如 int4multirange、tsmultirange。它把多个 range 合并为一个复合值,支持区间操作(并集、交集、重叠、包含)。multirange 能表示"多个时间段"这类不连续数据,操作符与 range 类似。适合排班、维护窗口等需求。

multirange 是 range 的集合扩展,用于表示不连续多区间,PG14+ 支持。