Bootstrap

数据库面试基础

数据库面试基础:

关于优化查询

一、优化查询的方法:

1、 使用索引

应尽量避免全表扫描,首先考虑where及order by,group by涉及的列上建立索引

2、 优化SQL语句

  • 通过exlain用来查看SQL语句的执行效果,可以选择更好的索引和优化查询语句,写出更好的优化语句。

  • 任何地方都不用使用select * from t,用具体的字段列表代替“*”,不要返回用不到的任何字段。

  • 不在索引列做运算或者使用函数。

  • 查询尽可能使用limit减少返回的行数,较少数据传输时间和带宽浪费。

3、 优化数据库对象

  • 优化数据类型:使用procedure analyse()函数对表进行分析,该函数可以对表中列的数据类型提出优化建议。能小就用小的,减小内存占用。
  • 对表进行拆分
  • 使用中间表来提高查询速度

4、 应用优化

  • 使用查询缓存

二、如果有一个特别大的访问量到数据库上,怎么做优化?

  • 使用查询优化
  • 主从复制、读写分离、负载均衡

目前,大部分的主流关系型数据库都提供了主从复制的功能,通过配置两台(或多台)数据库的主从关系,可以将一台数据库服务器的数据更新同步到另一台服务器上。网站可以利用数据库的这一功能,实现数据库的读写分离,从而改善数据库的负载压力。一个系统的读操作远远多于写操作,因此写操作发向master,读操作发向slaves进行操作(简单的轮循算法来决定使用哪个slave)。

MySql注入的问题

一、 sql语句应该考虑哪些安全性?

  • 防止sql注入,对特殊字符进行过滤、转义或者使用预编译的sql语句绑定变量
  • 当sql语句运行出错时,不要把数据库返回的错信息全部显示给用户,防止信息泄露

二、 什么叫Sql注入,如何防止?请举例说明:

1、例子:

职员姓名:__________ 该文本域对应上面方法的ename 参数。 如果用户在查询时向职员姓名文本域中输入的是如下信息:
’ or ‘1’='1

上面的字符串传到后台后,与其它select 等字符串拼成了如下的语句:
select empno,ename,deptno from emp where ename = ‘’ or ‘1’='1’
该条件恒成立。

2、解决办法

  • 参数绑定。为了防范这样”SQL 注入安全“可以用预编译解决(不要用拼接SQL 字符串,可以用prepareStatement,参数用set
    方法进行填装)。
  • 检查变量的数据类型和格式(可以使用正则表达式进行格式验证!)

设计存储过程的问题:

一、 存储过程的优缺点:

存储过程:就是一些编译好了的sql 语句,这些SQL语句代码像一个方法一样实现一些功能(对单表或多表的增删改查),然后再给这个代码块取一个名字,在用到这个功能的时候调用他就行了。

优点:

  • 存储过程因为SQL语句已经预编译过了,因此运行的速度比较快。
  • 存储过程在服务器端运行,减少客户端压力。
  • 允许模块化程序设计,只需要创建一次过程,以后程序中就可以调用该过程任意次,类似方法的复用。
  • 减少网络流量,客户端调用存储过程只需要传存储过程名和相关参数即可,与传输SQL语句相比自然数据量少了很多。
  • 增强了使用的安全性,充分利用系统管理员可以对执行的某一个存储过程进行权限限制,从而能够实现对某些数据访问的限制,避免非授权用户对数据的访问,保证数据的安全。程序员直接调用存储过程,根本不知道表结构是什么,有什么字段,没有直接暴露表明以及字段名给程序员。

缺点:

  • 调试麻烦,可移植性不灵活

二、 存储过程的例子

涉及范式的问题:

一、 数据库的三级范式:

  • 第一范式:字段不可分,原子性;
  • 第二范式:消除部分依赖,非主属性必须完全依赖于主属性;
  • 第三范式:在第二范式的基础上,消除传递依赖。

第二范式:

第三范式:

涉及事务的问题:

1、 数据库事务正确执行的四个基本要素:

  • 原子性:一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
  • 一致性:在事务开始和完成时,数据库中的数据都保持一致的状态,数据的完整性约束没有被破坏。(事务的执行使得数据库从一种正确状态转换成另一种正确状态)。具体来说就是,比如表与表之间存在外键约束关系,那么你对数据库进行的修改操作就必需要满足约束条件,即如果你修改了一张表中的数据,那你还需要修改与之存在外键约束关系的其他表中对应的数据,以达到一致性。
  • 隔离性:一个事务的执行不能被其他事务干扰。为了防止事务操作间的混淆,必须串行化或序列化请求,使得在同一时间仅有一个请求用于同一数据。(在事务正确提交之前,不允许把该事务对数据的任何改变提供给任何其他事务)。(事务处理过程中的中间状态对外部是不可见的)。隔离性通过锁就可以实现。
  • 持久性:一个事务一旦提交,它对数据库中数据的改变就应该是永久性的,并不会被回滚。

2、 并发事务带来的问题。

  • 更新丢失、脏读、不可重复读、幻读。

3、 并发控制的方式:

  • 加锁,如乐观锁和悲观锁。

涉及锁的问题:

1、乐观锁和悲观锁的概念,实现方式和适用场景。

  • 锁有两种机制:悲观锁和乐观锁。

悲观锁,锁如其名,他对世界是悲观的,他认为别人访问正在改变的数据的概率是很高的,所以从数据开始更改时就将数据锁住,直到更改完成才释放。

select * from account where name=”Erica” for update
这条sql 语句锁定了account 表中所有符合检索条件( name=”Erica” )的记录。本次事务提交之前(事务提交时会释放事务过程中的锁),外界无法修改这些记录。该语句用来锁定特定的行(如果有where 子句,就是满足where条件的那些行)。当这些行被锁定后,其他会话可以选择这些行,但不能更改或删除这些行,直到该语句的事务被commit 语句或rollback 语句结束为止。需要注意的是,select …for update 要放到mysql 的事务中,即begin 和commit 中,否则不起作用。

乐观锁,他对世界比较乐观,认为别人访问正在改变的数据的概率是很低的,所以直到修改完成准备提交所做的修改到数据库的时候才会将数据锁住,当你读取以及改变该对象时并不加锁,完成更改后释放。乐观锁不能解决脏读的问题。

适用场景:

如果并发量不大,可以使用悲观锁解决并发问题;但如果系统的并发量非常大的话,悲观锁定会带来非常大的性能问题,所以我们就要选择乐观锁定的方法.现在大部分应用都应该是乐观锁的。

涉及索引的问题:

一、 索引的优缺点

建立索引的优点:

  • 大大加快数据的检索速度;
  • 创建唯一性索引,保证数据库表中每一行数据的唯一性
  • 加速表和表之间的链接
  • 在使用分组和排序子句进行数据检索时,可以显著减少查询中分组和排序的时间

索引的缺点:

  • 索引需要占物理空间
  • 当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,降低了数据的维护速度

二、索引有哪些?

SQL语言中的索引创建与维护:

创建索引:

  • 在student表中穿件一个基于sname的索引:create index idxSname on student(sname)
  • 在student表中创建一个基于Sname和Sclass的索引:create index idxSnamcl on student(sname,sclass)

索引撤销 : DROP INDEX indexname
索引的分类:唯一索引/非唯一索引、主键索引、聚集索引/非聚集索引、组合索引

三、 数据库索引原理:

目前大部分数据库系统及文件系统都采用B-Tree(B 树)或其变种B+Tree(B+树)作为索引结构。B+Tree 是数据库系统实现索引的首选数据结构。在MySQL 中,索引属于存储引擎级别的概念,不同存储引擎对索引的实现方式是不同的,本文主要讨论MyISAMInnoDB 两个存储引擎的索引实现方式。

MyISAM 索引实现:

MyISAM 索引实现MyISAM 引擎使用B+Tree 作为索引结构,叶节点的data 域存放的是数据记录的地址。下图是MyISAM 索引的原理图:

这里设表一共有三列,假设我们以Col1 为主键,则上图是一个MyISAM 表的主索引(Primary key)示意。可以看出MyISAM 的索引文件仅仅保存数据记录的地址。

在MyISAM 中,主索引和辅助索引(Secondary key)在结构上没有任何区别只是主索引要求key 是唯一的,而辅助索引的key 可以重复。如果我们在Col2 上建立一个辅助索引,则此索引的结构如下图所示:

同样也是一颗B+Tree,data 域保存数据记录的地址。因此,MyISAM 中索引检索的算法为首先按照B+Tree 搜索算法搜索索引,如果指定的Key 存在,则取出其data 域的值,然后以data 域的值为地址,读取相应数据记录。
MyISAM 的索引方式也叫做**“非聚集索引”,之所以这么称呼是为了与InnoDB的聚集索引**区分。

InnoDB 索引实现

虽然InnoDB 也使用B+Tree 作为索引结构,但具体实现方式却与MyISAM 截然不同。

  • 第一个重大区别是InnoDB 的数据文件本身就是索引文件。从上文知道,MyISAM 索引文件和数据文件是分离的,索引文件仅保存数据记录的地址。而在InnoDB 中,表数据文件本身就是按B+Tree组织的一个索引结构,这棵树的叶节点data 域保存了完整的数据记录。这个索引的key 是数据表的主键,因此InnoDB表数据文件本身就是主索引。

上图是InnoDB 主索引(同时也是数据文件)的示意图,可以看到叶节点包含了完整的数据记录。这种索引叫做聚集索引。因为InnoDB 的数据文件本身要按主键聚集。

  • InnoDB 上采用自增字段做表的主键。因为InnoDB数据文件本身是一棵B+Tree,非单调的主键会造成在插入新记录时数据文件为了维持B+Tree的特性而频繁的分裂调整,十分低效,而使用自增字段作为主键则是一个很好的选择。如果表使用自增主键,那么每次插入新的记录,记录就会顺序添加到当前索引节点的后续位置,当一页写满,就会自动开辟一个新的页。这样就会形成一个紧凑的索引结构,近似顺序填满。由于每次插入时也不需要移动已有数据,因此效率很高,也不会增加很多开销在维护索引上。
  • 第三个与MyISAM 索引的不同是InnoDB 的辅助索引data 域存储相应记录主键的值而不是地址。换句话说,InnoDB
    的所有辅助索引都引用主键作为data 域。例如,下图为定义在Col3 上的一个辅助索引:

聚集索引这种实现方式使得按主键的搜索十分高效,但是辅助索引搜索需要检索两遍索引:首先检索辅助索引获得主键,然后用主键到主索引中检索获得记录。

总结:

  • InnoDB 使用的是聚簇索引,将主键组织到一棵B+树中,而行数据就储存在叶子节点上,若使用"where id =14"这样的条件查找主键,则按照B+树的检索算法即可查找到对应的叶节点,之后获得行数据。若对Name列进行条件搜索,则需要两个步骤:第一步在辅助索引B+树中检索Name,到达其叶子节点获取对应的主键。第二步使用主键在主索引B+树种再执行一次B+树检索操作,最终到达叶子节点即可获取整行数据。
  • MyISM使用的是非聚簇索引,非聚簇索引的两棵B+树看上去没什么不同,节点的结构完全一致只是存储的内容不同而已,主键索引B+树的节点存储了主键,辅助键索引B+树存储了辅助键。表数据存储在独立的地方,这两颗B+树的叶子节点都使用一个地址指向真正的表数据,对于表数据来说,这两个键没有任何差别。由于索引树是独立的,通过辅助键检索无需访问主键的索引树。

四、 MySQL的B+树索引的优点?为什么不用二叉树?B+树为什么比红黑树更合适?

数据库文件很大,需要存储到磁盘上,索引的结构组织要尽量减少查找过程中磁盘I/O 的存取次数。

1.高度原因

B+树中的每个结点可以包含大量的关键字,这样树的深度降低了,所以任何关键字的查找必须走一条从根结点到叶子结点的路,所有关键字查询的路径长度相同,导致每一个数据的查询效率相当,这就意味着查找一个元素只要很少结点从外存磁盘中读入内存,很快访问到要查找的数据,减少了磁盘I/O 的存取次数。

2.磁盘预读原理和局部性原理

将一个节点的大小设为等于一个页,这样每个节点只需要一次I/O 就可以完全载入。

;