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+MySQL 制作简单的留言本
Nov 02 PHP
五款常用mysql slow log分析工具的比较分析
May 22 PHP
PHP的5个安全措施小结
Jul 17 PHP
无JS,完全php面向过程数据分页实现代码
Aug 27 PHP
PHP生成Gif图片验证码
Oct 27 PHP
ThinkPHP模板自定义标签使用方法
Jun 26 PHP
destoon供应信息title调用出公司名称的方法
Aug 22 PHP
PHP实现的浏览器检查类
Apr 11 PHP
ThinkPHP自定义Redis处理SESSION的实现方法
May 16 PHP
深入理解PHP之源码目录结构与功能说明
Jun 01 PHP
php强制下载文件函数
Aug 24 PHP
php把字符串指定字符分割成数组的方法
Mar 12 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学习笔记之三 数据库基本操作
2011/01/17 PHP
Can't create/write to file 'C:\WINDOWS\TEMP\...MYSQL报错解决方法
2011/06/30 PHP
PHP imagegrabscreen和imagegrabwindow(截取网站缩略图)的实例代码
2013/11/07 PHP
thinkPHP js文件中U方法不被解析问题的解决方法
2016/12/05 PHP
Laravel 5.4向IoC容器中添加自定义类的方法示例
2017/08/15 PHP
SyntaxHighlighter代码加色使用方法
2008/09/07 Javascript
一些Javascript的IE和Firefox(火狐)兼容性的问题总结及常用例子
2009/05/21 Javascript
js事件冒泡实例分享(已测试)
2013/04/23 Javascript
通过正则表达式实现表单验证是否为中文
2014/02/18 Javascript
javascript实现获取浏览器版本、操作系统类型
2015/01/29 Javascript
网页从弹窗页面单选框传值至父页面代码分享
2015/09/29 Javascript
微信小程序 触控事件详细介绍
2016/10/17 Javascript
基于vue.js快速搭建图书管理平台
2017/10/29 Javascript
javascript自定义事件功能与用法实例分析
2017/11/08 Javascript
javascript字体颜色控件的开发 JS实现字体控制
2017/11/27 Javascript
Nodejs libuv运行原理详解
2019/08/21 NodeJs
微信小程序常用的3种提示弹窗实现详解
2019/09/19 Javascript
windows下create-react-app 升级至3.3.1版本踩坑记
2020/02/17 Javascript
微信浏览器左上角返回按钮监听的实现
2020/03/04 Javascript
wxpython 学习笔记 第一天
2009/02/09 Python
python通过ElementTree操作XML获取结点读取属性美化XML
2013/12/02 Python
python实现批量修改图片格式和尺寸
2018/06/07 Python
python实现多人聊天室
2020/03/31 Python
windows下 兼容Python2和Python3的解决方法
2018/12/05 Python
Python内置random模块生成随机数的方法
2019/05/31 Python
python pygame实现球球大作战
2019/11/25 Python
Python版中国省市经纬度
2020/02/11 Python
基于matplotlib中ion()和ioff()的使用详解
2020/06/16 Python
使用html5实现表格实现标题合并的实例代码
2019/05/13 HTML / CSS
HUGO BOSS美国官方网上商店:世界知名奢侈品牌
2017/08/04 全球购物
哈利波特商店:Harry Potter Shop
2018/11/30 全球购物
印尼网上商店:Alfacart.com
2019/03/11 全球购物
什么时候需要进行强制类型转换
2016/09/03 面试题
高二生物教学反思
2014/01/27 职场文书
公司自我介绍演讲稿
2014/08/21 职场文书
2015年审计人员工作总结
2015/05/26 职场文书