内容索引
mysql的体系结构
mysql的部件组成(mysql官网示例):
注:与php进行交互的是mysql下客户端mysql.dll;查询优化器,在数据量不一样时,给出的优化结果有可是不一样的,例如,数据量小时用索引1,大时用索引2,它会跟据自己的判断结果来优化,但我们也可以指定不管数据量的大小,统一使用索引1;
mysql表存储引擎
MyISAM存储引擎
注:TIMESTAMP时间戳不能用来存储生日之类的,范围有可能超出1970-2037这个范围的数据;
注:存储原则上应该选char的字段,实际使用中也可以用varchar代替,现在的存储空间相对来说都比较大,不用在乎varchar浪费掉的磁盘空间,而且varchar管理上比char方便;
MyISAM的锁机制
注:Table_locks_immediate / Table_locks_waited的值如果小于5000,说明有比较严重的争用情况,需要处理;
注:MyISAM比较适合读操作比较多,写操作比较少的情况;
注:MySQL中写操作的优先级比读操作要高;
MyISAM的索引和事务
InnoDB存储引擎
注:InnoDB的字段类型和MyISAM差不多;InnoDB除了行锁,也有表锁;
InnoDB存储引擎的锁
-------------------------------------------------------------------------------
注:InnoDB中,update时,如果没有使用索引,mysql的优化器确定不了update涉及到数据集时,整个表都会被加上排它锁;而select操作在InnoDB中是不加锁的,MyISAM中,会锁表(锁表可以防止在SELECT的时候,有INSERT或UPDATE的操作更改数据);
注:上图中,A_I是指Auto Increment,即自增;
总结:
注:当有写锁存在的时候,SELECT操作可以正常进行,但读取的数据是commit操作(如update、insert)之前的数据;
InnoDB事务
注:事务是为了保证数据库的一系列操作的一致性,即这一系列操作的状态如一种状态切换到另一种状态;
注:以上为扁平的事务,以下为带保存点(类似于游戏中存档点)的扁平化事务;
注:以下为分布式事务
事务的隔离级别
注: 1)非提交读是隔离级别最低的一种,会导致脏读,脏读是指在事务中update了一条数据,此时,有请求来查询这条数据,查询的就是update后的值,但如果该事务回滚了,又有请求来查询这条数据时,查询的结果就是update之前的值;也就是事务还未提交前,查询就能拿到事务中最新变更的值;
2)提交读解决了脏读的问题,提交读在两个事务同时进行,且事务涉及的数据有交集时,会产生问题,即同时进行的某一个事务提交后,改变了一些数据集,导致另一个同时进行的事务会读到同一条数据的两个不同的值;
3)可重复读解决了提交读的问题,即同时进行的事务互不影响;但可重复读以及前面的两种,均会产生幻读,即同时进行的两个事务,操作的数据集有6条数据,其中一个执行了insert操作,此时数据集变成了7条,另一个事务执行select操作时,得到的结果是6条,但如果执行update操作时,update会返回受到影响的数据有7条,而不是select查询出来的6条;
4)序列化的隔离级别可以解决幻读的问题, 但序列化的隔离级别下,无论是增删改查的那个操作,数据都会被锁住,导致并发性能不好;
总结:
php的mysql驱动和API
注:左边为老版本里php与mysql的驱动,右边为新版本的驱动,新版本里不是使用的客户端,而是集成在php的mysqlnd里面;
注:php里操作数据库的API驱动,在编译好了后,不能通过设置配置文件来改变;
示例代码:
注:mysql_real_escape_string是在mysql的扩展里;
注:prepare是mysqli扩展里的特性,类似于c语言里面的格式输出,是一种比较安全的使用方式,例如里,如sql注入的方式传进来的数据,会被过滤,强制转换成字符串;prepare是由
完成的,不是由Php完成的;
注:通过程序的方式执行该语句时,会报错,执行不了,此时需要用到mysqli_multi_query,这个多语句查询是msqyli中的,PDO不支持;
注:autocommit也是mysqli中的;在InnoDB存储引擎下,作何一个sql语句,数据库都默认加一个begin和commit;
mysql索引和全文检索
注:索引不能过度使用,在insert操作时,索引也会跟着变更;组合索引的左原则为,例如有三个字段A、B、C建立的组合索引,实际上是相当于建立了A索引,A+B索引,A+B+C索引,所以查询条件为A+C时,只会用到A的索引,而查询B+C时,不会用到索引;另外,查询条件进来的顺序是没有影响的,如where条件的顺序是C+B+A,也是可以使用索引的;
注:索引是一个已经排好序的数组,索引的方式就是查找索引的算法;
索引在存放的文件系统的数据结构为B+树
注:索引是以文件的形式存放在磁盘上的,磁盘的读写IO相比内存,是比较慢的,因此需要用B+树的方式来减少查找时,读取磁盘上文件的次数;
全文索引
注:一般实际使用时不会使用mysql的全文索引,而是使用像Lucene、sphinx等技术来解决全文检索的问题;
SQL语句优化和性能调优
注:数据库的瓶颈主要集中在IO层面,即存储在磁盘上的数据文件的读取速度;
sql语句执行逻辑示例:
注:1)sql执行逻辑中的第1步,连表查询时产生的笛卡尔积在数据量大时,会产生严重性能问题,如两张表各有1万数据量,笛卡尔积后会产生1亿的数据; 另外,select查询时,select某几个字段(SELECT A,B,C)和select全部字段(SELECT *)相比,性能差不多,SELECT前面的数据筛选才是影响查询速度的瓶颈,SELECT只是负责对已经筛选完的数据的显示,所以只影响查询结果的存储和传输过程中的速度;
2)sql实际执行连表的时候,会先通过筛选条件和索引将各个表,先单数据筛选出数据,再用筛选出的数据做笛卡尔积,该操作理论是上面第1步的操作是一样,但速度上会快非常多;
判断sql语句好不好不方式:
注:如果explain某语句后,type的值是const,说明该sql语句是可以的;
知道sql写得不好时,调整的原则:
注: 让查询的数据更少的方式,如让explpain中rows的值更小;
注:重构查询方式的标准是查询效率,跟据业务需求,可以将一个复杂的查询拆分成多个简单查询;
优化特定类型查询
注: b方法里,是将一条sql拆分成两条取差集,count(*)不带where条件时,可能类似于php数组里的count,可以直接返回记录的总数;c方法里得到的是按似值;
注:关联查询时,on或者using子句最好能用相同的索引; 子查询优化器会将其优化成关联查询,且子查询会用到临时表,但临时表里不一定有索引,所以有可以会很慢;
注:limit 10000,10时,会遍历9990条数据后,再从9991开始取10条数据,所以会很慢,因此分页数很多时,分页的查询结果可以用where id>9900代替;
mysql数据表的水平拆分和垂直拆分
注:1)垂直拆分是按数据表的字段拆分,即将A,B,C拆分成A和B和C,水平拆分是保持表结构不变,将数据分到多张表里;
2)保证重点业务和重点用户是指将用户使用频繁或业务使用频繁的拆分成一张表, 不频繁的拆分成一张表,如订单表里,将用户经常会用得的一个月或几个月内的订单记录存放在一张表,而基本不会用的几个月或一两年之前的数据存放在一张表里;
mysql数据库读写分离
注:读与分离后,读和写之间不相互影响,如果读的服务器全宕机了,写也是能正常运行的;
注:根据业务需求,解决数据同步的问题的方法:1)在同步的时间里,在程序页面上显示处理中,同步完成后,再显示处理成功;2)尽可能的缩短同步的时间;3)如果重要的业务,可以考虑直接从主库读数据,而不是去读从库的数据;
mysql数据库高可用方案
注:一主多从时,需要在从服务器上面加一层负载均衡,将请求发送到负载相对较小的服务器上去;
注:多主多从里,对于多个主服务器,可以采用心跳检测来检测主服务器是否宕机,如果宕机就立即切换到主服务器的备份机上;