构建高可用web站点(五)

数据库是web站点中重要的应用,放在第四篇是因为之前来不及总结的原因,在之前的文章我看到了无论是Mysql或者是nosql的一些缓存和分布式一些比较扩展性的功能。但是对于单个数据库来说,它的优化也是我们学习的重点。现在我就来简单说说我自己总结的一些东西。

关于Mysql:Mysql是web站点中应用很广泛的关系型数据库。这一块的东西也是有很多值得学习的东西,介绍的书籍也很多,比如《高性能Mysql》《Mysql性能调优和架构设计》《Mysql技术内幕:InnoDB引擎》等,数据库的知识也是一个很大的宝库,然后我说一下我比较想分享的。也是我日常的笔记,可能逻辑关系不太好,请多多见谅。

从Mysql执行一个查询开始说起:

1、客户端发送一条查询给服务器。

2、服务器先检查缓存(这个检查是通过一个对大小写敏感的哈希查找实现的。),如果命中了缓存,则立刻返回存储在缓存中的结果。否则进入下一阶段。

3、服务器端进行SQL解析,预处理,再由优化器生成对应的执行计划。

4、MySQL根据优化器生成的执行计划,调用存储引擎的API来执行查询。

5、将结果返回给客户端。

从中可以看出一些MySQL能够处理的优化类型:

     (1)重新定义关联表的顺序

     (2)将外链接转化成内连接

     (3)使用等价转换规则

     (4)优化COUNT()、MIN()、MAX()   没有任何WHERE的COUNT(*)例如MyISAM维护一个变量来存放数据表的行数。

     (5)预估并转化为常数表达式

     (6)覆盖索引扫描

     (7)子查询优化

     (8)提前终止查询

     (9)列表IN()比较  MySQL将IN()列表中的数据先进行排序,然后通过二分查找的方式来确定列表的值是否满足条件

Mysql这里其实是有一个语法树,对于如何书写SQL能让解析更快,我也是半知半解,就不详细说明,等大家和我继续一起学习

当然,很多人都知道添加索引可以提高数据查询的速度。

根据InnoDB引擎。索引主要有B-Tree索引,HASH索引等。

这里主要讲一下B-Tree索引

主要的特征:就是不论表中的行存储在什么位置,都能够以相同的方法和速度进行查询。

1.索引的创建:

     读取表的数据并对其进行排序,如果排序的内存需要超过设定,则排序将使用临时表空间

     把排序结果存储在索引段的叶块中,在存储空间到达索引块的PCTFREE之前,该叶块同时也担负着分支块的重任。

     当达到PCTFREE时,需要获得新的块用来存储索引行,同时生成一个分支块,在该分支块的头部存储着现有叶块的DBA,新的叶块中开始键值和它的DBA一起构成了分支块的一行数据

 

     能够提高叶块中数据存储密度的方法:

      在允许的情况下,尽量减少索引列的数量

      尽量使用较大的数据块大小

      灵活运用压缩键值的方法。在索引为非唯一索引的情况下,大部分键值都被重复存储,尤其是组合索引中

2.索引块的分割

     由于所有的索引行都是按照特定顺序进行存储的,当我们向其中插入新的索引行时,就需要“掰开”两个相互连续的索引行并将新行插入到该位置上。

     当中间值被插入时,由于所对应的索引块已经没有空余空间,所以需要分配一个新的索引块并将原来索引块中的行分开存储在两个索引块中。目的是为了放置索引块的连续分割。

 不论插入、删除、还是修改,都需要消耗存储空间。所以,需要定期对经常使用的表上的索引执行重构操作。

事务和锁:

锁机制用于管理对共享资源的并发访问。InnoDB存储引擎也会在数据库内部其他多个地方使用锁,从而允许对多种不同资源提供并发访问。例如,操作缓冲池中的LRU列表,删除、添加、移动LRU列表中的元素,为了保证一致性,必须有锁的介入。

latch 轻量级的锁,因为其要求锁定的时间必须非常短。若持续的时间长,则应用的性能会非常差。在InnoDB存储引擎中,latch又可以分为mutex(互斥量)和rwlock(读写锁)。其目的是用来保证并发线程操作临界资源的正确性,并且通常没有死锁检测的机制。

lock的对象是事务,用来锁定的是数据库中的对象(不同事务隔离级别释放的时间可能不同)

事务隔离级别:

·未提交读(Read Uncommitted):允许脏读,也就是可能读取到其他会话中未提交事务修改的数据

·提交读(Read Committed):只能读取到已经提交的数据。Oracle等多数数据库默认都是该级别 (不重复读)

·可重复读(Repeated Read):可重复读。在同一个事务内的查询都是事务开始时刻一致的,InnoDB默认级别。在SQL标准中,该隔离级别消除了不可重复读,但是还存在幻象读

·串行读(Serializable):完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞

 

脏读: 脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。(区分):脏页:指的是缓冲池中已经被修改的页。

不可重复读:是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。

幻读:第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。

InnoDB实现了两种标准的行级锁:

共享锁(S Lock) 允许事务读一行数据

排他锁(X Lock) 允许事务删除或更新一行数据

 

为了多粒度锁定。InnoDB支持意向锁(Intention Lock)

意向共享锁(IS Lock)一张表中某几行的共享锁

意向排他锁(IX Lock)

最后,讲一下我们平时怎么分析一条sql语句。除了打开例如慢查询日志等方式,还可以通过EXPLAIN来分析你的sql语句:

     EXPLAIN中的列

     id列  标识SELECT 所属的行

     select_type列 Simple:意味查询不包括子查询和UNION。如果有复杂的部分,最外层标记为Primary。其他部分标记如下:

      SUBQUERY:包含在SELECT列表中的子查询中的SELECT

      DERIVED: MySQL会递归执行并将结果放到一个临时表中。

      UNION:在UNION中的第二个和随后的SELECT被标记为UNION

     table列:可以从这一列中从上往下观察MySQL的关联优化器为查询选择的关联顺序。

     type列:依次从最差到最优:

      ALL:全表扫描

      index:只是MySQL扫描表时按索引次序进行。主要有点是避免了排序,如果在Extra列中看到Using index,说明MySQL正在使用覆盖索引,只扫描索引数据

      range:范围扫描就是一个有限制的索引扫描,它开始于索引里的某一个点,返回匹配这个值域的行。带有Between或在WHERE子句带有>的查询,例如IN()和OR

      ref:索引访问,返回所有匹配某个单个值的行。因此它是查找和扫描的混合体

      eq_ref:使用这种索引查找,MySQL知道最多返回一条符合条件的记录。这种访问方法可以在MySQL中使用主键或者唯一性索引查找时看到

      const,system:当MySQL能对查询的某部分进行优化并将其转换成一个常量时。举例:你通过将某一行的主键放入WHERE子句里的方式来选取此行的主键。

     possible_keys列:显示查询可以使用哪些索引

     key列:决定使用哪个索引来优化对该表的访问

     key_len列:显示MySQL在索引里使用的字节数

     ref列:显示了之前的表在key列记录的索引中查找值所用的列或常量。

     rows列:读取的行数

     Extra列:Using index:将使用覆盖索引

                   Using where: 将在存储引擎检索行后再进行过滤

                   Using temporary:使用临时表

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。