前端優化 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官方提供的
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代碼優化部分
第一章:程序優化部分(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框架,框架本身都會消耗一定的資源。
文件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讀取文件效率最高
相對來說,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。
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列中索引的位圖,並且是冗余的。
配置方面
服務器緩存
lvs負載均衡
web服務器集群,數據庫讀寫分離,分表分庫,緩存服務器,全部集體搭建配合工作
集群假設(負載均衡+緩存服務器+集群服務器+數據庫服務器+keeplive心跳線)
加速cdn 消息隊列排隊原理
cpu調優
內存的調優
本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。