0
点赞
收藏
分享

微信扫一扫

面试高频题之MySQL篇(3)

Python芸芸 2022-01-06 阅读 45

1、为什么要使用视图?什么是视图? 

为了提高复杂SQL语句的复用性和表操作的安全性,MySQL数据库管理系统提供了视图特性。所谓视图,本质上是一种虚拟表,在物理上是不存在的,其内容与真实的表相似,包含一系列带有名称的列和行数据。但是,视图并不在数据库中以储存的数据值形式存在。行和列数据来自定义视图的查询所引用基本表,并且在具体引用视图时动态生成。

视图使开发者只关心感兴趣的某些特定数据和所负责的特定任务,只能看到视图中所定义的数据,而不是视图所引用表中的数据,从而提高了数据库中数据的安全性。

2、视图的优点和缺点?

1. 查询简单化。视图能简化用户的操作

2. 数据安全性。视图使用户能以多种角度看待同一数据,能够对机密数据提供安全保护

3. 逻辑数据独立性。视图对重构数据库提供了一定程度的逻辑独立性

视图的缺点

1. 性能。数据库必须把视图的查询转化成对基本表的查询,如果这个视图是由一个复杂的多表查询所定义,那么,即使是视图的一个简单查询,数据库也把它变成一个复杂的结合体,需要花费一定的时间。

2. 修改限制。当用户试图修改视图的某些行时,数据库必须把它转化为对基本表的某些行的修改。事实上,当从视图中插入或者删除时,情况也是这样。对于简单视图来说,这是很方便的,但是,对于比较复杂的视图,可能是不可修改的

3、什么是存储过程?有哪些优缺点?

存储过程是一个预编译的SQL语句,优点是允许模块化的设计,就是说只需要创建一次,以后在该程序中就可以调用多次。如果某次操作需要执行多次SQL,使用存储过程比单纯SQL语句执行要快。

优点

1)存储过程是预编译过的,执行效率高。

2)存储过程的代码直接存放于数据库中,通过存储过程名直接调用,减少网络通讯。

3)安全性高,执行存储过程需要有一定权限的用户。

4)存储过程可以重复使用,减少数据库开发人员的工作量。

缺点

1)调试麻烦,但是用 PL/SQL Developer 调试很方便!弥补这个缺点。

2)移植问题,数据库端代码当然是与数据库相关的。但是如果是做工程型项目,基本不存在移植问题。

3)重新编译问题,因为后端代码是运行前编译的,如果带有引用关系的对象发生改变时,受影响的存储过程、包将需要重新编译(不过也可以设置成运行时刻自动编译)。

4)如果在一个程序系统中大量的使用存储过程,到程序交付使用的时候随着用户需求的增加会导致数据结构的变化,接着就是系统的相关问题了,最后如果用户想维护该系统可以说是很难很难、而且代价是空前的,维护起来更麻烦。

4、SQL语句主要分为哪几种?

数据定义语言DDL(Data Ddefinition Language)CREATE,DROP,ALTER主要为以上操作 即对逻辑结构等有操作的,其中包括表结构,视图和索引。

数据查询语言DQL(Data Query Language)SELECT这个较为好理解 即查询操作,以select关键字。各种简单查询,连接查询等都属于DQL。

数据操纵语言DML(Data Manipulation Language)INSERT,UPDATE,DELETE主要为以上操作 即对数据进行操作的,对应上面所说的查询操作 DQL与DML共同构建了多数初级程序员常用的增删改查操作。而查询是较为特殊的一种 被划分到DQL中。数据控制功能DCL(Data Control Language)GRANT,REVOKE,COMMIT,ROLLBACK主要为以上操作 即对数据库安全性完整性等有操作的,可以简单的理解为权限控制等。

5、SQL约束有哪几种?  

NOT NULL: 用于控制字段的内容一定不能为空(NULL)。

UNIQUE: 控件字段内容不能重复,一个表允许有多个 Unique 约束。

PRIMARY KEY: 也是用于控件字段内容不能重复,但它在一个表只允许出现一

个。

FOREIGN KEY: 用于预防破坏表之间连接的动作,也能防止非法数据插入外键

列,因为它必须是它指向的那个表中的值之一。

CHECK: 用于控制字段的值范围。

6、drop、delete与truncate的区别? 

三者都表示删除,但是三者有一些差别:

因此,在不再需要一张表的时候,用drop;在想删除部分数据行时候,用delete;在保留表而删除所有数据的时候用truncate。

 

7、SQL的生命周期?

1. 应用服务器与数据库服务器建立一个连接

2. 数据库进程拿到请求sql

3. 解析并生成执行计划,执行

4. 读取数据到内存并进行逻辑处理

5. 通过步骤一的连接,发送结果到客户端

6. 关掉连接,释放资源

 

8、大表数据查询,怎么优化?

1. 优化shema、sql语句+索引;

2. 第二加缓存,memcached, redis;

3. 主从复制,读写分离;

4. 垂直拆分,根据你模块的耦合度,将一个大的系统分为多个小的系统,也就是分布式系统;5. 水平切分,针对数据量大的表,这一步最麻烦,最能考验技术水平,要选择一个合理的sharding key, 为了有好的查询效率,表结构也要改动,做一定的冗余,应用也要改,sql中尽量带sharding key,将数据定位到限定的表上去查,而不是扫描全部的表;

9、超大分页怎么处理?

超大的分页一般从两个方向上来解决.

数据库层面,这也是我们主要集中关注的(虽然收效没那么大),类似于select *

from table where age > 20 limit 1000000,10这种查询其实也是有可以优化的余地的. 这条语句需要load1000000数据然后基本上全部丢弃,只取10条当然比较慢. 当时我们可以修改为select * from table where id in (select id from table where age> 20 limit 1000000,10).这样虽然也load了一百万的数据,但是由于索引覆盖,要查询的所有字段都在索引中,所以速度会很快. 同时如果ID连续的好,我们还可以select * from table where id > 1000000 limit 10,效率也是不错的,优化的可能性有许多种, 但是核心思想都一样,就是减少load的数据.从需求的角度减少这种请求…主要是不做类似的需求(直接跳转到几百万页之后的具体某一页.只允许逐页查看或者按照给定的路线走,这样可预测,可缓存)以及防止ID泄漏且连续被人恶意攻击.

解决超大分页,其实主要是靠缓存,可预测性的提前查到内容,缓存至redis等k-V数据库中,直接返回即可。

10、关心过业务系统里面的sql耗时吗?统计过慢查询吗?对慢查询都怎么优化过?

在业务系统中,除了使用主键进行的查询,其他的我都会在测试库上测试其耗时,慢查询的统计主要由运维在做,会定期将业务中的慢查询反馈给我们。慢查询的优化首先要搞明白慢的原因是什么? 是查询条件没有命中索引?是load了不需要的数据列?还是数据量太大?

所以优化也是针对这三个方向来的,首先分析语句,看看是否load了额外的数据,可能是查询了多余的行并且抛弃掉了,可能是加载了许多结果中并不需要的列,对语句进行分析以及重写。分析语句的执行计划,然后获得其使用索引的情况,之后修改语句或者修改索引,使得语句可以尽可能的命中索引。

如果对语句的优化已经无法进行,可以考虑表中的数据量是否太大,如果是的话

可以进行横向或者纵向的分表。

11、主键使用自增ID还是UUID?

推荐使用自增ID,不要使用UUID。

因为在InnoDB存储引擎中,主键索引是作为聚簇索引存在的,也就是说,主键索引的B+树叶子节点上存储了主键索引以及全部的数据(按照顺序),如果主键索引是自增ID,那么只需要不断向后排列即可,如果是UUID,由于到来的ID与原来的大小不确定,会造成非常多的数据插入,数据移动,然后导致产生很多的内存碎片,进而造成插入性能的下降。

总之,在数据量大一些的情况下,用自增主键性能会好一些。

关于主键是聚簇索引,如果没有主键,InnoDB会选择一个唯一键来作为聚簇索引,如果没有唯一键,会生成一个隐式的主键。

12、查询各种优化?

优化查询过程中的数据访问? 

访问数据太多导致查询性能下降

确定应用程序是否在检索大量超过需要的数据,可能是太多行或列

确认MySQL服务器是否在分析大量不必要的数据行

避免犯如下SQL语句错误

查询不需要的数据。解决办法:使用limit解决

多表关联返回全部列。解决办法:指定列名

总是返回全部列。解决办法:避免使用SELECT *

重复查询相同的数据。解决办法:可以缓存数据,下次直接读取缓存

是否在扫描额外的记录。解决办法:

使用explain进行分析,如果发现查询需要扫描大量的数据,但只返回少数的

行,可以通过如下技巧去优化:

使用索引覆盖扫描,把所有的列都放到索引中,这样存储引擎不需要回表获取对

应行就可以返回结果。

改变数据库和表的结构,修改数据表范式

重写SQL语句,让优化器可以以更优的方式执行查询。

优化长难的查询语句

一个复杂查询还是多个简单查询

MySQL内部每秒能扫描内存中上百万行数据,相比之下,响应数据给客户端就

要慢得多使用尽可能小的查询是好的,但是有时将一个大的查询分解为多个小的查询是很有必要的。

切分查询

将一个大的查询分为多个小的相同的查询

一次性删除1000万的数据要比一次删除1万,暂停一会的方案更加损耗服务器开销。

分解关联查询,让缓存的效率更高。

执行单个查询可以减少锁的竞争。

在应用层做关联更容易对数据库进行拆分。

查询效率会有大幅提升。

较少冗余记录的查询。

优化特定类型的查询语句

count(*)会忽略所有的列,直接统计所有列数,不要使用count(列名)MyISAM中,没有任何where条件的count(*)非常快。当有where条件时,MyISAM的count统计不一定比其它引擎快。可以使用explain查询近似值,用近似值替代count(*),增加汇总表,使用缓存。

优化关联查询

确定ON或者USING子句中是否有索引。

确保GROUP BY和ORDER BY只有一个表中的列,这样MySQL才有可能使用索引。

优化子查询

用关联查询替代

优化GROUP BY和DISTINCT

这两种查询据可以使用索引来优化,是最有效的优化方法

关联查询中,使用标识列分组的效率更高

如果不需要ORDER BY,进行GROUP BY时加ORDER BY NULL,MySQL不会再进行文件排序。

WITH ROLLUP超级聚合,可以挪到应用程序处理

优化LIMIT分页

LIMIT偏移量大的时候,查询效率较低

可以记录上次查询的最大ID,下次查询时直接根据该ID来查询

优化UNION查询

UNION ALL的效率高于UNION

13、数据库优化?

数据库优化为什么要优化

系统的吞吐量瓶颈往往出现在数据库的访问速度上

随着应用程序的运行,数据库的中的数据会越来越多,处理时间会相应变慢

数据是存放在磁盘上的,读写速度无法和内存相比

优化原则:减少系统瓶颈,减少资源占用,增加系统的反应速度。

数据库结构优化

一个好的数据库设计方案对于数据库的性能往往会起到事半功倍的效果。

需要考虑数据冗余、查询和更新的速度、字段的数据类型是否合理等多方面的内容。

将字段很多的表分解成多个表

对于字段较多的表,如果有些字段的使用频率很低,可以将这些字段分离出来形成新表。

因为当一个表的数据量很大时,会由于使用频率低的字段的存在而变慢。

增加中间表

对于需要经常联合查询的表,可以建立中间表以提高查询效率。

通过建立中间表,将需要通过联合查询的数据插入到中间表中,然后将原来的联合查询改为对中间表的查询。

增加冗余字段

设计数据表时应尽量遵循范式理论的规约,尽可能的减少冗余字段,让数据库设计看起来精致、优雅。但是,合理的加入冗余字段可以提高查询速度。表的规范化程度越高,表和表之间的关系越多,需要连接查询的情况也就越多,性能也就越差。

注意:

冗余字段的值在一个表中修改了,就要想办法在其他表中更新,否则就会导致数据不一致的问题。

14、大表怎么优化?某个表有近千万数据,CRUD比较慢,如何优化?分库分表了是怎么做的?分表分库了有什么问题?有用到中间件么?他们的原理知道么?

当MySQL单表记录数过大时,数据库的CRUD性能会明显下降,一些常见的优化措施如下:

1. 限定数据的范围: 务必禁止不带任何限制数据范围条件的查询语句。比如:我们当用户在查询订单历史的时候,我们可以控制在一个月的范围内。;

2. 读/写分离: 经典的数据库拆分方案,主库负责写,从库负责读;

3. 缓存: 使用MySQL的缓存,另外对重量级、更新少的数据可以考虑使用应用级别的缓存;还有就是通过分库分表的方式进行优化,主要有垂直分表和水平分表。

1. 垂直分区:

根据数据库里面数据表的相关性进行拆分。 例如,用户表中既有用户的登录信息又有用户的基本信息,可以将用户表拆分成两个单独的表,甚至放到单独的库做分库。

简单来说垂直拆分是指数据表列的拆分,把一张列比较多的表拆分为多张表。

如下图所示,这样来说大家应该就更容易理解了。

 

垂直拆分的优点: 可以使得行数据变小,在查询时减少读取的Block数,减少I/O次数。此外,垂直分区可以简化表的结构,易于维护。

垂直拆分的缺点: 主键会出现冗余,需要管理冗余列,并会引起Join操作,可以通过在应用层进行Join来解决。此外,垂直分区会让事务变得更加复杂;

垂直分表

把主键和一些列放在一个表,然后把主键和另外的列放在另一个表中

 

适用场景

1、如果一个表中某些列常用,另外一些列不常用

2、可以使数据行变小,一个数据页能存储更多数据,

查询时减少I/O次数

缺点

有些分表的策略基于应用层的逻辑算法,一旦逻辑算

法改变,整个分表逻辑都会改变,扩展性较差

对于应用层来说,逻辑算法增加开发成本管理冗余列,查询所有数据需要join操作

2. 水平分区:

保持数据表结构不变,通过某种策略存储数据分片。这样每一片数据分散到不同

的表或者库中,达到了分布式的目的。 水平拆分可以支撑非常大的数据量。

水平拆分是指数据表行的拆分,表的行数超过200万行时,就会变慢,这时可以把一张的表的数据拆成多张表来存放。举个例子:我们可以将用户信息表拆分成多个用户信息表,这样就可以避免单一表数据量过大对性能造成影响。

 

拆分可以支持非常大的数据量。需要注意的一点是:分表仅仅是解决了单一表数据过大的问题,但由于表的数据还是在同一台机器上,其实对于提升MySQL并发能力没有什么意义,所以 水平拆分最好分库

水平拆分能够 支持非常大的数据量存储,应用端改造也少,但 分片事务难以解决 ,跨界点Join性能较差,逻辑复杂。

尽量不要对数据进行分片,因为拆分会带来逻辑、部署、运维的各种复杂度 ,一般的数据表在优化得当的情况下支撑千万以下的数据量是没有太大问题的。如果实在要分片,尽量选择客户端分片架构,这样可以减少一次和中间件的网络I/O。

水平分表:

表很大,分割后可以降低在查询时需要读的数据和索引的页数,同时也降低了索

引的层数,提高查询次数

 

适用场景

1、表中的数据本身就有独立性,例如表中分表记录各个地区的数据或者不同时期的数据,特别是有些数据常用,有些不常用。

2、需要把数据存放在多个介质上。

水平切分的缺点

1、给应用增加复杂度,通常查询时需要多个表名,查询所有数据都需UNION操作

2、在许多数据库应用中,这种复杂度会超过它带来的优点,查询时会增加读一个索引层的磁盘次数

14、读写分离有哪些解决方案?

读写分离是依赖于主从复制,而主从复制又是为读写分离服务的。因为主从复制要求slave不能写只能读(如果对slave执行写操作,那么show slave status将会呈现Slave_SQL_Running=NO,此时你需要按照前面提到的手动同步一下slave)。

方案一

使用mysql-proxy代理

优点:直接实现读写分离和负载均衡,不用修改代码,master和slave用一样的帐号,mysql官方不建议实际生产中使用

缺点:降低性能, 不支持事务

方案二

使用AbstractRoutingDataSource+aop+annotation在dao层决定数据源。如果采用了mybatis, 可以将读写分离放在ORM层,比如mybatis可以通过mybatis plugin拦截sql语句,所有的insert/update/delete都访问master库,所有的select 都访问salve库,这样对于dao层都是透明。 plugin实现时可以通过注解或者分析语句是读写方法来选定主从库。不过这样依然有一个问题, 也就是不支持事务, 所以我们还需要重写一下 DataSourceTransactionManager, 将read-only的事务扔进读库, 其余的有读有写的扔进写库。

方案三

使用AbstractRoutingDataSource+aop+annotation在service层决定数据源,可以支持事务.缺点:类内部方法通过this.xx()方式相互调用时,aop不会进行拦截,需进行特殊处理。

15、MySQL的复制原理以及流程?

主从复制:将主数据库中的DDL和DML操作通过二进制日志(BINLOG)传输

到从数据库上,然后将这些日志重新执行(重做);从而使得从数据库的数据与

主数据库保持一致。

主从复制的作用

1. 主数据库出现问题,可以切换到从数据库。

2. 可以进行数据库层面的读写分离。

3. 可以在从数据库上进行日常备份。MySQL主从复制解决的问题

数据分布:随意开始或停止复制,并在不同地理位置分布数据备份

负载均衡:降低单个服务器的压力

高可用和故障切换:帮助应用程序避免单点失败

升级测试:可以用更高版本的MySQL作为从库

MySQL主从复制工作原理

在主库上把数据更高记录到二进制日志

从库将主库的日志复制到自己的中继日志

从库读取中继日志的事件,将其重放到从库数据中 

举报

相关推荐

0 条评论