首页 > 技术文章 > 高并发网站架设

wujunbin 2017-09-03 02:01 原文

 

前端优化 css同类型合并--压缩-图片压缩-缓存-js压缩等

https://www.zhihu.com/question/21658448 http://www.cnblogs.com/fangshidaima/p/5823465.html

后端优化     php引号-foreach-算法-函数实现方法比对(运行时间测试修改)

数据库优化(大数据优化)    索引-字段类型-位数-引擎

服务器优化  

数据传输优化  json格式 php系列化(serialize)

seo优化

 

redis

安全  数据过滤,验证,加密

 

http://www.tp-shop.cn/index.php/doc/indexbbc/video

网站高并发架设

 

这些技术不一定要全部用上

浏览器开启压缩存储

1,php开启压缩存储

 

j2) LocalStorage

LocalStorage是html5的一个新技术,可用于本地缓存。本技术只对支持html5的浏览器使用,如果要向下兼容,可以通过ajax异步通过Redis、Memcache等写入服务器的内存。

在什么地方可以查看呢?打开谷歌浏览器Chrome   按F12  点击Resources(参考图:demo\chapter1\demo2 \1-2.png)

 

3图片优化合并为一张

 

尽量少请求

一、大纲

 

二、php程序优化

一定要都用到知道的最优化方式,每个快个几百毫秒,一个大项目,几万行代码下了

 

就快了多少这样,特别是大数据,几亿数据遍历那样快了不知道多了都,

一个代码块实现有很多种方法,多测试,看看哪种速度最快,测试多了,积累经验,就能写出高效的代码

1.PHP性能优化工具篇Benchmark类调试执行时间

php官方提供的

http://www.jb51.net/article/29065.htm

 

http://pear.php.net/package/Benchmark/download

 

$arr[id] = 0;//The Case 1 is annotated this line   0.0071161985397339

$arr['id'] = 0;//The Case 1 is annotated this line  0.00069479942321777

 

能在客户端浏览器处理的尽量在客户端处理,不要在服务器,这样能节省网络开销等

通过比对php代码执行的时间

 

Javascript

php代码优化部分

2.第二讲讲义

 

第一章:程序优化部分(PHP/JavaScript)

1 Jacascript   部分

2 php 开发习惯

1.大家要记住一个原则,“能用JavaScript实现的就不要用PHP去实现”,其实质就是减少在服务器端运行程序。

1) Cookie

在安全性要求不高的地方,可以用JS(后面我们就用JS来代替JavaScript)实现Cookie的读取。比如:记录网友的浏览足迹,商城中未登录用户把产品添加进购物车等,这些操作没有必要写入数据库。

演示Js操作Cookie的例子…

这里有个美中不足的地方就是Cookie的大小是有限制的(参考图:demo\chapter1\demo1 \1-1.png),这也是为了安全需要而限定的。在这里我给大家介绍另一个技术:LocalStorage

2) LocalStorage

LocalStorage是html5的一个新技术,可用于本地缓存。本技术只对支持html5的浏览器使用,如果要向下兼容,可以通过ajax异步通过Redis、Memcache等写入服务器的内存。

在什么地方可以查看呢?打开谷歌浏览器Chrome   按F12  点击Resources(参考图:demo\chapter1\demo2 \1-2.png)

LocalStorage可支持的大小可以参考图:demo\chapter1\demo2 \1-3.png

 

3)Ajax

a.尽量Ajax去代替提交表达,避免刷新页面。(Ajax不在本课程讲解范围)

b.PHP和Js直接的最佳的通信方式就是json,尽量避免传递html格式的字符串。

 

2.PHP方面的优化细节

 

1) $row['id'] =0比 $row[id]=0 快,次数越大越明显/生产环境(Linux)下测试1个数量级;

2) 递增递减

a.递增(递减)一个预预定义的局部变量要比递增(递减)一个未定义的局部变量快;差别较大

b.执行变量$i的递增(递减)时,++$会比$i++快一些;这种差异是PHP特有的,并不适用于其他语言;差别较小

3) 在可行的情况下,避免使用正则表达式,str_replace 函数比 preg_replace,差别还是很明显的;

4)  include 文件时尽量使用绝对路径,因为它避免了 PHP 去 include_path 里查找文件的速 度,解析操作系统路径所需的时间会更少;差别不太明显

5) 用单引号(’’)代替双引号(””),单引号为强类型,将其中的所以字符都认作字符,而双引号的为弱类型,它会检测其中是否存在变量,测试差别不大

6) 避免使用“@”,早先测试的差别较大,本次测试的差别不大,应该是跟版本、系统等环境有关系

7) 在有必要的时候使使用引用(&),此处借鉴了C 语言的指针,测试差别较大,接近1个数量级

8) 尽量用include代替include_once,因为include_once多了一些检测,差别应该不大,此处部分用多次循环模拟。

9)for 和foreach;生产环境(Linux)下测试:foreach($row as &$v)略快于for($i = 0 ;$i < 10000; $i++);foreach($row as $k=>$v)最慢

 

10)判断字符串长度时,可用isset($str{15})代替strlen($str) < 15;因为isset()作为一种语言结构,而strlen()是函数,语言结构快于函数;

11) $n += $i 快于$n = $n + $i;测试差别不大

12) Apache 处理 PHP 脚本的速度要比静态页面慢 2-10 倍,因此尽量采用多的静态页面,少的脚本;PHP程序使用文件缓存性能会倍增;

13) 获取Unix时间戳时用$_SERVER['REQUEST_TIME'] 代替time(); wamp环境测试性能提示20~30%/Linux生产环境测试性能提升 500% (5倍)

 

14) $_SERVER['DOCUMENT_ROOT']代替str_replace('//','/',dirname(__FILE__) .'/');wamp测试无太大差别/Linux生产环境测试性能提升 500% (5倍)

 

15)  如果能将类的方法定义成 static,就尽量定义成 static,性能会有提示;测试差别不是很多;

16) 用Mysqli或pdo代替Mysql

18) 一般不建议启用auto_start(session.auto_start:是否自动启用) ,因为创建Session需要消耗系统资源,我们通常只会在需要用到Sesson时,才会使用session_start函数来开启Session功能。

19)直接将成员变量定义成共有并直接复制比通过方法向私有变量赋值效率高2~3倍,即提升200%~300%,但这跟违背了封装的风格,大家可自行决定;

 

last)尽量采用PHP内置函数

 

原生PHP代码是性能最高的,但用原生PHP开发网站,效率会低很多;任何的php框架,框架本身都会消耗一定的资源。

三、      缓存优化

3.        缓存例子

文件ob缓存静态html(解决php每访问一次解析一次,直接html,

十万篇文章,十万个用户,每个用户访问文章,这就是十万次数据库的读取,我们把他写出文件的静态缓存,大大的减少了服务器的开销

 

Opcache高并发中很重要(Opcache扩展要开启

例如框架,它是个单一入口,在请求框架单一入口时,会请求很多,比如会初始化一些常量,一些变量文件,初始化配置文件,初始化语言包,初始化函数库,初始化数据库连接等等,

假设这些有1万行代码,假设高并发中有1万个用户请求,那么php解析器逐行解析1万行,万*万就是1亿,用了Opcache就不用解析了,高效的提高

 

redis缓存(一个网站,用户访问,就要产生几十条数据库语句,假设10万个用户访问,那么几十*10万,就是几百万查询数据库了,对数据库很大开销。假如把分类,商店公告,站内快讯,产品列表,抢购页面,像这些不可能每次都去查询数据库,像这种情况,我们会把它们存到redis数据库,下次操作,直接从redis读取,这样减少了几十条数据查询,当用户成千上万时,就可以少了多少数据库语句了,这些都是可以算一下的)

 

 

===========

头部 header.php  要缓存的php,上面引入它  定义缓存过期时间

 

 

<?php

define('CACHE_EXPIRE',1800);

define('CACHE_PATH',$_SERVER['DOCUMENT_ROOT'].'/cache/');

define('REFRESH_EXPIRE',10);

is_dir(CACHE_PATH) or mkdir(CACHE_PATH,0777);

 

function refreshTimes(){

$currentUrl='http://'.$_SERVER["HTTP_HOST"].$_SERVER['REQUEST_URI'];

if(isset($_COOKIE['refreshTimes'])){

$cookArray=explode("\t",$_COOKIE['refreshTimes']);

if(isset($cookArray[1]) and $_SERVER['REQUEST_TIME'] - (int)$cookArray[1] < REFRESH_EXPIRE and isset($cookArray[0]) and $cookArray[0] == $currentUrl){

setcookie('refreshTimes',$currentUrl."\t".$_SERVER['REQUEST_TIME']."\t".(string)((int)$cookArray[2]+1),0,'/');

return (int)$cookArray[2];

}else{

setcookie('refreshTimes',$currentUrl."\t".$_SERVER['REQUEST_TIME']."\t1",0,'/');

return 0;

}

}else{

setcookie('refreshTimes',$currentUrl."\t".$_SERVER['REQUEST_TIME']."\t1",0,'/');

return 0;

}

}

 

$key = md5($_SERVER['REQUEST_URI']);

$path = CACHE_PATH.$key;

 

if(is_file($path)

 and filemtime($path)+CACHE_EXPIRE > $_SERVER['REQUEST_TIME']

 and refreshTimes() == 0

 ){

readfile($path);

exit();

}

 

ob_start();

?>

 

 

<?php

include 'head.php';

 

$title = "Hello world~";

?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

<head>

<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />

<title><?php echo $title?></title>

</head>

 

<body>

<?php

echo "你好,欢迎访问本站~~~~$$";

?>

</body>

</html>

<?php

include 'foot.php';

?>

====

 

foot.php

 

<?php

 

$html = ob_get_contents();

ob_clean();

 

file_put_contents($path,$html);

 

echo $html;

 

?>

 

 

上面代码用 下面2个函数,抓取地址保存为html,不保存时间,修改时,同时在执行下这代码,就可以了

 

File_put_contents

file_get_contents

 

 

 

 

readfile读取文件效率最高

4.        第三讲讲义

 

 

相对来说,java程序执行效率比较高,php每访问编译一次。把其缓存起来就比较快了

 

Rredis

文件缓存

Opcache

 

 

1.文件缓存

文件缓存是一种最常见,最方便实现的一种缓存方式,使用这种可以使网站的并发量得到显著的提高。如果你的网站只是购买的FTP空间,没有权限去修改PHP的设置,选择这种方法是最好的选择。

 

2.php的opcache缓存

) 在正式的生成环境中,一定要使用一块OPcode缓存插件

 

参考图:2-1

如果在编译安装的时候没有开启此选项也没有关系,我们可以以安装扩展的形式来安装:

 

 

参考图:2-2

安装步骤:

# cd  php-5.6.3/ext/opcache

# /usr/local/php/bin/phpize

# ./configure --with-php-config=/usr/local/php/bin/php-config

# make && make install

##安装成功,查看一下

# ll /usr/local/php/lib/php/extensions/no-debug-non-zts-20131226/

 

然后在php.ini文件中开启即可,关于opcache的选项共有27个(不包括指定扩展文件的选项zend_extension=opcache.so ),都有默认值

相关配置可以参考官方文档:

http://php.net/manual/zh/opcache.configuration.php

 

配置如下:

[opcache]

;指定对应的扩展文件(此项是唯一一个必须的选项)

zend_extension=opcache.so 

 

 

什么是CLI模式:

# /usr/local/php/bin/php -r "echo \"hello world\n\";"

# /usr/local/php/bin/php -r "phpinfo();"

 

 

关于参数 –r 大家可以查看帮助信息:

/usr/local/php/bin/php –h

 

 

 

 

讲解完毕演示效果

 

官网的一段推荐设置:

 

 

http://php.net/manual/zh/opcache.installation.php

注释:此方法在开发环境中不建议使用,会给开发者带来不便

3使用.redis进行缓存:

网站最大的瓶颈就是数据库部分,如果能把数据库中的数据读出来之后缓存到内存中,其性能将会有巨大的提升。

1)   redis安装及配置

 

大家可以取他们的官网下载最新的稳定版:http://redis.io/

我这里采用的是:redis-3.0.1.tar.gz

# tar xf redis-3.0.1.tar.gz

# mv redis-3.0.1 /usr/local/redis

# cd /usr/local/redis/

# make

安装完成…

# vim redis.conf

daemonize no 改为:daemonize yes(后台运行)

这里有个service启动脚本:

# cp ~/redis.service /etc/init.d/redis

# chmod +x /etc/init.d/redis

# chkconfig redis on

# chkconfig --list redis

redis          0:off 1:off 2:on 3:on 4:on 5:on 6:off

设置为开机自动启动,启动redis

# service redis start

 

打开配置文件(redis.conf),找到下列行为其设置秘密:

# requirepass foobared

复制一行改为:

requirepass 888888

保存退出并重启

# service redis restart

打开客户端:

src/redis-cli

授权:

 

 

 

 

 

2)安装php的redis扩展:

(压缩安装包:owlient-phpredis-2.1.1-1-g90ecd17.tar.gz)

# wget https://codeload.github.com/owlient/phpredis/zip/master

# unzip master

# cd phpredis-master/

# /usr/local/php/bin/phpize

# ./configure --with-php-config=/usr/local/php/bin/php-config

# make && make install

查看一下:

# ll /usr/local/php/lib/php/extensions/no-debug-non-zts-20131226/

配置php.ini文件

# vim /usr/local/php/lib/php.ini

双敲GG将光标移至最后增加一下部分:

[redis]

extension = redis.so

保存退出,重启php-fpm

# service php-fpm restart  #nginx 服务器

# service httpd restart      #apache服务器

 

在phpinfo()页面:

 

 

看到这跟说明大功告成。

 

 

测试程序:

<?php

$redis = new Redis();

$redis->connect('127.0.0.1','6379');

$redis->auth('888888');

echo $redis->get('name');

$redis->set('name','b');

 

 

四、      数据库优化

查询,高效的sql语句

索引/建表

服务器方面/主从复制

 

 

 

优化1查询一条数据 时加limit 1。

 

5.        第四讲讲义

 

1.优化数据类型:

下面几个原则有助于做出更好的选择:

1)     更小的通常更好:

像VARCHAR类型的,虽然是变长存储,但读取到内存的时候,依然是定长的。

2)简单就好

简单的数据类型的操作通常需要更少的CPU周期。例如,整数比字符操作代价更低,因为字符集合校对规则(排序规则)使用字符比较比整数型比较更复杂。

3)尽量避免NULL:

如果查询中包含可为NULL的列,对MySQL来说更难优化,因为可为NULL的列使得索引、索引统计和值比较更复杂。可为NULL的列会使用更多的存储空间,在MySQL里也需要特殊处理。当可为NULL的列被索引时,每个索引记录需要一个额外的字节,在MyISAM里甚至还可能导致固定大小的索引(例如只有一个整数列的索引)变成可变大小的索引。

通常把可为NULL的列改为NOT NULL带来的性能提升比较小,索引(调优时)没有必要首先在现有的数据库中查找并修改掉这种情况,除非确定这会导致问题,但是,如果计划在列上建索引,就应该尽量避免设计成可为NULL的列。

 

2.VARCHAR和CHAR类型

注意:

VARCHAR:最大长度同TEXT(2^16-1=65535)相似,是:65532(Mysql 5.0.3以上版本)加上起始和结尾占去3个字节也是65535

CHAR:最大长度是255个字节;

 

1)VARCHAR

VARCHAR类型用于存储可变长字符串,是最常见的字符串数据类型。它比定长类型更节省空间,因为它仅使用必要的空间(例如,越短的字符串使用越少的空间)。

由于行是变长的,在UPDATE时可能使行变的比原来更长,这就导致需要做额外的工作。

2)CHAR

CHAR类型是定长的:

CHAR适合存储很短的字符串,或者所有值都接近同一个长度,例如MD5值(密码)。对于经常变更的数据,CHAR也比VARCHAR更好,因为CHAR类型不容易产生碎片。

有个地方需要注意:CHAR会自动截取掉字符串结尾的空格。

实验:

创建两个表格:

CREATE TABLE `char_test` ( `char_col` char(10));

CREATE TABLE `varchar_test` ( `char_col` varchar(10));

插入数据:

INSERT INTO `char_test`(`char_col`) VALUES('string1'),(' string2'),('string3 ');

INSERT INTO `varchar_test`(`char_col`) VALUES('string1'),(' string2'),('string3 ');

检索的时候会发现,VARCHAR类型的string3末尾的空格被截掉了。

SELECT CONCAT("'",`char_col`,"'") FROM `char_test`;

SELECT CONCAT("'",`char_col`,"'") FROM `varchar_test`;

执行结果如下图:

 

 

 

提示:慷慨是不明智的

使用VARCHAR(5)和VARCHAR(200)存储’hello’的空间开销是一样的。那么短的列有什么优势吗?

事实证明有很大的优势。更长的列会消耗更多的内存,因为MySQL通常会分配固定大小的内存块来保存内部值。尤其是使用内存临时表进行排序或操作时会特别糟糕。在利用磁盘临时表进行排序时也同样糟糕。

所有最后的策略是只分配真正需要的空间。

 

索引

什么是索引?

我们先来说一下分表。常用的分表有横向切分和纵向切分,我们今天就来说一下表格的纵向切分。比如我们要做一个资讯系统,首先我们要设计存储文件的表格,比如需要的字段有:主键ID、表格title、文章类别ID、来源、发布时间、访问次数、概述、文章内容。最常见的分法就是内容放一个表格里(包含文章内容和一个主键)、其他部分放在一个表里,可以作为主表,通过主表的主机递增产生一个ID,将这个ID和内容存入内容表中。

如果数据超过了1000万条,内容表的至少都在1个G以上,而主表大小一般也就300M到500M之间。就文章列表页而言,想一下扫描一个三五百兆的文件和扫描一个几个跟G的文件那个快?这种分表的方式就是借鉴了索引的特点,这样大家就应该明白索引是怎么回事了吧。

 

索引主要的三个有点:

1)     索引大大减少了服务器需要扫描的数据量。

2)     索引可以帮助服务器避免排序和临时表。

3)     索引可以讲随机I/O变为顺序IO。

 

 

实验:有索引和没有索引的区别

下面这跟表是我几年前我在某分类信息网上通过一个php程序采集的一些用户的信息如手机号码等,表内数据共2509793条:

SELECT COUNT(*) FROM tb_test2;

SELECT COUNT(*) FROM tb_test1;

 

 

 

我将表tb_test1复制了一份为tb_test2,然后去掉了其主键索引,我们测试一下查询速度,如下所示:

SELECT name,mobel,eMail,address FROM tb_test2 WHERE urlID=1888\G

SELECT name,mobel,eMail,address FROM tb_test1 WHERE urlID=1888\G

 

 

 

 

我们看一下有索引和没有索引各自检索相应的记录所需要扫描的记录条数:

EXPLAIN SELECT name,mobel,eMail,address FROM tb_test1 WHERE urlID=1888\G

EXPLAIN SELECT name,mobel,eMail,address FROM tb_test2 WHERE urlID=1888\G

 

 

很显然,有索引的只需扫描一条即可,而没有索引的需要全表扫描。为什么索引只扫描一条呢,其实有索引的只需要扫描整个索引就可以了,找到对应的指针可以直接定位到相应的数据,可能有的同学要问了,第二个为什么要扫描全表呢,搜索前1888条不就找到了么?那是因为数据库也不知道符合条件的有多少条,所有要对比所有数据,把所有符合条件的都找出来。

换一种查询方法看看:

SELECT name,mobel,eMail,address FROM tb_test2 ORDER BY urlID ASC LIMIT 1000,25;

SELECT name,mobel,eMail,address FROM tb_test1 ORDER BY urlID ASC LIMIT 1000,25;

 

看一下两者的区别:

 

 

 

 

 

 

 

语句解释:

EXPLAIN SELECT name,mobel,eMail,address FROM tb_test2 ORDER BY urlID ASC

LIMIT 1000,25\G

EXPLAIN SELECT name,mobel,eMail,address FROM tb_test1 ORDER BY urlID ASC

LIMIT 1000,25\G

 

 

 

 

 

 

 

 

覆盖索引:

通常大家都会根据查询的WHERE条件来创建合适的索引,不过这只是索引优化的一个方面。设计优秀的索引应该考虑到整个查询,而不单单是WHERE条件部分。索引确实是一种查找数据的高效方式,但是MySQL也看看有使用索引来直接获取列的数据,这样就不再需要读取数据行。如果索引的叶子节点中已经包含要查询的数据,那么还有什么必要再回表查询呢?如果一个索引包含(或者说覆盖)所有需要查询的字段的值,我们就称之为“覆盖索引”。

当发起一个被索引覆盖的查询(也叫做索引覆盖查询)时,在EXPLAIN的Extra列可以看到“Using index”的信息。

 

 

 

 

 

 

 

 

 

 

对分页进行优化:

SELECT urlID,name,mobel,address FROM tb_test1 ORDER BY urlID ASC LIMIT 1000,10;

SELECT urlID,name,mobel,address FROM tb_test1 INNER JOIN(SELECT urlID FROM tb_test1 ORDER BY urlID ASC LIMIT 1000,10) AS uID USING(urlID);

 

我们把第二种检索方法叫做延迟关联,因为延迟了对列的访问。在查询的第一阶段MySQL可以使用覆盖索引,在FROM字句的查询中找到匹配的urlID,然后根据这些urlID值在外层查询匹配获取需要的列值。

 

各自扫描行数:

EXPLAIN SELECT urlID,name,mobel,address FROM tb_test1 ORDER BY urlID ASC LIMIT 1000,10\G

 

 

 

 

EXPLAIN SELECT urlID,name,mobel,address FROM tb_test1 INNER JOIN(SELECT urlID FROM tb_test1 ORDER BY urlID ASC LIMIT 1000,10) AS uID USING(urlID)\G

 

 

 

 

结尾

最后我们讲一下EXPLAIN:EXPLAIN是用来获取关于查询执行计划的信息,以及如何解释输出的。EXPLAIN命令是查看查询优化器如何决定执行查询的主要方法。这跟功能有局限性,并不总会说出真相,但它的输出是可以获取的最好信息,值得花时间了解,因为可以学习到查询是如何执行的。学会解释EXPLAIN将帮助你了解MySQL优化器是如何工作的。

EXPLAIN中的列:

EXPLAIN的输出总是有相同的列,可变的是行数及内容。下面我们一起来学习EXPLAIN结果中每一列的意义。注意:输出中的行以MySQL实际执行的查询部分的顺序出现,而这跟顺序不总是与其在原始SQL中的相一致。

id列

这一列总是包含一个编号,标识SELECT所属的行。如果在语句当中没有子查询或联合,那么只会有唯一的SELECT,于是每一行在这跟列中都将显示一个1。否则内层的SELECT语句一般会顺序编号,对应于其在原始语句中的位置。

 

select_type列

这一列显示了对应行是简单还是复杂的SELECT。SIMPLE值意味着查询不包括子查询和UNION。如果查询有任何复杂的子部分,则最外层部分标记为PRIMARY,其他部分标记如下。

SUBQUERY

     包含在SELECT列表中的子查询中的SELECT(换句话说,不在FROM字句中)标记为SUBQUERY。

DERIVED

DERIVED值用来表示包含在FROM字句的子查询中的SELECT,MySQL会地柜执行并将结果放到一个临时表中。服务器内部称其“派生表”,因此该临时表是从子查询中派生出来的。

UNION

在UNION中的第二个和随后的SELECT被标记为UNION。第一个SELECT被标记就好像它以部分外查询来执行。这就是之前的例子中在UNION中的第一个SELECT显示为PRIMARY的原因。如果UNION被FROM字句中的子查询包含,那么它的第一个SELECT会被标记为DERIVED。

UNION RESULT

用来从UNION的匿名临时表检索结果,SELECT被标记为UNION RESULT.

除了这些值,SUBQUERY和UNION还可以被标记为DEPENDENT和UNCACHABLE。 DEPENDENT意味着SELECT依赖于外层查询中发现的数据;UNCACHEABLE意味着SELECT中的某些特性阻止结果被缓存于一个Item_cache中。

 

table列

中一列显示了对应的正在访问的哪跟表,在通常情况下,它相当明了:它就是那跟表,或是该表的别名。

当FROM 子句中有子查询或有UNION时,table列会变得复杂的多,在这些场景下,确实没有一个“表”可以参考到,因为MySQL创建的匿名临时表仅在查询执行过程中存在。此项大家了解一下就可以了,具体情况可以取参考一下相关资料,下面我们来重点将一下type列。

type列

MySQL用户手册上说明这一列显示了“关联类型”,但我们认为更准确的说法是访问类型,换言之就是MySQL决定如何查找表中的行。下面是最重要的访问方法,一次从最差到最优。

ALL

这就是人们所称的全表扫描,通常意味着MySQL必须扫描整张表,从头到尾,去找到需要的行。(这里也有跟例外,例如在查询里使用了LIMIT或者Extra列显示“Using distinct/not exists”。)

index

这个跟全表扫描一样,只是MySQL扫描表时按索引次序进行而不是行。它的主要优点是避免了排序;最大的缺点是要承担按索引次序读取整个表的开销。这通常意味着若是按随机次序访问行,开销将会非常大。

如果在Extra列中看到“Using index”,说明MySQL正在使用覆盖索引,它只扫描索引的数据,而不是按索引次序的每一行。它比按索引次序全表扫描的开销要少很多。

Range

范围扫描就是一个有限制的索引扫描,它开始于索引里的某一点,返回匹配这跟值域的行。这笔全索引扫描好一些,因此它用不着便利全部索引。显而易见的范围扫描是带有BWTWEEN或WHERE子句里带有>的查询。

当MySQL使用索引去查找一系列值时,例如IN()和OR列表,也会显示为范围扫描。然而,这两者其实是相当不同的访问类型,在性能上有重要的差异。

ref

这是一种索引访问,它返回所有的匹配某跟单个的值的行。然而它可能会找到多个符合条件的行,因此,它是查找和扫描的混合体。此类索引访问只有当使用非唯一性索引或者唯一性索引的非唯一性前缀时才会发生。把它叫做ref是因为索引要跟某跟参考值相比较。这跟参考值或者是一个常数,或者是来自多表查询前一个表里的结果值。

ref_or_null是ref之上的一个变体,它意味着MySQL必须在初次查找的结果李进行第二次查找,以找出NULL挑目录。

eq_ref

使用这种索引查找,MySQL知道最多只返回一个符合条件的记录。这种访问方法可以在MySQL使用主键或唯一性索引查找时看到,它会将它们与某跟参考值做比较。MySQL对于这类访问类型的优化做的非常好,因为它知道无须估计匹配行的范围或在找到匹配行后再继续查找。

const,system

当MySQL能对查询的某部分进行优化并将其转换成一个常量时,它就会使用这些访问类型。举例来说,如果你通过将某一行的主键放入WHERE子句里的方式来选取此行的主键,MySQL就能把这个查询转换为一个常量。然后就可以高效地将表从连接执行中移除。

NULL

这种访问方式意味着MySQL能在优化阶段分解查询语句,在执行阶段甚至用不着再访问表或者索引。例如,从一个索引列里选取最小值可以通过单独查找索引来完成,不需要再执行时访问表。

possible_keys列

这一列显示了查询可以使用哪些索引,这是基于查询访问的列和使用的比较操作符来判断的。这个列表是在优化过程的早期创建的,因此有些罗列出来的索引可能对于后续优化过程是没有用的。

key列

这一列显示了MySQL决定采用哪跟索引来优化对该表的访问。如果该索引没有出现在possible_keys列中,那么MySQL选用它是出于另外的原因——例如,它可能选择了一个覆盖索引,哪怕没有WHERE子句。

换句话说,possible_keys揭示了哪一个索引能有助于高效地进行查找,而key显示的是优化采用哪一个索引可以最小化查询成本。

key_len列

该列显示了MySQL在索引里使用的字节数。如果MySQL正在使用的只是索引里的某些列,那么可以用这跟值来算出具体是哪些列。

ref列

这一列显示了之前的表在key列记录的索引中查找所用的列或常量。

row列

这一列是MySQL估计为了找到所需的行而要读取的行数。这个数字是内嵌循环关联计划里的循环数目。也就是说它不是MySQL认为它最终要从表里读取出来的行数,而是MySQL为了找到符合查询的每一点上标准的那些行而必须读取的行的平均数。

根据表的统计信息和索引的选用情况,这跟估算可能不是很准确。

 

Extra列

这一列包含的是不适合在其他列显示的额外信息。MySQL用户手册里记录了大多数可以在这里出现的值。

“Using  index”

此值表示MySQL将使用覆盖索引,以避免访问表。不用把覆盖索引和index访问类型弄混了。

“Using where”

    这意味着MySQL服务器将存储引起检索行后再进行过滤。许多WHERE条件里涉及索引中的列,当它读取索引时,就能被存储引擎检验,因此不是所有带WHERE子句的查询都会显示“Using where”。有时”Using where”的出现就是一个暗示:查询可受益不同的索引。

“Using temporary”

这意味着MySQL在对查询结果排序时会使用一个临时表。

“Using filesort”

这意味则会MySQL会对结果使用一个外部索引排序,而不是索引次序从表里读取行。

“Rang checked for each record(index map:N)”

这跟值意味着没有好用的索引,新的索引将在联接的每一行上重新估算。N是显示在possible_key列中索引的位图,并且是冗余的。

 

 

五、      nginx优化

配置方面

服务器缓存

六、      集群及综合优化

lvs负载均衡

web服务器集群,数据库读写分离,分表分库,缓存服务器,全部集体搭建配合工作

集群假设(负载均衡+缓存服务器+集群服务器+数据库服务器+keeplive心跳线)

加速cdn 消息队列排队原理

七、      Linux

cpu调优

内存的调优

推荐阅读