學(xué)校里做的項(xiàng)目都是默認(rèn)MySQL的InnoDB存儲(chǔ)引擎,沒有思考過為什么使用,也沒思考過其優(yōu)缺和其他數(shù)據(jù)庫存儲(chǔ)引擎。直到我去實(shí)習(xí)了,在學(xué)習(xí)優(yōu)化的過程中,才發(fā)現(xiàn)自己很無知,知識(shí)很局限。為此做次彌補(bǔ)。
本系列:demo下載
(一)MySQL優(yōu)化筆記(一)--庫與表基本操作以及數(shù)據(jù)增刪改
(二)MySQL優(yōu)化筆記(二)--查找優(yōu)化(1)(非索引設(shè)計(jì))
(三)MySQL優(yōu)化筆記(二)--查找優(yōu)化(2)(外連接、多表聯(lián)合查詢以及查詢注意點(diǎn))
(四) MySQL優(yōu)化筆記(三)--索引的使用、原理和設(shè)計(jì)優(yōu)化
(五) MySQL優(yōu)化筆記(四)--表的設(shè)計(jì)與優(yōu)化(單表、多表)
(六)MySQL優(yōu)化筆記(五)--數(shù)據(jù)庫存儲(chǔ)引擎
(七)MySQL優(yōu)化筆記(六)--存儲(chǔ)過程和存儲(chǔ)函數(shù)
(八)MySQL優(yōu)化筆記(七)--視圖應(yīng)用詳解
(九) MySQL優(yōu)化筆記(八)--鎖機(jī)制超詳細(xì)解析(鎖分類、事務(wù)并發(fā)、引擎并發(fā)控制)
文章結(jié)構(gòu):(1)存儲(chǔ)引擎概述;(2)MySQL各大存儲(chǔ)引擎;(3)InnoDB和MyIsam使用及其原理對(duì)比;(4)InnoDB和MyIsam引擎原理;(5)剩余引擎的使用DEMO(主要是Mrg_Myisam分表);
文章目錄:(例子下載在最下方)
(1)存儲(chǔ)引擎概述
- 為什么要合理選擇數(shù)據(jù)庫存儲(chǔ)引擎
- 定義
- 存儲(chǔ)引擎作用
- 如何修改數(shù)據(jù)庫引擎
- 怎么查看修改成功
(2)MySQL各大存儲(chǔ)引擎
- InnoDB
- 適用場景
- MySQL官方對(duì)InnoDB的講解
- MyIsam
- 適用場景
- 補(bǔ)充:ISAM索引方法--索引順序存取方法
- Memory(也叫HEAP)堆內(nèi)存嘛
- Mrg_Myisam:(分表的一種方式--水平分表)
- Blackhole(黑洞引擎)
(3)InnoDB和MyIsam使用及其原理對(duì)比
- 使用的效果與區(qū)別展示
- 效果對(duì)比總述
- 使用建議
(4)InnoDB和MyIsam引擎原理
- MyIASM引擎的索引結(jié)構(gòu)
- InnoDB引擎的索引結(jié)構(gòu)
(5)剩余引擎的使用DEMO(主要是Mrg_Myisam分表)
- Mrg_Myisam引擎分表
- 項(xiàng)目中如何使用MRG_MYISAM總表
- MRG_MYISAM分表的優(yōu)點(diǎn)
- 使用MRG_MyISAM分表的必須思考問題
一、存儲(chǔ)引擎的概述:
基于此博客MySQL數(shù)據(jù)庫引擎去擴(kuò)展,不過每個(gè)我都會(huì)用例子去驗(yàn)證,并寫出的見解。
(1)為什么要合理選擇數(shù)據(jù)庫存儲(chǔ)引擎:
MySQL中的數(shù)據(jù)用各種不同的技術(shù)存儲(chǔ)在文件(或者內(nèi)存)中。這些技術(shù)中的每一種技術(shù)都使用不同的存儲(chǔ)機(jī)制、索引技巧、鎖定水平并且最終提供廣泛的不同的功能和能力。通過選擇不同的技術(shù),你能夠獲得額外的速度或者功能,從而改善你的應(yīng)用的整體功能。
這些不同的技術(shù)以及配套的相關(guān)功能在MySQL中被稱作存儲(chǔ)引擎(也稱作表類型)。MySQL默認(rèn)配置了許多不同的存儲(chǔ)引擎,可以預(yù)先設(shè)置或者在MySQL服務(wù)器中啟用。你可以選擇適用于服務(wù)器、數(shù)據(jù)庫和表格的存儲(chǔ)引擎,以便在選擇如何存儲(chǔ)你的信息、如何檢索這些信息以及你需要你的數(shù)據(jù)結(jié)合什么性能和功能的時(shí)候?yàn)槟闾峁┳畲蟮撵`活性。
(2)定義:
數(shù)據(jù)庫引擎是用于存儲(chǔ)、處理和保護(hù)數(shù)據(jù)的核心服務(wù)。利用數(shù)據(jù)庫引擎可控制訪問權(quán)限并快速處理事務(wù),從而滿足企業(yè)內(nèi)大多數(shù)需要處理大量數(shù)據(jù)的應(yīng)用程序的要求。 使用數(shù)據(jù)庫引擎創(chuàng)建用于聯(lián)機(jī)事務(wù)處理或聯(lián)機(jī)分析處理數(shù)據(jù)的關(guān)系數(shù)據(jù)庫。這包括創(chuàng)建用于存儲(chǔ)數(shù)據(jù)的表和用于查看、管理和保護(hù)數(shù)據(jù)安全的數(shù)據(jù)庫對(duì)象(如索引、視圖和存儲(chǔ)過程)。
(3)存儲(chǔ)引擎作用:
1)設(shè)計(jì)并創(chuàng)建數(shù)據(jù)庫以保存系統(tǒng)所需的關(guān)系或XML文檔。
2)實(shí)現(xiàn)系統(tǒng)以訪問和更改數(shù)據(jù)庫中存儲(chǔ)的數(shù)據(jù)。包括實(shí)現(xiàn)網(wǎng)站或使用數(shù)據(jù)的應(yīng)用程序,還包括生成使用SQL Server工具和實(shí)用工具以使用數(shù)據(jù)的過程。
3)為單位或客戶部署實(shí)現(xiàn)的系統(tǒng)。
4)提供日常管理支持以優(yōu)化數(shù)據(jù)庫的性能。
(4)如何修改數(shù)據(jù)庫引擎:
方式一:
修改配置文件my.ini
將mysql.ini另存為my.ini,在[mysqld]后面添加default-storage-engine=InnoDB,重啟服務(wù),數(shù)據(jù)庫默認(rèn)的引擎修改為InnoDB
方式二:
在建表的時(shí)候指定
create table mytbl(
id int primary key,
name varchar(50)
)type=MyISAM;
方式三:
建表后更改
alter table table_name type = InnoDB;
(5)怎么查看修改成功?
方式一:
show table status from table_name;
方式二:
show create table table_name
方式三:
使用數(shù)據(jù)庫管理工具啊。
二、MySQL各大存儲(chǔ)引擎:
最好先看下你下的MySQL支持什么數(shù)據(jù)庫引擎
這里寫圖片描述
存儲(chǔ)引擎主要有: 1. MyIsam , 2. InnoDB, 3. Memory, 4. Blackhole, 5. CSV, 6. Performance_Schema, 7. Archive, 8. Federated , 9 Mrg_Myisam
但是我們主要分析使用MyIsam 和InnoDB。其余略微帶過,詳情請分別百度。
(1)InnoDB:
定義:(默認(rèn)的存儲(chǔ)引擎)
InnoDB是一個(gè)事務(wù)型的存儲(chǔ)引擎,有行級(jí)鎖定和外鍵約束。
Innodb引擎提供了對(duì)數(shù)據(jù)庫ACID事務(wù)的支持,并且實(shí)現(xiàn)了SQL標(biāo)準(zhǔn)的四種隔離級(jí)別,關(guān)于數(shù)據(jù)庫事務(wù)與其隔離級(jí)別的內(nèi)容請見數(shù)據(jù)庫事務(wù)與其隔離級(jí)別這類型的文章。該引擎還提供了行級(jí)鎖和外鍵約束,它的設(shè)計(jì)目標(biāo)是處理大容量數(shù)據(jù)庫系統(tǒng),它本身其實(shí)就是基于MySQL后臺(tái)的完整數(shù)據(jù)庫系統(tǒng),MySQL運(yùn)行時(shí)Innodb會(huì)在內(nèi)存中建立緩沖池,用于緩沖數(shù)據(jù)和索引。但是該引擎不支持FULLTEXT類型的索引,而且它沒有保存表的行數(shù),當(dāng)SELECT COUNT(*) FROM TABLE時(shí)需要掃描全表。當(dāng)需要使用數(shù)據(jù)庫事務(wù)時(shí),該引擎當(dāng)然是首選。由于鎖的粒度更小,寫操作不會(huì)鎖定全表,所以在并發(fā)較高時(shí),使用Innodb引擎會(huì)提升效率。但是使用行級(jí)鎖也不是絕對(duì)的,如果在執(zhí)行一個(gè)SQL語句時(shí)MySQL不能確定要掃描的范圍,InnoDB表同樣會(huì)鎖全表。
//這個(gè)就是select鎖表的一種,不明確主鍵。增刪改查都可能會(huì)導(dǎo)致鎖全表,在以后我們會(huì)詳細(xì)列出。
SELECT * FROM products WHERE name='Mouse' FOR UPDATE;
適用場景:
1)經(jīng)常更新的表,適合處理多重并發(fā)的更新請求。
2)支持事務(wù)。
3)可以從災(zāi)難中恢復(fù)(通過bin-log日志等)。
4)外鍵約束。只有他支持外鍵。
5)支持自動(dòng)增加列屬性auto_increment。
MySQL官方對(duì)InnoDB的講解:
1)InnoDB給MySQL提供了具有提交、回滾和崩潰恢復(fù)能力的事務(wù)安全(ACID兼容)存儲(chǔ)引擎。
2)InnoDB鎖定在行級(jí)并且也在SELECT語句提供一個(gè)Oracle風(fēng)格一致的非鎖定讀,這些特色增加了多用戶部署和性能。沒有在InnoDB中擴(kuò)大鎖定的需要,因?yàn)樵贗nnoDB中行級(jí)鎖定適合非常小的空間。
3)InnoDB也支持FOREIGN KEY強(qiáng)制。在SQL查詢中,你可以自由地將InnoDB類型的表與其它MySQL的表的類型混合起來,甚至在同一個(gè)查詢中也可以混合。
4)InnoDB是為處理巨大數(shù)據(jù)量時(shí)的最大性能設(shè)計(jì),它的CPU效率可能是任何其它基于磁盤的關(guān)系數(shù)據(jù)庫引擎所不能匹敵的。
5) InnoDB被用來在眾多需要高性能的大型數(shù)據(jù)庫站點(diǎn)上產(chǎn)生。
補(bǔ)充:什么叫事務(wù)?簡稱ACID
A 事務(wù)的原子性(Atomicity):指一個(gè)事務(wù)要么全部執(zhí)行,要么不執(zhí)行.也就是說一個(gè)事務(wù)不可能只執(zhí)行了一半就停止了.比如你從取款機(jī)取錢,這個(gè)事務(wù)可以分成兩個(gè)步驟:1劃卡,2出錢.不可能劃了卡,而錢卻沒出來.這兩步必須同時(shí)完成.要么就不完成.
C 事務(wù)的一致性(Consistency):指事務(wù)的運(yùn)行并不改變數(shù)據(jù)庫中數(shù)據(jù)的一致性.例如,完整性約束了a+b=10,一個(gè)事務(wù)改變了a,那么b也應(yīng)該隨之改變.
I 獨(dú)立性(Isolation):事務(wù)的獨(dú)立性也有稱作隔離性,是指兩個(gè)以上的事務(wù)不會(huì)出現(xiàn)交錯(cuò)執(zhí)行的狀態(tài).因?yàn)檫@樣可能會(huì)導(dǎo)致數(shù)據(jù)不一致.
D 持久性(Durability):事務(wù)的持久性是指事務(wù)執(zhí)行成功以后,該事務(wù)所對(duì)數(shù)據(jù)庫所作的更改便是持久的保存在數(shù)據(jù)庫之中,不會(huì)無緣無故的回滾.
(2)MyIsam:
定義:
MyIASM是MySQL默認(rèn)的引擎,但是它沒有提供對(duì)數(shù)據(jù)庫事務(wù)的支持,也不支持行級(jí)鎖和外鍵,因此當(dāng)INSERT(插入)或UPDATE(更新)數(shù)據(jù)時(shí)即寫操作需要鎖定整個(gè)表,效率便會(huì)低一些。
MyIsam 存儲(chǔ)引擎獨(dú)立于操作系統(tǒng),也就是可以在windows上使用,也可以比較簡單的將數(shù)據(jù)轉(zhuǎn)移到linux操作系統(tǒng)上去。
意味著:引擎在創(chuàng)建表的時(shí)候,會(huì)創(chuàng)建三個(gè)文件,一個(gè)是.frm文件用于存儲(chǔ)表的定義,一個(gè)是.MYD文件用于存儲(chǔ)表的數(shù)據(jù),另一個(gè)是.MYI文件,存儲(chǔ)的是索引。操作系統(tǒng)對(duì)大文件的操作是比較慢的,這樣將表分為三個(gè)文件,那么.MYD這個(gè)文件單獨(dú)來存放數(shù)據(jù)自然可以優(yōu)化數(shù)據(jù)庫的查詢等操作。有索引管理和字段管理。MyISAM還使用一種表格鎖定的機(jī)制,來優(yōu)化多個(gè)并發(fā)的讀寫操作,其代價(jià)是你需要經(jīng)常運(yùn)行OPTIMIZE TABLE命令,來恢復(fù)被更新機(jī)制所浪費(fèi)的空間。
適用場景:
1)不支持事務(wù)的設(shè)計(jì),但是并不代表著有事務(wù)操作的項(xiàng)目不能用MyIsam存儲(chǔ)引擎,可以在service層進(jìn)行根據(jù)自己的業(yè)務(wù)需求進(jìn)行相應(yīng)的控制。
2)不支持外鍵的表設(shè)計(jì)。
3)查詢速度很快,如果數(shù)據(jù)庫insert和update的操作比較多的話比較適用。
4)整天 對(duì)表進(jìn)行加鎖的場景。
5)MyISAM極度強(qiáng)調(diào)快速讀取操作。
6)MyIASM中存儲(chǔ)了表的行數(shù),于是SELECT COUNT(*) FROM TABLE時(shí)只需要直接讀取已經(jīng)保存好的值而不需要進(jìn)行全表掃描。如果表的讀操作遠(yuǎn)遠(yuǎn)多于寫操作且不需要數(shù)據(jù)庫事務(wù)的支持,那么MyIASM也是很好的選擇。
缺點(diǎn):
就是不能在表損壞后恢復(fù)數(shù)據(jù)。(是不能主動(dòng)恢復(fù))
補(bǔ)充:ISAM索引方法--索引順序存取方法
定義:
是一個(gè)定義明確且歷經(jīng)時(shí)間考驗(yàn)的數(shù)據(jù)表格管理方法,它在設(shè)計(jì)之時(shí)就考慮到 數(shù)據(jù)庫被查詢的次數(shù)要遠(yuǎn)大于更新的次數(shù)。
特性:
ISAM執(zhí)行讀取操作的速度很快,而且不占用大量的內(nèi)存和存儲(chǔ)資源。
在設(shè)計(jì)之初就預(yù)想數(shù)據(jù)組織成有固定長度的記錄,按順序存儲(chǔ)的。---ISAM是一種靜態(tài)索引結(jié)構(gòu)。
缺點(diǎn):
1.它不 支持事務(wù)處理
2.也不能夠容錯(cuò)。如果你的硬盤崩潰了,那么數(shù)據(jù)文件就無法恢復(fù)了。如果你正在把ISAM用在關(guān)鍵任務(wù)應(yīng)用程序里,那就必須經(jīng)常備份你所有的實(shí) 時(shí)數(shù)據(jù),通過其復(fù)制特性,MYSQL能夠支持這樣的備份應(yīng)用程序。
(3)Memory(也叫HEAP)堆內(nèi)存嘛:
定義:
使用存在內(nèi)存中的內(nèi)容來創(chuàng)建表。每個(gè)MEMORY表只實(shí)際對(duì)應(yīng)一個(gè)磁盤文件。MEMORY類型的表訪問非常得快,因?yàn)樗臄?shù)據(jù)是放在內(nèi)存中的,并且默認(rèn)使用HASH索引。
但是一旦服務(wù)關(guān)閉,表中的數(shù)據(jù)就會(huì)丟失掉。 HEAP允許只駐留在內(nèi)存里的臨時(shí)表格。駐留在內(nèi)存里讓HEAP要比ISAM和MYISAM都快,但是它所管理的數(shù)據(jù)是不穩(wěn)定的,而且如果在關(guān)機(jī)之前沒有進(jìn)行保存,那么所有的數(shù)據(jù)都會(huì)丟失。在數(shù)據(jù)行被刪除的時(shí)候,HEAP也不會(huì)浪費(fèi)大量的空間。HEAP表格在你需要使用SELECT表達(dá)式來選擇和操控?cái)?shù)據(jù)的時(shí)候非常有用。
適用場景:
1)那些內(nèi)容變化不頻繁的代碼表,或者作為統(tǒng)計(jì)操作的中間結(jié)果表,便于高效地堆中間結(jié)果進(jìn)行分析并得到最終的統(tǒng)計(jì)結(jié)果。
2)目標(biāo)數(shù)據(jù)比較小,而且非常頻繁的進(jìn)行訪問,在內(nèi)存中存放數(shù)據(jù),如果太大的數(shù)據(jù)會(huì)造成內(nèi)存溢出??梢酝ㄟ^參數(shù)max_heap_table_size控制Memory表的大小,限制Memory表的最大的大小。
3)數(shù)據(jù)是臨時(shí)的,而且必須立即可用得到,那么就可以放在內(nèi)存中。
4)存儲(chǔ)在Memory表中的數(shù)據(jù)如果突然間丟失的話也沒有太大的關(guān)系。
注意: Memory同時(shí)支持散列索引和B樹索引,B樹索引可以使用部分查詢和通配查詢,也可以使用<,>和>=等操作符方便數(shù)據(jù)挖掘,散列索引相等的比較快但是對(duì)于范圍的比較慢很多。
特性要求:
1)要求存儲(chǔ)的數(shù)據(jù)是數(shù)據(jù)長度不變的格式,比如,Blob和Text類型的數(shù)據(jù)不可用(長度不固定的)。
2)要記住,在用完表格之后就刪除表格。
(4)Mrg_Myisam:(分表的一種方式--水平分表)
定義:
是一個(gè)相同的可以被當(dāng)作一個(gè)來用的MyISAM表的集合?!跋嗤币馕吨斜硗瑯拥牧泻退饕畔ⅰ?/h4>
也就是說,他將MyIsam引擎的多個(gè)表聚合起來,但是他的內(nèi)部沒有數(shù)據(jù),真正的數(shù)據(jù)依然是MyIsam引擎的表中,但是可以直接進(jìn)行查詢、刪除更新等操作。
比如:我們可能會(huì)遇到這樣的問題,同一種類的數(shù)據(jù)會(huì)根據(jù)數(shù)據(jù)的時(shí)間分為多個(gè)表,如果這時(shí)候進(jìn)行查詢的話,就會(huì)比較麻煩,Merge可以直接將多個(gè)表聚合成一個(gè)表統(tǒng)一查詢,然后再刪除Merge表(刪除的是定義),原來的數(shù)據(jù)不會(huì)影響。
(5)Blackhole(黑洞引擎)
定義
任何寫入到此引擎的數(shù)據(jù)均會(huì)被丟棄掉, 不做實(shí)際存儲(chǔ);Select語句的內(nèi)容永遠(yuǎn)是空。
他會(huì)丟棄所有的插入的數(shù)據(jù),服務(wù)器會(huì)記錄下Blackhole表的日志,所以可以用于復(fù)制數(shù)據(jù)到備份數(shù)據(jù)庫。
使用場景:
1)驗(yàn)證dump file語法的正確性
2)以使用blackhole引擎來檢測binlog功能所需要的額外負(fù)載
3)充當(dāng)日志服務(wù)器
其余引擎,大家感興趣就各自先百度吧。本文主要是對(duì)比引擎使用以及其原理。
三、InnoDB和MyIsam使用及其原理對(duì)比:
(1)使用的效果與區(qū)別展示:
MySQL數(shù)據(jù)庫實(shí)戰(zhàn)例子(存儲(chǔ)引擎、視圖、鎖機(jī)制、分表)
(一)在一個(gè)普通數(shù)據(jù)庫中創(chuàng)建兩張分別以MyIsam和InnoDB作為存儲(chǔ)引擎的表。
create table testMyIsam(
id int unsigned primary key auto_increment,
name varchar(20) not null
)engine=myisam;
create table testInnoDB(
id int unsigned primary key auto_increment,
name varchar(20) not null
)engine=innodb;
嘿嘿嘿,,效果如圖,一會(huì)總結(jié)。
這里寫圖片描述
(二)對(duì)比插入效率(百萬級(jí)插入):(雖然速度上MyISAM快,但是增刪改是涉及事務(wù)安全的,所以用InnoDB相對(duì)好很多)
為了更好地對(duì)比,我們可以使用函數(shù)的方式或者存儲(chǔ)過程的方式。博主采用存儲(chǔ)過程。(存儲(chǔ)過程在往后的章節(jié)會(huì)講到)
//創(chuàng)建存儲(chǔ)過程
delimiter $$
drop procedure if exists ptestmyisam;
create procedure ptestmyisam()
begin
declare pid int ;
set pid = 1000000;
while pid>0
do
insert into testmyisam(name) values(concat("fuzhu", pid));
set pid = pid-1;
end while;
end $$
//使用存儲(chǔ)過程:
call ptestmyisam();
這里寫圖片描述
//創(chuàng)建存儲(chǔ)過程(盡量把Innodb的數(shù)量級(jí)壓低,不然,,卡在那里半天也不奇怪)
delimiter $$
drop procedure if exists ptestInndb;
create procedure ptestInndb()
begin
declare pid int ;
set pid = 1000000;
while pid>0
do
insert into testinnodb(name) values(concat("fuzhu", pid));
set pid = pid-1;
end while;
end $$
//使用存儲(chǔ)過程:
call ptestInndb();
本博主在幾次innodb測試百萬插入的時(shí)候,數(shù)據(jù)庫炸了(笑哭)。最終只成功插入1W條??梢娦蕦?duì)比。
當(dāng)然innodb默認(rèn)是開啟事務(wù)的,如果我們把事務(wù)給停了,會(huì)快很多。
//停掉事務(wù)
set autocommit = 0;
//調(diào)用存儲(chǔ)過程
call ptestInndb;
//重啟事務(wù)
set autocommit = 1;
這里寫圖片描述
(三)對(duì)比更新:(雖然速度上MyISAM快,但是增刪改是涉及事務(wù)安全的,所以InnoDB相對(duì)好很多)
//耗時(shí)3秒多
update testinnodb set name = 'fuzhu' where id>0 and id<10000;
//耗時(shí)0.171秒
update testmyisam set name = 'fuzhu' where id>0 and id<13525;
(四)查詢對(duì)比:
1)查詢總數(shù)目
select count(*) from testInnoDB;
select count(*) from testMyIsam;
這就是innodb查一萬跟myisam查一百萬的區(qū)別??效果對(duì)比立刻出現(xiàn)。
這里寫圖片描述
2)查詢無索引的列:(這些都自己拿我給出或者自己寫的數(shù)據(jù)庫去體驗(yàn)下吧,,差距很明顯)
select * from testMyIsam where name > "fuzhu100" ;
select * from testInnoDB where name > "fuzhu100" ;
3)查詢有索引的列:
select * from testMyIsam where id > 10 ;
select * from testinnodb where id > 10 ;
4)存儲(chǔ)大?。?/h4>
testMyIsam 存了一百萬。testinnodb 存了兩萬。
這里寫圖片描述
(2)效果對(duì)比總述:
1)事務(wù)。MyISAM類型不支持事務(wù)處理等高級(jí)處理,而InnoDB類型支持,提供事務(wù)支持已經(jīng)外部鍵等高級(jí)數(shù)據(jù)庫功能。
InnoDB表的行鎖也不是絕對(duì)的,假如在執(zhí)行一個(gè)SQL語句時(shí)MySQL不能確定要掃描的范圍,InnoDB表同樣會(huì)鎖全表,例如updatetable set num=1 where name like “a%”
就是說在不確定的范圍時(shí),InnoDB還是會(huì)鎖表的。
2)性能主題。MyISAM類型的表強(qiáng)調(diào)的是性能,其執(zhí)行數(shù)度比InnoDB類型更快。
3)行數(shù)保存。InnoDB 中不保存表的具體行數(shù),也就是說,執(zhí)行select count() fromtable時(shí),InnoDB要掃描一遍整個(gè)表來計(jì)算有多少行,但是MyISAM只要簡單的讀出保存好的行數(shù)即可。注意的是,當(dāng)count()語句包含where條件時(shí),兩種表的操作是一樣的。
4)索引存儲(chǔ)。對(duì)于AUTO_INCREMENT類型的字段,InnoDB中必須包含只有該字段的索引,但是在MyISAM表中,可以和其他字段一起建立聯(lián)合索引。
MyISAM支持全文索引(FULLTEXT)、壓縮索引,InnoDB不支持
MyISAM的索引和數(shù)據(jù)是分開的,并且索引是有壓縮的,內(nèi)存使用率就對(duì)應(yīng)提高了不少。能加載更多索引,而Innodb是索引和數(shù)據(jù)是緊密捆綁的,沒有使用壓縮從而會(huì)造成Innodb比MyISAM體積龐大不小。
InnoDB存儲(chǔ)引擎被完全與MySQL服務(wù)器整合,InnoDB存儲(chǔ)引擎為在主內(nèi)存中緩存數(shù)據(jù)和索引而維持它自己的緩沖池。InnoDB存儲(chǔ)它的表&索引在一個(gè)表空間中,表空間可以包含數(shù)個(gè)文件(或原始磁盤分區(qū))。這與MyISAM表不同,比如在MyISAM表中每個(gè)表被存在分離的文件中。InnoDB 表可以是任何尺寸,即使在文件尺寸被限制為2GB的操作系統(tǒng)上。
5)服務(wù)器數(shù)據(jù)備份。InnoDB必須導(dǎo)出SQL來備份,LOAD TABLE FROM MASTER操作對(duì)InnoDB是不起作用的,解決方法是首先把InnoDB表改成MyISAM表,導(dǎo)入數(shù)據(jù)后再改成InnoDB表,但是對(duì)于使用的額外的InnoDB特性(例如外鍵)的表不適用。
而且MyISAM應(yīng)對(duì)錯(cuò)誤編碼導(dǎo)致的數(shù)據(jù)恢復(fù)速度快。MyISAM的數(shù)據(jù)是以文件的形式存儲(chǔ),所以在跨平臺(tái)的數(shù)據(jù)轉(zhuǎn)移中會(huì)很方便。在備份和恢復(fù)時(shí)可單獨(dú)針對(duì)某個(gè)表進(jìn)行操作。
InnoDB是拷貝數(shù)據(jù)文件、備份 binlog,或者用 mysqldump,在數(shù)據(jù)量達(dá)到幾十G的時(shí)候就相對(duì)痛苦了。
6)鎖的支持。MyISAM只支持表鎖。InnoDB支持表鎖、行鎖 行鎖大幅度提高了多用戶并發(fā)操作的新能。但是InnoDB的行鎖,只是在WHERE的主鍵是有效的,非主鍵的WHERE都會(huì)鎖全表的
//用于把表的拷貝從主服務(wù)器轉(zhuǎn)移到從屬服務(wù)器。
LOAD TABLE tbl_name FROM MASTER
(3)使用建議:
以下兩點(diǎn)必須使用 InnoDB:
1)可靠性高或者要求事務(wù)處理,則使用InnoDB。這個(gè)是必須的。
2)表更新和查詢都相當(dāng)?shù)念l繁,并且表鎖定的機(jī)會(huì)比較大的情況指定InnoDB數(shù)據(jù)引擎的創(chuàng)建。
對(duì)比之下,MyISAM的使用場景:
1)做很多count的計(jì)算的。如一些日志,調(diào)查的業(yè)務(wù)表。
2)插入修改不頻繁,查詢非常頻繁的。
MySQL能夠允許你在表這一層應(yīng)用數(shù)據(jù)庫引擎,所以你可以只對(duì)需要事務(wù)處理的表格來進(jìn)行性能優(yōu)化,而把不需要事務(wù)處理的表格交給更加輕便的MyISAM引擎。對(duì)于 MySQL而言,靈活性才是關(guān)鍵。
四、InnoDB和MyIsam引擎原理:
在此之前,先去理解什么是聚簇和非聚簇索引。
(1)MyIASM引擎的索引結(jié)構(gòu):
MyISAM索引結(jié)構(gòu): MyISAM索引用的B+ tree來儲(chǔ)存數(shù)據(jù),MyISAM索引的指針指向的是鍵值的地址,地址存儲(chǔ)的是數(shù)據(jù)。
B+Tree的數(shù)據(jù)域存儲(chǔ)的內(nèi)容為實(shí)際數(shù)據(jù)的地址,也就是說它的索引和實(shí)際的數(shù)據(jù)是分開的,只不過是用索引指向了實(shí)際的數(shù)據(jù),這種索引就是所謂的非聚集索引。
圖取自博客
這里寫圖片描述
因此,過程為: MyISAM中索引檢索的算法為首先按照B+Tree搜索算法搜索索引,如果指定的Key存在,則取出其data域的值,然后以data域的值為地址,根據(jù)data域的值去讀取相應(yīng)數(shù)據(jù)記錄。
(2)InnoDB引擎的索引結(jié)構(gòu):
也是B+Treee索引結(jié)構(gòu)。Innodb的索引文件本身就是數(shù)據(jù)文件,即B+Tree的數(shù)據(jù)域存儲(chǔ)的就是實(shí)際的數(shù)據(jù),這種索引就是聚集索引。這個(gè)索引的key就是數(shù)據(jù)表的主鍵,因此InnoDB表數(shù)據(jù)文件本身就是主索引。
InnoDB的輔助索引數(shù)據(jù)域存儲(chǔ)的也是相應(yīng)記錄主鍵的值而不是地址,所以當(dāng)以輔助索引查找時(shí),會(huì)先根據(jù)輔助索引找到主鍵,再根據(jù)主鍵索引找到實(shí)際的數(shù)據(jù)。所以Innodb不建議使用過長的主鍵,否則會(huì)使輔助索引變得過大。
建議使用自增的字段作為主鍵,這樣B+Tree的每一個(gè)結(jié)點(diǎn)都會(huì)被順序的填滿,而不會(huì)頻繁的分裂調(diào)整,會(huì)有效的提升插入數(shù)據(jù)的效率。
這里寫圖片描述
上圖,可以看到葉節(jié)點(diǎn)包含了完整的數(shù)據(jù)記錄。這種索引叫做聚集索引。因?yàn)镮nnoDB的數(shù)據(jù)文件本身要按主鍵聚集,所以InnoDB要求表必須有主鍵(MyISAM可以沒有),如果沒有顯式指定,則MySQL系統(tǒng)會(huì)自動(dòng)選擇一個(gè)可以唯一標(biāo)識(shí)數(shù)據(jù)記錄的列作為主鍵,如果不存在這種列,則MySQL自動(dòng)為InnoDB表生成一個(gè)隱含字段作為主鍵,這個(gè)字段長度為6個(gè)字節(jié),類型為長整形。
而且,與MyISAM索引的不同是InnoDB的輔助索引data域存儲(chǔ)相應(yīng)記錄主鍵的值而不是地址。換句話說,InnoDB的所有輔助索引都引用主鍵作為data域。
因此,過程為:將主鍵組織到一棵B+樹中,而行數(shù)據(jù)就儲(chǔ)存在葉子節(jié)點(diǎn)上,若使用”where id = 13”這樣的條件查找主鍵,則按照B+樹的檢索算法即可查找到對(duì)應(yīng)的葉節(jié)點(diǎn),之后獲得行數(shù)據(jù)。若對(duì)Name列進(jìn)行條件搜索,則需要兩個(gè)步驟:第一步在輔助索引B+樹中檢索Name,到達(dá)其葉子節(jié)點(diǎn)獲取對(duì)應(yīng)的主鍵。第二步使用主鍵在主索引B+樹種再執(zhí)行一次B+樹檢索操作,最終到達(dá)葉子節(jié)點(diǎn)即可獲取整行數(shù)據(jù)。
五、剩余引擎的使用DEMO(主要是Mrg_Myisam分表)
Memory(Heap):
CREATE TABLE tbHeap (
id int unsigned primary key auto_increment,
name varchar(20) not null
) TYPE=Heap
(1)Mrg_Myisam引擎分表:
(一)先創(chuàng)建兩張user表,也就是說我要把用戶表進(jìn)行水平分表(因?yàn)橛脩籼嗬玻?0億)
//用戶表一
CREATE TABLE IF NOT EXISTS `user1` (
`id` int(11) NOT NULL ,
`name` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ;
//用戶表二
CREATE TABLE IF NOT EXISTS `user2` (
`id` int(11) NOT NULL ,
`name` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ;
//分別插入兩條測試數(shù)據(jù)先
INSERT INTO `user1` (`name`) VALUES('輔助');
INSERT INTO `user2` (`name`) VALUES('JackFrost');
分表的要求:
1)分表必須使用MyISAM存儲(chǔ)引擎;
2)每個(gè)分表的表結(jié)構(gòu)必須相同;
3)MySQL必須具有存儲(chǔ)分表數(shù)據(jù)文件和索引文件的目錄的讀寫權(quán)限;
4)必須啟用MySQL的符號(hào)鏈接支持功能。
文件存儲(chǔ):
1)MYD文件是MyISAM表的數(shù)據(jù)文件;
2)MYI文件是MyISAM表的索引文件;
3)frm文件用于存儲(chǔ)MyISAM表的表結(jié)構(gòu)。
(二)最后創(chuàng)建一個(gè)MERGE表,作為一個(gè)分發(fā)作用的總表。
CREATE TABLE IF NOT EXISTS `alluser` (
`id` int(11) NOT NULL ,
`name` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MRG_MYISAM
DEFAULT CHARSET=utf8
UNION=(user1,user2) ;
(三)測試:
1. 查詢:
select id,name from alluser;
可見根據(jù)總表把所有數(shù)據(jù)都查出來了
這里寫圖片描述
2. 然而,當(dāng)你測試插入的時(shí)候:
你會(huì)發(fā)現(xiàn),總表只有只讀權(quán)限
這里寫圖片描述
3. 但是我們又想在總表去插入,怎么辦呢??
允許通過總表插入數(shù)據(jù),數(shù)據(jù)存儲(chǔ)在MRG文件列出的第一個(gè)分表之中。例如,執(zhí)行以下SQL語句,將總表的INSERT_METHOD修改為FIRST,然后通過總表插入一條數(shù)據(jù):
//就是插入總表的時(shí)候,其實(shí)也是插入到第一個(gè)分表。
ALTER TABLE `test_engine`.`alluser` INSERT_METHOD = FIRST;
INSERT INTO `alluser` (id,`name`) VALUES(2,'插入到第一個(gè)分表');
這里寫圖片描述
這里寫圖片描述
而,允許通過總表插入數(shù)據(jù),數(shù)據(jù)存儲(chǔ)在MRG文件列出的最后一個(gè)分表之中。例如,執(zhí)行以下SQL語句,將總表的INSERT_METHOD修改為LAST,然后通過總表插入一條數(shù)據(jù):
//就是插入總表的時(shí)候,其實(shí)也是插入到最后一個(gè)分表。
ALTER TABLE `test_engine`.`alluser` INSERT_METHOD = LAST;
這里寫圖片描述
這里寫圖片描述
注意INSERT_METHOD :
INSERT_METHOD選項(xiàng)只會(huì)影響通過總表插入(INSERT)數(shù)據(jù)的行為,通過總表對(duì)數(shù)據(jù)進(jìn)行刪除(DELETE)、查詢(SELECT)、修改(UPDATE)、清空(TRUNCATE)都不會(huì)受影響。
(2)項(xiàng)目中如何使用MRG_MYISAM總表:
(一)插入(INSERT)數(shù)據(jù)時(shí),需要根據(jù)給定的路由策略將新數(shù)據(jù)分別插入不同的子表,此處采用對(duì)id進(jìn)行模3計(jì)算(可能結(jié)果為0、1、2)來決定插入哪個(gè)子表。
所以我們需要?jiǎng)?chuàng)建一張表專門去創(chuàng)建id。
CREATE TABLE `create_id` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
)
COLLATE='utf8_general_ci'
ENGINE=MyISAM
;
(二)ORM框架的時(shí)候使用上面這個(gè)表生成id
insert into create_id () values();
(三)真正插入的時(shí)候:
先獲取ID,然后根據(jù)拿到的創(chuàng)建ID去插入到分表。
INSERT INTO {$table_name} (id, name) VALUES ('{$id}');
(四)獲取表名和ID:
這個(gè)就需要我們自定義自己的規(guī)則了。比如取余、比如范圍預(yù)判斷。
其他的刪除(DELETE)、查詢(SELECT)、修改(UPDATE)、清空(TRUNCATE)等操作都可以通過總表alluser完成。
基于MRG_MYISAM存儲(chǔ)引擎實(shí)現(xiàn)的分表機(jī)制,比較適用于插入和查詢頻率較高的場景。由于MyISAM具有表級(jí)別的鎖機(jī)制,所以不適用于更新頻率較高的場景。
(3)MRG_MYISAM分表的優(yōu)點(diǎn):
(一)適用于存儲(chǔ)日志數(shù)據(jù)。例如,可以將不同月份的數(shù)據(jù)存入不同的表,然后使用一些工具壓縮數(shù)據(jù),最后通過一張MRG_MYISAM表來查詢這些數(shù)據(jù)。
(二)可以獲得更快的速度??梢愿鶕?jù)某種指標(biāo),將一張只讀的大表分割成若干張小表,然后將這些小表分別放在不同的磁盤上存儲(chǔ)。當(dāng)需要讀取數(shù)據(jù)時(shí),MERGE表可以將這些小表的數(shù)據(jù)組織起來,就好像使用先前的大表一樣,但是速度會(huì)快很多。
(三)可以提高搜索效率??梢愿鶕?jù)某種指標(biāo)將一張只讀的大數(shù)據(jù)表分割為若干個(gè)小表,然后根據(jù)不同的查詢維度,可以得到若干種小表的組合,然后再為這些組合分別創(chuàng)建不同的MERGE表。例如,有一張只讀的大數(shù)據(jù)表T,分割為T1、T2、T3、T4,共4張小表,有兩種查詢維度A和B,A可以得到小表組合T1、T2和T3,B可以得到小表組合T2、T3和T4,分別為A和B創(chuàng)建兩個(gè)MERGE表,也就是M1和M2,這兩個(gè)MERGE表分別關(guān)聯(lián)的小表是存在交疊的。
(四)可以更加有效的修復(fù)表。修復(fù)單個(gè)的小表要比修復(fù)大數(shù)據(jù)表更加容易。
(五)多個(gè)子表映射至一個(gè)總表的速度極快。因?yàn)镸ERGE表本身不會(huì)存儲(chǔ)和維護(hù)任何索引,索引都是由各個(gè)關(guān)聯(lián)的子表存儲(chǔ)和維護(hù)的,所以創(chuàng)建和重新映射MERGE表的速度非??臁?/h4>
(六)不受操作系統(tǒng)的文件大小限制。單個(gè)表會(huì)受到文件大小的限制,但是拆分成多個(gè)表,則可以無限擴(kuò)容。
(七)MERGE表還可以用來給單個(gè)表創(chuàng)建別名,并且?guī)缀醪粫?huì)影響性能。
(4)使用MRG_MyISAM分表的必須思考問題:(針對(duì)總表)
(一)總表(MERGE表)必須使用MRG_MyISAM存儲(chǔ)引擎,子表必須使用MyISAM存儲(chǔ)引擎,不可避免會(huì)受到MyISAM存儲(chǔ)引擎的限制。(比如不支持事務(wù))
(二)MERGE表不能使用某些MyISAM特性。例如,雖然可以為子表創(chuàng)建全文索引,但是卻不能使用全文索引,只能通過MERGE表查詢數(shù)據(jù)。
(三)若使用ALTER TABLE語句修改總表的存儲(chǔ)引擎,那么會(huì)立即丟失總表和子表的映射關(guān)系,并且會(huì)將所有子表的數(shù)據(jù)拷貝至修改后的新表。
(四)總表和子表的主鍵都不能使用自動(dòng)增長(auto increment)。
(五)子表之間不能保證唯一鍵約束,只能保證單個(gè)子表內(nèi)部的唯一性約束。也就是說,直接查總表全部,id可能會(huì)重復(fù)。
(六)由于不能保證唯一鍵約束,導(dǎo)致REPLACE語句的行為會(huì)不可預(yù)期,INSERT ... ON DUPLICATE KEY UPDATE語句也有類似問題。因此,只能使用路由策略,對(duì)子表使用這些語句,而不能對(duì)總表使用。
(七)當(dāng)正在使用總表時(shí),不能對(duì)任何子表執(zhí)行ANALYZE TABLE、REPAIR TABLE、OPTIMIZE TABLE、ALTER TABLE、DROP TABLE、DELETE或TRUNCATE TABLE語句,否則會(huì)導(dǎo)致不可預(yù)期的結(jié)果。
(八)總表和子表的表結(jié)構(gòu)必須完全一致。
(九)總表可以映射的所有子表的總行數(shù)上限為 2的64次方 行。
(十)不支持INSERT DELAYED語句。
數(shù)據(jù)庫DEMO下載:MySQL數(shù)據(jù)庫實(shí)戰(zhàn)例子(存儲(chǔ)引擎、視圖、鎖機(jī)制、分表)
好了,MySQL優(yōu)化筆記(五)--數(shù)據(jù)庫存儲(chǔ)引擎(主要分析對(duì)比InnoDB和MyISAM)講完了,又是一篇數(shù)據(jù)庫優(yōu)化記錄,這是積累的必經(jīng)一步,我會(huì)繼續(xù)出這個(gè)系列文章,分享經(jīng)驗(yàn)給大家。歡迎在下面指出錯(cuò)誤,共同學(xué)習(xí)??!你的點(diǎn)贊是對(duì)我最好的支持??!
更多內(nèi)容,可以訪問JackFrost的博客
create table testMyIsam(
id int unsigned primary key auto_increment,
name varchar(20) not null
)engine=myisam;
create table testInnoDB(
id int unsigned primary key auto_increment,
name varchar(20) not null
)engine=innodb;
這里寫圖片描述
//創(chuàng)建存儲(chǔ)過程
delimiter $$
drop procedure if exists ptestmyisam;
create procedure ptestmyisam()
begin
declare pid int ;
set pid = 1000000;
while pid>0
do
insert into testmyisam(name) values(concat("fuzhu", pid));
set pid = pid-1;
end while;
end $$
//使用存儲(chǔ)過程:
call ptestmyisam();
這里寫圖片描述
//創(chuàng)建存儲(chǔ)過程(盡量把Innodb的數(shù)量級(jí)壓低,不然,,卡在那里半天也不奇怪)
delimiter $$
drop procedure if exists ptestInndb;
create procedure ptestInndb()
begin
declare pid int ;
set pid = 1000000;
while pid>0
do
insert into testinnodb(name) values(concat("fuzhu", pid));
set pid = pid-1;
end while;
end $$
//使用存儲(chǔ)過程:
call ptestInndb();
//停掉事務(wù)
set autocommit = 0;
//調(diào)用存儲(chǔ)過程
call ptestInndb;
//重啟事務(wù)
set autocommit = 1;
這里寫圖片描述
//耗時(shí)3秒多
update testinnodb set name = 'fuzhu' where id>0 and id<10000;
//耗時(shí)0.171秒
update testmyisam set name = 'fuzhu' where id>0 and id<13525;
select count(*) from testInnoDB;
select count(*) from testMyIsam;
這里寫圖片描述
select * from testMyIsam where name > "fuzhu100" ;
select * from testInnoDB where name > "fuzhu100" ;
select * from testMyIsam where id > 10 ;
select * from testinnodb where id > 10 ;
testMyIsam 存了一百萬。testinnodb 存了兩萬。
這里寫圖片描述
(2)效果對(duì)比總述:
1)事務(wù)。MyISAM類型不支持事務(wù)處理等高級(jí)處理,而InnoDB類型支持,提供事務(wù)支持已經(jīng)外部鍵等高級(jí)數(shù)據(jù)庫功能。
InnoDB表的行鎖也不是絕對(duì)的,假如在執(zhí)行一個(gè)SQL語句時(shí)MySQL不能確定要掃描的范圍,InnoDB表同樣會(huì)鎖全表,例如updatetable set num=1 where name like “a%”
就是說在不確定的范圍時(shí),InnoDB還是會(huì)鎖表的。
2)性能主題。MyISAM類型的表強(qiáng)調(diào)的是性能,其執(zhí)行數(shù)度比InnoDB類型更快。
3)行數(shù)保存。InnoDB 中不保存表的具體行數(shù),也就是說,執(zhí)行select count() fromtable時(shí),InnoDB要掃描一遍整個(gè)表來計(jì)算有多少行,但是MyISAM只要簡單的讀出保存好的行數(shù)即可。注意的是,當(dāng)count()語句包含where條件時(shí),兩種表的操作是一樣的。
4)索引存儲(chǔ)。對(duì)于AUTO_INCREMENT類型的字段,InnoDB中必須包含只有該字段的索引,但是在MyISAM表中,可以和其他字段一起建立聯(lián)合索引。
MyISAM支持全文索引(FULLTEXT)、壓縮索引,InnoDB不支持
MyISAM的索引和數(shù)據(jù)是分開的,并且索引是有壓縮的,內(nèi)存使用率就對(duì)應(yīng)提高了不少。能加載更多索引,而Innodb是索引和數(shù)據(jù)是緊密捆綁的,沒有使用壓縮從而會(huì)造成Innodb比MyISAM體積龐大不小。
InnoDB存儲(chǔ)引擎被完全與MySQL服務(wù)器整合,InnoDB存儲(chǔ)引擎為在主內(nèi)存中緩存數(shù)據(jù)和索引而維持它自己的緩沖池。InnoDB存儲(chǔ)它的表&索引在一個(gè)表空間中,表空間可以包含數(shù)個(gè)文件(或原始磁盤分區(qū))。這與MyISAM表不同,比如在MyISAM表中每個(gè)表被存在分離的文件中。InnoDB 表可以是任何尺寸,即使在文件尺寸被限制為2GB的操作系統(tǒng)上。
5)服務(wù)器數(shù)據(jù)備份。InnoDB必須導(dǎo)出SQL來備份,LOAD TABLE FROM MASTER操作對(duì)InnoDB是不起作用的,解決方法是首先把InnoDB表改成MyISAM表,導(dǎo)入數(shù)據(jù)后再改成InnoDB表,但是對(duì)于使用的額外的InnoDB特性(例如外鍵)的表不適用。
而且MyISAM應(yīng)對(duì)錯(cuò)誤編碼導(dǎo)致的數(shù)據(jù)恢復(fù)速度快。MyISAM的數(shù)據(jù)是以文件的形式存儲(chǔ),所以在跨平臺(tái)的數(shù)據(jù)轉(zhuǎn)移中會(huì)很方便。在備份和恢復(fù)時(shí)可單獨(dú)針對(duì)某個(gè)表進(jìn)行操作。
InnoDB是拷貝數(shù)據(jù)文件、備份 binlog,或者用 mysqldump,在數(shù)據(jù)量達(dá)到幾十G的時(shí)候就相對(duì)痛苦了。
6)鎖的支持。MyISAM只支持表鎖。InnoDB支持表鎖、行鎖 行鎖大幅度提高了多用戶并發(fā)操作的新能。但是InnoDB的行鎖,只是在WHERE的主鍵是有效的,非主鍵的WHERE都會(huì)鎖全表的
//用于把表的拷貝從主服務(wù)器轉(zhuǎn)移到從屬服務(wù)器。
LOAD TABLE tbl_name FROM MASTER
(3)使用建議:
以下兩點(diǎn)必須使用 InnoDB:
1)可靠性高或者要求事務(wù)處理,則使用InnoDB。這個(gè)是必須的。
2)表更新和查詢都相當(dāng)?shù)念l繁,并且表鎖定的機(jī)會(huì)比較大的情況指定InnoDB數(shù)據(jù)引擎的創(chuàng)建。
對(duì)比之下,MyISAM的使用場景:
1)做很多count的計(jì)算的。如一些日志,調(diào)查的業(yè)務(wù)表。
2)插入修改不頻繁,查詢非常頻繁的。
MySQL能夠允許你在表這一層應(yīng)用數(shù)據(jù)庫引擎,所以你可以只對(duì)需要事務(wù)處理的表格來進(jìn)行性能優(yōu)化,而把不需要事務(wù)處理的表格交給更加輕便的MyISAM引擎。對(duì)于 MySQL而言,靈活性才是關(guān)鍵。
四、InnoDB和MyIsam引擎原理:
在此之前,先去理解什么是聚簇和非聚簇索引。
(1)MyIASM引擎的索引結(jié)構(gòu):
MyISAM索引結(jié)構(gòu): MyISAM索引用的B+ tree來儲(chǔ)存數(shù)據(jù),MyISAM索引的指針指向的是鍵值的地址,地址存儲(chǔ)的是數(shù)據(jù)。
B+Tree的數(shù)據(jù)域存儲(chǔ)的內(nèi)容為實(shí)際數(shù)據(jù)的地址,也就是說它的索引和實(shí)際的數(shù)據(jù)是分開的,只不過是用索引指向了實(shí)際的數(shù)據(jù),這種索引就是所謂的非聚集索引。
圖取自博客
這里寫圖片描述
因此,過程為: MyISAM中索引檢索的算法為首先按照B+Tree搜索算法搜索索引,如果指定的Key存在,則取出其data域的值,然后以data域的值為地址,根據(jù)data域的值去讀取相應(yīng)數(shù)據(jù)記錄。
(2)InnoDB引擎的索引結(jié)構(gòu):
也是B+Treee索引結(jié)構(gòu)。Innodb的索引文件本身就是數(shù)據(jù)文件,即B+Tree的數(shù)據(jù)域存儲(chǔ)的就是實(shí)際的數(shù)據(jù),這種索引就是聚集索引。這個(gè)索引的key就是數(shù)據(jù)表的主鍵,因此InnoDB表數(shù)據(jù)文件本身就是主索引。
InnoDB的輔助索引數(shù)據(jù)域存儲(chǔ)的也是相應(yīng)記錄主鍵的值而不是地址,所以當(dāng)以輔助索引查找時(shí),會(huì)先根據(jù)輔助索引找到主鍵,再根據(jù)主鍵索引找到實(shí)際的數(shù)據(jù)。所以Innodb不建議使用過長的主鍵,否則會(huì)使輔助索引變得過大。
建議使用自增的字段作為主鍵,這樣B+Tree的每一個(gè)結(jié)點(diǎn)都會(huì)被順序的填滿,而不會(huì)頻繁的分裂調(diào)整,會(huì)有效的提升插入數(shù)據(jù)的效率。
這里寫圖片描述
上圖,可以看到葉節(jié)點(diǎn)包含了完整的數(shù)據(jù)記錄。這種索引叫做聚集索引。因?yàn)镮nnoDB的數(shù)據(jù)文件本身要按主鍵聚集,所以InnoDB要求表必須有主鍵(MyISAM可以沒有),如果沒有顯式指定,則MySQL系統(tǒng)會(huì)自動(dòng)選擇一個(gè)可以唯一標(biāo)識(shí)數(shù)據(jù)記錄的列作為主鍵,如果不存在這種列,則MySQL自動(dòng)為InnoDB表生成一個(gè)隱含字段作為主鍵,這個(gè)字段長度為6個(gè)字節(jié),類型為長整形。
而且,與MyISAM索引的不同是InnoDB的輔助索引data域存儲(chǔ)相應(yīng)記錄主鍵的值而不是地址。換句話說,InnoDB的所有輔助索引都引用主鍵作為data域。
因此,過程為:將主鍵組織到一棵B+樹中,而行數(shù)據(jù)就儲(chǔ)存在葉子節(jié)點(diǎn)上,若使用”where id = 13”這樣的條件查找主鍵,則按照B+樹的檢索算法即可查找到對(duì)應(yīng)的葉節(jié)點(diǎn),之后獲得行數(shù)據(jù)。若對(duì)Name列進(jìn)行條件搜索,則需要兩個(gè)步驟:第一步在輔助索引B+樹中檢索Name,到達(dá)其葉子節(jié)點(diǎn)獲取對(duì)應(yīng)的主鍵。第二步使用主鍵在主索引B+樹種再執(zhí)行一次B+樹檢索操作,最終到達(dá)葉子節(jié)點(diǎn)即可獲取整行數(shù)據(jù)。
五、剩余引擎的使用DEMO(主要是Mrg_Myisam分表)
Memory(Heap):
CREATE TABLE tbHeap (
id int unsigned primary key auto_increment,
name varchar(20) not null
) TYPE=Heap
(1)Mrg_Myisam引擎分表:
(一)先創(chuàng)建兩張user表,也就是說我要把用戶表進(jìn)行水平分表(因?yàn)橛脩籼嗬玻?0億)
//用戶表一
CREATE TABLE IF NOT EXISTS `user1` (
`id` int(11) NOT NULL ,
`name` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ;
//用戶表二
CREATE TABLE IF NOT EXISTS `user2` (
`id` int(11) NOT NULL ,
`name` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ;
//分別插入兩條測試數(shù)據(jù)先
INSERT INTO `user1` (`name`) VALUES('輔助');
INSERT INTO `user2` (`name`) VALUES('JackFrost');
分表的要求:
1)分表必須使用MyISAM存儲(chǔ)引擎;
2)每個(gè)分表的表結(jié)構(gòu)必須相同;
3)MySQL必須具有存儲(chǔ)分表數(shù)據(jù)文件和索引文件的目錄的讀寫權(quán)限;
4)必須啟用MySQL的符號(hào)鏈接支持功能。
文件存儲(chǔ):
1)MYD文件是MyISAM表的數(shù)據(jù)文件;
2)MYI文件是MyISAM表的索引文件;
3)frm文件用于存儲(chǔ)MyISAM表的表結(jié)構(gòu)。
(二)最后創(chuàng)建一個(gè)MERGE表,作為一個(gè)分發(fā)作用的總表。
CREATE TABLE IF NOT EXISTS `alluser` (
`id` int(11) NOT NULL ,
`name` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MRG_MYISAM
DEFAULT CHARSET=utf8
UNION=(user1,user2) ;
(三)測試:
1. 查詢:
select id,name from alluser;
可見根據(jù)總表把所有數(shù)據(jù)都查出來了
這里寫圖片描述
2. 然而,當(dāng)你測試插入的時(shí)候:
你會(huì)發(fā)現(xiàn),總表只有只讀權(quán)限
這里寫圖片描述
3. 但是我們又想在總表去插入,怎么辦呢??
允許通過總表插入數(shù)據(jù),數(shù)據(jù)存儲(chǔ)在MRG文件列出的第一個(gè)分表之中。例如,執(zhí)行以下SQL語句,將總表的INSERT_METHOD修改為FIRST,然后通過總表插入一條數(shù)據(jù):
//就是插入總表的時(shí)候,其實(shí)也是插入到第一個(gè)分表。
ALTER TABLE `test_engine`.`alluser` INSERT_METHOD = FIRST;
INSERT INTO `alluser` (id,`name`) VALUES(2,'插入到第一個(gè)分表');
這里寫圖片描述
這里寫圖片描述
而,允許通過總表插入數(shù)據(jù),數(shù)據(jù)存儲(chǔ)在MRG文件列出的最后一個(gè)分表之中。例如,執(zhí)行以下SQL語句,將總表的INSERT_METHOD修改為LAST,然后通過總表插入一條數(shù)據(jù):
//就是插入總表的時(shí)候,其實(shí)也是插入到最后一個(gè)分表。
ALTER TABLE `test_engine`.`alluser` INSERT_METHOD = LAST;
這里寫圖片描述
這里寫圖片描述
注意INSERT_METHOD :
INSERT_METHOD選項(xiàng)只會(huì)影響通過總表插入(INSERT)數(shù)據(jù)的行為,通過總表對(duì)數(shù)據(jù)進(jìn)行刪除(DELETE)、查詢(SELECT)、修改(UPDATE)、清空(TRUNCATE)都不會(huì)受影響。
(2)項(xiàng)目中如何使用MRG_MYISAM總表:
(一)插入(INSERT)數(shù)據(jù)時(shí),需要根據(jù)給定的路由策略將新數(shù)據(jù)分別插入不同的子表,此處采用對(duì)id進(jìn)行模3計(jì)算(可能結(jié)果為0、1、2)來決定插入哪個(gè)子表。
所以我們需要?jiǎng)?chuàng)建一張表專門去創(chuàng)建id。
CREATE TABLE `create_id` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
)
COLLATE='utf8_general_ci'
ENGINE=MyISAM
;
(二)ORM框架的時(shí)候使用上面這個(gè)表生成id
insert into create_id () values();
(三)真正插入的時(shí)候:
先獲取ID,然后根據(jù)拿到的創(chuàng)建ID去插入到分表。
INSERT INTO {$table_name} (id, name) VALUES ('{$id}');