代码参看: php/classic.phpjavascript
把50331651记录进行分页,每页显示2条记录,因而咱们用传统php编码方式,编写分页代码以下:php
上传到/var/www/html下进行测试,结果以下:html
若是访问第1页和第4页,返回语句:java
使用explain执行计划查询比较靠前的页数,发觉速度很快由于可使用上索引:mysql
若是访问第4100000页,返回语句:jquery
使用explain分析结果以下:linux
发觉这时若是分页到了中间的页数,这时咱们既须要排序又要分页检索数据的时候,就会出现Using filesort的选项,这选项的出现致使分页在中间页面的时候使用不上索引,所以出现全表扫描的过程,因此这个语句的查询效率就大大的下降了,咱们在工做中若是遇到ALL的全表扫描咱们就必须优化这条语句,优化语句必须遵循一个理念:让慢语句使用上索引,使得ALL消失,但功能不能发生改变,这时咱们应该如何优化,这时咱们能够把分页语句调整以下优化:算法
分页传统的公式以下: order by id asc + limit 偏移量,长度sql
分页优化的公式以下: where id>偏移量 + order by id asc+ limit 长度数据库
查询第4100000页获得的结果以下:
通过优化后的算法,使用explain进行分析,能够获得以下结果:
发觉Using filesort被修改成Using Where所以分页优化获得提高,因此咱们未来在开发的过程当中若是须要分页的数据达到千万的级别时,咱们就须要使用如下优化分页公式:
分页优化的公式以下: where id>偏移量 + order by id asc + limit 长度
可是什么还要知道当前的算法查询的记录是否准确:
在现实开发当中,电子商务网站会有一个抢购的活动,若是有一个id=4而且库存量只有1的商品给用户进行抢购,那么这时有可能当全部的用户同时进行抢购的时候就会发生一种叫作并发的行为,这时会致使不少的用户同时抢购一个商品成功,为了防止这个状况,确保只能有一我的抢购成功,咱们就须要使用Myisam中的表锁,创建表结构和数据以下:
代码参考: code/StoreGoods.sql
插入相关的测试数据以下:
因而咱们传统编写的抢购代码以下所示:
代码参考: code/goods.php
问题来了:若是这时发生了并不是的行为,那么其实有可能有大部分的用户,能够进入抢购的update代码当中,那么这时有可能发生多人抢购成功,而且库存变为负数的状况,这时若是须要避免这个结果的产生,咱们须要加上表锁,把代码修改以下:
把代码上传到/var/www/html下,测试以下:
若是成功抢购,那么继续刷新就会提示如下结果:
在表的创建中数值数据选取原则
人的年龄能够选择:
人通常很难超过139岁,若是你选择int类型来存储就是占用4个字节,若是1000条记录的大小就是4*1000=4000字节,若是你选择tinyint就只有1个字节,1000条记录只有1000字节的大小比原来int节约了4倍的存储空间,所以人的年龄选择tinyint
乌龟的年龄能够选择:
乌龟最短年龄也能够超过500年,因此tinyint没法存储乌龟的年龄,所以咱们能够选择smallint来存储,这时其实理论上能够保存万年神龟的年龄
主键能够选择:
假设是一个小学生的博客系统,那么其实主键id选择tinyint便可,由于小学生很难写超过100篇文章,若是是技术人员的技术博客都属于一些我的的笔记,因此咱们选择smallint做为主键的id就够了,由于通常人很难写超过2000篇文章,就算是金庸写的博客也很难超过,假设你我的开发了一个商城网站,专卖手机产品,那么应该选择smallint,若是是一个间小公司的电子商务(中山壹加壹连锁超市)能够选择MEDIUMINT,若是你开发是京东商城那么请选择int作主键
金钱能够选择:
若是遇到存储货币或者金钱类型的字段,想都不用想使用DECIMAL(6,2)
若是未来还须要用到时间的字段,建议直接使用timestamp,若是你使用int虽然也是4个字节,然而int存储的是Unix时间戳,那么就意味你有一个php代码的转化过程,很是的麻烦,而timestamp依然是4个字节但这个字段不须要你作任何的转化,只须要使用一个mysql中的数据库函数叫now()就能够完成.
对mysql的timestamp字段插入数据,会发觉存在2个问题:
代码参考: code/timestamp.sql
这时以上的时间有可能不对的,由于在linux当中咱们安装时候,安装通常是系统时间,在linux修改时间须要同时修改系统时间和硬件时间,修改Linux的时间,须要使用如下两个命令:
假设咱们须要把Linux的时间修改成2017-08-22 08:13:52秒
1)使用date命令
date在没有任何的选项的时候,是用于查询系统时间,发觉这个时间不是咱们想要的时间,所以咱们可使用date -s来进行时间的设置,-s是修改系统时间的选项
CST的意思是中国沿海时间的时区,通常在linux当中咱们使用中国时区都使用CST
2)使用clock --show命令显示linux硬件时间
以上问题,能够会在开发当中获取的时间产生bug,所以咱们须要同步系统和硬件时间为一致的时间,使用clock --systohc同步,--systohc就是把系统时间和硬件时间进行同步的选项:
执行命令,以下 :
这时再次对比系统时间和硬件时间以下:
若是咱们把字段的时间类型修改成timestamp也同时调整了Linux系统时间和硬件时间,那么这时咱们若是使用php进行该字段的插入,那么咱们在php中应该怎么作呢?
代码参考:php/news.php
上传到/var/www/html下,测试效果以下:
上述代码必须设置 时区,now()不要进行预处理
若是你作博客或者新闻发布信息的系统,标题字段选择varchar,内容选择text,这个进本上是一种常见的应用,BLOB的数据通常可能会产生一些乱码的状况因此建议不要使用在中文内容当中.
在php开发咱们常常须要作时间字段的优化还有日志记录系统当中Ip字段的优化.
255.255.255.255 = 15字节(varhcar(15))
192.168.1.1 = 15字节(varchar(15)) = 15 * 1000 = 15000 字节
ip字段其实能够优化成为4个字节进行存储,那么就是4*1000=4000字节
因此若是使用varchar(15)或者char(15)来存储ip的时候,你就有优化ip字段存储的必要性了,若是但愿把ip地址优化成为4个字节的大小,咱们应该选择int数据类型对ip进行存储,可是若是把ip转化成为int呢,那么这时咱们要学习两个函数:
①为ip字段选择的数据类型(ip2long)
根据转换的结果可使用如下在设计表时来选择Ip字段的数据类型选择Int
代码详细请参考:code/ip.sql
编写php代码以下:
代码详细请参考:php/ip2long.php
在默认状况下,ip2long函数会把ip转化成有签名整型,所以咱们在php当中会获取到负数的状况,以下所示:
ip若是为负数的转化是属于失败的转化,那咱们就须要把ip转成无签名整型获取正整数
咱们就须要使用sprintf函数,函数描述以下:
编写修改代码以下:
上传到/var/www/html下测试结果以下所示:
获取了ip转化无符号的结果,这时若是你但愿直到当前的整数是否转化成功,那么就须要把整型转化为ip地址来进行验证,使用long2ip
②long2ip函数(把整型转换为ip地址)
php代码参看:php/long2ip.php(该代码须要上传到linux的/var/www/html下测试)
执行结果以下:
⑥ip优化的综合实例,把ip为192.168.84.88插入的数据表ipAddress当中,而且把插入的数在该表当中读取出来,代码以下所示:
php代码参看:php/caseIp.php(该代码须要上传到linux的/var/www/html下测试)
第1步:先完成pdo对ip地址转化为整型数据插入工做,代码以下:
执行结果以下所示:
第2步:把ip地址从数据库读取出来而且把整型转化成为ip地址,代码以下:
执行结果以下所示:
物理分表又称为手工分表,故名思议物理分表的工做是靠本身手动进行完成的,它的目的是把数据进行拆分管理.在物理分表中主要的分表思想有垂直分表和水平分表两种,这种分表是一种数据库的优化思想,因此须要引入数据库范式的概念进行支持.
在现实开发当中咱们通常是针对需求来知足需求,因而若是有如下需求咱们若是你看到眼前而不考虑长远,咱们能够把需求分析和设计作出如下决定,以下图所示:
这样的表设计天然可以知足需求1,然而它有利于长远的发展吗?若是你想知道是否适合长远的发展最好就是继续提出一个新的需求看看是否容易拓展或者直接知足,继续提出需求以下:
要解决需求2若是你只看到眼前,那么你可能会作出如下解决的,就是增长一个字段来添加历史学科的成绩:
这时又一个新的需求提出,这时问题就再次出现了,以下图所示:
由于不断字段去知足需求就会致使字段不断增长,形成数据的冗余,若是你但愿解决以上这些问题的出现就须要使用物理垂直分表进行解决,然而垂直分表通常发生开发者开发项目和设计阶段出现较多,因此与垂直分表相关的又一个叫作数据库范式的理论进行支持,范式理论以下:
数据库第1范式:把数据合理的进行拆分让他们的共同点造成一个总体,而且造成后没有继续拆分必要 性,那么就证实该总体一个合理的总体成为符合数据库第1范式(1NF),如上述问题,解决方案符合第1范式以下:
数据库第2范式:因为数据表又可能会存在相同而且重复的记录可能,咱们须要解决整个问题就是加入主键,如上述问题,符合数据库第2范式以下:
数据库第3范式:因为咱们把数据分别成为了一个总体,那么就须要把总体进行联合,咱们把拥有主键的总体部分红为主表,把关联主表的总体部分红为附属表,那么关联他们的标识就是数据库的第3方式的核心也就是外键,因此能够认为认为数据库第3范式的核心就是关联性,如上述问题,符合第3范式设计以下:
数据库三范式通常人也有把理解为物理垂直分表的标准,只要符合数据库三范式全部的规则,那么都是垂直分表的过程而整个过程通常是咱们手动完成,所以物理垂直分表也称为手工垂直分表。
分表时候,每一张表都是结构独立的,表与表之间经过外键的形式把数据连接在一块儿进行查询。只要符合数据库三范式的设计都属于垂直分表的思想.
代码详细请参考:code/students.sql
1)业务需求
2)根据三范式设计表的结构
首先知足1NF和2NF,设计表结构以下:
然而知足3NF,设置关联和外键,设计表结构以下:
3)为表插入对应的数据
4)使用连表查询得到数据
若是但愿查找学号为s123的人咱们就须要把学号字段进行主表和附属表的关联,原理以下:
编写如下查询语句连表查询操做:
执行结果以下所示:
5)使用explain执行计划查看索引使用状况
执行结果发觉,垂直分表可使用到索引,由于符合数据库3范式的设计就必定可以使用上索引。
逆范式化指的是经过增长冗余或重复的数据来提升数据库的读性能.逆范式通俗的理解其实就是经过违反数据库三范式的定义达到某种合理的设计的一种应用.其中水平分表就是一种逆范式的应用
在早期的网页游戏当中有一种叫组团攻城的活动,每个游戏的玩家能够在某一游戏中进行报名组建其余的玩家一块儿玩游戏,有时候可能不是只有一个游戏开展攻城的活动,而是多个游戏开展攻城的活动,这时为了更好地维护游戏,这时咱们就可使用到水平分表,其原理图以下所示:
咱们能够把案例,按照以下步骤,部署到Linux当中
第1步:把代码经过ftp上传/var/www/html
第2步:创建一个名为37games的数据以下:
第3步:切换到/var/www/html下执行数据库表的安装,执行install_db.php文件
在执行脚本以前先确认数据库连接的用户名和密码以及数据库名称,打开db.php文件,内容以下,能够根据本身喜欢修改:
确认无误后,就在/var/www/html下使用php命令执行install_db.php文件,以下图所示:
查看数据库37games当中发觉有2张表分别:tlcs_users和cycs_users
2张表的字段都是同样的,只是表名不同
第4步:在浏览中访问linux中ip地址,出现如下界面,表明案例部署成功
第5步:分析案例的目录和文件以下:
js目录 : 放置javascript库文件的,jq.js是一个jquery框架
smarty目录:用于放置smarty类库的目录
templates:是html模板的目录
templates_c:是smarty编译模板后的目录
common.php : 一个数据库连接,smarty实例化,游戏产品列表数据引导的核心文件
count.php : 统计报团攻城的人数信息的文件
db.php : 数据库的连接配置文件
games.php:游戏产品的数组文件
index.php:网站报团首页文件
install_db.php : linux安装时执行的脚本文件
register.php: 报团插入数据库的php文件
第6步:分析首页可知,页面点机报团按钮后,会把如下表单信息传至register.php页面
第7步:在register.php代码当中编写以下代码,获取信息并插入数据库当中
若是用户报的屠龙传说游戏,那么就会在tlcs_users当中添加数据:
若是用户报的赤月传说游戏,那么就会在cycs_users当中添加数据:
第8步:实现水平分表的统计,咱们须要在count.php文件中编写代码以下:
测试结果以下:
这时问题来了,若是这时老板提出一个新的需求,把一个叫作传奇霸业的游戏(mir)也进行攻城活动,那么咱们就须要修改代码以下:
第9步:在games.php文件中加入对应游戏代码和游戏名称
在首页就会显示多一个游戏
同时咱们还须要创建一张名为mir_users的水平分表,来存储传奇霸业的用户信息,使用命令以下:
第10步:修改count.php的统计报表数据,代码以下所示:
第11步:修改smarty的模板文件templates/count.html,代码以下:
测试以下:
物理水平分表自定义和拆分大数据的能力虽然很是的强,然而它有一个缺点就是因为咱们形成数据的冗余分布,致使数据的统计变得麻烦,只能不一样不断修改代码来知足需求,所以物理水平分表有优势也有缺点,所以水平分表的物理优化咱们要付出必定的php逻辑编写的时间代价,有没有更好取代这种分表的,让咱们的统计变得简单的方法呢?在mysql5.1以后,其官方开发者提供了一种叫逻辑水平分表的手段
物理水平分表的好处在于自定义能力很强,但物理分表不利于数据的统计,所以MySql为了解决物理水平分表的缺陷提出了逻辑水平分表的概念,逻辑水平分表是MySql自带功能,它的好处就是分表的过程是系统自动完成的,而咱们写的代码不会像物理水平分表那样疲于应对需求,逻辑水平分表主要有两种。一种称为Range分表,一种称为List分表。
业界有些说法也叫Range分区和List分区。
1-1000:是5000的第1个范围,把该范围的数据做为一张表
1001-2000:是5000的第2个范围,把该范围的数据做为一张表
2001-3000:是5000的第3个范围,把该范围的数据做为一张表
3001-4000:是5000的第3个范围,把该范围的数据做为一张表
4001-5000:是5000的第4个范围,把该范围的数据做为一张表
若是有以上的需求,那么就可使用MySql的range分表技术,其原理图以下:
若是把5000条记录当作蛋糕,那么拆分的数据就是把蛋糕切成了5等份
代码详细请参考:code/range.sql
语法规则:
partition by range (字段)(
partition 分表名称 values less than (范围)
)
发觉系统自动帮咱们产生2个分表的区域
假设我但愿有一张一些数据处于cake1000这张分表当中,那么我应该如何插入?
分析可知:因为这个分表是从id的范围来分,若是id的范围是1-999那么就会处于cake1000当中,因此咱们插入数据以下:
执行结果以下:
发觉你插入数据其实能够有效控制范围
假设咱们插入的数据的id=2001,那么会出现怎么样的状况呢?
然而咱们的数据是分布在不一样的分表当中,若是咱们使用select count(*) from cakes能整成统计出记录总数吗?
这个答案是确定的,由于逻辑分表的功能和算法是开发者帮您实现的
假设咱们删除了cake2000这个分表,那么统计会改变吗?也就是说数据会丢失吗?
代码详细请参考:code/del_range.sql
语法规则:alter table 表名 drop partition 分表名称;
若是咱们删除cake2000这个分表,那么咱们查询id=1000是能够查出来的
若是执行分表删除,以下;
执行结果以下:
若是使用select count(*)进行统计查询会发觉数据丢失了
注意:分表删除数据会丢失
代码详细请参考:code/add_range.sql
若是咱们添加一个数据超过了分表范围,那么就会报错
语法规则:
alter table 表名 add partition (
partition 分表名称 values less than (范围)
)
执行的结果以下所示:
List分表其实简单地理解为把一年按季度的进行分表的应用便可,由于实际开发当中List分表主要用于年度季度报表的应用比较多,List分表也是按范围的分表技术。假设当前要把1年的数据进行季度拆分,那么1年能够分为4个季度:
3,4,5月分为春季
6,7,8月分为夏季
9,10,11月分为秋季
12,1,2月份分为冬季
这时range分表其实没法达到这个功能,若是须要知足当前这个需求则能够选择List分表技术,其原理图以下:
list分表通常用于财务报表的统计系统当中
代码详细请参考:code/list.sql
语法规则:
partition by list (条件语句)(
partition 分表名称 values in (范围)
)
执行结果以下:
执行结果以下:
代码详细请参考:code/del_list.sql
语法规则:alter table 表名 drop partition 分表名称;
执行结果会发觉,数据跟range同样会丢失:
注意:分表删除数据会丢失,list分表最好不要删除分表,由于list的分表应用多数用于财务系统,财务系统的数据通常不建议删除,因此最好不要删除list分表种的分表
代码详细请参考:code/add_list.sql
语法规则:
alter table 表名 add partition (
partition 分表名称 values in (范围)
)
执行结果以下:
list分表有1个特色,就是在mysql5.1.73版本,建议id字段设置为普通索引,由于惟一性索引和主键在list分表当中不起做用,且没法添加
这时咱们若是创建的是普通索引,那么就不会出错了
执行结果以下:
①备份命令mysqldump
命令格式: mysqldump -uroot -p123456 [数据库名称] > 保存文件的路径和名称
在/root/桌面就会存在37wan.sql这个文件,内容以下:
这时假设咱们删除了37games这个数据库,那么就能够利用备份的文件进行导入恢复
使用导入37wan.sql的方法进行数据库恢复,步骤以下:
①创建37games的数据库
退出mysql
②执行导入