SQL 大厂面试题目(由浅入深)

今天给大家带来一份大厂SQL面试覆盖:基础语法 → 复杂查询 → 性能优化 → 架构设计,大家需深入理解执行原理并熟悉实际业务场景的解决方案。



1. 基础查询与过滤

题目:查询 employees 表中所有薪资(salary)大于 10000 且部门编号(dept_id)为 5 的员工姓名(name)和入职日期(hire_date)。

sql 复制代码
SELECT name, hire_date 
FROM employees 
WHERE salary > 10000 AND dept_id = 5;

2. 聚合函数与分组

题目:统计每个部门(dept_id)的平均薪资,并仅显示平均薪资高于 15000 的部门。

sql 复制代码
SELECT dept_id, AVG(salary) AS avg_salary
FROM employees
GROUP BY dept_id
HAVING AVG(salary) > 15000;

3. 多表连接(JOIN)

题目:查询员工姓名(name)及其所属部门名称(dept_name),表结构为 employees(id, name, dept_id)和 departments(id, dept_name)。

sql 复制代码
SELECT e.name, d.dept_name
FROM employees e
JOIN departments d ON e.dept_id = d.id;

4. 子查询与 EXISTS

题目:查询没有订单的客户(customers 表的 id 不在 orders 表的 customer_id 中)。

sql 复制代码
SELECT c.id, c.name
FROM customers c
WHERE NOT EXISTS (
    SELECT 1 FROM orders o WHERE o.customer_id = c.id
);

5. 窗口函数

题目:查询每个部门薪资排名前 3 的员工姓名和薪资。

sql 复制代码
WITH ranked_employees AS (
    SELECT 
        name, salary, dept_id,
        RANK() OVER (PARTITION BY dept_id ORDER BY salary DESC) AS rank
    FROM employees
)
SELECT name, salary, dept_id
FROM ranked_employees
WHERE rank <= 3;

6. 递归查询(CTE)

题目:查询树形结构表 categories(id, name, parent_id)中 ID=5 的所有子节点。

sql 复制代码
WITH RECURSIVE sub_categories AS (
    SELECT id, name, parent_id
    FROM categories
    WHERE id = 5
    UNION ALL
    SELECT c.id, c.name, c.parent_id
    FROM categories c
    JOIN sub_categories sc ON c.parent_id = sc.id
)
SELECT * FROM sub_categories;

7. 索引优化

题目:在 orders 表中,如何为 customer_id 和 order_date 设计联合索引以优化查询 WHERE customer_id = 100 AND order_date > '2024-02-10'?

答案:

sql 复制代码
CREATE INDEX idx_customer_order_date ON orders (customer_id, order_date);

**原理:**联合索引按最左前缀匹配原则,优先按 customer_id 过滤,再按 order_date 范围查询。


8. 事务与隔离级别

题目:解释"不可重复读"(Non-Repeatable Read)和"幻读"(Phantom Read)的区别。

答案:

**不可重复读:**同一事务中两次读取同一行数据,结果不同(由其他事务的 UPDATE 或 DELETE 导致)。

**幻读:**同一事务中两次查询同一范围的数据,结果行数不同(由其他事务的 INSERT 导致)。


9. 执行计划分析

题目:以下查询的执行计划中出现了 Full Table Scan,如何优化?

SELECT * FROM products WHERE category = 'Electronics' AND price > 1000;

答案:
添加联合索引 (category, price):

sql 复制代码
CREATE INDEX idx_category_price ON products (category, price);

10. 复杂场景设计

题目:设计一个数据库表结构,支持用户每日签到(可重复签到但仅第一次有效),并统计某用户最近 30 天的签到次数。

答案:

sql 复制代码
CREATE TABLE user_checkins (
    user_id INT,
    checkin_date DATE,
    PRIMARY KEY (user_id, checkin_date) -- 唯一约束避免重复
);

-- 统计最近30天签到次数
SELECT COUNT(*) 
FROM user_checkins 
WHERE user_id = 100 
AND checkin_date >= CURRENT_DATE - INTERVAL '30 days';

11. 死锁分析与解决

题目:两个事务分别执行以下操作,如何发生死锁?

事务1:UPDATE accounts SET balance = balance - 100 WHERE id = 1; UPDATE accounts SET balance = balance + 100 WHERE id = 2;

事务2:UPDATE accounts SET balance = balance - 200 WHERE id = 2; UPDATE accounts SET balance = balance + 200 WHERE id = 1;

答案:

事务1锁定id=1后等待id=2,事务2锁定id=2后等待id=1,形成循环等待。

**解决方案:**按固定顺序更新(如先更新id小的账户)。


12. 时间窗口统计

题目:统计每小时内订单量最多的前3个小时(表 orders 含字段 order_time)。

sql 复制代码
WITH hourly_orders AS (
    SELECT 
        EXTRACT(HOUR FROM order_time) AS hour,
        COUNT(*) AS order_count
    FROM orders
    GROUP BY EXTRACT(HOUR FROM order_time)
)
SELECT hour, order_count
FROM hourly_orders
ORDER BY order_count DESC
LIMIT 3;

13. 数据去重

题目:删除 logs 表中重复记录(保留id最小的一条)。

sql 复制代码
DELETE FROM logs
WHERE id NOT IN (
    SELECT MIN(id)
    FROM logs
    GROUP BY user_id, log_time, content
);

14. 分页查询优化

题目:优化大表的分页查询 SELECT * FROM users ORDER BY id LIMIT 1000000, 10;。

答案:
使用覆盖索引 + 游标分页:

sql 复制代码
SELECT * FROM users 
WHERE id > 1000000 
ORDER BY id 
LIMIT 10;

15. 分区表设计

题目:如何按时间范围对 sales 表进行分区以优化查询性能?

答案:

sql 复制代码
-- 按月分区(以 PostgreSQL 为例)
CREATE TABLE sales (
    sale_id SERIAL,
    sale_date DATE,
    amount NUMERIC
) PARTITION BY RANGE (sale_date);

CREATE TABLE sales_2023_01 PARTITION OF sales
    FOR VALUES FROM ('2024-01-10') TO ('2024-02-10');

16. JSON 数据处理

题目:从 products 表的 attributes(JSON 字段)中提取颜色(color)和尺寸(size)。

sql 复制代码
-- 以 MySQL 为例
SELECT 
    attributes->>'$.color' AS color,
    attributes->>'$.size' AS size
FROM products;

17. 高级窗口函数

题目:计算每个员工薪资与所在部门平均薪资的差值。

sql 复制代码
SELECT 
    name,
    salary,
    salary - AVG(salary) OVER (PARTITION BY dept_id) AS diff_from_avg
FROM employees;

18. 动态SQL与存储过程

题目:编写存储过程,根据输入的城市名动态查询 customers 表。

sql 复制代码
-- 以 PostgreSQL 为例
CREATE OR REPLACE PROCEDURE get_customers_by_city(city_name TEXT)
LANGUAGE plpgsql
AS $$
BEGIN
    EXECUTE 'SELECT * FROM customers WHERE city = $1' USING city_name;
END;
$$;

19. 分布式ID生成方案

题目:在分布式系统中,如何设计全局唯一的订单ID?

答案:

雪花算法(Snowflake):时间戳 + 机器ID + 序列号。

UUID:随机生成,但存储效率低。

数据库分段分配:中央数据库分配ID范围给各节点。


20. 数据一致性保障

题目:如何实现"扣减库存时防止超卖"?

答案:

sql 复制代码
-- 事务内原子操作(以 MySQL 为例)
START TRANSACTION;
SELECT stock FROM products WHERE id = 100 FOR UPDATE;
UPDATE products SET stock = stock - 1 WHERE id = 100 AND stock > 0;
COMMIT;
相关推荐
Lee川1 天前
优雅进化的JavaScript:从ES6+新特性看现代前端开发范式
javascript·面试
倔强的石头_1 天前
kingbase备份与恢复实战(二)—— sys_dump库级逻辑备份与恢复(Windows详细步骤)
数据库
Lee川1 天前
从异步迷雾到优雅流程:JavaScript异步编程与内存管理的现代化之旅
javascript·面试
晴殇i1 天前
揭秘JavaScript中那些“不冒泡”的DOM事件
前端·javascript·面试
绝无仅有1 天前
Redis过期删除与内存淘汰策略详解
后端·面试·架构
绝无仅有1 天前
Redis大Key问题排查与解决方案全解析
后端·面试·架构
AAA梅狸猫2 天前
Looper.loop() 循环机制
面试
AAA梅狸猫2 天前
Handler基本概念
面试
Wect2 天前
浏览器缓存机制
前端·面试·浏览器
掘金安东尼2 天前
Fun with TypeScript Generics:玩转 TS 泛型
前端·javascript·面试