儲存引擎概念介紹
- MySQL中的資料用各種不同的技術存儲在檔案中,每一種技術都使用不同的存儲機制、索引技巧、鎖定水準并最終提供不同的功能和能力,這些不同的技術以及配套的功能在MySQL中成為存儲引擎
- 存儲引擎是MySQL将資料存儲在檔案系統中的存儲方式或者存儲格式
- MySQL資料庫中的元件,負責執行實際的資料I/O操作
- MySQL系統中,存儲引擎處于檔案之上,在資料儲存到資料檔案之前會傳輸到存儲引擎,之後按照各個存儲引擎的存儲格式進行存儲
- MySQL常用的存儲引擎(MyISAM、InnoDB)
MyISAM儲存引擎
MyISAM的特點
- MyISAM不支援事務,也不支援外鍵限制,隻支援全文索引,資料檔案和索引檔案是分開儲存的
- 通路速度快,對事務完整性沒有要求
- MyISAM适合查詢、插入為主的應用
- MyISAM在磁盤上存儲成三個檔案,檔案名和表名都相同,擴充名分别為:
- .frm檔案存儲表結構的定義
- 資料檔案的擴充名為.MYD(MYData)
- 索引檔案的擴充名是.MYI(MYIndex)
- 表級鎖定形式,資料在更新時鎖定整個表
- 資料庫在讀寫過程中互相阻塞
- 會在資料寫入的過程阻塞使用者資料的讀取
- 也會在資料讀取的過程中阻塞使用者的資料寫入
- 資料單獨寫入或讀取,速度過程較快且占用資源相對少
- MyISAM支援的存儲格式
- 靜态表
- 動态表
- 壓縮表
MyISAM表支援的儲存格式
- 靜态(固定長度)表
靜态表是預設的存儲格式,靜态表中的字段都是非可變字段,這樣每個記錄都是固定長度的,這種存儲方式的優點是存儲非常迅速,容易緩存,出現故障容易恢複,缺點是占用的空間通常比動态表多
- 動态表
動态表包含可變字段,記錄不是固定長度的,這樣存儲的優點是占用空間較小,但是頻繁的更新、删除記錄會産生碎片,需要定期執行OPTIMIZE TABLE語句或myiaamchk -r指令來改善性能,并且出現故障的時候恢複相對比較困難
- 壓縮表
壓縮表由myiaamchk工具建立,占據非常小的空間,因為每條記錄都是被單獨壓縮的,是以隻有非常小的通路開支
常用的存儲引擎
- MyISAM:不支援事務和外鍵限制,占用資源較小,通路資源較小,通路速度快,表級鎖定,适用于不需要事務處理,單獨寫入或查詢的應用場景
- InnoDB:支援事務處理、外鍵限制、占用資源比MyISAM大,支援行級鎖定,讀寫并發能力較好,使用于一緻性要求高、資料更新頻繁的應用場景
MyISAM适用場景
- 公司業務不需要事務的支援
- 單方面讀取或寫入資料比較多的業務
- MyISAM存儲引擎資料讀寫都比較頻繁場景不适合
- 使用讀寫并發通路相對較低的業務
- 資料修改相對較少的業務
- 對資料業務一緻性要求不是非常高的業務
- 伺服器硬體資源相對比較差
InnoDB存儲引擎
InnoDB介紹
- 支援事務,支援4個事務隔離級别
- MySQL從5.5.5版本開始,預設的存儲引擎為InnoDB
- 讀寫阻塞與事務隔離級别相關
- 能非常高效地緩存索引和資料
- 表與主鍵以簇的方式存儲 BTREE
- 支援分區、表空間,類似oracle資料庫
- 支援外鍵限制,5.5前不支援全文索引,5.5後支援全文索引
- 對硬體資源要求還是比較高的場合
- 行級鎖定,但是全表掃描仍然會是表級鎖定,如
- update table set a=1 where user like '%zhang%';
小貼士:
- 使用like進行模糊查詢時,會進行全表掃描,鎖定整個表。
- 對沒有建立索引的字段進行查詢,也會進行全表掃描鎖定整個表。
- 使用索引進行查詢,則是行級鎖定。
InnoDB的特點
- InnoDB中不儲存表的行數,如 select count(*) from table; 時,InnoDB需要掃描一遍整個表來計算有多少行,但是MyISAM隻要簡單的讀出儲存好的行數即可。需要注意的是當count(*)語句包含where條件時MyISAM也需要掃描整個表。
- 對于自增長的字段,InnoDB 中必須包含隻有該字段的索引,但是在MyISAM表中可以和其他字段一起建立組合索引。
- delete清空整個表時,InnoDB 是一行一 行的删除,效率非常慢。MyISAM則會重建表。
InnoDB适用生産場景分析
- 業務是需要事務的支援。
- 行級鎖定對高并發有很強的适應能力,但是需要確定查詢是通過索引來完成。
- 業務資料更新較頻繁的場景。如:論壇,微網誌等。
- 業務資料一緻性要求較高。如:銀行業務等。
- 硬體裝置記憶體較大,利用InnoDB較好的緩存能力來提高記憶體使用率,減少磁盤IO的壓力。
MyISAM和InnoDB的差別:
MyISAM: 不支援事務和外鍵限制,占用空間較小,通路速度快,表級鎖定,适用于不需要事務處理、單獨寫入或查詢的應用場景。(寫入和查詢不一起使用的場景)
InnoDB: 支援事務處理、外鍵限制、占用空間比MyISAM 大,支援行級鎖定,讀寫開發能力較好,适用于需要事務處理、讀寫頻繁的應用場景。
企業選擇存儲引擎依據
1、需要考慮每個存儲引擎提供了哪些不同的核心功能及應用場景。
2、支援的字段和資料類型
- 所有引擎都支援通用的資料類型
- 但不是所有的弓|擎都支援其它的字段類型,如二進制對象.
3、鎖定類型:不同的存儲引擎支援不同級别的鎖定
- 表鎖定:MyISAM 支援
- 行鎖定:InnoDB 支援
檢視存儲引擎
檢視系統支援的存儲引擎
show engines;
#Engine:存儲引擎的名稱。
#Support:YES表示引擎受支援且處于活動狀态,NO表示不支援,DEFAULT表示預設存儲引擎。DISABLED表示支援引擎但已将其禁用。
#Comment:存儲引擎的簡要說明。
#Transactions:存儲引擎是否支援事務。
#XA:存儲引擎是否支援XA事務。
#Savepoints:存儲引擎是否支援復原點(标記點)。
複制代碼
檢視資料表使用的存儲引擎
方法一:
show table status from 庫名 where name='表名'\G
複制代碼
方法二:
use 庫名;
show create table 表名;
複制代碼
修改存儲引擎
方法一:alter table修改
修改目前資料表使用的存儲引擎。
use 庫名;
alter table 表名 engine=存儲引擎名稱;
#注意:因為MyISAM不支援外鍵限制,如果資料表設定了外鍵,則無法修改為MyISAM。
複制代碼
方法二:修改配置檔案,指定預設存儲引擎
注意:此方法隻對修改配置檔案并重新開機mysql服務之後新建立的表有效,已經存在的表不會有變更。
建立資料表時如果沒有指定存儲引擎,則會使用預設存儲引擎。
vim /etc/my.cnf
......
[mysqld]
default-storage-engine=InnoDB #修改這一行,指定預設存儲引擎為InnoDB
systemctl restart mysqld #重新開機服務
複制代碼
方法三:create table 建立表時指定存儲引擎
use 庫名;
create table 表名(字段1 資料類型,...) engine=存儲引擎名稱;
複制代碼
InnoDB行鎖與索引的關系
準備一個資料表t1:
create table t1(id int primary key,name char(10),age int);
insert into t1 values(1,'aaa',22);
insert into t1 values(2,'bbb',23);
insert into t1 values(3,'aaa',24);
insert into t1 values(4,'bbb',25);
insert into t1 values(5,'ccc',26);
insert into t1 values(6,'zzz',27);
alter table t1 add index name_index(name); #對name字段建立普通索引
複制代碼
行級鎖定與表級鎖定
InnoDB行鎖是通過給索引項加鎖來實作的,如果沒有索引,InnoDB将通過隐藏的聚簇索引來對記錄加鎖。
1)delete from t1 where id=1;
因為id字段是主鍵,Innodb對于主鍵使用了聚簇索引,删除過程中會直接鎖住整行記錄。行級鎖定。
2)delete from t1 where name='aaa';
因為name字段是普通索引,會先鎖住索引的兩行(因為aaa有兩行),接着會鎖住相應主鍵對應的記錄。行級鎖定。
3)delete from t1 where age=23;
因為age字段沒有索引,會使用全表掃描過濾,這時表上的各個記錄都将加上鎖。表級鎖定。
死鎖
死鎖一般是事務互相等待對方資源,最後形成環路造成的。
session1 | session2 |
begin; | begin; |
delete from t1 where id=5;#事務結束前,id=5的行會被鎖定 | |
select * from t1 where id=1 for update; #加排他鎖,模拟并發情況,鎖定id=1的行 | |
delete from t1 where id=1; #死鎖産生 | |
update t1 set name='abc' where id=5; #死鎖産生。因為會話1中id=5的行還在删除過程中,該行已被鎖定 | |
rollback; #復原,結束事務。id=5的行被解鎖 | |
update t1 set name='abc' where id=5; #成功更新資料 |
for update: 可以為資料庫中的行上一個排它鎖。當一個事務的操作未完成時,其他事務可以讀取該行資料,但是不能寫入、更新或删除。
死鎖示範:
注釋紅色字為會話1,黃色字為會話2
如何盡可能避免死鎖
1、使用更合理的業務邏輯,以固定的順序通路表和行。
2、大事務拆小。大事務更傾向于死鎖,如果業務允許,将大事務拆小。
3、在同一個事務中,盡可能做到一次鎖定所需要的所有資源,減少死鎖機率。
4、降低隔離級别。如果業務允許,将隔離級别調低也是較好的選擇,比如将隔離級别從RR調整為RC,可以避免掉很多因為gap鎖造成的死鎖。
5、為表添加合理的索引。如果不使用索引将會為表的每一行記錄添加上鎖,死鎖的機率大大增加。
總結:
MyISAM和InnoDB的差別:
MyISAM: 不支援事務和外鍵限制,占用空間較小,通路速度快,表級鎖定,适用于不需要事務處理、單獨寫入或查詢的應用場景。(寫入和查詢不一起使用的場景)
InnoDB: 支援事務處理、外鍵限制、占用空間比MyISAM 大,支援行級鎖定,讀寫開發能力較好,适用于需要事務處理、讀寫頻繁的應用場景。
檢視系統支援的存儲引擎:
show engines;
檢視表使用的存儲引擎:
方法一:show table status from 庫名 where name='表名'\G
方法二:show create table 表名;
修改存儲引擎:
方法一:修改已存在的表使用的存儲引擎
alter table 表名 engine=存儲引擎名稱;
方法二:修改配置檔案,指定預設存儲引擎
vim /etc/my.cnf
[mysqld]
default-storage-engine=InnoDB #修改這一行,指定預設存儲引擎為InnoDB
systemctl restart mysqld #重新開機服務
方法三:建立表時指定存儲引擎
create table 表名(字段1 資料類型,...) engine=存儲引擎名稱;
原文:https://juejin.cn/post/7162825723118354439