SQL常见面试题总结

SQL常见面试题总结

(原创不易,你们对阿超的赞就是阿超持续更新的动力!)

(以免丢失,建议收藏,阿超持续更新中…)

(------------------------------------------------------------------------)

常用SQL语句

--  默认升序排序(ASC)

--增
insert into user values (123,'女','猪猪')

--删
delete from student where id = 6

--改
update student set sname = '猪猪' where sid = 1

--查
select * from user where uid = 1
select * from user where userName = 'admin' and password = '123'

-- 多表关联查询
-- 左连接  left join 或 left outer join
左外连接包含left join左表所有行,如果左表中某行在右表没有匹配,则结果中对应行右表的部分全部为空(NULL).
select * from student left join course on student.ID=course.ID

-- 右连接
右外连接包含right join右表所有行,如果左表中某行在右表没有匹配,则结果中对应左表的部分全部为空(NULL)select * from student right join course on student.ID=course.ID

-- 内连接
在每个表中找出符合条件的共有记录
隐式内连接:select * from A,B where 条件;
显示内连接:select * from A inner join B on 条件;

-- 排序
order by 默认升序排序(ASC)

-- 分组
group by

-- 分页查询
m的含义表示从数据的第(m + 1)条开始查询(mysql中第一条数据m=0)
n的含义是从第m条数据开始往后查询n条数据
SELECT * FROM user limit m,n


-- SQL Server
-- 分页查询
select top (@pagesize) * from user
where userid 
not in(
	select top 
		(@pagesize*(@currentPage-1))
 	userid
 	from user) 
 	
-- 查询有几条表数据
select count(*) from user

-- 获得当前日期+时间
oracle: select sysdate from dual;
sqlserver: select getdate();
mysql: select sysdate()	或者 select now()date + time)函数:now() 

SQL常用的聚合函数

  • max(求最大值)
  • min(求最小值)
  • sum(求累加和)
  • avg(求平均)
  • count(统计行数数量)

如何提高MySql的安全性

  • 避免从互联网访问MySQL数据库,确保特定主机才拥有访问特权
  • 定期备份数据库
    任何系统都有可能发生灾难。服务器、MySQL也会崩溃,也有可能遭受入侵,数据有可能被删除。只有为最糟糕的情况做好了充分的准备,才能够在事后快速地从灾难中恢复。企业最好把备份过程作为服务器的一项日常工作。
  • 禁用或限制远程访问
  • 设置root用户的口令并改变其登录名。
  • 移除测试(test)数据库
  • 禁用LOCAL INFILE
  • 移除匿名账户和废弃的账户
  • 降低系统特权
  • 降低用户的数据库特权
  • 移除和禁用.mysql_history文件
  • 安全补丁
  • 启用日志
  • 改变root目录
    Unix操作系统中的chroot可以改变当前正在运行的进程及其子进程的root目录。重新获得另一个目录root权限的程序无法访问或命名此目录之外的文件,此目录被称为“chroot监狱”。
    通过利用chroot环境,你可以限制MySQL进程及其子进程的写操作,增加服务器的安全性。

为什么不使用readonly使全局库只读

既然表级锁是全库只读,为何不直接set global readonly = true
readonly是可以让全库进入只读状态,还是建议使用FTWRL,原因如下:

  • 一是在一些系统中,readonly的值会用作其它逻辑,比如用来判断一个库的主库还是备库,所以修改global变量的方式影响面更大;
  • 二是在异常处理机制上有差异,如果执行FTWRL命令之后由于客户端发生异常断开,那么MySQL会自动释放这个全局锁,整个库回到正常更新的状态;而将整个库设置为readonly之后,如果客户端发生异常,则数据库就会一直保持readonly状态,这样会导致整个库长时间处于不可写状态,风险较高;

备份为什么要加锁

假设你现在要维护“极客时间”的购买系统,关注的是用户账户余额表和用户课程表。现在发起一个逻辑备份。假设备份期间,有一个用户,他购买了一门课程,业务逻辑里就要扣掉他的余额,然后往已购课程里面加上一门课。
可以看到,这个备份结果里,用户 A 的数据状态是“账户余额没扣,但是用户课程表里面已经多了一门课”。如果后面用这个备份来恢复数据的话,用户 A 就发现,自己赚了。
也就是说,不加锁的话,备份系统备份的得到的库不是一个逻辑时间点,这个视图是逻辑不一致的。

MySQL存储引擎

mysql默认的存储引擎就是innodb,它的索引结构是优化后的B+tree,原B+tree的叶子节点之间是单向指向,组合成一个单向链表,而优化后,叶子节点之间双向指向,组合成双向链表。

索引分为聚簇索引和非聚簇索引,聚簇索引的叶子节点一个索引携带一row的数据,非聚簇索引下索引携带对应主键数据。

索引主要针对查询,索引可以加快查询效率,例如我们建立索引时尽量在where,orderBy这样的条件需要的字段加索引,因为查询时根据条件查询,条件上加了索引,可以快速定位到需要查询的数据。

我们使用索引时,可以尽量去使用覆盖索引来避免回表的过程,因为我们自己建的索引为非聚簇索引,根据索引定位到数据后,可以找到索引列数据和主键数据,但是如果你的索引不是覆盖索引,那你需要的字段并没有全部包含在当前已经查询到的数据,所以需要根据主键进行回表,通过聚簇索引,查询到当前行的数据,在取出你所需要查询字段的数据,这个回表过程是不必要的。

如果需要建立多个单列索引,我们尽量去使用组合索引,当然组合索引需要注意最左前缀匹配原则,按照建立组合索引的顺序,必须保证当前字段前面的索引列存在才能保证组合索引生效。并且如果当前使用组合索引时,某字段采用了范围查询,就会导致该字段后面的索引失效。

最后我们需要注意的是索引是为了索引表内少量的数据,所以如果你在条件查询时,条件是大量的数据,那么sql语句经过优化器时,就会分析走当前索引还不如走全文检索,索引就会走全文索引,也会造成索引的失效。

还有插入语句的时候,如果是批量插入,我们尽量去使用主键顺序插入,如果数据量国语庞大可以使用load来进行加载。

还有一个除了索引可以优化的点,innoDB它相比于MyISAM他是支持行级锁的,但是有时候我们在操作的时候会有一些误操作,使得行级锁上升到表级锁,就比如我们根据一个字段做条件去更新本行数据时,当前字段没有建立索引,那就会走一个全文检索,那整张表就会被锁住,行级锁就会上升到表级锁,这也是为什么需要在条件字段添加索引的另一个原因。

间隙锁:对表进行改动时,使用了范围条件,当前范围内就会被锁住。

MySQL的事务隔离级别

  • 读未提交(Read Uncommitted):允许脏读,也就是可能读取到其他会话中未提交事务修改的数据
  • 读已提交(Read Committed):只能读取到已经提交的数据。Oracle等多数数据库默认都是该级别 (不重复读)
  • 可重复读(Repeated Read):可重复读。在同一个事务内的查询都是事务开始时刻一致的,InnoDB默认级别。在SQL标准中,该隔离级别消除了不可重复读,但是还存在幻象读,但是innoDB解决了幻读
  • 串行读(Serializable):完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞

MySQL中的MyISAM与InnoDB 的区别

MyISAM是MySQL的默认数据库引擎(5.5版之前)

  • InnoDB支持事务,MyISAM不支持。
  • InnoDB支持外键,而MyISAM不支持。
  • InnoDB是聚集索引,使用B+Tree作为索引结构,数据文件是和(主键)索引绑在一起的(表数据文件本身就是按B+Tree组织的一个索引结构),必须要有主键,通过主键索引效率很高。但是辅助索引需要两次查询,先查询到主键,然后再通过主键查询到数据。因此,主键不应该过大,因为主键太大,其他索引也都会很大。

MyISAM是非聚集索引,也是使用B+Tree作为索引结构,索引和数据文件是分离的,索引保存的是数据文件的指针。主键索引和辅助索引是独立的。

  • InnoDB不保存表的具体行数*,*而MyISAM用一个变量保存了整个表的行数
  • Innodb不支持全文索引,而MyISAM支持全文索引
    (5.7以后的InnoDB支持全文索引了)
  • MyISAM表格可以被压缩后进行查询操作
  • InnoDB支持表、行(默认)级锁,而MyISAM支持表级锁
  • InnoDB表必须有唯一索引(如主键)(用户没有指定的话会自己找/生产一个隐藏列Row_id来充当默认主键),而Myisam可以没有
  • Innodb存储文件有frm、ibd,而Myisam是frm、MYD、MYI

如何选择MyISAM和InnoDB

  • 是否要支持事务,如果要请选择 InnoDB,如果不需要可以考虑 MyISAM;
  • 如果表中绝大多数都只是读查询,可以考虑 MyISAM,如果既有读写也挺频繁,请使用InnoDB。
  • 系统奔溃后,MyISAM恢复起来更困难,能否接受,不能接受就选 InnoDB;
  • MySQL5.5版本开始Innodb已经成为Mysql的默认引擎(之前是MyISAM),说明其优势是有目共睹的。如果你不知道用什么存储引擎,那就用InnoDB,至少不会差。

索引常见的几种失效情况

  • 对于联合索引,没有遵循左前缀原则
  • 索引的字段区分度不大,可能引起索引近乎全表扫描
  • 对于join操作,索引字段的编码不一致,导致使用索引失效
  • 对于hash索引,范围查询失效,hash索引只适合精确匹配
  • 有索引,但操作索引项字段“·不干净” 加了函数或者各种骚操作
    (对于sql执行耗时问题 最好使用explain和 profilings 查看执行计划详细信息)
  • 对于innodb 或myisam,is null 走索引的情况 不走索引的情况?
    is not null 对于索引字段设计不管允许为空或不许为null 都不走索引
    is null 对于索引字段设计为可许为null时 走索引 ;如果字段设计不可null 则不走索引
  • 条件中用or,即使其中有条件带索引,也不会使用索引查询(这就是查询尽量不要用or的原因,用in吧)

索引失效与优化

  • 全值匹配
  • 最佳左前缀法则(带头大哥不能死,中间兄弟不能少)
  • 不在索引列上做任何操作(计算、函数、(自动or手动)类型转换),会导致索引失效而转向全表扫描
  • 存储引擎不能使用索引中范围条件右边的列
  • 尽量使用覆盖索引(只访问索引的查询(索引列和查询列一直)),减少select *
  • mysql在使用不等于(!=或者<>)的时候无法使用索引会导致全表扫描
  • 使用is null, is not null也无法使用索引
  • like以通配符开头(‘%abc…’)mysql索引失效会变成全表扫描的操作
  • 字符串不加单引号索引失效
  • 少用or,用它来连接时索引会失效

请说出sql语句中 left join ,inner join 和right join的区别

left join(左联接) :返回包括左表中的所有记录和右表中联结字段相等的记录
right join(右联接) :返回包括右表中的所有记录和左表中联结字段相等的记录
inner join(等值连接) :只返回两个表中联结字段相等的行

分库分表的问题如何实现分布式全局唯一ID

在分库分表的环境中,数据分布在不同的分片上,不能再借助数据库自增长特性直接生成,否则会造成不同分片上的数据表主键会重复。

Group By和Order By

GROUP BY 和 ORDER BY同时使用的方法及注意事项:

GROUP BY和ORDER BY同时存在的情况是,ORDER BY对GROUP BY后的结果再进行排序,所以ORDER BY后面的排序字段需要在SELECT里出现,ORDER BY 子句中的列必须包含在聚合函数或 GROUP BY 子句中

where和having子句的区别

having和where的区别:

  • 作用的对象不同。WHERE 子句作用于表和视图,HAVING 子句作用于组。
  • WHERE 在分组和聚集计算之前选取输入行(因此,它控制哪些行进入聚集计算), 而 HAVING 在分组和聚集之后选取分组的行。因此,WHERE 子句不能包含聚集函数; 因为试图用聚集函数判断那些行输入给聚集运算是没有意义的。 相反,HAVING 子句总是包含聚集函数。(严格说来,你可以写不使用聚集的 HAVING 子句, 但这样做只是白费劲。同样的条件可以更有效地用于 WHERE 阶段。)
  • WHERE不需要聚集。 这样比在 HAVING 里增加限制更加高效,因为我们避免了为那些未通过 WHERE 检查的行进行分组和聚集计算

综上所述:
having一般跟在group by之后,执行记录组选择的一部分来工作的。
where则是执行所有数据来工作的。
再者having可以用聚合函数,如having sum(qty)>1000

SQL优化

  • 对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。
  • 应尽量避免在 where 子句中使用 or 来连接条件, 用 union all来代替
  • 应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。
  • 不要写一些没有意义的查询,如需要生成一个空表结构
  • 索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,
  • innodb引擎下,尽可能的使用 varchar 代替 char ,因为varchar长度可变。
  • 尽量避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理。

MySQL优化

  • 创建索引
  • 复合索引
  • 索引不会包含有NULL值的列
  • 使用短索引
  • 排序的索引问题
  • like语句操作
  • 不要在列上进行运算
  • 不使用NOT IN和<>操作

索引

索引是为了加速对表中数据行的检索而创建的一种分散的存储结构实现原理(B+树) 通俗点说类似于一本书的目录,通过目录可以快速查到你想要的数据。

索引有什么用

索引能大幅度提高查询效率
但是数据的变更(增删改)都需要维护索引,因此更多的索引意味着更多的维护成本
更多的索引意味着也需要更多的空间 (就比如说一本100页的书,却有50页目录)
过小的表,建索引还可能会更慢(就比如说读个2页的宣传手册,你还先去找目录)

索引的优缺点

索引的优点:

  • 创建唯一性索引,保证数据库表中每一行数据的唯一性
  • 大大加快数据的检索速度,这也是创建索引的最主要的原因
  • 加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。
  • 在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间。
  • 通过使用索引,可以在查询的过程中使用优化隐藏器,提高系统的性能。

索引的缺点:

  • 创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加
  • 索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚簇索引,那么需要的空间就会更大
  • 当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,降低了数据的维护速度

事物的特性有哪些

  • 原子性 (atomicity):强调事务的不可分割.
  • 一致性 (consistency):事务的执行的前后数据的完整性保持一致.
  • 隔离性 (isolation):一个事务执行的过程中,不应该受到其他事务的干扰
  • 持久性(durability) :事务一旦结束,数据就持久到数据库

什么是事务

数据库事务是指作为单个逻辑工作单元执行的一系列操作(SQL语句)。这些操作要么全部执行,要么全部不执行。

为什么需要事务

经典的银行转账行为,A账户转给B账户10元,数据库操作需要两步,第一步A账户减10元,第二步B账户加10元,如果没有事务并且在两步中间发生异常,就会导致A的账户少了10元,但B的账户没有变化,如果不能保证这两步操作统一,银行的转账业务也没法进行展开了。

count(*)和count(1)有什么区别

count(1) 含义

count(1) 会统计表中的所有的记录数,包含字段为null 的记录
count(1)指的并不是计算1的个数,而是指表的第一个字段

用count对字段为null的数据可以查出来吗

不可以
对于返回的结果集,一行行地判断,如果 count 函数的参数不是 NULL,累计值就加 1,否则不加。最后返回累计值

count(*)和count(1)哪个执行效率高

如果count(1)是聚索引 id,那肯定是count(1)快

执行效果上

count(*)包括了所有的列,相当于行数,在统计结果的时候,不会忽略列值为NULL
count(1)包括了忽略所有列,用1代表代码行,在统计结果的时候,不会忽略列值为NULL
count(列名)只包括列名那一列,在统计结果的时候,会忽略列值为空(这里的空不是只空字符串或者0,而是表示null)的计数,即某个字段值为NULL时,不统计

执行效率上

列名为主键,count(列名)会比count(1)快
列名不为主键,count(1)会比count(列名)快
如果表多个列并且没有主键,则 count(1) 的执行效率优于 count ( * )
如果有主键,则 select count(主键)的执行效率是最优的
如果表只有一个字段,则 select count ( * )最优

MySQL 的全局锁、表锁和行锁

行级锁(row-level locking)是Mysql中锁定粒度最细的一种锁,表示只针对当前操作的行进行加锁。行级锁能大大减少数据库操作的冲突。其加锁粒度最小,但加锁的开销也最大。

表级锁(table-level locking)是MySQL中锁定粒度最大的一种锁,表示对当前操作的整张表加锁,它实现简单,资源消耗较少,被大部分MySQL引擎支持。最常使用的MYISAM与INNODB都支持表级锁。

全局锁

全局锁就是对整个数据库实例加锁,mysql提供了一个加全局读锁的方法,命令是flush tables with read lock。让你需要让整个库处于只读状态的时候,可以使用这个命令,之后其他线程的语句都会被阻塞:

  • 数据更新语句(数据的增删改)
  • 数据定义语句(包括建表、修改表结构等)
  • 更新类事务的提交语句

全局锁使用场景: 全库逻辑备份

表级锁

mysql里面表级别的锁有两种:一种是表锁,一种是元数据锁(meta data lock,MDL)
表锁的语法是lock tables …read/write,与ftwrl类似,可以用unlock tables 主动释放锁,也可以在客户端断开的时候自动释放。需要注意,lock tables语法除了会限制别的线程的读写外,也限定了本线程接下来的操作对象。
另一个表级锁是MDL,元数据锁,这个锁在访问一个表时自动进行加上,防止读写不正确。

行锁

行锁就是针对数据表中行记录的锁,比如事务A更新了一行,而这时候事务B也要更新一行,则必须等事务A的操作完成后才能进行更新。

死锁和死锁检测

当并发系统中不同线程出现循环资源依赖,涉及的线程都在等待别的线程释放资源时,就会导致这几个线程都进入无限等待的状态,称为死锁。

当出现死锁以后,有两种策略:

  • 一种策略是,直接进入等待,直至超时。这个超时时间可以通过参数innodb_lock_wait_timeout来设置
  • 另一种策略是,发起死锁检测,发现死锁后,主动回滚死锁链条中的某一个事务,让其他事务得以继续执行,将参数innodb_deadlock_detect设置为on,表示开启这个逻辑

在Innodb中,innodb_lock_wait_timeout的默认值是50s,意味着如果采用第一个策略,当出现死锁后,第一个被锁住的线程要过50s才会超时退出,然后其他线程才有可能继续执行,对于在线服务来说,这个等待时间往往是无法接受的。但是如果设置为一个很小的值,又很容易误伤。
对记录加锁时,加锁的基本单位是 next-key lock,它是由记录锁和间隙锁组合而成的,next-key lock 是前开后闭区间,而间隙锁是前开后开区间。
但是,next-key lock 在一些场景下会退化成记录锁或间隙锁

唯一索引等值查询

当我们用唯一索引进行等值查询的时候,查询的记录存不存在,加锁的规则也会不同:

  • 当查询的记录是存在的,在用「唯一索引进行等值查询」时,next-key lock 会退化成「记录锁」。
  • 当查询的记录是不存在的,在用「唯一索引进行等值查询」时,next-key lock 会退化成「间隙锁」。

关系型数据库和非关系型数据库区别

关系型数据库

关系型数据库代表

mysql / oracle / sql server / sqlite

什么是关系型数据库

关系型数据库最典型的数据结构是表,由二维表及其之间的联系所组成的一个数据组织。

优点:

  • 易于维护:都是使用表结构,格式一致;
  • 使用方便:SQL语言通用,可用于复杂查询;
  • 复杂操作:支持SQL,可用于一个表以及多个表之间非常复杂的查询。

缺点:

  • 读写性能比较差,尤其是海量数据的高效率读写;
  • 固定的表结构,灵活度稍欠;
  • 高并发读写需求,传统关系型数据库来说,硬盘I/O是一个很大的瓶颈。

非关系型数据库

非关系型数据库代表

redis / hbase / mongoDB / CouchDB / Neo4J 【注意:hive 不是数据库,是数据仓库 不是一个概念】

什么是非关系型数据库

非关系型数据库严格上不是一加粗样式种数据库,应该是一种数据结构化存储方法的集合,可以是文档或者键值对等。

优点:

  • 格式灵活:存储数据的格式可以是key,value形式、文档形式、图片形式等等,文档形式、图片形式等等,使用灵活,应用场景广泛,而关系型数据库则只支持基础类型。
  • 速度快:nosql可以使用硬盘或者随机存储器作为载体,而关系型数据库只能使用硬盘;
  • 高扩展性;
  • 成本低:nosql数据库部署简单,基本都是开源软件。

缺点:

  • 不提供sql支持,学习和使用成本较高;
  • 无事务处理;
  • 数据结构相对复杂,复杂查询方面稍欠。

非关系型数据库的分类

  • 文档型
  • key-value型
  • 列式数据库
  • 图形数据库

---------------------------面试题总结-----------------------------

Java基础知识点总结

MyBatis常见面试题总结

Spring常见面试题总结

SpringMVC常见面试题总结

SpringBoot常见面试题总结

消息中间件常见面试题总结

Kafka常见面试题

Redis面试题总结

SQL常见面试题总结

Dubbo常见面试题总结

SpringCloud常见面试题总结

TCP和UDP详解

数据库事务详解

猜你喜欢

转载自blog.csdn.net/Mr_Gaojinchao/article/details/120943303