表結(jié)構(gòu)
mysql引擎主要有兩種實現(xiàn)方式,一種是B+樹,一種是hash。而回表產(chǎn)生在B+樹上(本文主要針對于innodb引擎來講),這里還有一個內(nèi)容:
1.聚簇索引 :葉子節(jié)點直接存放數(shù)據(jù) (innodb)
聚簇索引結(jié)構(gòu)
2.非聚簇索引: 葉子節(jié)點存放的是數(shù)據(jù)的地址(myisam)
非聚簇索引結(jié)構(gòu)
回表
在innodb中,如果采用主鍵進行查詢則會直接訪問到數(shù)據(jù),也就是只需要進行一次查表
例:select * from student where id = ?
而如果采用二級索引(輔助索引)的情況則需要先使用二級索引查詢到主鍵的值,再用主鍵查詢來獲取所需要的值,也就是回表。
回表會影響查詢效率
例: select * from student where name = ?
使用該語句的情況下,會先根據(jù)二級索引(name)查詢到值主鍵值(id),再根據(jù)id查詢到對應(yīng)數(shù)據(jù)
回表
圖片來源:https://zhuanlan.zhihu.com/p/29118331
索引覆蓋
索引覆蓋其實就是一種避免回表的方式,只需要在一棵索引樹上就能獲取SQL所需的所有列數(shù)據(jù)。
例:select id,name from student where name = '大哥'
在第一次使用二級索引時,就能夠查詢到對應(yīng)的id值再加上自己本身的name值,左移只用在一顆索引樹上做查詢
那么在此基礎(chǔ)上還想要查詢到更多的值呢?
可以將被查詢的字段建立到聯(lián)合索引里去
例:
alter table student add index 'stu_ns_idx' (name,sex)
select id,name,sex from student where name = ?
索引下推
例 select * from student where name = ? and sex = ?
- 沒有索引下推:
先從存儲引擎中拉去數(shù)據(jù)(根據(jù)name篩選數(shù)據(jù))
再mysql server 根據(jù)sex進行數(shù)據(jù)篩選
壓力在服務(wù)器 - 有索引下推
會在拉取數(shù)據(jù)的時候直接根據(jù)name,sex來獲取數(shù)據(jù),不需要server做任何數(shù)據(jù)操作
壓力在磁盤
索引下推唯一的缺點是需要再磁盤上做篩選,原來的篩選是放在內(nèi)存的,現(xiàn)在放在了磁盤查找數(shù)據(jù)的環(huán)節(jié),這樣做看起來成本比較高,但是在數(shù)據(jù)庫中所有數(shù)據(jù)都是排序的,所有的數(shù)據(jù)是聚集存放,所以性能不會有影響,而且整體io量會大大減少,反而會提升性能