經過上圖能夠直接的看出, 在MyISAM對B+樹的運用中明顯的特色以下:node
MyISAM引擎 索引文件的查看: mysql
在 /var/lib/mysql目錄中算法
.myd 即 my data , 數據庫中表的數據文件sql
.myi 即 my index , 數據庫中 索引文件數據庫
.log 即 mysql的日誌文件centos
InnoDB引擎 索引文件的查看: 性能
一樣在 /var/lib/mysql 目錄下面操作系統
InnoDB的實現方式業內也稱其爲聚簇索引, 什麼是聚簇索引呢? 就是相鄰的行的簡直被存儲到一塊兒, 對比上面的兩幅圖片就會發現, 在InnDB中, B+樹的葉子節點中存儲的是數據行中的一行行記錄, 缺點: 由於索引文件被存放在硬盤上, 因此很佔硬盤的空間.net
通常咱們會在每個表中添加一列 取名 id, 設置它爲primary key , 即將他設置成主鍵, 若是使用的存儲引擎也是InnoDB的話, 底層就會創建起主鍵索引, 也是聚簇索引, 而且會自動按照id的大小爲咱們排好序,(由於它的一個有序的樹)日誌
局部性原理是指CPU訪問存儲器時,不管是存取指令仍是存取數據,所訪問的存儲單元都趨於彙集在一個較小的連續區域中。 更進一步說, 當咱們經過程序向操做系統發送指令讓它讀取咱們指定的數據時, 操做系統會一次性讀取一頁(centos 每頁4kb大小,InnoDB存儲引擎中每一頁16kb)的數據, 它遵循局部性理論, 猜想當用戶須要使用某個數據時, 用戶極可能會使用這個數據周圍的數據,故而進行一次
什麼是頁呢? 簡單說,就是一條條數據被的存儲在磁盤上, 使用數據時須要先將數據從磁盤上讀取到內存中, InnoDB每次讀出數據時一樣會遵循 局部性原理, 而不是一條條讀取, 因而InnoDB將數據劃分紅一個一個的頁, 以頁做爲和磁盤之間交互的基本單位
經過以下sql, 能夠看到,InnoDB中每一頁的大小是16kb
show global status like 'Innodb_page_size';
名稱 | 簡述 |
---|---|
File Header | 文件頭部, 存儲頁的一些通用信息 |
Page Header | 頁面頭部, 存儲數據頁專有的信息 |
Infinum + supremum | 最大記錄和最小記錄, 這是兩個虛擬的行記錄 |
User Records | 用戶記錄, 用來實際存儲行記錄中的內容 |
Free Space | 空閒空間, 頁中尚位使用的空間 |
Page Directory | 頁面目錄, 存儲頁中某些記錄的位置 |
File Tailer | 文件尾部 , 用來校驗頁是否完整 |
每一頁中存儲的行數據越多. 總體的性能就會越強
compact的行格式以下圖所示
能夠看到在行格式中在存儲真正的數據的前面會存儲一些其餘信息, 這些信息是爲了描述這條記錄而不得不添加的一些信息, 這些額外的信息就是上圖中的前三行
在mysql中char是固定長度的類型, 同時mysql還支持諸如像 varchar這樣可變長度的類型, 不止varchar , 想 varbinary text blob這樣的變長數據類型, 由於 變長的數據類型的列存儲的數據的長度是不固定的, 因此說咱們在存儲真正的數據時, 也得將這些數據到底佔用了多大的長度也給保存起來
compact行格式會將值能夠爲NULL的列統一標記在 NULL標誌位中, 若是數據表中全部的字段都被標記上not null , 那麼就沒有NULL值列表
記錄頭信息, 顧名思義就是用來描述記錄頭中的信息, 記錄頭信息由固定的5個字節組成, 一共40位, 不一樣位表明的意思也不一樣, 以下表
名稱 | 單位 bit | 簡介 |
---|---|---|
預留位1 | 1 | 未使用 |
預留位2 | 1 | 未使用 |
delete_mark | 1 | 標記改行記錄是否被刪除了 |
min_rec_mark | 1 | 標記在 B+樹中每層的非葉子節點中最小的node |
n_owned | 4 | 表示當前記錄擁有的記錄數 |
heap_no | 13 | 表示當前記錄在堆中的位置 |
record_type | 3 | 表示當前記錄的類型 , 0表示普通記錄, 1表示B+樹中非葉子節點記錄, 2表示最小記錄 ,3表示最大記錄 |
next_record | 16 | 表示下一條記錄的相對位置 |
在mysql中每一行, 能存儲的最大的字節數是65535個字節數, 此時咱們使用下面的sql執行時就會出現行溢出現象
CREATE TABLE test ( c VARCHAR(65535) ) CHARSET=ascii ROW_FORMAT=Compact;
給varchar申請最大65535 , 再加上compact行格式中還有前面三個非數據列佔用內存,因此一準溢出, 若是不想溢出, 能夠適當的將 65535 - 3
前面說了, InnoDB中數據的讀取按照頁爲單位, 每一頁的大小是 16kb, 換算成字節就是16384個字節, 可是每行最多存儲 65535個字節啊, 也就是說一行數據可能須要好幾個頁來存儲
怎麼辦呢?
通常咱們都是將表中的id列設置爲主鍵, 這就會造成主鍵索引, 因而咱們須要注意了:
主鍵的佔用的空間越小,總體的檢索效率就會越高
爲何這麼說呢? 這就能夠結合頁的概念來解析, 在B+樹這種數據結果中, 葉子節點中用來存儲數據, 存儲數據的格式相似Key-value key就是索引值, value就是數據內容, 若是索引佔用的空間太大的話, 單頁16kb能存儲的索引就越小, 這就致使數據被分散在更多的頁上, 導致查詢的效率下降
爲某一列創建索引
給text表中的title列建立索引, 索引名字 my_index alter table text add index my_index (title);
雖然創建索引能提高查詢的效率, 根據前人的經驗看, 這並非必定的, 創建索引自己會直接消耗內存空間, 同時索, 插入,刪除, 這種寫操做就會打破B+樹的平衡面臨索引的重建, 通常出現以下兩種狀況時,是不推薦創建索引的
所謂選擇性,其實就是說不重複出現的索引值(基數,Cardinality) 與 表中的記錄數的比值
即: 選擇性= 基數 / 記錄數
選擇性的取值範圍在(0,1]之間, 選擇性越接近1 , 說明創建索引的必要性就越強, 好比對sex列進行創建索引,這裏面非男即女, 若是對它創建索引的話, 實際上是沒意義的, 還不如直接進行全表掃描來的快
如何使用sql計算選擇性呢? 嚴格遵循上面的公式
SELECT count(DISTINCT(title))/count(*) AS Selectivity FROM employees.titles; count(基數/記錄數) DISTINCT(title) / /count(*)
更詳細的例子看下面的鏈接
注意事項
索引沒法存儲null值
若是條件中有or, 即便條件中存在索引也不會使用索引,若是既想使用or,又想使用索引, 就給全部or條件控制的列加上索引
使用like查詢時, 若是以%開頭,確定是進行全表掃描
使用like查詢時, 若是%在條件後面
若是列的類型是字符串類型, 那麼必定要在條件中將數據用引號引發來,否則也會是索引失效
若是mysql認爲全表掃描比用索引塊, 一樣不會使用索引
聯合索引, 也叫複合索引,說白了就是多個字段一塊兒組合成一個索引
像下面這樣使用 id + title 組合在一塊兒構成一個聯合索引
CREATE TABLE `text` ( `id` int(11) NOT NULL AUTO_INCREMENT, `title` varchar(255) NOT NULL, `content` text NOT NULL, PRIMARY KEY (`id`,`title`) ) ENGINE=InnoDB AUTO_INCREMENT=3691 DEFAULT CHARSET=utf8
使用聯合索引進行查詢時必定要遵循左前綴原則, 什麼是左前綴原則呢? 就是說想讓索引生效的話,必定要添加上第一個索引, 只使用第二個索引進行查詢的話會致使索引失效
好比上面建立的聯合索引, 假如咱們的查詢條件是 where id = '1' 或者 where id = '1' and title = '唐詩宋詞' 索引都會不失效
可是若是咱們不使用第一個索引id, 像這樣 where title = '唐詩' , 結果就是致使索引失效
仍是使用這個例子:
CREATE TABLE `text` ( `id` int(11) NOT NULL AUTO_INCREMENT, `title` varchar(255) NOT NULL, `content` text NOT NULL, PRIMARY KEY (`id`,`title`) ) ENGINE=InnoDB AUTO_INCREMENT=3691 DEFAULT CHARSET=utf8
demo1: 當咱們像下面這樣寫sql時, 就會先按照id進行排序, 當id相同時,再按照title進行排序
select * form text order by id, title;
demo2: 當咱們像下面這樣寫sql時, 就會先將id相同的劃分爲一組, 再將title相同的劃分爲一組
select id,title form text group by id, title;
demo3: ASC和DESC混用, 其實你們都知道底層使用B+樹, 自己就是有序的, 要是不加限制的話,默認就是ASC, 反而是混着使用就使得索引失效
select * form text order by id ASC, title DESC;
相關參數
名稱 | 簡介 |
---|---|
slow_query_log | 慢查詢的開啓狀態 |
slow_query_log_file | 慢查詢日誌存儲的位置 |
long_query_time | 查詢超過多少秒才記錄下來 |
經常使用sql
# 查看mysql是否開啓了慢查詢 show variables like 'slow_query_log'; # 將全局變量設置爲ON set global slow_query_log ='on'; # 查看慢查詢日誌存儲的位置 show variables like 'slow_query_log_file'; # 查看規定的超過多少秒才被算做慢查詢記錄下來 show variables like 'long_query_time'; show variables like 'long_query%'; # 超過一秒就記錄 , 每次修改這個配置都從新創建一次連接 set global long_query_time=1;