为了提高PHP的运行效率,程序员不光须要写出逻辑清晰,效率很高的代码,还要能对query语句进行优化。虽然咱们对数据库的读取写入速度上倒是无能为力,但在一些数据库类扩展像memcache、mongodb、redis这样的数据存储服务器的帮助下,PHP也能达到更快的存取速度,因此了解学习这些扩展也是很是必要。php
大型存储方面优化mysql
数据库主从复制和读写分离laravel
一、master将改变记录到二进制日志中,slave将master的二进制拷贝到它的中继日志中,从新将数据返回到它本身的数据中,达到复制主服务器数据的目的。 主从复制能够用做:数据库负载均衡、数据库备份、读写分离等功能。 二、配置主服务器master 修改my.ini/my.conf [mysqld] log-bin=mysql-bin //启用二进制日志 server-id=102 //服务器惟一ID 三、配置从服务器slave log-bin=mysql-bin //启用二进制日志 server-id=226 //服务器惟一ID 四、在主服务器上受权从服务器 GRANT REPLICATION SLAVE ON *.* to 'slavename'@'IP' identified by 'root' 五、在从服务器上使用 change master to master_host="masterip", master_user="masteruser", master_password="masterpasswd"; 六、而后使用start slave命令开始进行主从复制。 不要忘记在每次修改配置后重启服务器,而后能够在主从服务器上用show master/slave status查看主/从状态。 实现数据库的读写分离要依赖MySQL的中间件,如mysql_proxy,atlas等。经过配置这些中间件来对主从服务器进行读写分离,使从服务器承担被读取的责任,从而减轻主服务器的负担。
数据库的sharding
在数据库中数据表中的数据量很是庞大的时候,不管是索引仍是缓存等压力都很大,对数据库进行sharding,使之分别以多个数据库服务器或多个表存储,以减轻查询压力。方式有垂直切分、水平切分和联合切分。程序员
垂直切分:在数据表很是多的时候,把数据库中关系紧密(如同一模块,常常链接查询)的表切分出来分别放到不一样的主从server上。面试
水平切分:在表很少,而表里的数据量很是大的时候,为了加快查询,能够用哈希等算法,将一个数据表分为几个,分别放到不一样的服务器上,加快查询。水平切分和数据表分区的区别在于其存储介质上的不一样。redis
联合切分:更多的状况是数据表和表中的数据量都很是大,则要进行联合切分,即同时进行垂直和水平分表,将数据库切分为一个分布式的矩阵来存储。
这些数据库的优化方式,每一种拿出来均可以写做一篇文章,可谓是博大精深,了解并记忆了这些方式,能够在有须要的时候进行有目的的选择优化,达到数据库效率的高效。算法
索引方面优化sql
在MySQL中,索引属于存储引擎级别的概念,不一样存储引擎对索引的实现方式是不一样的,下面主要讨论MyISAM和InnoDB两个存储引擎的索引实现方式。mongodb
MyISAM索引实现
MyISAM引擎使用B+Tree做为索引结构,叶节点的data域存放的是数据记录的地址。下图是MyISAM索引的原理图:shell
这里设表一共有三列,假设咱们以Col1为主键,则图1是一个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表数据文件自己就是主索引。
图3
图3是InnoDB主索引(同时也是数据文件)的示意图,能够看到叶节点包含了完整的数据记录。这种索引叫作汇集索引。由于InnoDB的数据文件自己要按主键汇集,因此InnoDB要求表必须有主键(MyISAM能够没有),若是没有显式指定,则MySQL系统会自动选择一个能够惟一标识数据记录的列做为主键,若是不存在这种列,则MySQL自动为InnoDB表生成一个隐含字段做为主键,这个字段长度为6个字节,类型为长整形。
第二个与MyISAM索引的不一样是InnoDB的辅助索引data域存储相应记录主键的值而不是地址。换句话说,InnoDB的全部辅助索引都引用主键做为data域。例如,图4为定义在Col3上的一个辅助索引:
图4
这里以英文字符的ASCII码做为比较准则。汇集索引这种实现方式使得按主键的搜索十分高效,可是辅助索引搜索须要检索两遍索引:首先检索辅助索引得到主键,而后用主键到主索引中检索得到记录。
了解不一样存储引擎的索引实现方式对于正确使用和优化索引都很是有帮助,例如知道了InnoDB的索引实现后,就很容易明白为何不建议使用过长的字段做为主键,由于全部辅助索引都引用主索引,过长的主索引会令辅助索引变得过大。
再例如,用非单调的字段做为主键在InnoDB中不是个好主意,由于InnoDB数据文件自己是一颗B+Tree,非单调的主键会形成在插入新记录时数据文件为了维持B+Tree的特性而频繁的分裂调整,十分低效,而使用自增字段做为主键则是一个很好的选择。
数据查询方面优化
在每个消耗大量时间的查询案例中,都能看到一些没必要要的额外操做、某些操做被额外地重复了不少次、某些操做执行得太慢等。优化查询的目的就是减小和消除这些操做所花费的时间。
1、首选要优化数据访问
查询性能底下最基本的缘由是访问的数据太多。因此,对于低效的查询,通常经过两个步骤来分析:
确认应用程序是否在检索大量超过须要的数据。这一般意味着访问了太多的行,但有时候也多是访问了太多的列。确认MySQL服务器层是否在分析大量超过须要的数据行。
1.一、是否向数据库请求了不须要的数据
在访问数据库时,应该只请求须要的行和列,请求多余的行和列会消耗MySQL服务器的CPU和内存资源,并增长网络开销。
一、在处理分页时,应该使用LIMIT限制MySQL只返回须要的数据,而不是向应用程序返回所有数据后,再由应用程序过滤不须要的行。
二、多表关联时,或获取单表数据时,尽可能避免不加思考地使用SELECT *
三、当一些数据被屡次使用时能够考虑将数据缓存起来,避免每次使用都要到MySQL查询。
1.二、MySQL是否在扫描额外的记录,应该让MySQL使用最合适的方式查询数据
对于MySQL,最简单的衡量查询开销有三个指标:响应时间、扫描的行数和返回的行数。这里主要考虑提升扫描的方式,即查询数据的方式。
查询数据的方式有全表扫描、索引扫描、范围扫描、惟一索引查询、常数引用等。这些查询方式,速度从慢到快,扫描的行数也是从多到少。能够经过EXPLAIN语句中的type列反应查询采用的是哪一种方式。
一般能够经过添加合适的索引改善查询数据的方式,使其尽量减小扫描的数据行,加快查询速度。
例如,当发现查询须要扫描大量的数据行但只返回少数的行,那么能够考虑使用覆盖索引,即把全部须要用到的列都放到索引中。这样存储引擎无须回表获取对应行就能够返回结果了。
2、重构查询的方法
设计查询的时候须要考虑是否须要把一个复杂的查询分红多个简单的查询。在个人印象中,曾经无数次听到一个经验法则:能够在数据库中作的事不要放在应用程序中,数据库比咱们想象的要厉害的多。这个经验法则是在华夏基金使用Oracle编写SQL时一位Oracle牛人告诉个人,后来我把它使用到MySQL上,真是吃尽苦头。
固然这其中的缘由有Oracle和MySQL本来就不是同样的处理逻辑,而且如今的网络通讯、查询解析和优化的代价并无之前那么高啦。再次说明,经验法则有在某种特定笼子里才有效。
分解复杂的查询:
能够将一个大查询切分红多个小查询执行,每一个小查询只完成整个查询任务的一小部分,每次只返回一小部分结果。
删除旧的数据是一个很好的例子。
若是只用一条语句一次性执行一个大的删除操做,则可能须要一次锁住不少数据,占满整个事务日志,耗尽系统资源、阻塞不少小的但重要的查询。将一个大的删除操做分解成多个较小的删除操做能够将服务器上本来一次性的压力分散到屡次操做上,尽量小地影响MySQL性能,减小删除时锁的等待时间,同时也减小了MySQL主从复制的延迟。这个方法我一直在用。
另外一个例子是分解关联查询,即对每一个要关联的表进行单表查询,而后将结果在应用程序中进行关联。我在以前一家公司和一位在阿里待过不少年的同事一块儿编码时,他就是这么干的。后来我在心中默默地鄙视着他,由于我内心有这么一个经验法则(能够在数据库中作的事不要放在应用程序中,数据库比咱们想象的要厉害的多),而且我在行动上也是保持能用一个SQL解决的事绝对不会用两个SQL。
这么作固然处理经验法则的缘由以外还有一个缘由是:获取数据的逻辑尽可能与业务代码分离,这样之后在切换数据库时也很方便。其实是这样吗?未必啊。那次的无知让我吃尽苦头啊,后来由于SQL的性能问题再把我写的大部分SQL进行分解。
用分解关联查询的方式重构查询有以下的优点:
让缓存的效率更高。许多应用程序能够方便地缓存单表查询对应的结果对象。将查询分解后,执行单个查询能够减小锁的竞争。在应用层作关联,能够更容易对数据库进行拆分,更容易作到高性能和可扩展。查询自己效率也可能会有所提高。能够减小冗余记录的查询。在应用层作关联查询,
意味着对于某条记录应用只须要查询一次,而在数据库中作关联查询,则可能须要重复地访问一部分数据。从这点看,这样的重构还可能会减小网络和内存的消耗。更进一步,这样作至关于在应用中实现了哈希关联,而不是使用MySQL的嵌套循环关联。某些场景哈希关联的效率要高不少。
数据库设计方面优化
一、数据库设计符合第三范式,为了查询方即可以有必定的数据冗余。 二、选择数据类型优先级 int > date,time > enum,char>varchar > blob,选择数据类型时,能够考虑替换,如ip地址能够用ip2long()函数转换为unsign int型来进行存储。 三、对于char(n)类型,在数据完整的状况下尽可能较小的的n值。 四、在建表时用partition命令对单个表分区能够大大提高查询效率,MySQL支持RANGE,LIST,HASH,KEY分区类型,其中以RANGE最为经常使用,分区方式为: CREATE TABLE tablename{ }ENGINE innodb/myisam CHARSET utf8 //选择数据库引擎和编码 PARTITION BY RANGE/LIST(column),//按范围和预约义列表进行分区 PARTITION partname VALUES LESS THAN /IN(n),//命名分区并详细限定分区的范围 五、选择数据库引擎时要注意innodb 和 myisam的区别。 存储结构:MyISAM在磁盘上存储成三个文件。而InnoDB全部的表都保存在同一个数据文件中,通常为2GB 事务支持:MyISAM不提供事务支持。InnoDB提供事务支持事务。 表锁差别:MyISAM只支持表级锁。InnoDB支持事务和行级锁。 全文索引:MyISAM支持 FULLTEXT类型的全文索引(不适用中文,因此要用sphinx全文索引引擎)。InnoDB不支持。 表的具体行数:MyISAM保存有表的总行数,查询count(*)很快。InnoDB没有保存表的总行数,须要从新计算。 外键:MyISAM不支持。InnoDB支持
几条MySQL小技巧
一、SQL语句中的关键词最好用大写来书写,第一易于区分关键词和操做对象,第二,SQL语句在执行时,MySQL会将其转换为大写,手动写大写能增长查询效率(虽然很小)。
二、若是咱们们经对数据库中的数据行进行增删,那么会出现数据ID过大的状况,用ALTER TABLE tablename AUTO_INCREMENT=N,使自增ID从N开始计数。
三、对int类型添加 ZEROFILL 属性能够对数据进行自动补0
四、导入大量数据时最好先删除索引再插入数据,再加入索引,否则,mysql会花费大量时间在更新索引上。
五、建立数据库书写sql语句时 ,咱们能够在IDE里建立一个后缀为.sql的文件,IDE会识别sql语法,更易于书写。更重要的是,若是你的数据库丢失了,你还能够找到这个文件,在当前目录下使用/path/mysql -uusername -ppassword databasename < filename.sql来执行整个文件的sql语句(注意-u和-p后紧跟用户名密码,无空格)。
以上内容但愿帮助到你们, 不少PHPer在进阶的时候总会遇到一些问题和瓶颈,业务代码写多了没有方向感,不知道该从那里入手去提高,对此我整理了一些资料,包括但不限于:分布式架构、高可扩展、高性能、高并发、服务器性能调优、TP6,laravel,Redis,Swoole、Swoft、Kafka、Mysql优化、shell脚本、Docker、微服务、Nginx等多个知识点高级进阶干货须要的能够免费分享给你们 ,须要戳这里 PHP进阶架构师>>>实战视频、大厂面试文档免费获取