<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
面試題:
索引是幫助我們實現快速查詢資料庫的資料結構。
在很多時候,表中存放的記錄非常的多,需要用到好多的資料頁來存放這些記錄,在很多頁中查詢記錄可以分為2個步驟:
1、定位到記錄所在的頁
2、從所在頁內查詢相應的記錄
在沒有索引的情況下,無論是根據主鍵列還是其他列的值進行查詢,由於我們不能快速的定位到記錄所在的頁,所以只能從第一頁沿著雙向連結串列一直往下找,因為需要遍歷所有的資料頁,這種方式超級消耗效能。因此人們期望一種能高效完成搜尋的方法,因此就出現了索引,索引就是一種資料結構。
索引可以讓伺服器快速的定位到表的指定位置 (索引大大減少了伺服器需要需要掃描的資料量)。最常見的B-Tree索引,按照順序儲存資料,所以mysql
可以來做order by
和group by
操作(索引可以幫助伺服器避免排序和臨時表)。因為資料是有序的,所以B-Tree也就會將相關的列值都儲存在一起(索引可以將隨機IO變為順序IO)。因為索引中儲存了實際的列值,所以某些查詢值使用索引就能完成全部查詢。因此,總結下來的索引的優點為:
1、索引大大減少了伺服器需要需要掃描的資料量;
2、索引可以幫助伺服器避免排序和臨時表;
3、索引可以將隨機IO變為順序IO;
1、空間上的代價:
建立索引需要佔用物理空間
InnoDB儲存引擎預設使用的B+樹索引,每建立一個索引,都要為它建立一顆B+樹,每一顆B+樹的每一個節點都是一個資料頁,一個資料頁預設會佔用16KB的儲存空間,而一顆很大的B+樹由許多資料頁組成,這將佔用很大的一片儲存空間。
2、時間上的代價:
因為每次對錶記錄進行增刪改,需要進行動態維護索引,導致增刪改時間變長
每當對錶中的資料進行增刪改查操作時,都需要修改各個B+樹索引,B+樹中的每層節點都按照索引列的值從小到大的順序組成了雙向連結串列,無論是葉子節點中的記錄還是非葉子節點中的記錄都按照索引列的值從小到大的順序排成了單向連結串列。而增刪改查操作可能會對節點和記錄的排序造成破壞,所以儲存引擎需要額外的時間進行頁面分裂、頁面回收等操作,以維護節點和記錄的順序。
在執行查詢語句前,首先要生成一個執行計劃,一般情況下,一條查詢語句在執行過程中最多使用一個二級索引,因此,在生成執行計劃時需要計算使用不同索引執行查詢時所需的成本,最後選取成本最小的那個索引執行查詢,如果建立了太多的索引,可能會導致成本分析耗時太多,從而影響查詢語句的執行效能。
在建立和使用索引是應該注意下列事項:
建立一張資料庫表:
create table single_table( id int not auto_increment, key1 varchar(100), key2 int, key3 varchar(100), key_part1 varchar(100), key_part2 varchar(100), key_part3 varchar(100), common_field varchar(100), primary key(id), # 聚簇索引 key idx_key1(key1), # 二級索引 unique key uk_key2(key2), # 二級索引,而且該索引是唯一二級索引 key idx_key3(key3), # 二級索引 key idx_key_part(key_part1,key_part2,key_part3) # 二級索引,也是聯合索引 )Engine=InnoDB CHARSET=utf8;
我們只為出現在where
子句中的列、order by
或group by
子句中的列、連線子句中的連線列建立索引。僅出現在查詢列表中的列就沒有必要建立索引了。
比如下面的查詢語句:
select common_field,key_part3 from single_table where key1='a';
我們只需要為出現在where
子句中的key1
建立索引就可以了,而查詢列表中的common_field、key_part3
這兩個列就沒有必要建立索引了。
在定義表結構時,要顯式的指定列的型別。以整數型別為例,有tingint、mediumint、int、bigint
這幾種,他們佔用的儲存空間的大小依次遞增,他們能表示的整數範圍當然也是依次遞增。如果想要對某個整數型別的列建立索引,在表示的整數範圍允許的情況下,儘量讓索引列使用較小的型別,比如使用int
就不要用bigint
,因為資料型別越小,索引佔用的儲存空間就越少,在一個資料頁內就可以存放更多的記錄,磁碟IO帶來的效能損耗也就越小,讀寫效率也就越高。
這個建議對錶的主鍵來說更加適用,因為不僅聚簇索引會儲存主鍵值,所有的二級索引的節點都會儲存一份記錄的主鍵值,如果主鍵使用更小的資料型別,也就意味著能節省更多的儲存空間。
一個字串其實是由若干個字元組成的,假如字串很長,那麼儲存這個字串就會佔用很多的儲存空間。在為這個字串所在的列建立索引時,就需要在對應的B+樹中,把列的完整字串儲存起來,字串越長,在索引中佔用的儲存空間越大。
索引列的字串字首其實也是排好序的,所以索引的設計人員設計了一個方案,即只將字串的前幾個字元存放到索引中,也就是說二級索引的記錄中只保留字串的前幾個字元。
比如可以這樣修改idx_key1
索引,讓索引中只保留字串的前10個字元:
alert table single_table drop index idx_key1; alert table single_table add index idx_key1(key1(10));
然後再執行下面的查詢語句:
select * from single_table where key1='abcdefghijklmn';
由於在idx_key1
的二級索引記錄中只保留字串的前10個字元,所以我們只能定位到字首為‘abcdefghij'
的二級索引記錄,在掃描這些二級索引記錄時再判斷它們是否滿足key1='abcdefghijklmn'
條件,當列中儲存的字串包含的字元較多時,這種為列字首建立索引的方式可以明顯減少索引大小。
不過,在只對字首建立索引的情況下,下面這個查詢語句就不能使用索引來完成排序需求了:
select * from single_table order by key1 limit 10;
因為二級索引idx_key1
中不包含完整的key1
列資訊,所以在僅使用idx_key1
索引執行查詢時,無法對key1
列前10個字元相同但其餘字元不同的記錄進行排序,也就是說,只為列字首建立索引的方式無法支援使用索引進行排序的需求。
為了徹底告別回表操作帶來的效能損耗,建議最好在查詢列表中只包含索引列,比如這個查詢語句:
select key1,id from single_table where key1>'a' and key1<'c';
由於我們只查詢key1
列和id
列的值,所以在使用idx_key1
索引來掃描('a','c')
區間中的二級索引時,可以直接從獲取到的二級索引記錄中讀出key1
列和id
列的值,而不需要再通過id
值到聚簇索引中執行回表操作了,這樣就省去了回表操作帶來的效能損耗。
我們把這種索引中已經包含了所有需要讀取的列的查詢方式稱為覆蓋索引。如果索引的葉子節點中已經包含要查詢的資料,那麼還有必要再回表查詢呢?如果一個索引包含所有需要查詢的欄位的值,就稱為覆蓋索引。
排序操作也優先使用覆蓋索引進行查詢,比如下面這個查詢語句:
select key1 from single_table order by key1;
雖然這個查詢語句中沒有limit子句,但是由於可以採用覆蓋索引,所以查詢優化器會直接使用idx_key1
索引進行排序,而不需要執行回表操作。
當然,如果業務需要查詢索引列以外的列,還是要以保證業務需求為重,如無必要,最好把業務中需要的列放在查詢列表中,而不是以簡單的*
替代。
在下面這兩個查詢語句中,搜尋條件中的語意是一樣的:
select * from single_table where key2*2<4; select * from single_table where key2<4/2;
在第一個查詢語句的搜尋條件中,key2
列並不是以單獨列名的形式出現的,而是以key2*2
這樣的形式表現的,MySQL
並不會嘗試簡化key2*2<4
表示式,而是直接認為這個搜尋條件不能形成合適的掃描區間來減少需要掃描的記錄數量,所以該查詢語句只能以全表掃描的方式來執行。
在第二個查詢語句的搜尋條件中,key2
列並是以單獨列名的形式出現的,MySQL
可以分析出key2<2
,這樣可以減少需要掃描的記錄數量。所以MySQL
可能使用uk_key2
來執行查詢。
所以,如果想讓某個查詢使用索引來執行,請讓索引列以列名的形式單獨出現在搜尋條件中。
我們知道,對於一個使用InnoDB
儲存引擎的表來說,在沒有顯式建立索引時,表中的資料實際上儲存在聚簇索引的葉子節點中,而且B+樹的每一層資料頁以及頁面中的記錄都是按照主鍵值從小到大的順序排序的,如果新插入記錄的主鍵值是依次遞增的話,每插滿一個資料頁就換到下一個資料頁繼續插入,如果新插入記錄的主鍵值忽大忽小,就比較麻煩了。
假設某個資料頁儲存的聚簇索引記錄已經滿了,它儲存的主鍵值在1~100
之間,此時如果再插入一提哦啊主鍵值為9
的記錄,因為這個資料頁已經滿了,新紀錄應該插入到哪裡呢?
我們需要把當前頁面分裂成兩個頁面,把本頁中的一些記錄移動到新建立的一些頁中,頁分裂意味著效能損耗,所以如果想盡量避免這種無謂的效能損耗,最好讓插入記錄的主鍵值依次遞增。即讓主鍵擁有auto_increment
屬性,MySQl
會自動為新插入的記錄生成遞增的主鍵值。
針對single_table表,可以單獨針對key_part1列建立一個idx_key_part1索引:
alert table single_table and index idx_key_part1(key_part1);
而此時我們已經有了一個針對key_part1、key_part2、key_part3
列建立的聯合索引idx_key_par
。idx_key_part
索引的二級索引記錄本身就是按照key_part1
列的值排序的,此時再單獨為key_part1
列建立一個索引其實是沒必要的,我們可以把整個新建的idx_key_part1
索引看作一個冗餘索引,該冗餘索引是沒有必要的。
有時,我們可能會對同一個列建立多個索引,比如下面兩個新增索引的語句:
alert table single_table add unique key uk_id(id); alert table single_table add index idx_id(id);
我們針對id
列又建立了一個唯一二級索引uk_id
,還建立了一個普通二級索引idx_id
,可是id
列本身就是single_table
表的主鍵,InnoDB
自動為該列建立了聚簇索引,此時uk_id
和idx_id
就是重複的,這種重複索引應該避免。
本篇文章就到這裡了,希望能夠給你帶來幫助,也希望您能夠多多關注it145.com的更多內容!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45