事务是不可分割的操作单元,acid通过undo log(原子性)、约束与逻辑(一致性)、锁/mvcc(隔离性)、redo log(持久性)保障;inner join仅返回匹配行,left join保留左表全部记录;主键唯一非空且建聚簇索引,唯一索引允许null,普通索引仅加速查询;count(*)统计所有行且最快,count(字段)仅计非null值。

SQL面试中,数据库基础知识是必考内容,重点不在死记硬背语法,而在于理解底层逻辑和实际场景的应对能力。以下从四个高频维度梳理核心要点,覆盖概念辨析、查询逻辑、数据完整性与性能意识。
什么是事务?ACID怎么保证的?
事务是一组不可分割的操作单元,典型场景如银行转账:扣款和入账必须同时成功或同时失败。ACID是它的四个关键特性:
- 原子性(Atomicity):靠undo log实现回滚,任一语句失败,整个事务撤销
- 一致性(Consistency):由应用逻辑+约束(如外键、CHECK)共同保障,数据库本身不自动“保证业务一致”
- 隔离性(Isolation):通过锁机制或MVCC控制并发读写,常见隔离级别有READ UNCOMMITTED到SERIALIZABLE
- 持久性(Durability):靠redo log确保崩溃后可恢复,提交后的数据不会丢失
面试常问“脏读、不可重复读、幻读分别发生在哪个隔离级别?”——本质是考察对MVCC和锁行为的理解,不是背级别名称。
INNER JOIN 和 LEFT JOIN 的区别到底在哪?
关键看驱动表(左表)的记录是否全部保留:
- INNER JOIN:只返回左右表都能匹配上的行,不匹配的行全被过滤
- LEFT JOIN:以左表为基准,左表每行都出现;右表无匹配时,对应字段为NULL
易错点:WHERE条件写在JOIN之后会把LEFT JOIN“变相转成INNER JOIN”。例如SELECT * FROM A LEFT JOIN B ON A.id = B.a_id WHERE B.status = 'active'——B无匹配时B.status为NULL,不满足WHERE,结果等效于INNER JOIN。正确做法是把过滤条件放到ON子句中:ON A.id = B.a_id AND B.status = 'active'。
主键、唯一索引、普通索引的区别和使用场景
三者都可用于加速查询,但约束能力和设计意图不同:
- 主键(PRIMARY KEY):唯一 + 非空 + 自动创建聚簇索引(InnoDB),一张表只能有一个
- 唯一索引(UNIQUE INDEX):唯一 + 允许NULL(注意:多个NULL不算重复),适合业务上要求唯一的字段,如手机号、邮箱
- 普通索引(INDEX):仅加速查询,不约束数据,适合高频WHERE或ORDER BY字段,如create_time、status
补充:联合索引遵循最左前缀原则。比如(index_a_b_c),能命中a=1、a=1 AND b=2、a=1 AND b=2 AND c=3,但不能命中b=2或c=3单独查询。
为什么COUNT(*)比COUNT(字段)快?NULL值怎么影响统计?
COUNT函数统计的是行数,但语义不同:
- COUNT(*):统计所有行,包括含NULL的行,优化器通常直接读取元数据或聚簇索引行数,无需查字段内容
- COUNT(字段):只统计该字段非NULL的行数,需逐行判断字段值是否为NULL,开销更大
- COUNT(1):和COUNT(*)基本等价,都是统计行数,现代MySQL优化器已无实质差异
特别注意:COUNT(id)如果id是主键,也等价于COUNT(*);但如果id允许NULL,那COUNT(id)就只算非空id的行数——这点常被忽略。










