1. 程式人生 > 實用技巧 >MySQL 儲存引擎及事務

MySQL 儲存引擎及事務

一.mysql 的儲存引擎

01)InnoDB 
02)MyISAM
03)MEMORY
04)ARCHIVE
05)FEDERATED
06)EXAMPLE
07)BLACKHOLE
08)MERGE
09)NDBCLUSTER
10)CSV

二. 常用 InnoDB 和MyISAM儲存引擎的物理區別 及簡介

# InnoDB  儲存引擎
var/lib/mysql/mysql city.frm #表結構
var/lib/mysql/mysql city.ibd #表資料
InnoDB是一個事務型的儲存引擎,設計目標是處理大數量資料時提供高效能的服務,它在執行時會在記憶體中建立緩衝池,用於緩衝資料和索引。
InnoDB優點
1.支援事務處理、ACID事務特性;
2.實現了SQL標準的四種隔離級別;
3.支援行級鎖和外來鍵約束;
4.可以利用事務日誌進行資料恢復。
InnoDB缺點
1.不支援FULLTEXT型別的索引,因為它沒有儲存表的行數,當使用COUNT統計時會掃描全表。
InnoDB適用場景
1.需要事務的操作;
2.更新資料需要使用行級鎖;
3.大資料量讀寫;
4.大型網際網路應用。
# myisam 儲存引擎
var/lib/mysql/mysql user.frm #表結構
var/lib/mysql/mysql user.MYD #使用者和密碼
var/lib/mysql/mysql user.MYI #使用者
MyISAM是MySQL預設的引擎,它的設計目標是快速讀取。
MyISAM優點
1.高效能讀取;
2.因為它儲存了表的行數,當使用COUNT統計時不會掃描全表;
MyISAM缺點
1.不支援資料庫事務;
2.不支援行級鎖和外來鍵;
3.INSERT和UPDATE操作需要鎖定整個表;
4.不支援故障恢復;
MyISAM適用場景
1.不需要事務的操作;
2.插入、更新少,讀取頻繁;
3.頻繁的統計計算。

三. 儲存引擎相關命令

1). 檢視儲存引擎

mysql> show engines;

2). 檢視當前庫的儲存引擎

mysql> select @@default_storage_engine;

3). 查看錶的儲存引擎

# 檢視指定表的儲存引擎
mysql> show create table city;
# 檢視哪些表時innodb儲存引擎
mysql> select TABLE_SCHEMA,TABLE_Name,ENGINE from tables where ENGINE='innodb';
# 檢視哪些表時myisam儲存引擎
mysql> select TABLE_SCHEMA,TABLE_Name,ENGINE from tables where ENGINE='myisam';

4). 修改儲存引擎

# 臨時修改
mysql> set @@default_storage_engine=myisam;
# 永久修改
vim /etc/my.cnf
[mysqld]
default_storage_engine=myisam
# 建表時指定儲存引擎
mysql> create table innodb(id int) ENGINE=innodb;
# 更換表儲存引擎
alter table innodb engine=myisam;

四. Innodb 儲存引擎 表空間概念

1)表空間概念

 1. Innodb儲存引擎可將所有資料存放於ibdata*的共享表空間,也可將每張表存放於獨立的.ibd檔案的獨立表空間.
2. 共享表空間以及獨立表空間都是針對資料的儲存方式而言的。
# 共享表空間
某一個數據庫的所有的表資料,索引檔案全部放在一個檔案中,預設這個共享表空間的檔案路徑在data目錄下。 預設的檔名為:ibdata1 初始化為10M。
# 獨立表空間
每一個表都將會生成以獨立的檔案方式來進行儲存,每一個表都有一個.frm表描述檔案,還有一個.ibd檔案。 其中這個檔案包括了單獨一個表的資料內容以及索引內容,預設情況下它的儲存位置也是在表的位置之中。

2)優缺點

# 共享表空間
優點:
可以將表空間分成多個檔案存放到各個磁碟上(表空間檔案大小不受表大小的限制,如一個表可以分佈在不同的檔案上)。資料和檔案放在一起方便管理。
缺點:
所有的資料和索引存放到一個檔案中,雖然可以把一個大檔案分成多個小檔案,但是多個表及索引在表空間中混合儲存,這樣對於一個表做了大量刪除操作後表空間中將會有大量的空隙,特別是對於統計分析,日值系統這類應用最不適合用共享表空間。
# 獨立表空間
優點:
1.每個表都有自已獨立的表空間。
2.每個表的資料和索引都會存在自已的表空間中。
3.可以實現單表在不同的資料庫中移動。
4.空間可以回收(除drop table操作處,表空不能自已回收)
a.Drop table操作自動回收表空間,如果對於統計分析或是日值表,刪除大量資料後可以通過:alter table TableName engine=innodb;回縮不用的空間。
b.對於使innodb-plugin的Innodb使用turncate table也會使空間收縮。
c.對於使用獨立表空間的表,不管怎麼刪除,表空間的碎片不會太嚴重的影響效能,而且還有機會處理。
缺點:
1.單表增加過大,如超過100個G。
2.相比較之下,使用獨佔表空間的效率以及效能會更高一點。

3) 配置共享表空間

vim /etc/my.cnf
[mysqld]
innodb_data_file_path=ibdata1:76M;tmp/ibdata2:50M:autoextend

4) 查看錶空間

# 檢視共享表空間
mysql> show variables like '%path%';
+----------------------------------+----------------------------------------+
| Variable_name | Value |
+----------------------------------+----------------------------------------+
| innodb_data_file_path | ibdata1:76M;tmp/ibdata2:50M:autoextend |
# 檢視是否開啟獨立表空間
mysql> show variables like '%per_table%';
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| innodb_file_per_table | ON |
+-----------------------+-------+

五. Innodb核心特性-事務

1)什麼是事務

主要針對DML語句(update,delete,insert)
1.一組資料操作執行步驟,這些步驟被視為一個工作單元:
1)用於對多個語句進行分組
2)可以在多個客戶機併發訪問同一個表中的資料時使用
2.所有步驟都成功或都失敗
1)如果所有步驟正常,則執行
2)如果步驟出現錯誤或不完整,則取消

2) 事務的特性

Atomic(原子性)
所有語句作為一個單元全部成功執行或全部取消。

Consistent(一致性)
如果資料庫在事務開始時處於一致狀態,則在執行該。事務期間將保留一致狀態。

Isolated(隔離性)
事務之間不相互影響。

Durable(永續性)
事務成功完成後,所做的所有更改都會準確地記錄在資料庫中。所做的更改不會丟失。

3) 事務的控制語句

BEGIN (或START TRANSACTION):顯式開始一個新事務
SAVEPOINT:分配事務過程中的一個位置,以供將來引用
COMMIT:永久記錄當前事務所做的更改
ROLLBACK:取消當前事務所做的更改
ROLLBACK TO SAVEPOINT:取消在 savepoint 之後執行的更改
RELEASE SAVEPOINT:刪除 savepoint 識別符號
SET AUTOCOMMIT:為當前連線禁用或啟用預設 autocommit 模式

4)事務提交

# 自動提交
1.現在版本在開啟事務時,不需要手工begin,只要你輸入的是DML語句,就會自動開啟事務。
2.有些情況下事務會被隱式提交
# 隱式提交
1.在事務執行期間,手工執行begin的時候會自動提交上個事務
2.在事務執行期間,加入DDL、DCL操作會自動提交上個事務
3.在事務執行期間,執行鎖定語句(lock tables、unlock tables)
4.load data infile匯出資料成一個檔案
5.在autocommit=1的時候

#臨時設定關閉
mysql> set autocommit=0;
Query OK, 0 rows affected (0.02 sec)

#永久設定關閉
[root@db01 world]# vim /etc/my.cnf
[mysqld]
autocommit=0

5) 事務週期運用

# 成功的事務
begin; # 開始一個新事務
sql 語句1
sql 語句2
.....
commit # 永久記錄當前事務所做的更改

# 失敗的事務 回滾
begin; # 開始一個新事務
sql 語句1
sql 語句2
.....
rollback # 取消當前事務所做的更改

六 . 事務的日誌

1) redo log

redo log是重做日誌,提供前滾操作
1.在事務ACID過程中,實現的是“D”持久化的作用。
2.REDO:記錄的是,記憶體資料頁的變化過程
3.特性:WAL(Write Ahead Log)日誌優先寫

1.1) 流程

#修改
1)首先將表中id=1的行所在資料頁載入到記憶體中data buffer page
2)MySQL例項在記憶體中將id=1的資料頁改成id=2
3)id=1變成id=2的變化過程會記錄到,redo記憶體區域,也就是redo buffer page中
4)當敲下commit命令的瞬間,MySQL會將redo buffer page寫入磁碟區域redo log
5)當寫入成功之後,commit返回ok
#查詢
1.首先將表中id=1的行所在資料頁載入到記憶體中data buffer page
2.將redo log中id=1變成id=2的變化過程取載入到redo buffer page
3.通過data buffer page和redo buffer page得到一個結果

2) undo log

undo,顧名思義“回滾日誌”,是事務日誌的一種
在事務ACID過程中,實現的是“A”原子性的作用。當然CI的特性也和undo有關

2.2) 流程

https://blog.csdn.net/qq_39459385/article/details/84644005

3) redo和undo的儲存位置

#redo位置
[root@db01 data]# ll /application/mysql/data/
-rw-rw---- 1 mysql mysql 50331648 Aug 15 06:34 ib_logfile0
-rw-rw---- 1 mysql mysql 50331648 Mar 6 2017 ib_logfile1

#undo位置
[root@db01 data]# ll /application/mysql/data/
-rw-rw---- 1 mysql mysql 79691776 Aug 15 06:34 ibdata1
-rw-rw---- 1 mysql mysql 79691776 Aug 15 06:34 ibdata2

七 . 事務中的鎖

1) 什麼是鎖

“鎖”顧名思義就是鎖定的意思。
在事務ACID特性過程中,“鎖”和“隔離級別”一起來實現“I”隔離性的作用。
資料庫鎖定機制簡單來說,就是資料庫為了保證資料的一致性,而使各種共享資源在被併發訪問變得有序所設計的一種規則。對於任何一種資料庫來說都需要有相應的鎖定機制,所以MySQL自然也不能例外。MySQL資料庫由於其自身架構的特點,存在多種資料儲存引擎,每種儲存引擎所針對的應用場景特點都不太一樣,為了滿足各自特定應用場景的需求,每種儲存引擎的鎖定機制都是為各自所面對的特定場景而優化設計,所以各儲存引擎的鎖定機制也有較大區別。MySQL各儲存引擎使用了三種類型(級別)的鎖定機制:表級鎖定,行級鎖定和頁級鎖定。

2) 鎖的類別

排他鎖:保證在多事務操作時,資料的一致性。(在我修改資料時,其他人不得修改)
共享鎖:保證在多事務工作期間,資料查詢時不會被阻塞。
樂觀鎖:多實務操作時,資料可以同時修改,誰先提交,以誰為準
悲觀鎖:多實務操作時,資料只有一個人可以修改

3) 多版本併發控制

1.只阻塞修改類操作(排他鎖),不阻塞查詢類操作(共享鎖)
2.樂觀鎖的機制(誰先提交誰為準)

4) 鎖的粒度

1.MyIsam:表級鎖
2.Innodb:行級鎖

八. 事務中的隔離級別

1) 四種隔離級別

1.RU級別:READ UNCOMMITTED(獨立提交):未提交讀,允許事務檢視其他事務所進行的未提交更改
2.RC級別:READ COMMITTED:允許事務檢視其他事務所進行的已提交更改,檢視不需要重新記入資料庫
3.RR級別:REPEATABLE READ:允許事務檢視其他事務所進行的已提交更改,檢視資料需要重新進入資料庫(InnoDB 的預設級別)
4.序列化:SERIALIZABLE:將一個事務的結果與其他事務完全隔離

2) 隔離級別語句

# 檢視隔離級別
mysql> show variables like '%iso%';
# 設定隔離級別 RU
vim /etc/my.cnf
transaction_isolation=read-uncommit
# # 設定隔離級別 RC
vim /etc/my.cnf
transaction_isolation=read-commit

3) 名詞

1.髒讀:RU級別,執行事務修改資料,被讀取,但是資料最終回滾了,查詢到的資料就是髒讀
2.幻讀:刪除所有表資料,刪除的同時有人插入資料,檢視資料時以為是沒刪乾淨
3.不可重複讀:修改資料後被讀取,被讀取之後再次修改資料,兩次資料不一致

企業案例 一

1)模擬斷電錶損壞

#1.將db03上的資料庫資料目錄下的 world傳到一臺新資料庫的資料目錄下
[root@db03 data]# scp -r world 172.16.1.52:/usr/local/mysql/data/

#2.到db02上授權目錄
[root@db02 data]# chown -R mysql.mysql world/

#3.登入資料庫檢視,資料已損壞
mysql> show tables;
+-----------------+
| Tables_in_world |
+-----------------+
| city |
| country |
| countrylanguage |
+-----------------+
11 rows in set (0.00 sec)

mysql> select * from city;
ERROR 1146 (42S02): Table 'world.city' doesn't exist

2)修復資料庫表

#1.找到建表語句,建立一個新表
CREATE TABLE `city_new` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`Name` char(35) NOT NULL DEFAULT '',
`CountryCode` char(3) NOT NULL DEFAULT '',
`District` char(20) NOT NULL DEFAULT '',
`Population` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`ID`),
KEY `CountryCode` (`CountryCode`),
KEY `inx_name` (`Name`),
KEY `index_popu` (`Population`)
) ENGINE=InnoDB AUTO_INCREMENT=4080 DEFAULT CHARSET=latin1;

#2.移除新表的表空間
mysql> alter table city_new discard tablespace;
Query OK, 0 rows affected (0.09 sec)

#3.損壞表空間的資料檔案複製給新表
[root@db02 world]# cp city.ibd city_new.ibd
[root@db02 world]# chown -R mysql.mysql city_new.ibd

#4.新表讀取表空間
mysql> alter table city_new import tablespace;
Query OK, 0 rows affected, 1 warning (0.22 sec)

#5.運維修改資料庫名
#刪除表空間
mysql> drop table city;
ERROR 1051 (42S02): Unknown table 'world.city'
#物理刪除表資料
[root@db02 world]# rm city.ibd
rm: remove regular file ‘city.ibd’? y
#資料庫改名
mysql> alter table city_new rename city;
Query OK, 0 rows affected (0.11 sec)

企業案例 二

1)專案背景

公司原有的架構:一個展示型的網站,LAMT,MySQL5.1.77版本(MYISAM),50M資料量。

2)升級原因

1、表級鎖:對錶中任意一行資料修改類操作時,整個表都會鎖定,對其他行的操作都不能同時進行。
2、不支援故障自動恢復(CSR):當斷電時有可能會出現資料損壞或丟失的問題。

3)解決方案

1.提建議將現有的MYISAM引擎替換為Innodb,將版本替換為5.6.38
1)如果使用MYISAM會產生”小問題”,效能安全不能得到保證,使用innodb可以解決這個問題。
2)5.1.77版本對於innodb引擎支援不夠完善,5.6.38版本對innodb支援非常完善了。

4)執行計劃

1.準備一臺新的資料庫,版本為5.6.38
2.就資料庫備份資料
[root@db01 ~]# mysqldump -uroot -p123 --triggers -R --master-data=2 -B >/tmp/full.sql
3.將備份的資料庫傳到新資料庫
scp、rsync、NFS、匯出匯入、sftp
4.修改sql中的儲存引擎
sed -i 's#MyISAM#InnoDB#g' /tmp/full.sql
5.將修改後的sql檔案匯入新資料
mysql < /tmp/full.sql
source
\.
6.將程式碼中的資料庫地址修改為新的資料庫地址
7.通過binlog將資料遷移過程中新生成的資料也倒入新庫