本文目錄一覽:
mysql索引
二叉搜索樹、N叉樹
頁分裂:B+樹的插入可能會引起數據頁的分裂,刪除可能會引起數據頁的合併,二者都是比較重的IO消耗,所以比較好的方式是順序插入數據,這也是我們一般使用自增主鍵的原因之一。
頁分裂逆過程:頁合併,當刪除數據後,相鄰的兩個數據頁利用率很低的時候會做數據頁合併
主鍵索引:key:主鍵,value:數據頁,存儲每行數據
非主鍵索引:key:非主鍵索引,value:主鍵key,導致回表
最左匹配:優先將區分度高的列放到前面,這樣可以高效索引,
最左匹配原則遇到範圍查詢就停止匹配,範圍查詢(、、between、like)為什麼?因為出現範圍匹配後,後面的索引欄位無法保證有序,局部有序失去,順序失去則無法提高查詢效率
SELECT * FROM table WHERE a IN (1,2,3) and b 1;
如何建立索引?
還是對(a,b)建立索引,因為IN在這裡可以視為等值引用,不會中止索引匹配,所以還是(a,b)!
索引組織表
索引用頁存儲:key【10】-point【6】,通過調整key大小,當頁大小固定的情況下,通過調整key大小,使得N叉樹變化;
如key 10, point 6則單個索引16位元組,頁大小為16k,則頁面總共可以存儲1024個索引,即N大小
覆蓋索引: 二級索引的信息已經存在想要的列,例如主鍵
如果現在有一個高頻請求,要根據市民的身份證號查詢他的姓名,這個聯合索引就有意義了。它可以在這個高頻請求上用到覆蓋索引,不再需要回表查整行記錄,減少語句的執行時間。
索引下推優化:可以在索引遍歷過程中,對索引中包含的欄位先做判斷,直接過濾掉不滿足條件的記錄,減少回表次數。
整理索引碎片,重建表:alter table T engine=InnoDB
首先是看key的大小,另外是數據頁的大小,如果需要改變N,則需要從這兩個方面做改動;
一個innoDB引擎的表,數據量非常大,根據二級索引搜索會比主鍵搜索快,文章闡述的原因是主鍵索引和數據行在一起,非常大搜索慢,我的疑惑是:通過普通索引找到主鍵ID後,同樣要跑一邊主鍵索引,對於使用覆蓋索引的情況下,使用覆蓋索引可以直接解決問題
mysql之普通索引和唯一索引
常見的索引類型:哈希表、有序數組、搜索樹。
mysql之普通索引和唯一索引。
執行查詢的語句是 select id from T where k=5
這個查詢語句在索引樹上查找的過程,先是通過 B+ 樹從樹根開始,按層搜索到葉子節點,也就是圖中右下角的這個數據頁,然後可以認為數據頁內部通過二分法來定位記錄。
InnoDB的索引組織結構:
change buffer:持久化的數據。InnoDB將更新操作緩存在 change buffer中,也就是說,change buffer 在內存中有拷貝,也會被寫入到磁碟,主要節省的則是隨機讀磁碟的IO消耗。
change buffer 只限於用在普通索引的場景下,而不適用於唯一索引.
merge:將 change buffer 中的操作應用到原數據頁,得到最新結果的過程。
merge執行流程:
1、從磁碟讀入數據頁到內存
2、從change buffer里找出這個數據頁的change buffer記錄,依次應用,得到新版數據頁
3、寫redo log,這個redo log包含了數據的變更和change buffer的變更。
change buffer 用的是 buffer pool 里的內存,因此不能無限增大。change buffer 的大小,可以通過參數 innodb_change_buffer_max_size=50 表示 change buffer 的大小最多只能佔用 buffer pool 的 50%。
如果要在這張表中插入一個新記錄 (4,400) 的話,InnoDB 的處理流程是怎樣的。
第一種情況是,這個記錄要更新的目標頁在內存中
這時,InnoDB 的處理流程如下:
第二種情況是,這個記錄要更新的目標頁不在內存中
這時,InnoDB 的處理流程如下:
mysql insert into t(id,k) values(id1,k1),(id2,k2); 當前 k 索引樹的狀態,查找到位置後,k1 所在的數據頁在內存 (InnoDB buffer pool) 中,k2 所在的數據頁不在內存中。
分析這條更新語句,你會發現它涉及了四個部分:內存、redo log(ib_log_fileX)、 數據表空間(t.ibd)、系統表空間(ibdata1)。這條更新語句做了如下的操作(按照圖中的數字順序):
帶change buffer的更新過程:
select * from t where k in (k1, k2) ,如果讀語句發生在更新語句後不久,內存中的數據都還在,那麼此時的這兩個讀操作就與系統表空間(ibdata1)和 redo log(ib_log_fileX)無關了.
MySQL資料庫的索引的操作知多少
MySQL索引類型包括:
(1)普通索引
這是最基本的索引,它沒有任何限制。它有以下幾種創建方式:
◆創建索引
CREATE INDEX indexName ON mytable(username(length)); 如果是CHAR,VARCHAR類型,length可以小於欄位實際長度;如果是BLOB和TEXT類型,必須指定 length,下同。
◆修改表結構
ALTER mytable ADD INDEX [indexName] ON (username(length))
◆創建表的時候直接指定
CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, INDEX [indexName] (username(length)) ); 刪除索引的語法:
DROP INDEX [indexName] ON mytable;
(2)唯一索引
與前面的普通索引類似,不同的就是:索引列的值必須唯一,但允許有空值。如果是組合索引,則列值的組合必須唯一。它有以下幾種創建方式:
◆創建索引
CREATE UNIQUE INDEX indexName ON mytable(username(length))
◆修改表結構
ALTER mytable ADD UNIQUE [indexName] ON (username(length))
◆創建表的時候直接指定
CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, UNIQUE [indexName] (username(length)) );
(3)主鍵索引
它是一種特殊的唯一索引,不允許有空值。一般是在建表的時候同時創建主鍵索引:
CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, PRIMARY KEY(ID) ); 當然也可以用 ALTER 命令。記住:一個表只能有一個主鍵。
(4)組合索引
為了形象地對比單列索引和組合索引,為表添加多個欄位:
CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, city VARCHAR(50) NOT NULL, age INT NOT NULL ); 為了進一步榨取MySQL的效率,就要考慮建立組合索引。就是將 name, city, age建到一個索引里:
ALTER TABLE mytable ADD INDEX name_city_age (name(10),city,age); 建表時,usernname長度為 16,這裡用 10。這是因為一般情況下名字的長度不會超過10,這樣會加速索引查詢速度,還會減少索引文件的大小,提高INSERT的更新速度。
如果分別在 usernname,city,age上建立單列索引,讓該表有3個單列索引,查詢時和上述的組合索引效率也會大不一樣,遠遠低於我們的組合索引。雖然此時有了三個索引,但MySQL只能用到其中的那個它認為似乎是最有效率的單列索引。
建立這樣的組合索引,其實是相當於分別建立了下面三組組合索引:
usernname,city,age usernname,city usernname 為什麼沒有 city,age這樣的組合索引呢?這是因為MySQL組合索引「最左前綴」的結果。簡單的理解就是只從最左面的開始組合。並不是只要包含這三列的查詢都會用到該組合索引,下面的幾個SQL就會用到這個組合索引:
SELECT * FROM mytable WHREE username=”admin” AND city=”鄭州” SELECT * FROM mytable WHREE username=”admin” 而下面幾個則不會用到:
SELECT * FROM mytable WHREE age=20 AND city=”鄭州” SELECT * FROM mytable WHREE city=”鄭州”
(5)建立索引的時機
一般來說,在WHERE和JOIN中出現的列需要建立索引,但也不完全如此,因為MySQL只對,=,=,,=,BETWEEN,IN,以及某些時候的LIKE才會使用索引。例如:
SELECT t.Name FROM mytable t LEFT JOIN mytable m ON t.Name=m.username WHERE m.age=20 AND m.city=’鄭州’ 此時就需要對city和age建立索引,由於mytable表的userame也出現在了JOIN子句中,也有對它建立索引的必要。
剛才提到只有某些時候的LIKE才需建立索引。因為在以通配符%和_開頭作查詢時,MySQL不會使用索引。例如下句會使用索引:
SELECT * FROM mytable WHERE username like’admin%’ 而下句就不會使用:
SELECT * FROM mytable WHEREt Name like’%admin’ 因此,在使用LIKE時應注意以上的區別。
(6)索引的不足之處
上面都在說使用索引的好處,但過多的使用索引將會造成濫用。因此索引也會有它的缺點:
◆雖然索引大大提高了查詢速度,同時卻會降低更新表的速度,如對錶進行INSERT、UPDATE和DELETE。因為更新表時,MySQL不僅要保存數據,還要保存一下索引文件。
◆建立索引會佔用磁碟空間的索引文件。一般情況這個問題不太嚴重,但如果你在一個大表上創建了多種組合索引,索引文件的會膨脹很快。
索引只是提高效率的一個因素,如果你的MySQL有大數據量的表,就需要花時間研究建立最優秀的索引,或優化查詢語句。
(7)使用索引的注意事項
使用索引時,有以下一些技巧和注意事項:
◆索引不會包含有NULL值的列
只要列中包含有NULL值都將不會被包含在索引中,複合索引中只要有一列含有NULL值,那麼這一列對於此複合索引就是無效的。所以我們在資料庫設計時不要讓欄位的默認值為NULL。
◆使用短索引
對串列進行索引,如果可能應該指定一個前綴長度。例如,如果有一個CHAR(255)的列,如果在前10個或20個字元內,多數值是惟一的,那麼就不要對整個列進行索引。短索引不僅可以提高查詢速度而且可以節省磁碟空間和I/O操作。
◆索引列排序
MySQL查詢只使用一個索引,因此如果where子句中已經使用了索引的話,那麼order by中的列是不會使用索引的。因此資料庫默認排序可以符合要求的情況下不要使用排序操作;盡量不要包含多個列的排序,如果需要最好給這些列創建複合索引。
◆like語句操作
一般情況下不鼓勵使用like操作,如果非使用不可,如何使用也是一個問題。like 「%aaa%」 不會使用索引而like 「aaa%」可以使用索引。
◆不要在列上進行運算
select * from users where YEAR(adddate)2007; 將在每個行上進行運算,這將導致索引失效而進行全表掃描,因此我們可以改成
select * from users where adddate『2007-01-01』;
◆不使用NOT IN和操作
MySQL 資料庫索引 — B+樹模型
這時我們需要:
1、定位到記錄所在的頁
2、從頁內查找相應的記錄
在前面我們知道了為了主鍵快速一條記錄在頁中的位置而設立頁目錄,類似的辦法,為了定位一條記錄在所在的數據頁我們也可以建立一個別的目錄,在建立這個目錄的過程中,我們必須做2件事情:
上文敘述的目錄項和用戶記錄長得挺像,只不過目錄項中的兩個列是主鍵和頁號。所以,我們可以直接復用之前的數據頁來存儲目錄項。採用 record_type 欄位區分普通的記錄
同時,目錄項的 min_rec_flag 為1,普通記錄都為0
上面的數據結構就是B+樹,真正用來存放用戶記錄的都是B+樹最底層的葉子節點,其餘用來存放目錄項記錄的節點稱為非葉子節點或者內節點,最上邊的節點稱為根節點。
這裡我們假設一個數據頁,只能存3條記錄,實際上一個頁可以存很多條記錄。假設一個數據頁可以存100條用戶記錄,1000條目錄項記錄,那麼:
如果B+樹只有1層,則最多存放 100 條用戶記錄
如果B+樹只有2層,則最多能存放 1000 * 100 =
如果B+樹只有3層,則最多能存放 1000 * 1000 * 100 =
如果B+樹只有4層,則最多能存放 1000 * 1000 * 1000 * 100 =
所以,我們一般用到的B+樹不會超過4層,也就意味著通過主鍵查找記錄時,最多只需要進行4個頁面的查找就可以找到。
InnoDB 會自動為主鍵或者帶有 UNIQUE 屬性的列建立索引。
KEY 和 INDEX 是同義詞,創建索引命名時以 idx 為前綴,後面跟著需要建立索引的列名,且多個列名之間用下劃線隔開。
也可以在修改表結構的時候添加索引
最後,刪除這個索引。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/293927.html