php面試專題---Mysql索引原理及SQL優化


php面試專題---Mysql索引原理及SQL優化

一、總結

一句話總結:

注意:只寫精品

 

1、為表設置索引要付出代價 是什么?

存儲空間:一是增加了數據庫的存儲空間
修改插入變動索引時間:二是在插入和修改數據時要花費較多的時間(因為索引也要隨之變動)

 

2、在哪些列上面創建索引比較合適?

1、連接的列:在經常用在連接的列上,這些列主要是一些外鍵,可以加快連接的速度;
2、范圍:在經常需要根據范圍進行搜索的列上創建索引,因為索引已經排序,其指定的范圍是連續的;
3、排序:在經常需要排序的列上創建索引,因為索引已經排序,這樣查詢可以利用索引的排序,加快排序查詢時間;
4、where字句:在經常使用在 WHERE 子句中的列上面創建索引,加快條件的判斷速度。



1、在經常需要搜索的列上,可以加快搜索的速度;
2、在作為主鍵的列上,強制該列的唯一性和組織表中數據的排列結構;
3、在經常用在連接的列上,這些列主要是一些外鍵,可以加快連接的速度;
4、在經常需要根據范圍進行搜索的列上創建索引,因為索引已經排序,其指定的范圍是連續的;
5、在經常需要排序的列上創建索引,因為索引已經排序,這樣查詢可以利用索引的排序,加快排序查詢時間;
6、在經常使用在 WHERE 子句中的列上面創建索引,加快條件的判斷速度。

 

3、將某列設置為主鍵的時候是否就已經為這一列添加了主鍵索引?

默認添加:當一張表,把某個列設為主鍵的時候,則該列就是主鍵索引

 

4、唯一索引是什么?

列的值不重復:索引列的所有值都只能出現一次,即必須唯一

 

5、mysql全文索引使用注意?

|||-begin

FULLTEXT

CREATE TABLE articles (
       id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
       title VARCHAR(200),
       body TEXT,
       FULLTEXT (title,body)
     )engine=myisam charset utf8;

INSERT INTO articles (title,body) VALUES
     ('MySQL Tutorial','DBMS stands for DataBase ...'),
     ('How To Use MySQL Well','After you went through a ...'),
     ('Optimizing MySQL','In this tutorial we will show ...'),
     ('1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'),
     ('MySQL vs. YourSQL','In the following database comparison ...'),
     ('MySQL Security','When configured properly, MySQL ...');

錯誤用法:

select * from articles where body like '%mysql%'; 錯誤用法 索引不會生效

正確用法:

select * from articles where match(title,body) against ( 'database');

說明:

在mysql中fulltext 索引只針對 myisam生效,只有myisam支持全文索引

mysql自己提供的fulltext針對英文生效->sphinx (coreseek) 技術處理中文

使用方法是 match(字段名..) against(‘關鍵字’)

全文索引:停止詞, 因為在一個文本中,創建索引是一個無窮大的數,因此,對一些常用詞和字符,就不會創建,這些詞,稱為停止詞.比如(a,b,mysql,the)

mysql> select match(title,body) against ('database') from articles;(輸出的是每行和database的匹配度)

|||-end

1、錯誤用法:select * from articles where body like '%mysql%'; 錯誤用法 索引不會生效
2、正確用法:select * from articles where match(title,body) against ( 'database');
3、只有myisam支持全文索引:在mysql中fulltext 索引只針對 myisam生效,只有myisam支持全文索引
4、輸出的是每行和database的匹配度:select match(title,body) against ('database') from articles;(輸出的是每行和database的匹配度)

 

 

6、mysql索引優缺點總結?

優點:提高查詢效率
缺點:增刪慢,索引文件需要更新,增加內存

 

7、使用group by 分組查詢是 默認分組后,還會排序,可能會降低速度,如何解決這個問題?

1、在group by 后面增加 order by null 就可以禁止排序.
2、explain select * from emp group by deptno order by null;

 

8、select * from userId >= 101 和select * from userId > 100 哪個效率高?

后者:在工作中盡量不要使用>= 、 <=因為會做兩次全表掃描,使用> 、 < 、 !=、<>

 

9、應盡量避免在 where 子句中對字段進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描,如:select id from t where num is null?

NULL占空間,數據庫用NOT NULL填充:最好不要給數據庫留 NULL,盡可能的使用 NOT NULL 填充數據庫。不要以為 NULL 不需要空間,比如:char(100) 型,在字段建立時,空間就固定了, 不管是否插入值(NULL 也包含在內),都是占用 100 個字符的空間的,如果是 varchar 這樣的變長字段, null 不占用空間。

 

10、in 和 not in 也要慎用,否則會導致全表掃描,如:select id from t where num in(1,2,3)?

1、對於連續的數值,能用 between 就不要用 in 了:select id from t where num between 1 and 3
2、很多時候用 exists 代替 in 是一個好的選擇:select num from a where num in(select num from b) 用后面的語句替換: select num from a where exists(select 1 from b where num=a.num)

 

 

 

二、Mysql索引原理及SQL優化

轉自或參考:Mysql索引原理及SQL優化
https://blog.csdn.net/itcats_cn/article/details/82152336

一、什么是索引?

索引用來快速地尋找那些具有特定值的記錄,所有MySQL索引都以B-tree的形式保存。如果沒有索引,執行查詢時MySQL必須從第一個記錄開始掃描整個表的所有記錄,直至找到符合要求的記錄。表里面的記錄數量越多,這個操作的代價就越高。如果作為搜索條件的列上已經創建了索引,MySQL無需掃描任何記錄即可迅速得到目標記錄所在的位置。如果表有100萬條記錄,通過索引查找記錄至少要比順序掃描記錄快1000倍。

 

二、索引的原理

為表設置索引要付出代價的:一是增加了數據庫的存儲空間,二是在插入和修改數據時要花費較多的時間(因為索引也要隨之變動)。

上圖展示了一種可能的索引方式。左邊是數據表,一共有兩列七條記錄,最左邊的是數據記錄的物理地址(注意邏輯上相鄰的記錄在磁盤上也並不是一定物理相鄰的)。為了加快 Col2 的查找,可以維護一個右邊所示的二叉查找樹,每個節點分別包含索引鍵值和一個指向對應數據記錄物理地址的指針,這樣就可以運用二叉查找在 O(log2n)的復雜度內獲取到相應數據。

創建索引可以大大提高系統的性能:

第一,通過創建唯一性索引,可以保證數據庫表中每一行數據的唯一性。

第二,可以大大加快數據的檢索速度,這也是創建索引的最主要的原因。

第三,可以加速表和表之間的連接,特別是在實現數據的參考完整性方面特別有意義。

第四,在使用分組和排序子句進行數據檢索時,同樣可以顯著減少查詢中分組和排序的時間。

第五,通過使用索引,可以在查詢的過程中,使用優化隱藏器,提高系統的性能。

也許會有人要問:增加索引有如此多的優點,為什么不對表中的每一個列創建一個索引呢?

因為,增加索引也有許多不利的方面:

第一,創建索引和維護索引要耗費時間,這種時間隨着數據量的增加而增加。

第二,索引需要占物理空間,除了數據表占數據空間之外,每一個索引還要占一定的物理空間,如果要建立聚簇索引,那么需要的空間就會更大。

第三,當對表中的數據進行增加、刪除和修改的時候,索引也要動態的維護,這樣就降低了數據的維護速度。

 

索引是建立在數據庫表中的某些列的上面。在創建索引的時候,應該考慮在哪些列上可以創建索引,在哪些列上不能創建索引。一般來說,應該在這些列上創建索引:

1、在經常需要搜索的列上,可以加快搜索的速度;

2、在作為主鍵的列上,強制該列的唯一性和組織表中數據的排列結構;

3、在經常用在連接的列上,這些列主要是一些外鍵,可以加快連接的速度;

4、在經常需要根據范圍進行搜索的列上創建索引,因為索引已經排序,其指定的范圍是連續的;

5、在經常需要排序的列上創建索引,因為索引已經排序,這樣查詢可以利用索引的排序,加快排序查詢時間;

6、在經常使用在 WHERE 子句中的列上面創建索引,加快條件的判斷速度。

根據數據庫的功能,可以在數據庫設計器中創建三種索引:唯一索引、主鍵索引和聚集索引

 

 

三、索引的分類:

主鍵索引

主鍵是一種唯一性索引,但它必須指定為“PRIMARY KEY”。如果你曾經用過AUTO_INCREMENT類型的列,你可能已經熟悉主鍵之類的概念了。主鍵一般在創建表的時候指定,例如“CREATE TABLE tablename ( [...], PRIMARY KEY (列的列表) ); ”。但是,我們也可以通過修改表的方式加入主鍵,例如“ALTER TABLE tablename ADD PRIMARY KEY (列的列表); ”。每個表只能有一個主鍵。

當一張表,把某個列設為主鍵的時候,則該列就是主鍵索引

create table aaa(

id int unsigned primary key auto_increment ,

name varchar(32) not null default '');

這是id 列就是主鍵索引.

如果你創建表時,沒有指定主鍵索引,也可以在創建表后,在添加, 指令:

實例:

alter table 表名 add primary key (列名);

刪除主鍵索引

alter table articles drop primary key;

 

查詢索引

desc  表名;   不能顯示索引名稱

show index from 表名

show keys from 表名

 

普通索引

普通索引(由關鍵字KEY或INDEX定義的索引)的唯一任務是加快對數據的訪問速度。因此,應該只為那些最經常出現在查詢條件(WHERE column= )或排序條件(ORDER BY column)中的數據列創建索引。只要有可能,就應該選擇一個數據最整齊、最緊湊的數據列(如一個整數類型的數據列)來創建索引。

create table ccc(
id int unsigned,
name varchar(32)
);

create index 索引名 on 表 (列1,列2);

 

唯一索引(不能用重復'')

這種索引和前面的“普通索引”基本相同,但有一個區別:索引列的所有值都只能出現一次,即必須唯一。唯一性索引可以用以下幾種方式創建:

創建索引,例如CREATE UNIQUE INDEX <索引的名字> ON tablename (列的列表);

修改表,例如ALTER TABLE tablename ADD UNIQUE [索引的名字] (列的列表);

創建表的時候指定索引,例如CREATE TABLE tablename ( [...], UNIQUE [索引的名字] (列的列表) );

create table ddd(
id int primary key auto_increment ,
name varchar(32) unique);

注意

unique字段可以為NULL,並可以有多NULL, 但是如果是具體內容,則不能重復,

但是不能存有重復的空字符串’’

 

組合索引(my_ind)

創建一個組合索引

alter table dept add index my_ind (dname,loc); //dname 左邊的列,loc就是右邊的列

只使用dname而不使用loc一起作為條件查找,dname會使用組合索引進行查找TYPEmy_ind,但只使用loc不使用dname作為條件查找,不會使用索引TYPEALL(后面會提到mysql的執行計划ALL為全文查找)。

 

 

全文索引

FULLTEXT

CREATE TABLE articles (
       id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
       title VARCHAR(200),
       body TEXT,
       FULLTEXT (title,body)
     )engine=myisam charset utf8;

INSERT INTO articles (title,body) VALUES
     ('MySQL Tutorial','DBMS stands for DataBase ...'),
     ('How To Use MySQL Well','After you went through a ...'),
     ('Optimizing MySQL','In this tutorial we will show ...'),
     ('1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'),
     ('MySQL vs. YourSQL','In the following database comparison ...'),
     ('MySQL Security','When configured properly, MySQL ...');

 

錯誤用法:

select * from articles where body like '%mysql%'; 錯誤用法 索引不會生效

正確用法:

select * from articles where match(title,body) against ( 'database');

說明:

在mysql中fulltext 索引只針對 myisam生效,只有myisam支持全文索引

mysql自己提供的fulltext針對英文生效->sphinx (coreseek) 技術處理中文

使用方法是 match(字段名..) against(‘關鍵字’)

全文索引:停止詞, 因為在一個文本中,創建索引是一個無窮大的數,因此,對一些常用詞和字符,就不會創建,這些詞,稱為停止詞.比如(a,b,mysql,the)

mysql> select match(title,body) against ('database') from articles;(輸出的是每行和database的匹配度)

 

 

四、MySQL explain執行計划解讀

當我們在查詢前能否預先估計查詢究竟要涉及多少行、使用哪些索引、運行時間呢?答案是能的,mysql提供了相應的功能和語法來實現該功能。

MySql提供了EXPLAIN語法用來進行查詢分析,在SQL語句前加一個"EXPLAIN"即可。比如我們要分析如下SQL語句:

explain select * from table where table.id = 1;

運行上面的sql語句后你會看到,下面的表頭信息:
table | type | possible_keys | key | key_len | ref | rows | Extra

table
顯示這一行的數據是關於哪張表的

type
這是重要的列,顯示連接使用了何種類型。從最好到最差的連接類型為const、eq_reg、ref、range、indexhe和ALL

說明:不同連接類型的解釋(按照效率高低的順序排序)

system:表只有一行:system表。這是const連接類型的特殊情況。

const :表中的一個記錄的最大值能夠匹配這個查詢(索引可以是主鍵或唯一索引)。因為只有一行,這個值實際就是常數,因為MYSQL先讀這個值然后把它當做常數來對待。

eq_ref:在連接中,MYSQL在查詢時,從前面的表中,對每一個記錄的聯合都從表中讀取一個記錄,它在查詢使用了索引為主鍵或惟一鍵的全部時使用。

ref:這個連接類型只有在查詢使用了不是唯一或主鍵的鍵或者是這些類型的部分(比如,利用最左邊前綴)時發生。對於之前的表的每一個行聯合,全部記錄都將從表中讀出。這個類型嚴重依賴於根據索引匹配的記錄多少—越少越好。

range:這個連接類型使用索引返回一個范圍中的行,比如使用>或<查找東西時發生的情況。

index:這個連接類型對前面的表中的每一個記錄聯合進行完全掃描(比ALL更好,因為索引一般小於表數據)。

ALL:這個連接類型對於前面的每一個記錄聯合進行完全掃描,這一般比較糟糕,應該盡量避免。

my_ind:組合索引

key
實際使用的索引。如果為NULL,則沒有使用索引。很少的情況下,MYSQL會選擇優化不足的索引。這種情況下,可以在SELECT語句中使用USE INDEX(indexname)來強制使用一個索引或者用IGNORE INDEX(indexname)來強制MYSQL忽略索引

key_len
使用的索引的長度。在不損失精確性的情況下,長度越短越好

ref
顯示索引的哪一列被使用了,如果可能的話,是一個常數

rows
MYSQL認為必須檢查的用來返回請求數據的行數

extra列返回的描述的意義

Distinct :一旦mysql找到了與行相聯合匹配的行,就不再搜索了。

Not exists :mysql優化了LEFT JOIN,一旦它找到了匹配LEFT JOIN標准的行,就不再搜索了。

Range checked for each Record(index map:#) :沒有找到理想的索引,因此對從前面表中來的每一個行組合,mysql檢查使用哪個索引,並用它來從表中返回行。這是使用索引的最慢的連接之一。

Using filesort :看到這個的時候,查詢就需要優化了。mysql需要進行額外的步驟來發現如何對返回的行排序。它根據連接類型以及存儲排序鍵值和匹配條件的全部行的行指針來排序全部行。

Using index :列數據是從僅僅使用了索引中的信息而沒有讀取實際的行動的表返回的,這發生在對表的全部的請求列都是同一個索引的部分的時候。

Using temporary :看到這個的時候,查詢需要優化了。這里,mysql需要創建一個臨時表來存儲結果,這通常發生在對不同的列集進行ORDER BY上,而不是GROUP BY上。

Where used :使用了WHERE從句來限制哪些行將與下一張表匹配或者是返回給用戶。如果不想返回表中的全部行,並且連接類型ALL或index,這就會發生,或者是查詢有問題。

因此,弄明白了explain語法返回的每一項結果,我們就能知道查詢大致的運行時間了,如果查詢里沒有用到索引、或者需要掃描的行過多,那么可以感到明顯的延遲。因此需要改變查詢方式或者新建索引。mysql中的explain語法可以幫助我們改寫查詢,優化表的結構和索引的設置,從而最大地提高查詢效率。當然,在大規模數據量時,索引的建立和維護的代價也是很高的,往往需要較長的時間和較大的空間,如果在不同的列組合上建立索引,空間的開銷會更大。因此索引最好設置在需要經常查詢的字段中。

 

五、總結

優點:提高查詢效率

缺點:增刪慢,索引文件需要更新,增加內存

什么情況需要用到索引

  • 在where條件經常使用
  • 該字段的內容不是唯一的幾個值,如性別男0,女1
  • 字段內容不是頻繁變化

關於索引注意事項【重要】:

記住:聯合、like、or、null、字符串、in、group by、

1、聯合查詢 alter table dept add index my_ind (dname,loc) 使用dname或使用兩者作為條件才會使用到索引

2、模糊查詢在like前面有%百分號開頭會失效,因此在使用索引時候,不要使用%開頭,否則全表掃描,應寫成like "條件%"

3、如果條件中有or,即使其中有條件帶索引也不會使用。換言之,就是要求使用的所有字段,都必須建立索引, 我們建議大家盡量避免使用or關鍵字。or中,條件必須都為索引,否則只要有一個不為索引,則都不會進行索引

4、如果列類型是字符串,那一定要在條件中將數據使用引號引用起來,否則不使用索引。(添加時,字符串必須''), 也就是,如果列是字符串類型,就一定要用 '' 把他包括起來。

 

SQL優化【重要】:

1、使用group by 分組查詢是——默認分組后,還會排序,可能會降低速度

在group by 后面增加 order by null 就可以禁止排序.

explain select * from emp group by deptno order by null;

2、select * from userId >= 101 和select * from userId > 100 哪個效率高?

在工作中盡量不要使用>= 、 <=因為會做兩次全表掃描,使用> 、 < 、 !=、<>

3、應盡量避免在 where 子句中對字段進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描,如:

select id from t where num is null

最好不要給數據庫留 NULL,盡可能的使用 NOT NULL 填充數據庫。不要以為 NULL 不需要空間,比如:char(100) 型,在字段建立時,空間就固定了, 不管是否插入值(NULL 也包含在內),都是占用 100 個字符的空間的,如果是 varchar 這樣的變長字段, null 不占用空間。

4、in 和 not in 也要慎用,否則會導致全表掃描,如:

select id from t where num in(1,2,3)

對於連續的數值,能用 between 就不要用 in 了:

select id from t where num between 1 and 3

很多時候用 exists 代替 in 是一個好的選擇:

select num from a where num in(select num from b)

用下面的語句替換:

select num from a where exists(select 1 from b where num=a.num)

更多參考:

http://www.cnblogs.com/yunfeifei/p/3850440.html

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM