MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

這篇文章主要講解了“MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法”吧!

專注于為中小企業(yè)提供成都做網(wǎng)站、網(wǎng)站建設(shè)服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)墨玉免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動了近千家企業(yè)的穩(wěn)健成長,幫助中小企業(yè)通過網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。

MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

0 存儲引擎介紹

MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法
myisam存儲:如果表對事務(wù)要求不高,同時是以查詢和添加為主的,我們考慮使用myisam存儲引擎,比如bbs 中的發(fā)帖表,回復(fù)表

  • 需要定時進(jìn)行碎片整理(因?yàn)閯h除的數(shù)據(jù)還是存在):optimize table table_name;
    MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

InnoDB存儲:對事務(wù)要求高,保存的數(shù)據(jù)都是重要數(shù)據(jù),我們建議使用INN0DB,比如訂單表,賬號表.

面試問MyISAM和INNODB的區(qū)別

  • 1.事務(wù)安全

  • 2.查詢和添加速度

  • 3.支持全文索引

  • 4.鎖機(jī)制

  • 5.外鍵MyISAM不支持外鍵,INNODB 支持外鍵.

Mermory存儲:比如我們數(shù)據(jù)變化頻繁,不需要入庫,同時又頻繁的查詢和修改,我們考慮使用memory

查看mysql以提供什么存儲引擎show engines;

查看mysql當(dāng)前默認(rèn)的存儲引擎show variables like '%storage_engine%';

1 SQL性能分析

SQL性能下降原因

  • 1、查詢語句寫的爛

  • 2、索引失效(數(shù)據(jù)變更)

  • 3、關(guān)聯(lián)查詢太多join(設(shè)計缺陷或不得已的需求)

  • 4、服務(wù)器調(diào)優(yōu)及各個參數(shù)設(shè)置(緩沖、線程數(shù)等)

通常SQL調(diào)優(yōu)過程

  • 觀察,至少跑1天,看看生產(chǎn)的慢SQL情況。

  • 開啟慢查詢?nèi)罩荆O(shè)置闕值,比如超過5秒鐘的就是慢SQL,并將它抓取出來。

  • explain + 慢SQL分析。

  • show profile。

  • 運(yùn)維經(jīng)理 or DBA,進(jìn)行SQL數(shù)據(jù)庫服務(wù)器的參數(shù)調(diào)優(yōu)。

總結(jié)

  • 1、慢查詢的開啟并捕獲

  • 2、explain + 慢SQL分析

  • 3、show profile查詢SQL在Mysql服務(wù)器里面的執(zhí)行細(xì)節(jié)和生命周期情況

  • 4、SQL數(shù)據(jù)庫服務(wù)器的參數(shù)調(diào)優(yōu)

2 常見通用的JOIN查詢

SQL執(zhí)行加載順序

手寫順序

SELECT DISTINCT
    <select_list>FROM
    <left_table> <join_type>JOIN <right_table> on <join_codition> //join_codition:比如員工的部門ID和部門表的主鍵id相同WHERE
    <where_condition>GROUP BY
    <group_by_list>HAVING
    <having_condition>ORDER BY
    <order_by_condition>LIMIT
    <limit_number>

MySQL機(jī)讀順序

1 FROM <left_table>
2 ON <join_condition>
3 <join_type> JOIN <right_table>
4 WHERE <where_condition>
5 GROUP BY <group_by_list>
6 HAVING <having_condition>
7 SELECT
8 DISTINCT <select_list>
9 ORDER BY <order_by_condition>
10 LIMIT <limit_number>

總結(jié)

  • 運(yùn)行順序一上一下
    MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

七種JOIN寫法

MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法
創(chuàng)建表插入數(shù)據(jù)(左右主外鍵相連):

CREATE TABLE tbl_dept(
	id INT(11) NOT NULL AUTO_INCREMENT,
	deptName VARCHAR(30) DEFAULT NULL,
	locAdd VARCHAR(40) DEFAULT NULL,
	PRIMARY KEY(id))ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;//設(shè)置存儲引擎,主鍵自動增長和默認(rèn)文本字符集CREATE TABLE tbl_emp (
	id INT(11) NOT NULL AUTO_INCREMENT,
	NAME VARCHAR(20) DEFAULT NULL,
	deptId INT(11) DEFAULT NULL,
	PRIMARY KEY (id),
	KEY fk_dept_Id (deptId)
	#CONSTRAINT 'fk_dept_Id' foreign key ('deptId') references 'tbl_dept'('Id'))ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;INSERT INTO tbl_dept(deptName,locAdd) VALUES('RD',11);INSERT INTO tbl_dept(deptName,locAdd) VALUES('HR',12);INSERT INTO tbl_dept(deptName,locAdd) VALUES('MK',13);INSERT INTO tbl_dept(deptName,locAdd) VALUES('MIS',14);INSERT INTO tbl_dept(deptName,locAdd) VALUES('FD',15);INSERT INTO tbl_emp(NAME,deptId) VALUES('z3',1);INSERT INTO tbl_emp(NAME,deptId) VALUES('z4',1);INSERT INTO tbl_emp(NAME,deptId) VALUES('z5',1);INSERT INTO tbl_emp(NAME,deptId) VALUES('w5',2);INSERT INTO tbl_emp(NAME,deptId) VALUES('w6',2);INSERT INTO tbl_emp(NAME,deptId) VALUES('s7',3);INSERT INTO tbl_emp(NAME,deptId) VALUES('s8',4);INSERT INTO tbl_emp(NAME,deptId) VALUES('s9',51);#查詢執(zhí)行后結(jié)果mysql> select * from tbl_dept;+----+----------+--------+| id | deptName | locAdd |+----+----------+--------+|  1 | RD       | 11     ||  2 | HR       | 12     ||  3 | MK       | 13     ||  4 | MIS      | 14     ||  5 | FD       | 15     |+----+----------+--------+5 rows in set (0.00 sec)mysql> select * from tbl_emp;+----+------+--------+| id | NAME | deptId |+----+------+--------+|  1 | z3   |      1 ||  2 | z4   |      1 ||  3 | z5   |      1 ||  4 | w5   |      2 ||  5 | w6   |      2 ||  6 | s7   |      3 ||  7 | s8   |      4 ||  8 | s9   |     51 |+----+------+--------+8 rows in set (0.00 sec)

1、inner join:只有 deptId 和 id 的共有部分
MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

2、left join(全A):前七條共有數(shù)據(jù);第八條a表獨(dú)有數(shù)據(jù),b表補(bǔ)null
MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

3、right join(全B):前七條共有數(shù)據(jù);第八條b表獨(dú)有數(shù)據(jù),a表補(bǔ)null
MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法
4、左join獨(dú)A:表A獨(dú)有部分
MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法
5、右join獨(dú)B:表B獨(dú)有部分
MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法
6、full join:MySQL不支持full join,用全a+全b,union去重中間部分

  • union關(guān)鍵字可以合并去重

MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法
7、A、B各自獨(dú)有集合
MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

3 索引介紹

3.1 索引是什么

MySQL官方對索引的定義為:索引(Index)是幫助MySQL高效獲取數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu)(索引的本質(zhì)是數(shù)據(jù)結(jié)構(gòu),排序+查詢兩種功能)。

索引的目的在于提高查詢效率,可以類比字典。

如果要查“mysql”這個單詞,我們肯定需要定位到m字母,然后從下往下找到y(tǒng)字母,再找到剩下的sql。

如果沒有索引,那么你可能需要逐個逐個尋找,如果我想找到Java開頭的單詞呢?或者Oracle開頭的單詞呢?

是不是覺得如果沒有索引,這個事情根本無法完成?

索引可以理解為排好序的快速查找數(shù)據(jù)結(jié)構(gòu)

下圖就是一種可能的索引方式示例:
MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法
假如:找4號這本書,掃碼得到對應(yīng)的編號為91,91比34大往右邊找,91比89大往右邊找,然后找到(比較三次后就可以找到,然后檢索出對應(yīng)的物理地址)

為了加快Col2的查找,可以維護(hù)一個右邊所示的二叉查找樹,每個節(jié)點(diǎn)分別包含索引鍵值和一個指向?qū)?yīng)數(shù)據(jù)記錄物理地址的指針,這樣就可以運(yùn)用二叉查找在一定的復(fù)雜度內(nèi)獲取到相應(yīng)數(shù)據(jù),從而快速的檢索出符合條件的記錄

結(jié)論在數(shù)據(jù)之外,數(shù)據(jù)庫系統(tǒng)還維護(hù)著滿足特定查找算法的數(shù)據(jù)結(jié)構(gòu),這些數(shù)據(jù)結(jié)構(gòu)以某種方式引用(指向)數(shù)據(jù),這樣就可以在這些數(shù)據(jù)結(jié)構(gòu)上實(shí)現(xiàn)高級查找算法。這種數(shù)據(jù)結(jié)構(gòu),就是索引

一般來說索引本身也很大,不可能全部存儲在內(nèi)存中,因此索引往往以索引文件的形式存儲的磁盤上。

我們平常所說的索引,如果沒有特別指明,都是指B樹(多路搜索樹,并不一定是二叉的)結(jié)構(gòu)組織的索引。其中聚集索引,次要索引,覆蓋索引,復(fù)合索引,前綴索引,唯一索引默認(rèn)都是使用B+樹索引,統(tǒng)稱索引。當(dāng)然,除了B+樹這種類型的索引之外,還有哈稀索引(hash index)等

3.2 索引優(yōu)劣勢

優(yōu)勢

  • 類似大學(xué)圖書館建書目索引,提高數(shù)據(jù)檢索的效率,降低數(shù)據(jù)庫的IO成本。

  • 通過索引列對數(shù)據(jù)進(jìn)行排序,降低數(shù)據(jù)排序的成本,降低了CPU的消耗。

劣勢

  • 實(shí)際上索引也是一張表,該表保存了主鍵與索引字段,并指向?qū)嶓w表的記錄,所以索引列也是要占用空間的(占空間)

  • 雖然索引大大提高了查詢速度,同時卻會降低更新表的速度,如對表進(jìn)行INSERT、UPDATE和DELETE。因?yàn)楦卤頃r,MySQL不僅要保存數(shù)據(jù),還要保存一下索引文件每次更新添加了索引列的字段,都會調(diào)整因?yàn)楦滤鶐淼逆I值變化后的索引信息。

  • 索引只是提高效率的一個因素,如果你的MysQL有大數(shù)據(jù)量的表,就需要花時間研究建立最優(yōu)秀的索引,或優(yōu)化查詢

3.3 索引分類和建索引命令語句

主鍵索引:索引值必須是唯一的,且不能為NULL

  • 第一種:CREATE TABLE table_name(id int PRIMARY KEY aoto_increment,name varchar(10));

  • 第二種: ALTER TABLE table_name ADD PRIMARY KEY (columnName);

普通索引:索引值可出現(xiàn)多次

  • 第一種:CREATE INDEX index_name on table_name(columnName);

  • 第二種:ALTER TABLE table_name ADD INDEX index_name (columnName);

全文索引:主要是針對文本的檢索,如:文章,全文索引只針對MyISAM引擎有效,并且只針對英文內(nèi)容生效

  • 建表時創(chuàng)建

    #建表CREATE TABLE articles(
    	id INT UNSIGNED ATUO_INCREMENT NOT NULL PRIMARY KEY,
    	title VARCHAR(200),
    	body TEXT,
    	FULLTEXT(title,body))engine=myisam charset utf8;	#指定引擎#使用select * from articles where match(title,body) against('英文內(nèi)容'); #只針對英語內(nèi)容生效#說明#1、在mysql中fultext索引只針對 myisam 生效#2、mysq1自己提供的flltext只針對英文生效->sphinx (coreseek)技術(shù)處理中文工#3、使用方法是match(字段名...) against(‘關(guān)鍵字')#4、全文索引一個叫停止詞,因?yàn)樵谝粋€文本中創(chuàng)建索引是一個無窮大的數(shù),因此對一些常用詞和字符就不會創(chuàng)建,這些詞稱為停止詞
  • ALTER TABLE table_name ADD FULLTEXT index_name (columnName);

唯一索引:索引列的值必須唯一,但允許有空值NULL,并可以有多個。

  • 第一種: CREATE UNIQUE INDEX index_name ON table_name(columnName);

  • 第二種:ALTER TABLE table_name ADD UNIQUE INDEX index_name ON (columnName);

單值索引:即一個索引只包含單個列,一個表可以有多個單列索引。

  • 第一種: CREATE INDEX index_name ON table_name(columnName);

  • 第二種:ALTER TABLE table_name ADD INDEX index_name ON (columnName);

select * from user where name='';
//經(jīng)常查name字段,為其建索引create index idx_user_name on user(name);

復(fù)合索引:即一個索引包含多個列

  • 第一種: CREATE INDEX index_name ON table_name(columnName1,columnName2...);

  • 第二種:ALTER TABLE table_name ADD INDEX index_name ON (columnName1,columnName2...);

select * from user where name='' and email='';
//經(jīng)常查name和email字段,為其建索引create index idx_user_name on user(name, email);

查詢索引

  • 第一種:SHOW INDEX FROM table_name;

  • 第二種:SHOW KEYS FROM table_name;

刪除索引

  • 第一種: DROP INDEX index_name ON table_name;

  • 第二種:ALTER TABLE table_name DROP INDEX index_name;

  • 刪除主鍵索引:ALTER TBALE table_name DROP PRIMARY KEY;

3.4 索引結(jié)構(gòu)與檢索原理

MySQL索引結(jié)構(gòu)

  • BTree索引

  • Hash索引

  • full-text全文索引

  • R-Tree索引
    MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

初始化介紹

一顆b+樹,淺藍(lán)色的塊我們稱之為一個磁盤塊,可以看到每個磁盤塊包含幾個數(shù)據(jù)項(深藍(lán)色所示)和指針(黃色所示),如磁盤塊1包含數(shù)據(jù)項17和35,包含指針P1、P2、P3,
P1表示小于17的磁盤塊,P2表示在17和35之間的磁盤塊,P3表示大于35的磁盤塊。

真實(shí)的數(shù)據(jù)存在于葉子節(jié)點(diǎn):3、5、9、10、13、15、28、29、36、60、75、79、90、99。

非葉子節(jié)點(diǎn)只不存儲真實(shí)的數(shù)據(jù),只存儲指引搜索方向的數(shù)據(jù)項,如17、35并不真實(shí)存在于數(shù)據(jù)表中。

查找過程

如果要查找數(shù)據(jù)項29,那么首先會把磁盤塊1由磁盤加載到內(nèi)存,此時發(fā)生一次IO。在內(nèi)存中用二分查找確定 29 在 17 和 35 之間,鎖定磁盤塊1的P2指針,內(nèi)存時間因?yàn)榉浅6蹋ㄏ啾却疟P的IO)可以忽略不計,通過磁盤塊1的P2指針的磁盤地址把磁盤塊3由磁盤加載到內(nèi)存,發(fā)生第二次IO,29 在 26 和 30 之間,鎖定磁盤塊3的P2指針,通過指針加載磁盤塊8到內(nèi)存,發(fā)生第三次IO,同時內(nèi)存中做二分查找找到29,結(jié)束查詢,總計三次IO

真實(shí)的情況是,3層的b+樹可以表示上百萬的數(shù)據(jù),如果上百萬的數(shù)據(jù)查找只需要三次IO,性能提高將是巨大的,如果沒有索引,每個數(shù)據(jù)項都要發(fā)生一次IO,那么總共需要百萬次的IO,顯然成本非常非常高

3.5 哪些情況適合建索引

  • 主鍵自動建立唯一索引

  • 頻繁作為查詢條件的字段應(yīng)該創(chuàng)建索引

  • 查詢中與其它表關(guān)聯(lián)的字段,外鍵關(guān)系建立索引

  • 單鍵/組合索引的選擇問題,who?(在高并發(fā)下傾向創(chuàng)建組合索引)

  • 查詢中排序的字段,排序字段若通過索引去訪問將大大提高排序速度

  • 查詢中統(tǒng)計或者分組字段

3.6 哪些情況不適合建索引

  • Where條件里用不到的字段不創(chuàng)建索引

  • 表記錄太少(300w以上建)

  • 經(jīng)常增刪改的表(提高了查詢速度,同時卻會降低更新表的速度,如對表進(jìn)行INSERT、UPDATE和DELETE。因?yàn)楦卤頃r,MySQL不僅要保存數(shù)據(jù),還要保存一下索引文件)

  • 數(shù)據(jù)重復(fù)且分布平均的表字段,因此應(yīng)該只為最經(jīng)常查詢和最經(jīng)常排序的數(shù)據(jù)列建立索引。注意,如果某個數(shù)據(jù)列包含許多重復(fù)的內(nèi)容,為它建立索引就沒有太大的實(shí)際效果。(比如:國籍、性別)

假如一個表有10萬行記錄,有一個字段A只有T和F兩種值,且每個值的分布概率天約為50%,那么對這種表A字段建索引一般不會提高數(shù)據(jù)庫的查詢速度。

索引的選擇性是指索引列中不同值的數(shù)目與表中記錄數(shù)的比。如果一個表中有2000條記錄,表索引列有1980個不同的值,那么這個索引的選擇性就是1980/2000=0.99。一個索引的選擇性越接近于1,這個索引的效率就越高

4 性能分析

4.1 性能分析前提知識

MySQL Query Optimizer(查詢優(yōu)化器)[?kw??ri] [??pt?ma?z?]
Mysql中專門負(fù)責(zé)優(yōu)化SELECT語句的優(yōu)化器模塊,主要功能:通過計算分析系統(tǒng)中收集到的統(tǒng)計信息,為客戶端請求的Query提供他認(rèn)為最優(yōu)的執(zhí)行計劃(他認(rèn)為最優(yōu)的數(shù)據(jù)檢索方式,但不見得是DBA認(rèn)為是最優(yōu)的,這部分最耗費(fèi)時間)

當(dāng)客戶端向MySQL請求一條Query,命令解析器模塊完成請求分類,區(qū)別出是SELECT并轉(zhuǎn)發(fā)給MySQL Query Optimizer時,MySQL Query Optimizer首先會對整條Query進(jìn)行優(yōu)化,處理掉一些常量表達(dá)式的預(yù)算直接換算成常量值。并對Query中的查詢條件進(jìn)行簡化和轉(zhuǎn)換,如去掉一些無用或顯而易見的條件、結(jié)構(gòu)調(diào)整等。然后分析Query 中的 Hint信息(如果有),看顯示Hint信息是否可以完全確定該Query的執(zhí)行計劃。如果沒有Hint 或Hint信息還不足以完全確定執(zhí)行計劃,則會讀取所涉及對象的統(tǒng)計信息,根據(jù)Query進(jìn)行寫相應(yīng)的計算分析,然后再得出最后的執(zhí)行計劃

MySQL常見瓶頸

  • CPU:CPU在飽和的時候一般發(fā)生在數(shù)據(jù)裝入內(nèi)存或從磁盤上讀取數(shù)據(jù)時候

  • IO:磁盤I/O瓶頸發(fā)生在裝入數(shù)據(jù)遠(yuǎn)大于內(nèi)存容量的時候

  • 服務(wù)器硬件的性能瓶頸:top,free,iostat和vmstat來查看系統(tǒng)的性能狀態(tài)

4.2 Explain使用簡介

使用EXPLAIN關(guān)鍵字可以模擬優(yōu)化器執(zhí)行SQL查詢語句,從而知道MySQL是如何處理你的SQL語句的。分析你的查詢語句或是表結(jié)構(gòu)的性能瓶頸

官網(wǎng)地址

Explain的作用

  • 表的讀取順序

  • 數(shù)據(jù)讀取操作的操作類型

  • 哪些索引可以使用

  • 哪些索引被實(shí)際使用

  • 表之間的引用

  • 每張表有多少行被優(yōu)化器查詢

使用Explain

  • explain + sql語句

  • 執(zhí)行計劃包含的信息(重點(diǎn)) :| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |

mysql> select * from tbl_emp;
+----+------+--------+
| id | NAME | deptId |
+----+------+--------+
|  1 | z3   |      1 |
|  2 | z4   |      1 |
|  3 | z5   |      1 |
|  4 | w5   |      2 |
|  5 | w6   |      2 |
|  6 | s7   |      3 |
|  7 | s8   |      4 |
|  8 | s9   |     51 |
+----+------+--------+
8 rows in set (0.00 sec)

mysql> explain select * from tbl_emp;
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------+
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------+
|  1 | SIMPLE      | tbl_emp | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    8 |   100.00 | NULL  |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

4.3 執(zhí)行計劃包含的信息字段解釋(重中之重)

執(zhí)行計劃包含的信息(重點(diǎn)) :| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |

面試重點(diǎn)id、type、key、rows、Extra

id(表的讀取順序)

select查詢的序列號,包含一組數(shù)字,表示查詢中執(zhí)行select子句或操作表的順序

三種情況

  • 1、id相同,執(zhí)行順序由上至下(t1、t3、t2)
    MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

  • 2、id不同,如果是子查詢,id的序號會遞增,id值越大優(yōu)先級越高,越先被執(zhí)行(t3、t1、t2)
    MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

  • 3、id相同不同,同時存在。先走數(shù)字大的,數(shù)字相同的由上至下(t3、s1、t2)
    MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

select_type( 數(shù)據(jù)讀取操作的操作類型)

查詢的類型,主要是用于區(qū)別普通查詢、聯(lián)合查詢、子查詢等的復(fù)雜查詢。
MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

  • SIMPLE [?s?npl] :簡單的select查詢,查詢中不包含子查詢或者UNION

  • PRIMARY:查詢中若包含任何復(fù)雜的子部分,最外層查詢則被標(biāo)記為(最后加載的那個)

  • SUBQUERY [?kw??ri] :在SELECT或WHERE列表中包含了子查詢

  • DERIVED [d??ra?vd]:在FROM列表中包含的子查詢被標(biāo)記為DERIVED(衍生)MySQL會遞歸執(zhí)行這些子查詢,把結(jié)果放在臨時表里

  • UNION [?ju?ni?n]:若第二個SELECT出現(xiàn)在UNION之后,則被標(biāo)記為UNION;若UNION包含在FROM子句的子查詢中外層SELECT將被標(biāo)記為:DERIVED

  • UNION RESULT [r??z?lt] :從UNION表獲取結(jié)果的SELECT(兩個select語句用UNION合并)

table(顯示執(zhí)行的表名)

顯示這一行的數(shù)據(jù)是關(guān)于哪張表的

type(訪問類型排列)

顯示查詢使用了何種類型

訪問類型排列system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index >ALL

type常用八種類型
MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

結(jié)果值從最好到最壞依次是(重點(diǎn)):system > const > eq_ref > ref > range > index > ALL

一般來說,得保證查詢至少達(dá)到range級別,最好能達(dá)到ref

詳細(xì)說明

  • system:表只有一行記錄(等于系統(tǒng)表),這是const類型的特列,平時不會出現(xiàn),這個也可以忽略不計。

  • const:表示通過索引一次就找到了,const用于比較primary key或者unique索引。因?yàn)橹黄ヅ湟恍袛?shù)據(jù),所以很快如將主鍵置于where列表中,MySQL就能將該查詢轉(zhuǎn)換為一個常量。
    MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

  • eq_ref:唯一性索引掃描,對于每個索引鍵,表中只有一條記錄與之匹配。常見于主鍵或唯一索引掃描。
    MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

  • ref:非唯一性索引掃描,返回匹配某個單獨(dú)值的所有行,本質(zhì)上也是一種索引訪問,它返回所有匹配某個單獨(dú)值的行,然而,它可能會找到多個符合條件的行,所以他應(yīng)該屬于查找和掃描的混合體
    MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

  • range:只檢索給定范圍的行,使用一個索引來選擇行。key列顯示使用了哪個索引一般就是在你的where語句中出現(xiàn)了between、<、>、in等的查詢。這種范圍掃描索引掃描比全表掃描要好,因?yàn)樗恍枰_始于索引的某一點(diǎn),而結(jié)束語另一點(diǎn),不用掃描全部索引
    MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

  • index:Full Index Scan,index與ALL區(qū)別為index類型只遍歷索引列。這通常比ALL快,因?yàn)樗饕募ǔ1葦?shù)據(jù)文件?。ㄒ簿褪钦f雖然all和Index都是讀全表,但index是從索引中讀取的,而all是從硬盤中讀的)
    MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

  • all:Full Table Scan,將遍歷全表以找到匹配的行
    MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法
    工作案例:經(jīng)理這條SQL我跑了一下Explain分析,在系統(tǒng)上可能會有ALL全表掃描的情況,建議嘗試一下優(yōu)化。我把這條SQL改了改,我優(yōu)化后是這么寫,這個效果已經(jīng)從ALL變成了…

possible_keys(哪些索引可以使用)

顯示可能應(yīng)用在這張表中的索引,一個或多個。查詢涉及到的字段火若存在索引,則該索引將被列出,但不一定被查詢實(shí)際使用(系統(tǒng)認(rèn)為理論上會使用某些索引)

key(哪些索引被實(shí)際使用)

實(shí)際使用的索引。如果為NULL,則沒有使用索引(要么沒建,要么建了失效)

查詢中若使用了覆蓋索引,則該索引僅出現(xiàn)在key列表中

覆蓋索引:建的索引字段和查詢的字段一致,如下圖
MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

key_len(消耗的字節(jié)數(shù))

表示索引中使用的字節(jié)數(shù),可通過該列計算查詢中使用的索引的長度。在不損失精確性的情況下,長度越短越好

key_len顯示的值為索引字段的最大可能長度,并非實(shí)際使用長度,即key_len是根據(jù)表定義計算而得,不是通過表內(nèi)檢索出的

MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

ref(表之間的引用)

顯示索引的哪一列被使用了,如果可能的話,是一個常數(shù)。哪些列或常量被用于查找索引列上的值。
MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

rows(每張表有多少行被優(yōu)化器查詢)

根據(jù)表統(tǒng)計信息及索引選用情況,大致估算出找到所需的記錄所需要讀取的行數(shù)(越小越好)

未建索引時
MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法
建索引后:掃描行數(shù)減少
MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

Extra [?ekstr?]

包含不適合在其他列中顯示但十分重要的額外信息

信息種類:Using filesort 、Using temporary 、Using index 、Using where 、Using join buffer 、impossible where 、select tables optimized away 、distinct

Using filesort(需要優(yōu)化)

說明mysql會對數(shù)據(jù)使用一個外部的索引排序,而不是按照表內(nèi)的索引順序進(jìn)行讀取。MySQL中無法利用索引完成的排序操作稱為"文件排序"
MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

Using temporary(需要優(yōu)化)

使了用臨時表保存中間結(jié)果,MysQL在對查詢結(jié)果排序時使用臨時表。常見于排序order by和分組查詢group by

MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

Using index(good)

表示相應(yīng)的select操作中使用了覆蓋索引(Covering Index),避免訪問了表的數(shù)據(jù)行,效率不錯!

  • 情況一:
    MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

  • 情況二:
    MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

覆蓋索引 / 索引覆蓋(Covering Index)。

  • 理解方式一:就是select的數(shù)據(jù)列只用從索引中就能夠取得,不必讀取數(shù)據(jù)行,MySQL可以利用索引返回select列表中的字段,而不必根據(jù)索引再次讀取數(shù)據(jù)文件,換句話說查詢列要被所建的索引覆蓋。
    MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

  • 理解方式二:索引是高效找到行的一個方法,但是一般數(shù)據(jù)庫也能使用索引找到一個列的數(shù)據(jù),因此它不必讀取整個行。畢竟索引葉子節(jié)點(diǎn)存儲了它們索引的數(shù)據(jù);當(dāng)能通過讀取索引就可以得到想要的數(shù)據(jù),那就不需要讀取行了。一個索引包含了(或覆蓋了)滿足查詢結(jié)果的數(shù)據(jù)就叫做覆蓋索引。

注意

  • 如果要使用覆蓋索引,一定要注意select列表中只取出需要的列,不可select*

  • 因?yàn)槿绻麑⑺凶侄我黄鹱鏊饕龝?dǎo)致索引文件過大,查詢性能下降

Using where:表明使用了where過濾。

Using join buffer:使用了連接緩存
MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

impossible where:where子句的值總是false,不能用來獲取任何元組
MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

select tables optimized away

在沒有GROUPBY子句的情況下,基于索引優(yōu)化MIN/MAX操作,或者對于MyISAM存儲引擎優(yōu)化COUNT(*)操作,不必等到執(zhí)行階段再進(jìn)行計算,查詢執(zhí)行計劃生成的階段即完成優(yōu)化。

distinct

優(yōu)化distinct操作,在找到第一匹配的元組后即停止找同樣值的動作。

練習(xí)

寫出下圖的表的執(zhí)行順序
MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

第一行(執(zhí)行順序4):id列為1,表示是union里的第一個select,select_type列的primary表示該查詢?yōu)橥鈱硬樵?,table列被標(biāo)記為,表示查詢結(jié)果來自一個衍生表,其中derived3中3代表該查詢衍生自第三個select查詢,即id為3的select?!緎elect d1.name… 】

第二行(執(zhí)行順序2):id為3,是整個查詢中第三個select的一部分。因查詢包含在from中,所以為derived?!緎elect id,namefrom t1 where other_column=’’】

第三行(執(zhí)行順序3):select列表中的子查詢select_type為subquery,為整個查詢中的第二個select?!緎elect id from t3】

第四行(執(zhí)行順序1):select_type為union,說明第四個select是union里的第二個select,最先執(zhí)行【select name,id from t2】

第五行(執(zhí)行順序5):代表從union的臨時表中讀取行的階段,table列的<union1,4>表示用第一個和第四個select的結(jié)果進(jìn)行union操作?!緝蓚€結(jié)果union操作】

5 索引優(yōu)化

5.1 索引單表優(yōu)化案例

建表:

CREATE TABLE IF NOT EXISTS article(
	id INT(10) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
	author_id INT(10) UNSIGNED NOT NULL,
	category_id INT(10) UNSIGNED NOT NULL,
	views INT(10) UNSIGNED NOT NULL,
	comments INT(10) UNSIGNED NOT NULL,
	title VARCHAR(255) NOT NULL,
	content TEXT NOT NULL
);

INSERT INTO article(author_id,category_id,views,comments,title,content)
VALUES
(1,1,1,1,'1','1'),
(2,2,2,2,'2','2'),
(1,1,3,3,'3','3');

//查詢
mysql> select * from article;
+----+-----------+-------------+-------+----------+-------+---------+
| id | author_id | category_id | views | comments | title | content |
+----+-----------+-------------+-------+----------+-------+---------+
|  1 |         1 |           1 |     1 |        1 | 1     | 1       |
|  2 |         2 |           2 |     2 |        2 | 2     | 2       |
|  3 |         1 |           1 |     3 |        3 | 3     | 3       |
+----+-----------+-------------+-------+----------+-------+---------+
3 rows in set (0.00 sec)

案例

要求:查詢 category_id 為 1 且 comments 大于1 的情況下,views 最多的 article_id

//功能實(shí)現(xiàn)
mysql> SELECT id, author_id FROM article WHERE category_id = 1 AND comments > 1 ORDER BY views DESC LIMIT 1;
+----+-----------+
| id | author_id |
+----+-----------+
|  3 |         1 |
+----+-----------+
1 row in set (0.00 sec)

//explain分析
mysql> explain SELECT id, author_id FROM article WHERE category_id = 1 AND comments > 1 ORDER BY views DESC LIMIT 1;
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-----------------------------+
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra                       |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-----------------------------+
|  1 | SIMPLE      | article | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    3 |    33.33 | Using where; Using filesort |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-----------------------------+
1 row in set, 1 warning (0.00 sec)

結(jié)論:很顯然,type是ALL,即最壞的情況。Extra里還出現(xiàn)了Using filesort,也是最壞的情況。優(yōu)化是必須的

開始優(yōu)化

新建索引(給WHERE語句后使用的字段添加索引)

創(chuàng)建方式:

  • create index idx_article_ccv on article(category_id,comments,views);

  • ALTER TABLE 'article' ADD INDEX idx_article_ccv ( 'category_id , 'comments', 'views' );
    MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

索引用處不大,刪除:DROP INDEX idx_article_ccv ON article;

結(jié)論:

  • type變成了range,這是可以忍受的。但是extra里使用Using filesort仍是無法接受的。

  • 但是我們已經(jīng)建立了索引,為啥沒用呢?

  • 這是因?yàn)榘凑誃Tree索引的工作原理,先排序category_id,如果遇到相同的category_id則再排序comments,如果遇到相同的comments 則再排序views。

  • 當(dāng)comments字段在聯(lián)合索引里處于中間位置時,因comments > 1條件是一個范圍值(所謂range),MySQL無法利用索引再對后面的views部分進(jìn)行檢索,即range類型查詢字段后面的索引無效。

改進(jìn)

上次創(chuàng)建索引相比,這次不為comments字段創(chuàng)建索引
MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

結(jié)論:type變?yōu)榱藃ef,ref 中是 const,Extra 中的 Using filesort也消失了,結(jié)果非常理想

5.2 索引兩表優(yōu)化案例

建表:

CREATE TABLE IF NOT EXISTS class(
	id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
	card INT(10) UNSIGNED NOT NULL,
	PRIMARY KEY(id)
);

CREATE TABLE IF NOT EXISTS book(
	bookid INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
	card INT(10) UNSIGNED NOT NULL,
	PRIMARY KEY(bookid)
);

INSERT INTO class(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card) VALUES(FLOOR(1+(RAND()*20)));

INSERT INTO book(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card) VALUES(FLOOR(1+(RAND()*20)));

//查詢
mysql> select * from class;
+----+------+
| id | card |
+----+------+
|  1 |   17 |
|  2 |    2 |
|  3 |   18 |
|  4 |    4 |
|  5 |    4 |
|  6 |    8 |
|  7 |    9 |
|  8 |    1 |
|  9 |   18 |
| 10 |    6 |
| 11 |   15 |
| 12 |   15 |
| 13 |   12 |
| 14 |   15 |
| 15 |   18 |
| 16 |    2 |
| 17 |   18 |
| 18 |    5 |
| 19 |    7 |
| 20 |    1 |
| 21 |    2 |
+----+------+
21 rows in set (0.00 sec)

mysql> select * from book;
+--------+------+
| bookid | card |
+--------+------+
|      1 |    8 |
|      2 |   14 |
|      3 |    3 |
|      4 |   16 |
|      5 |    8 |
|      6 |   12 |
|      7 |   17 |
|      8 |    8 |
|      9 |   10 |
|     10 |    3 |
|     11 |    4 |
|     12 |   12 |
|     13 |    9 |
|     14 |    7 |
|     15 |    6 |
|     16 |    8 |
|     17 |    3 |
|     18 |   11 |
|     19 |    5 |
|     20 |   11 |
+--------+------+
20 rows in set (0.00 sec)

開始Explain分析:type都是all,需要優(yōu)化(總有一個表來添加索引驅(qū)動)
MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

  • 左連接為左表加索引
    MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

刪除索引:drop index y on class;

  • 左連接為右表添加索引
    MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

刪除索引:drop index Y on book;

  • 案例:如果別人建的索引位置不對,只需要自己查詢時調(diào)整左右表的順序即可
    MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

結(jié)論

  • 第二行的type變?yōu)榱藃ef,rows也變少了,優(yōu)化比較明顯。這是由左連接特性決定的。LEFT JOIN條件用于確定如何從右表搜索行,左邊一定都有,所以右邊是我們的關(guān)鍵點(diǎn),一定需要在右表建立索引(小表驅(qū)動大表)。

  • 左連接,右表加索引

  • 同理:右連接,左表加索引

5.3 索引三表優(yōu)化案例

建表:

CREATE TABLE IF NOT EXISTS phone(
	phoneid INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
	card INT(10) UNSIGNED NOT NULL,
	PRIMARY KEY(phoneid)
)ENGINE=INNODB;

INSERT INTO phone(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card) VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card) VALUES(FLOOR(1+(RAND()*20)));

//查詢
mysql> select * from phone;
+---------+------+
| phoneid | card |
+---------+------+
|       1 |   10 |
|       2 |   13 |
|       3 |   17 |
|       4 |    5 |
|       5 |   12 |
|       6 |    7 |
|       7 |   15 |
|       8 |   17 |
|       9 |   17 |
|      10 |   14 |
|      11 |   19 |
|      12 |   13 |
|      13 |    5 |
|      14 |    8 |
|      15 |    2 |
|      16 |    8 |
|      17 |   11 |
|      18 |   14 |
|      19 |   13 |
|      20 |    5 |
+---------+------+
20 rows in set (0.00 sec)

用上一節(jié)兩個表,刪除他們的索引:

MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法
三表查詢語句應(yīng)為SELECT * FROM class LEFT JOIN book ON class.card = book.card LEFT JOIN phone ON book.card = phone.card;

創(chuàng)建索引

  • 應(yīng)該為第一個LFET JOIN 的右表 book 建索引

    alter table `book` add index Y(`card`);
  • 應(yīng)該為第二個LFET JOIN 的右表 phone 建索引

    alter table `phone` add index z(`card`);

Explain分析:
MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法
后2行的 type 都是ref且總 rows優(yōu)化很好,效果不錯。因此索引最好設(shè)置在需要經(jīng)常查詢的字段中

結(jié)論

  • Join語句的優(yōu)化

  • 盡可能減少Join語句中的NestedLoop的循環(huán)總次數(shù):“永遠(yuǎn)用小結(jié)果集驅(qū)動大的結(jié)果集(比如:書的類型表驅(qū)動書的名稱表)”。

  • 優(yōu)先優(yōu)化NestedLoop的內(nèi)層循環(huán),保證Join語句中被驅(qū)動表上Join條件字段已經(jīng)被索引。

  • 當(dāng)無法保證被驅(qū)動表的Join條件字段被索引且內(nèi)存資源充足的前提下,不要太吝惜JoinBuffer的設(shè)置

5.4 索引失效

建表:

CREATE TABLE staffs(
	id INT PRIMARY KEY AUTO_INCREMENT,
	`name` VARCHAR(24) NOT NULL DEFAULT'' COMMENT'姓名',
	`age` INT NOT NULL DEFAULT 0 COMMENT'年齡',
	`pos` VARCHAR(20) NOT NULL DEFAULT'' COMMENT'職位',
	`add_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT'入職時間'
)CHARSET utf8 COMMENT'員工記錄表';

INSERT INTO staffs(`name`,`age`,`pos`,`add_time`) VALUES('z3',22,'manager',NOW());
INSERT INTO staffs(`name`,`age`,`pos`,`add_time`) VALUES('July',23,'dev',NOW());
INSERT INTO staffs(`name`,`age`,`pos`,`add_time`) VALUES('2000',23,'dev',NOW());

ALTER TABLE staffs ADD INDEX index_staffs_nameAgePos(`name`,`age`,`pos`);

索引失效案例

  • 1、全值匹配我最愛
    MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

  • 2、最佳左前綴法則(重要!):如果索引了多列,要遵守最左前綴法則。指的是查詢從索引的最左前列開始并且不跳過復(fù)合索引中間列。
    MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法中間列不能斷:
    MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

  • 3、不在索引列上做任何操作(計算、函數(shù)、(自動or手動)類型轉(zhuǎn)換),會導(dǎo)致索引失效而轉(zhuǎn)向全表掃描。
    MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

  • 4、存儲引擎不能使用索引中范圍條件右邊的列(范圍之后全失效,范圍列并不是做的查詢而是排序)。
    MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

  • 5、盡量使用覆蓋索引(只訪問索引的查詢(索引列和查詢列一致)),減少select *。
    MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

  • 6、mysql在使用不等于(!=或者<>)的時候無法使用索引會導(dǎo)致全表掃描。
    MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

  • 7、is null, is not null 也無法使用索引。
    MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法

  • 8、like以通配符開頭(’%abc…’),mysql索引失效會變成全表掃描的操作(%寫在最右邊索引不會失效,或覆蓋索引)。
    MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法
    問題:解決like '%字符串%'時索引不被使用的方法? 采用覆蓋索引的方法!
    建表:

    CREATE TABLE `tbl_user`(
    	`id` INT(11) NOT NULL AUTO_INCREMENT,
    	`name` VARCHAR(20) DEFAULT NULL,
    	`age`INT(11) DEFAULT NULL,
    	`email` VARCHAR(20) DEFAULT NULL,
    	PRIMARY KEY(`id`))ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;INSERT INTO tbl_user(`name`,`age`,`email`)VALUES('1aa1',21,'a@163.com');INSERT INTO tbl_user(`name`,`age`,`email`)VALUES('2bb2',23,'b@163.com');INSERT INTO tbl_user(`name`,`age`,`email`)VALUES('3cc3',24,'c@163.com');INSERT INTO tbl_user(`name`,`age`,`email`)VALUES('4dd4',26,'d@163.com');//查詢mysql> select * from tbl_user;+----+------+------+-----------+| id | name | age  | email     |+----+------+------+-----------+|  1 | 1aa1 |   21 | a@163.com ||  2 | 2bb2 |   23 | b@163.com ||  3 | 3cc3 |   24 | c@163.com ||  4 | 4dd4 |   26 | d@163.com |+----+------+------+-----------+4 rows in set (0.00 sec)

    創(chuàng)建索引:

    CREATE INDEX idx_user_nameAge ON tbl_user(NAME,age);

    索引成功使用:
    MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法
    MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法
    索引失效:
    MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法
    MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法總結(jié):%寫在最右邊,如果非要寫在最左邊,就使用覆蓋索引

  • 9、字符串不加單引號索引失效。
    MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法
    Explain分析:
    MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制            <p>
                分享文章:<a href=MySQL中SQL優(yōu)化、索引優(yōu)化、鎖機(jī)制、主從復(fù)制的方法
    當(dāng)前URL:http://bm7419.com/article18/igsddp.html

    成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供全網(wǎng)營銷推廣、軟件開發(fā)移動網(wǎng)站建設(shè)、微信小程序、網(wǎng)站制作、App設(shè)計

    廣告

    聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站建設(shè)