SQL语句面试题

以下是针对SQL语句相关面试问题的回答思路和示例答案,结合原理、应用场景及优化技巧,帮助你清晰展现技术理解:


1. JOIN的类型(INNER JOIN、LEFT JOIN等)及区别?

在这里插入图片描述

回答思路

  • 先分类说明JOIN类型,再对比差异,最后结合实际场景举例。
  • 重点:明确不同JOIN对数据匹配逻辑的影响,避免混淆ONWHERE的作用。

示例回答

JOIN类型及区别

  • INNER JOIN(内连接):仅返回两表中匹配的行。
    SELECT * FROM A INNER JOIN B ON A.key = B.key;  
    
  • LEFT JOIN(左连接):返回左表所有行,右表无匹配时补NULL。
    SELECT * FROM A LEFT JOIN B ON A.key = B.key;  
    
  • RIGHT JOIN(右连接):返回右表所有行,左表无匹配时补NULL(实际开发中较少使用,通常用LEFT JOIN替代)。
  • FULL OUTER JOIN(全外连接):返回左右表所有行,无匹配时补NULL(MySQL不支持,需用UNION模拟)。

核心区别

  • INNER JOIN关注交集,LEFT JOIN保留左表全集,FULL JOIN保留所有数据。

应用场景举例

  • INNER JOIN:查询“已下单的用户详情”(仅需匹配成功的记录)。
  • LEFT JOIN:统计“所有用户的订单数量”(包括未下单用户)。

常见陷阱

  • 多表JOIN时注意连接顺序和索引使用(小表驱动大表)。
  • WHERE条件对LEFT JOIN的影响:若在WHERE中对右表字段过滤(如B.id IS NULL),可能将LEFT JOIN转换为INNER JOIN。

加分点

  • 提到“MySQL的JOIN算法(Nested-Loop Join、Block Nested-Loop Join、Hash Join)及优化器选择逻辑”。
  • 举例说明项目中如何优化多表JOIN(如“通过冗余字段或缓存中间表减少JOIN层级”)。

2. GROUP BY和HAVING的作用?与WHERE的执行顺序?

回答思路

  • 明确GROUP BY和HAVING的功能,并与WHERE的执行顺序对比。
  • 重点:区分“行级过滤”和“组级过滤”。

示例回答

GROUP BY的作用:按指定列分组,常与聚合函数(如COUNT、SUM)结合使用。
HAVING的作用:对分组后的结果进行过滤(类似WHERE,但针对分组)。

执行顺序

  1. WHERE:在数据分组前过滤行(无法使用聚合函数)。
  2. GROUP BY:对过滤后的数据进行分组。
  3. HAVING:对分组后的结果再次过滤(可使用聚合函数)。

示例

-- 统计每个部门的平均工资,仅显示平均工资>5000的部门  
SELECT department, AVG(salary) AS avg_salary  
FROM employees  
WHERE hire_date > '2020-01-01'  -- 先过滤入职时间  
GROUP BY department  
HAVING avg_salary > 5000;       -- 再过滤分组结果  

常见错误

  • 在WHERE中使用聚合函数(如WHERE AVG(salary) > 5000)会导致语法错误。
  • GROUP BY字段未出现在SELECT中(MySQL宽松模式下允许,但不符合SQL标准)。

加分点

  • 提到“WITH ROLLUP生成分组汇总行”或“窗口函数(如MySQL 8.0的ROW_NUMBER())替代复杂GROUP BY”。
  • 举例说明项目中如何优化GROUP BY性能(如“通过覆盖索引避免全表扫描”)。

3. 如何优化一条慢SQL?举例说明。

回答思路

  • 分步骤说明优化流程,结合具体案例。
  • 重点:展现系统性思维(分析→定位→解决→验证)。

示例回答

优化步骤

  1. 定位慢SQL:通过慢查询日志或监控工具(如Prometheus + Grafana)抓取目标SQL。
  2. 分析执行计划:使用EXPLAIN查看扫描类型(type字段)、索引使用(key字段)、扫描行数(rows字段)。
  3. 索引优化
    • 确保WHERE、JOIN、ORDER BY字段有索引。
    • 避免索引失效(如函数转换、隐式类型转换)。
  4. 重写SQL
    • 减少子查询,改用JOIN。
    • 分页优化(避免深分页,改用游标分页)。
    • 避免SELECT *,只取必要字段。
  5. 数据库调参:调整innodb_buffer_pool_size等参数。
  6. 架构升级:引入读写分离、缓存(Redis)、分库分表。

案例

  • 问题SQL
    SELECT * FROM orders  
    WHERE user_id = 1001  
    ORDER BY create_time DESC  
    LIMIT 1000, 10;  
    
  • 分析user_id无索引,导致全表扫描;深分页效率低。
  • 优化方案
    1. user_id添加索引,联合索引(user_id, create_time)更好。
    2. 改用游标分页(记录上一页最后一条的create_timeid):
      SELECT * FROM orders  
      WHERE user_id = 1001 AND create_time < '2023-10-01'  
      ORDER BY create_time DESC  
      LIMIT 10;  
      

加分点

  • 提到“使用EXPLAIN ANALYZE(MySQL 8.0+)获取实际执行统计信息”。
  • 举例说明“通过覆盖索引(Covering Index)减少回表查询”。

4. 如何防止SQL注入?预编译语句的原理?

回答思路

  • 先解释SQL注入的危害,再说明防御手段,重点剖析预编译原理。
  • 重点:对比“拼接字符串”和“预编译”的本质差异。

示例回答

SQL注入示例

-- 攻击者输入用户名:' OR '1'='1  
SELECT * FROM users WHERE username = '' OR '1'='1' AND password = '...';  

防御手段

  1. 预编译语句(Prepared Statements)
    • 原理:将SQL语句与参数分离。
      • 第一步:发送SQL模板(如SELECT * FROM users WHERE username = ?)到数据库编译。
      • 第二步:发送参数值(如'admin'),数据库将其视为纯数据而非SQL指令。
    • 效果:彻底避免参数值中的恶意SQL被执行。
    • 代码示例(Java + JDBC):
      String sql = "SELECT * FROM users WHERE username = ?";  
      PreparedStatement stmt = connection.prepareStatement(sql);  
      stmt.setString(1, inputUsername);  // 安全处理参数  
      
  2. 其他措施
    • 输入验证(白名单过滤特殊字符)。
    • 最小权限原则(数据库账号禁止高危操作)。
    • 使用ORM框架(如Hibernate、MyBatis的#{}占位符)。

预编译的优势

  • 安全性:参数化查询杜绝注入。
  • 性能:同一SQL模板可复用,减少解析开销。

加分点

  • 提到“预编译在MySQL协议中的实现(二进制协议 vs 文本协议)”。
  • 举例说明“项目中如何强制使用预编译”(如Code Review时禁用字符串拼接)。

总结回答技巧

  1. 结构化表达:分点说明(问题→原理→解决方案→案例)。
  2. 结合原理与实战:避免纯理论堆砌,用项目经验佐证(如“在XX项目中,我们通过优化索引将查询时间从2s降到50ms”)。
  3. 主动展示深度:适当延伸知识点(如从JOIN算法谈到索引选择)。
  4. 辩证分析:说明不同方案的权衡(如“虽然预编译安全,但在某些ORM框架中需注意动态SQL的拼接风险”)。
涉及到了基础SQL的所有知识点 desc emp;描述一下emp表的结构 2 select from salgrade; 3 select ename sal 12 from emp; 4 select 2 3 from emp;会出现14行 5 select 2 3 from dual;只有一行 专门提供计算数学表达式的 6 select sysdate from dual;获取当前系统时间 7 select ename sal 12 annual salary from emp;给sal 12取了个别名叫做annual salary 8 select ename sal 12 "annual salary" from emp;用双引号将别名括起来 这样可以保留住空格 大小写 中文等等 9 select ename comm from emp;其中comm中包括空值 空值不等于0 10 select ename sal 12+comm "总年薪" from emp;任何数加上空值都等于空值 11 select ename||sal from emp;字符串连接符 12 select ename||" nihao" from emp;在SQL语句中 字符串是由单引号括起来的若干字符 13 select ename||" niahao""dajiahao" from emp;如果字符串中本身就有一个单引号 那么在SQL语句中进行表示时 用两个单引号表示一个单引号 14 select distinct deptno from emp;select distinct deptno job from emp; 15 select from emp where ename "CLARK";where中添加条件约束 并且字符串需要加上单引号来表示 16 select ename job sal from emp where ename > "CBA";字符串比较 先比较第一个 比C大 就TRUE 第一个字母相同)否则比较下一个 比B大 就TRUE 否则 17 select ename sal from emp where sal<>ALL 1500 2000 2500 3000 ;<>表示不等于 <>ALL表示不等于所有的( ) 18 select from emp where sal between 800 and 1300;和select from emp where sal> 800 and sal< 1300;的效果是一样的 19 select from emp where comm is null;is null表示是空值 is not null表示非空值 不可以用 20 select ename sal from emp where ename in "SMITH" "CLARK" "SCOTT" ;ename在()中的人选出来 ()中也可以是其他类型 21 select ename sal hiredate from emp where hiredate > "20 2月 81";日期的格式 22 select ename sal from emp where ename like " A%"; 表示一个字符 %表示0个或多个字符 23 select from emp where ename like "% %%" escape " ";其中 作为转义字符的符号 select from emp where ename like "% %%"; %表示百分号 24 select empno ename from emp order by empno asc;升序排列(默认);select deptno dname from dept order by deptno desc;降序排列 25 select empno ename from emp where deptno<>10 order by empno desc;可以先选择在排序 26 select ename sal deptno from emp order by deptno asc ename desc;先按照deptno进行升序排列 在deptno相同的地方 按照ename进行降序排列 27 select ename sal 12 annual sal from emp where ename not like " A%’ and sal > 800 order by desc; 28 select ename sal from emp where lower ename like " a%";小写 29 select substr ename 2 3 from emp;从第二个字符开始 截3个字符出来作为结果 30 select chr 65 from dual;把ASCII码转化成字符 31 select ascii "A" from dual;把字符转化成ASCII码 32 select round 23 643 2 from dual;四舍五入为23 64 默认第二个参数为0 即四舍五入到各位 也可以为 1 则为20 33 select to char sal "$99 999 9999" from emp;美元 9代表一个数字 “ ”代表一个千分位符号 select to char sal "L99 999 9999" from emp;人民币 select to char sal "L00000 0000" from emp; 34 select to char hiredate "YYYY MM DD HH:MI:SS" from emp;转换Date类型的时间表示方法 select to char sysdate "MM DD YY HH24:MI:SS" from dual;24小时制 35 select ename hiredate from emp where hiredate > to Date "1981 2 3 14:23:12" "YYYY MM DD HH24:MI:SS" ;to date "" "" 将日期转换成自己想要的格式 36 select ename sal 12 + nvl comm 0 from emp;nvl comm 0 是将comm中的空值设为0 非空值还是本身 37 to number "$1250 00" "$9 999 99" ;有点问题 ">涉及到了基础SQL的所有知识点 desc emp;描述一下emp表的结构 2 select from salgrade; 3 select ename sal 12 from emp; 4 select 2 3 from emp;会出现14行 5 select 2 3 from dual;只有一行 专门提供计算数学表达式的 6 select sysdate from dual;获 [更多]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值