PHP数据库编程之MySQL优化策略概述


Posted in PHP onAugust 16, 2017

本文简单讲述了PHP数据库编程之MySQL优化策略。分享给大家供大家参考,具体如下:

前些天看到一篇文章说到PHP的瓶颈很多情况下不在PHP自身,而在于数据库。我们都知道,PHP开发中,数据的增删改查是核心。为了提升PHP的运行效率,程序员不光需要写出逻辑清晰,效率很高的代码,还要能对query语句进行优化。虽然我们对数据库的读取写入速度上却是无能为力,但在一些数据库类扩展像memcache、mongodb、redis这样的数据存储服务器的帮助下,PHP也能达到更快的存取速度,所以了解学习这些扩展也是非常必要,这一篇先说一下MySQL常见的优化策略。

几条MySQL小技巧

1、SQL语句中的关键词最好用大写来书写,第一易于区分关键词和操作对象,第二,SQL语句在执行时,MySQL会将其转换为大写,手动写大写能增加查询效率(虽然很小)。
2、如果我们们经对数据库中的数据行进行增删,那么会出现数据ID过大的情况,用ALTER TABLE tablename AUTO_INCREMENT=N,使自增ID从N开始计数。
3、对int类型添加 ZEROFILL 属性可以对数据进行自动补0
4、导入大量数据时最好先删除索引再插入数据,再加入索引,不然,mysql会花费大量时间在更新索引上。
5、创建数据库书写sql语句时 ,我们可以在IDE里创建一个后缀为.sql的文件,IDE会识别sql语法,更易于书写。更重要的是,如果你的数据库丢失了,你还可以找到这个文件,在当前目录下使用/path/mysql -uusername -ppassword databasename < filename.sql来执行整个文件的sql语句(注意-u和-p后紧跟用户名密码,无空格)。

数据库设计方面优化

1、数据库设计符合第三范式,为了查询方便可以有一定的数据冗余。

2、选择数据类型优先级 int > date,time > enum,char>varchar > blob,选择数据类型时,可以考虑替换,如ip地址可以用ip2long()函数转换为unsign int型来进行存储。

3、对于char(n)类型,在数据完整的情况下尽量较小的的n值。

4、在建表时用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),//命名分区并详细限定分区的范围

5、选择数据库引擎时要注意innodb 和 myisam的区别

存储结构:MyISAM在磁盘上存储成三个文件。而InnoDB所有的表都保存在同一个数据文件中,一般为2GB
事务支持:MyISAM不提供事务支持。InnoDB提供事务支持事务。
表锁差异:MyISAM只支持表级锁。InnoDB支持事务和行级锁。
全文索引:MyISAM支持 FULLTEXT类型的全文索引(不适用中文,所以要用sphinx全文索引引擎)。InnoDB不支持。
表的具体行数:MyISAM保存有表的总行数,查询count(*)很快。InnoDB没有保存表的总行数,需要重新计算。
外键:MyISAM不支持。InnoDB支持

索引方面优化

1、innodb是聚簇索引,存储索引时必须有主键,如果没有指定,引擎会自动生成一个隐藏的主键,生成一个主索引,索引内存放的是主键的物理地址,数据靠主键存放,每次使用索引时要先找到主索引,然后找到主索引下的数据。

优点通过主键查找特别快,缺点是次级索引会变慢,因为需要先通过次级索引(次级索引里是主索引的位置。)找到主索引,然后通过主索引找数据。并且如果主键无规律,插入新值时需要移动较多数据块,会影响效率,所以要尽量使用有规律递增的int型做主键。还有因为数据紧跟着主键放,所以如果数据中有数据量特别大的列(text/blob),innodb查询时会跳过很多数据块,也会导致慢。

2、myisam的索引各个索引都相同统一指向磁盘上各个行的地址,都是轻量级的指针数据。缺点是各个索引的建立不是通过主键,查询没有聚簇索引查找主键快。但其因为存储的是地址,所以在插入新值时比较方面移动改变。

3、进行多条件查询时,对多条件分别建立索引时,执行sql查询时,MySQL只会选择一个最贴近的索引来使用,所以如果需要多条件查询,要建立联合索引,即使会造成数据冗余。

联合索引的BTREE建立方法:对第一个条件建立索引,在第一个索引的BTREE区域对第二个条件建立索引,以此类推,所以,在使用索引时,不用第一个条件用第二个条件也不会用到联合索引。使用索引时要条件要有顺序,有序列的使用。

4、索引长度对查询也有很大影响,我们应该尽量建立短的索引长度,我们可以使用查询列

SELECT COUNT(DISTINCT LEFT(column)) / COUNT(*) FROM tablename  来测试对column列建立索引时选取不同的长度,索引的覆盖率有多大,我们选择一下接近饱和的n个长度来建立索引
ALTER TABLE tablename ADD INDEX (column(n));  来对某一列的前n个字符建立索引。若前n个字符相同,我们甚至可以对字符串进行反转存储,然后建立索引。

5、对于经常修改导致的索引碎片的维护方式:ALTER TABLE tablename ENGINE oldengine;即再次应用一下表存储引擎,使其自动维护;也可以用 OPTIMIZE tablename 命令来进行维护。

数据查询方面优化

数据库操作尽量少查询,有查询时尽量不在数据库层面上进行数据操作,而是返回到PHP脚本中操作数据,减轻数据库压力。

一旦发现有数据库性能问题,要及时解决,一般用慢查询日志记录查询很"慢"的语句,用EXPLAIN分析查询和索引使用情况,用PROFILE分析语句执行时的具体资源消耗。

慢查询日志:

1、在my.ini或my.cnf的[mysqld]下添加

slow_query_log_file=/path //设置日志存储路径
long_query_time=n //设置如果语句执行时间达到n秒,就会被记录下来

2、然后在MySQL里设置SET slow_query_log='ON'来开启慢查询。

3、记录下日志后,我们用/bin/目录下的mysqldumpslow filename来查看日志,其常用参数如下:

-g pattern 使用正则表达式
-t n返回前n条数据
-s c/t/l/r 以记录次数/时间/查询时间/返回记录数来排序

EXPLAIN语句

使用方法,在要执行的查询语句前面加EXPLAIN

EXPLAIN SELECT * FROM user;

得到形如下图的结果:

PHP数据库编程之MySQL优化策略概述

下面是对每一项的解释:

id 查询语句的id,简单查询无意义,多重查询时可以看出执行查询的顺序
select-type 执行的查询语句的类型,对应多重查询,有simple/primary/union等。
tabel 查询语句查询的数据表
type  获得数据的类型 常见的类型效率从高到低为 null>const>eq_ref>ref>range>index>all
possible-keys:可能使用到的索引
key 使用到的索引
key_len索引长度
ref 使用哪个列与索引一起从表中选择。
rows  查找到数据要扫描的大概行数,可看出索引的优劣
extra  常见的有
using filesort 查询到数据后进行文件排序,较慢,需要优化索引
using where 读取整行数据后进行判断过滤,是否符合where条件
using index 索引覆盖,即在牵引中已经有这存储了目标数据,直接读取索引,很快。

PROFILE

用SELECT @@frofiling来查看PROFILE的开启状态。
如果未开启,用SET profiling=1来开启。
开启之后,再执行查询语句,MySQL会自动记录profile信息。
应用show profiles查看所有的sql信息,结果为 Query_ID Duration Query三列结果,分别是查询ID,用时和所用的sql语句。
我们可以使用

SHOW PFROFILE [type[,type]][FOR QUREY Query_ID][Limit rwo_count [OFFSET offset]]

type常见有ALL(全部) BLOCK IO(显示IO相关开销) CPU(CPU开销) MEMORY(内存开销)等

大型存储方面优化

数据库主从复制和读写分离

1、master将改变记录到二进制日志中,slave将master的二进制拷贝到它的中继日志中,重新将数据返回到它自己的数据中,达到复制主服务器数据的目的。

主从复制可以用作:数据库负载均衡、数据库备份、读写分离等功能。

2、配置主服务器master

修改my.ini/my.conf

[mysqld]
log-bin=mysql-bin //启用二进制日志
server-id=102 //服务器唯一ID

3、配置从服务器slave

log-bin=mysql-bin //启用二进制日志
server-id=226 //服务器唯一ID

4、在主服务器上授权从服务器

GRANT REPLICATION SLAVE ON *.* to 'slavename'@'IP' identified by 'root'

5、在从服务器上使用

change master to
master_host="masterip",
master_user="masteruser",
master_password="masterpasswd";

6、然后使用start slave命令开始进行主从复制。

不要忘记在每次修改配置后重启服务器,然后可以在主从服务器上用show master/slave status查看主/从状态。

实现数据库的读写分离要依赖MySQL的中间件,如mysql_proxy,atlas等。通过配置这些中间件来对主从服务器进行读写分离,使从服务器承担被读取的责任,从而减轻主服务器的负担。

数据库的sharding

在数据库中数据表中的数据量非常庞大的时候,无论是索引还是缓存等压力都很大,对数据库进行sharding,使之分别以多个数据库服务器或多个表存储,以减轻查询压力。

方式有垂直切分、水平切分和联合切分。

垂直切分:在数据表非常多的时候,把数据库中关系紧密(如同一模块,经常连接查询)的表切分出来分别放到不同的主从server上。

水平切分:在表不多,而表里的数据量非常大的时候,为了加快查询,可以用哈希等算法,将一个数据表分为几个,分别放到不同的服务器上,加快查询。水平切分和数据表分区的区别在于其存储介质上的不同。

联合切分:更多的情况是数据表和表中的数据量都非常大,则要进行联合切分,即同时进行垂直和水平分表,将数据库切分为一个分布式的矩阵来存储。

这些数据库的优化方式,每一种拿出来都可以写作一篇文章,可谓是博大精深,了解并记忆了这些方式,可以在有需要的时候进行有目的的选择优化,达到数据库效率的高效。

接下来我们会进一步总结一下常用的PHP数据库类扩展memcache、redis和mongodb的基本使用场景和使用方式。

希望本文所述对大家PHP程序设计有所帮助。

PHP 相关文章推荐
用Php实现链结人气统计
Oct 09 PHP
php实现从ftp服务器上下载文件树到本地电脑的程序
Feb 10 PHP
PHP源码之 ext/mysql扩展部分
Jul 17 PHP
基于PHP常用函数的用法详解
May 10 PHP
PHP 面向对象程序设计(oop)学习笔记 (五) - PHP 命名空间
Jun 12 PHP
php实现根据字符串生成对应数组的方法
Sep 22 PHP
PHP中substr函数字符串截取用法分析
Jan 07 PHP
php 数组元素快速去重
May 05 PHP
Laravel使用消息队列需要注意的一些问题
Dec 13 PHP
laravel 查询数据库获取结果实现判断是否为空
Oct 24 PHP
yii2.0框架数据库操作简单示例【添加,修改,删除,查询,打印等】
Apr 13 PHP
七种PHP开发环境搭建工具
Jun 28 PHP
PHP回调函数与匿名函数实例详解
Aug 16 #PHP
搭建自己的PHP MVC框架详解
Aug 16 #PHP
Laravel使用支付宝进行支付的示例代码
Aug 16 #PHP
laravel 中如何使用ajax和vue总结
Aug 16 #PHP
yii gridview实现时间段筛选功能
Aug 15 #PHP
PHP使用GD库制作验证码的方法(点击验证码或看不清会刷新验证码)
Aug 15 #PHP
Laravel学习教程之IOC容器的介绍与用例
Aug 15 #PHP
You might like
PHP Array交叉表实现代码
2010/08/05 PHP
PHP中创建和编辑Excel表格的方法
2018/09/13 PHP
cnblogs中在闪存中屏蔽某人的实现代码
2010/11/14 Javascript
javascript 原型继承介绍
2011/08/30 Javascript
js浮点数保留两位小数点示例代码(四舍五入)
2013/12/26 Javascript
js使用ajax读博客rss示例
2014/05/06 Javascript
JavaScript数组随机排列实现随机洗牌功能
2015/03/19 Javascript
JavaScript中反正弦函数Math.asin()的使用简介
2015/06/14 Javascript
javascript的变量、传值、传址、参数之间关系
2015/07/26 Javascript
利用PM2部署node.js项目的方法教程
2017/05/10 Javascript
iscroll实现下拉刷新功能
2017/07/18 Javascript
原生js实现省市区三级联动代码分享
2018/02/12 Javascript
Vue 仿QQ左滑删除组件功能
2018/03/12 Javascript
Django+vue跨域问题解决的详细步骤
2019/01/20 Javascript
vue 2.5.1 源码学习 之Vue.extend 和 data的合并策略
2019/06/04 Javascript
VUE实现自身整体组件销毁的示例代码
2020/01/13 Javascript
从零使用TypeScript开发项目打包发布到npm
2020/02/14 Javascript
JavaScript实现随机点名器
2020/03/25 Javascript
[46:55]Ti4 冒泡赛第二轮 LGD vs C9
2014/07/14 DOTA
Python批量重命名同一文件夹下文件的方法
2015/05/25 Python
基于Python和Scikit-Learn的机器学习探索
2017/10/16 Python
Django自定义manage命令实例代码
2018/02/11 Python
python3+dlib实现人脸识别和情绪分析
2018/04/21 Python
pygame游戏之旅 如何制作游戏障碍
2018/11/20 Python
详解Python正则表达式re模块
2019/03/19 Python
python字符串查找函数的用法详解
2019/07/08 Python
matplotlib.pyplot画图并导出保存的实例
2019/12/07 Python
关于keras.layers.Conv1D的kernel_size参数使用介绍
2020/05/22 Python
利用Python实现Json序列化库的方法步骤
2020/09/09 Python
websocket+sockjs+stompjs详解及实例代码
2018/11/30 HTML / CSS
俄罗斯第一家篮球店:StreetBall
2020/07/30 全球购物
Python里面search()和match()的区别
2016/09/21 面试题
求职信结尾怎么写
2014/05/26 职场文书
汉字听写大会观后感
2015/06/12 职场文书
婚礼嘉宾致辞
2015/07/28 职场文书
在redisCluster中模糊获取key方式
2021/07/09 Redis