事务性 DDL 与写入热点与限流与内外连接

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

1. DDL 与并发查询的冲突,长事务持有元数据锁导致 DDL 阻塞?

说明长事务持有元数据锁导致 DDL 阻塞的问题?

  • 元数据锁
  • DDL 阻塞
  • 长事务

DDL 需要获得元数据锁。MySQL 中 DML 持有元数据共享锁,DDL 需排他元数据锁;若存在长事务持续持有共享锁,DDL 会一直等待,导致 ALTER/DROP 阻塞。PostgreSQL 中 DDL 需 ACCESS EXCLUSIVE 锁,同样会被并发查询阻塞。

长事务 + 未提交查询会阻塞 DDL,造成"改表失败"等事故。需监控长事务并设置 lock_timeout。

#
★★★

2. DDL 在事务中的回滚,哪些操作可以回滚、哪些不可以?

说明 DDL 在事务中的回滚能力?

  • 事务性 DDL
  • 各数据库差异
  • 可回滚性

PostgreSQL 支持事务性 DDL,CREATE/ALTER/DROP 在事务内可回滚;MySQL 传统 DDL 隐式提交,不可回滚(MySQL 8.0 原子 DDL 改善但并非事务性回滚);SQL Server 支持事务性 DDL。Oracle 的 DDL 隐式提交不可回滚。

事务性 DDL 依赖数据库实现,PostgreSQL 最佳,MySQL/Oracle 需谨慎。

#
★★★

3. DDL 锁的粒度,ACCESS EXCLUSIVE(PostgreSQL)、Metadata Lock(MySQL)?

说明 DDL 锁的粒度差异?

  • ACCESS EXCLUSIVE
  • Metadata Lock
  • 锁粒度

PostgreSQL 的 DDL 使用 ACCESS EXCLUSIVE 锁(表级,阻止所有并发访问);MySQL 使用元数据锁(MDL),ALTER 时可能用共享锁(允许并发)或排他锁。粒度与并发性不同。

PostgreSQL 的 DDL 锁较重(阻塞读写),MySQL 的部分 DDL 更灵活但仍有阻塞。

#
★★★

4. MySQL 8.0 引入原子 DDL(Atomic DDL)解决了哪些历史问题?

说明 MySQL 8.0 原子 DDL 解决的历史问题?

  • 原子 DDL
  • 崩溃一致性
  • 历史问题

MySQL 8.0 的原子 DDL 将 DDL 操作与数据字典更新放进单一原子事务,解决历史问题:DDL 中途崩溃导致数据字典与表不一致、DDL 中途失败留下半成品状态、部分 DDL 不可回滚。现在 DDL 失败/崩溃可整体回滚。

原子 DDL 保证崩溃时字典与文件一致,避免"表已建但字典没记录"等脏状态。

#
★★★

5. PostgreSQL 原生支持事务性 DDL(CREATE/DROP/ALTER TABLE)的实现机制(catalog 与 heap 双写)?

说明 PostgreSQL 事务性 DDL 的实现机制?

  • catalog 事务
  • 双写
  • 回滚

PostgreSQL 的事务性 DDL 通过把系统目录(catalog)作为普通表,用 MVCC 与 WAL 管理:DDL 在事务中修改 catalog 行,与数据 heap 一起参与事务提交/回滚。未提交的 DDL 对他人不可见,回滚则撤销 catalog 变更。

catalog 即普通表,天然支持事务性,这是 PostgreSQL 事务性 DDL 的基石。

#
★★★

6. SQL Server 的 DDL 事务性,是否支持事务回滚 CREATE TABLE?

说明 SQL Server 的 DDL 事务性?

  • 事务性 DDL
  • CREATE TABLE 回滚
  • TRY/CATCH

SQL Server 支持事务性 DDL,CREATE/ALTER/DROP TABLE 可在事务内执行,可被 ROLLBACK 回滚。可用 BEGIN TRAN ... COMMIT/ROLLBACK 包裹 DDL,配合错误处理。

SQL Server 与 PostgreSQL 类似,DDL 是事务性的。

#
★★★

7. CREATE INDEX CONCURRENTLY 与 DDL 事务的关系?

说明 CREATE INDEX CONCURRENTLY 与 DDL 事务的关系?

  • CONCURRENTLY
  • 不阻塞
  • 事务限制

PostgreSQL 的 CREATE INDEX CONCURRENTLY 不加 ACCESS EXCLUSIVE 锁,允许并发读写,但会分阶段进行,且不能在事务块内执行(否则报错)。它不阻塞 DML,但建索引期间不能有其他 DDL。

CONCURRENTLY 牺牲期间锁,换取在线建索引,但限制在事务内使用。

#
★★★

8. DDL 与 MVCC,DDL 修改对正在执行查询的可见性?

说明 DDL 与 MVCC 的可见性?

  • 快照
  • DDL 可见性
  • 并发查询

在 MVCC 下,正在执行的查询基于语句开始时的快照,DDL 的修改(如 DROP/ALTER)对已开始查询的可见性取决于锁。PostgreSQL 的 DDL 加 ACCESS EXCLUSIVE 锁,会阻塞并发查询;查询完成前的 DDL 需等待。已开始的查询不受后续 DDL 影响(快照隔离)。

快照隔离保证查询一致性,但 DDL 锁会阻塞新查询。

#
★★★

9. DDL 的可恢复性(Recoverable DDL)?

说明 DDL 的可恢复性?

  • 崩溃恢复
  • 原子 DDL
  • 可恢复

DDL 的可恢复性指在崩溃/失败后能否恢复到一致状态。PostgreSQL 通过事务性 DDL + WAL 保证可恢复;MySQL 8.0 原子 DDL 保证崩溃一致性;老版本 MySQL 的 DDL 可能残留半成品。可恢复性依赖日志与字典原子更新。

可恢复的 DDL 避免崩溃后不一致,是 8.0 原子 DDL 的核心价值。

#
★★★

10. DDL 的审计日志(CREATE TABLE 时间戳)?

说明 DDL 的审计日志?

  • 审计
  • CREATE TABLE 时间戳
  • 元数据

DDL 审计可通过查询系统目录元数据(如 MySQL information_schema.tables 中的 create_time)或启用审计日志(MySQL general_log、审计插件)记录 DDL 操作。可记录建表时间、变更者等。

DDL 审计通过系统目录元数据(建表时间戳)或审计日志实现,是安全合规与问题回溯的基础;答题应先说明查元数据与开日志两条路径,再强调其用途,避免只说可以审计而没有具体手段。

#
★★★

11. DDL 的锁等待超时设置(lock_timeout)?

说明 DDL 的锁等待超时设置?

  • lock_timeout
  • 避免无限等待
  • 参数

PostgreSQL 可用 lock_timeout(如 SET lock_timeout = '5s')限制 DDL/DML 等待锁的时间,超时即放弃,避免无限阻塞。MySQL 用 lock_wait_timeout 控制元数据锁等待。

设置锁等待超时避免 DDL 被长事务无限阻塞。

SET lock_timeout = '5s';
ALTER TABLE t ADD COLUMN c int;
#
★★★

12. DDL 触发器的 BEFORE/AFTER 语义?

说明 DDL 触发器的语义?

  • DDL 触发器
  • BEFORE/AFTER
  • 支持情况

部分数据库支持 DDL 触发器(如 SQL Server 的 DDL 触发器、Oracle 的 DDL 触发器),可在 CREATE/ALTER/DROP 前(BEFORE)后(AFTER)执行。MySQL/PostgreSQL 标准不支持 DDL 触发器(需用事件触发器扩展)。

DDL 触发器用于治理(防止误删表)、审计。

#
★★★

13. MySQL 中 DDL 是否在事务中?

说明 MySQL 的 DDL 是否在事务中?

  • 隐式提交
  • DDL 非事务性
  • 回滚

MySQL 中 DDL 隐式提交,执行 DDL 前自动提交当前事务,DDL 本身不可回滚(8.0 原子 DDL 改善崩溃一致性,但不是事务性回滚)。因此 DDL 不能与 DML 在同一事务中原子执行。

MySQL 的 DDL 非事务性,这是与 PostgreSQL 的关键差异。

#
★★★

14. MySQL 的 ALGORITHM=COPY 与 INPLACE 的差异?

说明 MySQL ALGORITHM=COPY 与 INPLACE?

  • COPY 重建表
  • INPLACE 就地
  • 锁与性能

ALGORITHM=COPY 会创建新表 + 复制数据 + 重建索引,锁定表(阻塞写),代价高;ALGORITHM=INPLACE 就地修改表结构,部分操作加锁开销小(如 ADD COLUMN 只需元数据锁或短暂锁),性能更好。可用 ALGORITHM=INPLACE 指定。

8.0 默认优先 INPLACE,COPY 用于某些不支持原位操作的结构变更。

#
★★★

15. MySQL 的 metadata lock 等待链?

说明 MySQL 的元数据锁(MDL)等待链?

  • MDL 等待
  • 阻塞链
  • 定位

MySQL 的元数据锁(MDL)等待链:一个 DDL 需要 MDL 排他锁,若被 DML 的共享锁阻塞,后续的 DDL/DML 都会排队,形成长阻塞链。可用 performance_schema.metadata_locks 或 SHOW PROCESSLIST 定位。

一个未提交长事务可阻塞整个表的 DDL 及后续操作,需及时定位。

#
★★★

16. PostgreSQL 中 BEGIN; CREATE TABLE t; ROLLBACK; 是否回滚?

说明 PostgreSQL 中 BEGIN; CREATE TABLE; ROLLBACK 是否回滚?

  • 事务性 DDL
  • 回滚
  • 结果

会回滚。PostgreSQL 支持事务性 DDL,ROLLBACK 会撤销 CREATE TABLE,表不会存在。这是 PostgreSQL 的重要特性。

PostgreSQL 的 catalog 是普通表,DDL 参与事务,ROLLBACK 即回滚。

BEGIN;
CREATE TABLE t (id int);
ROLLBACK;
-- 表 t 不存在
#
★★★

17. 写入热点(Write Hotspot)的成因,自增主键最后页竞争、热点行更新、唯一键冲突?

说明写入热点(Write Hotspot)的成因:自增主键最后页竞争、热点行更新、唯一键冲突分别如何产生?

  • 自增主键最后页竞争
  • 热点行更新
  • 唯一键冲突

写入热点成因:自增主键导致所有插入集中在最后页(页锁竞争);热点行更新导致同一行锁竞争;唯一键冲突导致索引锁竞争。这些问题在并发写入时放大。

消除热点:用随机/哈希主键、分片、减少对热点行的更新、避免频繁唯一键冲突。

#
★★★

18. 热点行(Hot Row)的锁竞争,秒杀场景如何解决?

说明热点行锁竞争与秒杀场景的解决?

  • 热点行
  • 秒杀
  • 库存扣减

秒杀场景所有请求更新同一库存行,造成热点行锁竞争严重。解决:削减库存行(拆分为多行)、用 Redis 预扣减、异步化、乐观锁重试、或分区库存。目标是减少对单行的串行写。

秒杀场景所有请求争抢同一库存行,单行写串行化成为吞吐瓶颈;拆分库存行、Redis 预扣减、异步化都是把单点写分散的手段,答出减少对单行的串行写这一核心思路即可覆盖多数追问。

#
★★★

19. 连接池的写入排队(c3p0、HikariCP、DBCP)?

说明连接池(HikariCP、c3p0、DBCP)的写入排队现象及其成因,连接耗尽后写请求如何等待?

  • 连接池配置
  • 连接耗尽
  • HikariCP

连接池(HikariCP、c3p0、DBCP)管理的连接数有限,写请求并发过高时连接耗尽,请求排队等待。合理的 maximumPoolSize、连接超时、最小空闲连接配置影响写吞吐。HikariCP 推荐用较小的连接池 + 高并发排队。

连接池排队是吞吐瓶颈,需合理配置池大小与等待时间。

#
★★★

20. MySQL 的 innodb_write_io_threads 调优?

说明 innodb_write_io_threads 调优?

  • 写线程数
  • I/O 吞吐
  • 调优

innodb_write_io_threads 控制 InnoDB 用于刷写脏页的 IO 线程数,默认 4。增大可提升写吞吐,尤其在 SSD 高并发写场景。但过大会增加 I/O 竞争。需结合磁盘能力调优。

写线程数影响写性能,需与 I/O 能力匹配。

#
★★★

21. PostgreSQL 的 max_wal_senders 限制?

说明 PostgreSQL 的 max_wal_senders 限制?

  • WAL 发送进程
  • 流复制
  • 限制

max_wal_senders 限制用于流复制(WAL 发送)的进程数。若 standby/复制连接超过该值会失败。也影响逻辑复制与备份。需根据副本数与复制需求调大。

副本数多时要调大 max_wal_senders,否则复制连接失败。

#
★★★

22. CROSS JOIN(笛卡尔积)的语义与性能陷阱?

说明 CROSS JOIN 的语义与性能陷阱?

  • 笛卡尔积
  • 无连接条件
  • 性能爆炸

CROSS JOIN 产生两表所有行的组合(笛卡尔积),行数 = 行数相乘。无 ON 条件。若忘记 WHERE/连接条件,会生成巨大结果集,性能爆炸。应避免无意的笛卡尔积。

无连接条件的笛卡尔积行数爆炸,务必避免无意的全连接。

SELECT * FROM a CROSS JOIN b;  -- 行数 = |a| * |b|
#
★★

23. INNER JOIN、LEFT JOIN、RIGHT JOIN、FULL JOIN 的完整语义与执行差异?

说明四种 JOIN 的完整语义?

  • INNER 交集
  • LEFT/RIGHT 保留
  • FULL 并集

INNER JOIN 只返回匹配行;LEFT JOIN 保留左表所有行,右表无匹配填 NULL;RIGHT JOIN 保留右表所有行;FULL JOIN 保留两表所有行(无匹配填 NULL)。执行上 INNER 可用 Hash/Nested Loop,OUTER 需保留多余行。

理解保留语义决定 OUTER JOIN 的 NULL 填充行为。

#
★★

24. JOIN 与子查询的等价转换,EXISTS 子查询可改写为半连接?

说明 EXISTS 子查询改写为半连接?

  • 半连接优化
  • EXISTS
  • 等价转换

优化器把 EXISTS 子查询改写成半连接(SEMI JOIN),只关注"是否存在匹配",匹配即停止,避免重复返回。半连接通过 Hash/Unique 实现,比普通 JOIN + DISTINCT 高效。

半连接是优化器对 EXISTS/IN 的自动转换。

#
★★

25. JOIN 中空值(NULL)的处理,NULL = NULL 永假导致左表行被丢弃?

说明 JOIN 中 NULL 的处理?

  • NULL = NULL 永假
  • ON 条件
  • 行丢失

ON 连接条件中 NULL = NULL 结果为 UNKNOWN(永假),因此连接的 NULL 值不会匹配。对 INNER JOIN 会导致 NULL 行被丢弃;对 LEFT JOIN 左表 NULL 行在右表无匹配时保留但填 NULL。

处理 NULL 连接需用 IS NOT DISTINCT FROM 或 COALESCE。

#
★★

26. JOIN 条件 ON 与 WHERE 在 OUTER JOIN 中的差异,误用 WHERE 导致 OUTER 退化为 INNER?

说明 ON 与 WHERE 在 OUTER JOIN 中的差异?

  • ON 控制连接
  • WHERE 过滤结果
  • OUTER 退化

ON 条件在连接时评估,控制哪些行匹配;WHERE 在连接后过滤结果。对 LEFT JOIN,若在 WHERE 中过滤右表列(如 WHERE b.id IS NOT NULL),会清除 NULL 填充行,使 LEFT JOIN 退化为 INNER JOIN。应把右表过滤放 ON。

这是 OUTER JOIN 的经典陷阱,过滤条件位置决定语义。

#
★★

27. JOIN 的执行算法,Nested Loop、Hash Join、Sort Merge Join 的适用场景?

说明三种 JOIN 算法的适用场景?

  • Nested Loop
  • Hash Join
  • Sort Merge Join

Nested Loop 适合小表驱动大表、有索引、连接条件可索引查找;Hash Join 适合等值连接、大表无索引、无需排序;Sort Merge Join 适合已排序输入或非等值连接(>、<)。优化器按代价选择。

算法选择影响性能,理解适用场景便于调优。

#
★★

28. JOIN 的非等值条件(>, <, BETWEEN)的实现,Hash Join 不支持非等值?

说明非等值 JOIN 的实现?

  • 非等值条件
  • Hash Join 限制
  • Merge Join

Hash Join 只支持等值连接(=),非等值条件(>、<、BETWEEN)不能用 Hash Join,需用 Nested Loop 或 Sort Merge Join。优化器会自动选择合适算法。

非等值连接通常用 Nested Loop(需索引)或排序合并。

#
★★

29. JOIN 顺序对执行计划的影响,PostgreSQL 的 join_collapse_limit、MySQL 的 optimizer_search_depth?

说明 JOIN 顺序对执行计划的影响?

  • join_collapse_limit
  • optimizer_search_depth
  • 连接顺序

JOIN 顺序决定执行代价。PostgreSQL 的 join_collapse_limit 控制优化器是否展开显式 JOIN 重新排列;MySQL 的 optimizer_search_depth 控制搜索深度。合理设置可提升优化器质量。

连接顺序影响大表是否先过滤,优化器搜索空间有限。

#
★★

30. LEFT JOIN 的语义,保留左表所有行,右表无匹配时填 NULL?

说明 LEFT JOIN 的语义?

  • 保留左表
  • NULL 填充
  • 匹配

LEFT JOIN 保留左表所有行;对右表有匹配的行连接,无匹配的行右表列填 NULL。即使右表无匹配,左表行也保留。

这是外连接保留语义的核心,理解它才能正确解释 NULL 填充。

#
★★

31. NATURAL JOIN 的风险,同名列自动等值连接导致非预期笛卡尔积?

说明 NATURAL JOIN 的风险?

  • 同名列
  • 自动连接
  • 风险

NATURAL JOIN 自动用两表同名列做等值连接,无需显式 ON。风险:若同名列过多或命名意外,会产生非预期连接条件或结果;不明确列名使查询难以维护。应避免使用 NATURAL JOIN。

NATURAL JOIN 隐式连接列,可读性与可控性差。

#
★★

32. 多表 JOIN 的链式与总线式,从事实表出发还是从维度表出发?

说明多表 JOIN 的链式与总线式?

  • 链式 JOIN
  • 总线式
  • 驱动表

链式 JOIN 是逐表串联(A→B→C);总线式是从事实表出发连接多个维度表。星型模型常用总线式。驱动表选择影响性能,通常用小表/过滤后表作驱动。

从事实表出发连接维度表是星型模型常见模式。

#
★★

33. 半连接(SEMI JOIN)的语义,返回左表中在右表有匹配的行,每行只出现一次?

半连接(SEMI JOIN)的语义是什么?它与普通 JOIN 在返回行数上有何区别?为什么每行只返回一次?

  • 半连接
  • 返回左表匹配行
  • 去重

半连接(SEMI JOIN)返回左表中在右表有匹配的行,每行只出现一次(即使右表多行匹配)。等价于 EXISTS/IN 子查询。通过 Hash Semi Join 等实现。

半连接不等价于普通 JOIN(会重复行),确保去重。

#
★★

34. JOIN 扇出(fan-out)为何会让 COUNT(*)/SUM() 结果膨胀(一对多连接使主表行被重复计数)?如何用先聚合再连接或半连接(EXISTS)规避?

说明 JOIN 扇出导致计数膨胀及规避?

  • 一对多扇出
  • COUNT/SUM 膨胀
  • 先聚合再连接

一对多连接时,主表一行被重复连接多次,导致 COUNT(*)/SUM() 重复计数膨胀。规避:先聚合子表再连接,或用半连接(EXISTS)只判断存在性,避免行重复。

一对多连接会让主表行被复制多份,COUNT/SUM 随之膨胀,这是聚合结果失真的常见根因;先聚合子表再连接或改用 EXISTS 判断存在性,是面试中考察懂不懂 JOIN 语义的标准答案。

#
★★

35. 驱动表选择错误与统计信息失真为何会让 Nested Loop 的内表被反复全表扫描、代价爆炸?如何用 ANALYZE 更新统计或调整连接顺序/Hint 纠正?

说明驱动表选择错误导致代价爆炸及纠正?

  • 驱动表
  • Nested Loop 内表扫描
  • 统计信息

Nested Loop 中内表被反复扫描,若驱动表选错(内表无索引或统计失真),代价爆炸。纠正:ANALYZE 更新统计信息,用 Hints 调整连接顺序,或建索引。准确统计信息帮助优化器选对驱动表。

统计信息失真导致优化器选错计划,是性能问题的常见根因。

#
★★

36. JOIN 与覆盖索引,SELECT 仅引用 JOIN 列时是否走索引覆盖?

说明 JOIN 与覆盖索引?

  • 覆盖索引
  • 索引列
  • 回表

若 SELECT 和 JOIN 条件都只引用索引列,可走覆盖索引(Index-Only Scan),避免回表。覆盖索引能显著提升连接查询性能。需确保所需列都在索引中。

覆盖索引减少回表,是 JOIN 调优常用手段。

#
★★

37. JOIN 性能调优,调整 join_collapse_limit、from_collapse_limit?

说明 JOIN 性能调优参数?

  • join_collapse_limit
  • from_collapse_limit
  • 优化器

PostgreSQL 的 join_collapse_limit 控制显式 JOIN 是否被优化器重新排列(越大越允许重排,越接近 1 越按书写顺序);from_collapse_limit 控制 FROM 列表子查询的折叠。调整它们影响连接顺序搜索与计划质量。

这两个参数控制优化器对显式 JOIN 与 FROM 子查询的重排自由度,直接影响连接顺序搜索空间与计划质量;数值越小越贴近书写顺序,越大越可能找到更优计划但搜索成本更高,答题需点出重排自由度这一本质。

#
★★

38. 如何用 LATERAL 子查询在连接前完成每行预聚合,从而避免“先连接后聚合”的扇出放大?

说明用 LATERAL 预聚合避免扇出放大?

  • LATERAL
  • 预聚合
  • 扇出规避

LATERAL 子查询对外层每一行执行一次,可先在子查询中聚合关联数据,再与主表连接,避免先连接后聚合导致的扇出放大。例如对每笔订单取聚合明细。

LATERAL 逐行预聚合后再连接,从根上消除一对多扇出。

SELECT o.id, agg.total
FROM orders o
LEFT JOIN LATERAL (
  SELECT SUM(amount) AS total FROM order_items i WHERE i.order_id = o.id
) agg ON true;
#
★★

39. FULL JOIN 在 PostgreSQL 与 MySQL 的支持?

说明 FULL JOIN 的支持情况?

  • PostgreSQL 支持
  • MySQL 不支持
  • 模拟

PostgreSQL 原生支持 FULL JOIN;MySQL 不支持 FULL JOIN(直到 8.0 仍不支持),需用 LEFT JOIN UNION RIGHT JOIN 模拟。

FULL JOIN 支持情况是方言差异,MySQL 需 UNION 模拟。

#
★★

40. INNER JOIN 与逗号连接的等价?

说明 INNER JOIN 与逗号连接的等价?

  • 逗号连接
  • 等价
  • WHERE 过滤

逗号连接(FROM a, b)等价于 CROSS JOIN,加上 WHERE 过滤后等价于 INNER JOIN。但用显式 JOIN 更清晰、可读性更好。

逗号连接是笛卡尔积,加 WHERE 过滤后与 INNER JOIN 等价。

SELECT * FROM a, b WHERE a.id = b.id;   -- 等价于 INNER JOIN
SELECT * FROM a INNER JOIN b ON a.id = b.id;
#
★★

41. JOIN 与 DISTINCT 的执行顺序?

说明 JOIN 与 DISTINCT 的执行顺序?

  • 先 JOIN 后 DISTINCT
  • 语义
  • 扇出

逻辑上先执行 JOIN(含 WHERE),再对结果做 DISTINCT 去重。若 JOIN 产生重复行,DISTINCT 会去重。但 JOIN 扇出 + DISTINCT 代价高,可用半连接/EXISTS 避免。

SELECT DISTINCT 在 JOIN 之后,先连接再去重。

#
★★

42. JOIN 与 GROUP BY 的协同?

说明 JOIN 与 GROUP BY 的协同?

  • 先 JOIN 后 GROUP
  • 聚合
  • 扇出

逻辑上先 JOIN 再 GROUP BY 聚合。若 JOIN 产生扇出(一对多),GROUP BY 聚合会统计重复行。需在 GROUP BY 前消除扇出(先聚合再连接)保证正确。

JOIN 扇出 + GROUP BY 是常见错误来源。

#
★★

43. JOIN 中 USING 与 ON 的等价与差异?

说明 USING 与 ON 的差异?

  • USING 列
  • ON 条件
  • 列合并

USING (col) 连接同名列,结果中该列只出现一次(合并);ON 用任意条件,结果中两表列都保留。USING 更简洁但要求列名相同;ON 更灵活。

USING 合并同名列,ON 保留两表列,属性与可读性不同。

SELECT * FROM a JOIN b USING (id);   -- id 只出现一次
SELECT * FROM a JOIN b ON a.id = b.id; -- 两个 id 都出现
#
★★

44. JOIN 子句能否引用 CTE?

说明 JOIN 子句能否引用 CTE?

  • CTE 引用
  • JOIN
  • 作用域

可以。CTE 定义后可作为表在 JOIN 中使用,如 SELECT ... FROM t JOIN cte ON ...。CTE 在 JOIN 中作为普通表源。

CTE 定义后作为普通表源,可在 JOIN 中直接引用。

WITH cte AS (SELECT id, val FROM t2)
SELECT * FROM t1 JOIN cte ON t1.id = cte.id;
#
★★

45. JOIN 的别名 t1 INNER JOIN t2 的简化语法?

说明 JOIN 的简化语法?

  • 别名
  • 简化
  • INNER 省略

INNER JOIN 可省略 INNER 写为 JOIN;表可用别名(t1、t2)。如 FROM t1 JOIN t2 ON ...。别名提高可读性。

INNER 可省略且可用别名,简化书写并提升可读性。

SELECT ... FROM a t1 JOIN b t2 ON t1.id = t2.id;
#
★★

46. JOIN 的执行计划解读(Hash Join vs Nested Loop)?

说明 JOIN 执行计划解读?

  • Hash Join
  • Nested Loop
  • 计划解读

执行计划中 Hash Join 显示"Hash Join / Hash -> 扫描"(构建哈希表);Nested Loop 显示"Nested Loop / 外层-内层"反复扫描。通过解读可判断连接算法与驱动表。

执行计划节点直接反映连接算法:Hash Join 有 Hash 构建节点,Nested Loop 体现内外层反复扫描,解读它们能判断驱动表与顺序;这是定位慢查询的基本功,常以 EXPLAIN 追问。

#
★★

47. JOIN 的连接谓词下推(Join Predicate Pushdown)?

什么是连接谓词下推(Join Predicate Pushdown)?优化器如何提前过滤以减少参与连接的数据量?

  • 谓词下推
  • 提前过滤
  • 优化

连接谓词下推是把过滤条件(如 WHERE a.x=1)下推到扫描/连接前执行,减少数据量。优化器自动下推,提升性能。也可手动在子查询中提前过滤。

谓词下推即"先过滤再连接",减少参与连接的行数。

#
★★

48. LATERAL JOIN 与普通 JOIN 的差异?

说明 LATERAL JOIN 与普通 JOIN 的差异?

  • LATERAL 相关
  • 每行计算
  • 普通 JOIN

LATERAL JOIN 允许子查询引用外层表的列(相关子查询),对外层每行计算一次;普通 JOIN 的子查询不能引用外层列。LATERAL 更灵活,适合逐行关联计算。

LATERAL 是"相关子查询"的 FROM 化。

#
★★

49. LEFT JOIN 与 LEFT OUTER JOIN 的关系?

说明 LEFT JOIN 与 LEFT OUTER JOIN 的关系?

  • 等价
  • 关键字
  • 语义

LEFT JOIN 与 LEFT OUTER JOIN 完全等价,JOIN 默认是 INNER,OUTER 关键字可省略。同理 RIGHT JOIN、FULL JOIN。

OUTER 关键字可省略,两者是完全等价的写法。

#
★★

50. LEFT JOIN 的反向推导(找出左表独有的行)?

说明用 LEFT JOIN 找左表独有的行?

  • LEFT JOIN + IS NULL
  • 反连接
  • 等价

用 LEFT JOIN t2 ON t1.id=t2.id WHERE t2.id IS NULL 找出左表在右表无匹配的行(等价于 NOT EXISTS/NOT IN 反连接)。此时要过滤右表列,注意保持 LEFT 语义。

右表列 IS NULL 即无匹配,等价于反连接找左表独有行。

SELECT t1.* FROM t1 LEFT JOIN t2 ON t1.id = t2.id WHERE t2.id IS NULL;
#
★★

51. NATURAL JOIN 与 JOIN ... USING 的差异?

说明 NATURAL JOIN 与 USING 的差异?

  • NATURAL 自动
  • USING 显式
  • 差异

NATURAL JOIN 自动使用所有同名列连接;JOIN ... USING (col) 显式指定连接列。USING 更可控、可读性好;NATURAL 隐式可能连接过多列。

USING 显式指定列更可控,NATURAL 隐式连接同名列风险高。

#
★★

52. RIGHT JOIN 何时应改写为 LEFT JOIN?

说明 RIGHT JOIN 改写为 LEFT JOIN?

  • 等价改写
  • 可读性
  • 语义

RIGHT JOIN 保持右表所有行,可交换表顺序改写为 LEFT JOIN(FROM a RIGHT JOIN b 等价于 FROM b LEFT JOIN a),语义相同但可读性更好(习惯用 LEFT)。

交换表顺序即可把 RIGHT JOIN 改为 LEFT JOIN,语义不变。

SELECT * FROM a RIGHT JOIN b ON a.id = b.id;
-- 等价于
SELECT * FROM b LEFT JOIN a ON a.id = b.id;
#
★★

53. STRAIGHT_JOIN(MySQL)的强制顺序?

说明 STRAIGHT_JOIN 的强制顺序?

  • STRAIGHT_JOIN
  • 强制连接顺序
  • 优化器

STRAIGHT_JOIN 强制 MySQL 按书写顺序连接表,跳过优化器重排,用于优化器选错驱动表时手动纠正。也用于测试连接顺序影响。

STRAIGHT_JOIN 绕过优化器重排,用于手动纠正驱动表。

SELECT * FROM t1 STRAIGHT_JOIN t2 ON t1.id = t2.id;
#
★★

54. Oracle 的 DDL 隐式提交,执行 DDL 自动 COMMIT 的行为?

说明 Oracle 的 DDL 隐式提交?

  • 隐式提交
  • DDL 自动 COMMIT
  • 不可回滚

Oracle 中执行 DDL 会隐式提交当前事务,DDL 本身自动提交且不可回滚。因此 DDL 与 DML 不能在同一事务中原子执行。设计事务时需注意。

Oracle 的 DDL 隐式提交是重要特性。

#
★★

55. DDL 的命名规范(IF NOT EXISTS)?

说明 DDL 的 IF NOT EXISTS?

  • IF NOT EXISTS
  • 幂等
  • 各数据库

CREATE TABLE IF NOT EXISTS / CREATE INDEX IF NOT EXISTS 使 DDL 幂等,对象已存在时不报错。PostgreSQL、MySQL 支持。用于迁移脚本避免重复执行错误。

IF NOT EXISTS 让 DDL 幂等,迁移脚本重复执行不报错。

CREATE TABLE IF NOT EXISTS t (id int PRIMARY KEY);
#
★★

56. SET TRANSACTION 与 DDL 的关系?

说明 SET TRANSACTION 与 DDL 的关系?

  • SET TRANSACTION
  • 隔离级别
  • DDL

SET TRANSACTION 设置事务特性(隔离级别、只读等),在事务开始前执行。DDL 在 MySQL/Oracle 中隐式提交,会中断事务特性;PostgreSQL 中 DDL 在事务内保持特性。两者关系因数据库而异。

设置隔离级别后再执行 DDL,MySQL/Oracle 会提交。

#
★★

57. Sequence 的 cache 参数对写入并发的影响?

说明 Sequence 的 cache 参数?

  • cache
  • 预分配
  • 并发

Sequence 的 cache 参数决定一次预取多少序列值缓存到内存,减少数据库访问,提升写入并发。但 cache 大时实例崩溃会丢失未用部分(空洞),且多实例共享时需注意。

cache 提升并发但增加空洞与重启丢失风险。

#
★★

58. 写入并发度的数据库参数调优,max_connections、innodb_thread_concurrency?

说明写入并发度参数调优?

  • max_connections
  • innodb_thread_concurrency
  • 并发度

max_connections 限制最大连接数,过高导致资源竞争;innodb_thread_concurrency 限制 InnoDB 并发执行线程,避免过多线程竞争。合理设置平衡并发与资源。

并发度过高会引发锁竞争与资源耗尽,需权衡。

#

59. 写合并(Write Coalescing)与批量写入(Batch Write)?

说明写合并(Write Coalescing)与批量写入(Batch Write):二者如何减少 I/O 提升写入吞吐?

  • 写合并
  • 批量写入
  • 性能

写合并(Write Coalescing)把多个小写操作合并为一次大 I/O,减少 I/O 次数;批量写入(Batch Write)把多条记录合并提交。两者都降低 I/O 开销,提升写入吞吐。

合并写操作减少 I/O 系统调用与 fsync 次数。

#

60. 异步写入(Async Commit)的 fsync 风险?

说明异步提交的 fsync 风险?

  • async commit
  • fsync
  • 持久性

异步提交(synchronous_commit=off)在事务提交时不等待 fsync,减少延迟但增加崩溃时数据丢失风险(已提交但未落盘)。需权衡性能与持久性。

异步提交牺牲持久性换取吞吐,适合可容忍丢失的场景。

#

61. 队列化写入(Queue-based Write)模式?

说明队列化写入(Queue-based Write)模式:如何用消息队列缓冲写入,实现削峰填谷与系统解耦?

  • 消息队列
  • 异步写入
  • 削峰

队列化写入用消息队列(Kafka、Redis)缓冲写入,应用异步消费落库,削峰填谷、解耦系统。适合高并发写入、非强一致场景。

队列化写入提升吞吐与稳定性,但引入延迟与一致性问题。

#

62. 限流(Rate Limiting)的应用层与数据库层实现?

说明限流的应用层与数据库层实现?

  • 应用限流
  • 数据库限流
  • 令牌桶

应用层限流用令牌桶/漏桶算法(如 Redis、Guava RateLimiter)控制请求速率;数据库层限流用连接数限制、max_connections、请求队列、或独立限流中间件。两者结合保护数据库。

限流分为应用层(令牌桶/漏桶)与数据库层(连接数、队列)两道防线,目标是防止过载拖垮后端;答出两层各自的典型手段并说明两者结合使用即可,同时注意区分限流与降级、熔断的边界。

#

63. DDL 与闪回(Flashback)?

说明 DDL 与闪回(Flashback):Oracle 与 MySQL 各如何恢复被误操作的 DDL?

  • 闪回
  • DDL 恢复
  • Oracle

闪回(Flashback)是恢复误操作的能力。Oracle 的 Flashback Drop 可恢复被 DROP 的表;Flashback Query 可查询历史。MySQL 无原生闪回,可基于 binlog 用第三方工具(如 binlog2sql)实现近似闪回。DDL 误操作可通过闪回或备份恢复。

闪回降低误删风险,但需依赖内存/日志/备份。

#

64. Online DDL 的失败回滚?

说明 Online DDL 的失败回滚?

  • Online DDL
  • 失败回滚
  • 原子 DDL

Online DDL 执行中失败时,MySQL 8.0 原子 DDL 会回滚到原状态;老版本可能残留(如索引已建一半)。PostgreSQL 的 DDL 事务性保证失败回滚。Online DDL 的回滚能力依赖版本。

原子 DDL 提升 Online DDL 失败回滚的可靠性。