Teleport 傳送門基礎功能
MySQL 索引、事務與儲存引擎
目錄MySQL 索引
索引的概念
資料庫索引
- 索引是一個排序的列表,在這個列表中儲存著索引的值和包含這個值的資料所在行的實體地址(類似於c語言的連結串列通過指標指向資料記錄的記憶體地址)
- 使用索引後可以不用掃描全表來定位某行的資料,而是先通過索引表找到該行資料對應的實體地址然後訪問相應的資料,因此能加快資料庫的查詢速度。
- 索引就好比是一本書的目錄,可以根據目錄中的頁碼快速找到所需的內容。
- 索引是表中一列或者若干列值排序的方法。
- 建立索引的目的是加快對錶中記錄的查詢或排序。
索引的作用及副作用
索引的作用
- 設定了合適的索引之後,資料庫利用各種快速定位技術,能夠大大加快查詢速度,這是建立索引的最主要的原因。
- 當表很大或查詢涉及到多個表時,使用索引可以成千上萬倍地提高查詢速度。
- 可以降低資料庫的Io成本,並且索引還可以降低資料庫的排序成本。
- 通過建立唯一性索引,可以保證資料表中每一行資料的唯一性。
- 可以加快表與表之間的連線。
- 在使用分組和排序時,可大大減少分組和排序的時間。
- 建立索引在搜尋和恢復資料庫中的資料時能顯著提高效能
索引的副作用
- 索引需要佔用額外的磁碟空間。
- 對於MyISAM引擎而言,索引檔案和資料檔案是分離的,索引檔案用於儲存資料記錄的地址。而InnoDB 引擎的表資料檔案本身就是索引檔案。
- 在插入和修改資料時要花費更多的時間,因為索引也要隨之變動。
建立索引的原則依據
索引雖可以提升資料庫查詢的速度,但並不是任何情況下都適合建立索引。因為索引本身會消耗系統資源,在有索引的情況下,資料庫會先進行索引查詢,然後定位到具體的資料行,如果索引使用不當,反而會增加資料庫的負擔。
- 表的主鍵、外來鍵必須有索引。因為主鍵具有唯一性,外來鍵關聯的是主表的主鍵,查詢時可以快速定位。
- 記錄數超過300行的表應該有索引。如果沒有索引,每次查詢都需要把表遍歷一遍,會嚴重影響資料庫的效能。
- 經常與其他表進行連線的表,在連線欄位上應該建立索引。
- 唯一性太差的欄位不適合建立索引。·更新太頻繁地欄位不適合建立索引。
- 經常出現在where子句中的欄位,特別是大表的欄位,應該建立索引。
- 在經常進行GROUP BY、ORDERBY的欄位上建立索引;
- 索引應該建在選擇性高的欄位上
- 索引應該建在小欄位上,對於大的文字欄位甚至超長欄位,不要建索引。
索引的分類和建立
普通索引
- 著基本的索引型別,沒有唯一性之類的限制
直接建立索引
CREATE INDEX 索引名 ON 表名 (列名[(length)]);
- (列名(length)):length是可選項,下同。如果忽略 length 的值,則使用整個列的值作為索引。如果指定使用列前的 length 個字元來建立索引,這樣有利於減小索引檔案的大小。
- 索引名建議以“_index”結尾。
修改表結構方式建立索引
ALTER TABLE 表名 ADD INDEX 索引名 (列名);
建立表的時候指定索引
CREATE TABLE 表名 ( 欄位1 資料型別,欄位2 資料型別[,...],INDEX 索引名 (列名));
唯一索引
與普通索引類似,但區別是唯一索引列的每個值都唯一。唯一索引允許有空值(注意和主鍵不同)。如果是用組合索引建立,則列值的組合必須唯一。新增唯一鍵將自動建立唯一索引。
直接建立唯一索引
CREATE UNIQUE INDEX 索引名 ON 表名(列名);
修改表方式建立唯一索引
ALTER TABLE 表名 ADD UNIQUE 索引名 (列名);
建立表的時候指定唯一索引
CREATE TABLE 表名 (欄位1 資料型別,欄位2 資料型別[,...],UNIQUE 索引名 (列名));
主鍵索引
是一種特殊的唯一索引,必須指定為“PRIMARYKEY"。一個表只能有一個主鍵,不允許有空值。新增主鍵將自動建立主鍵索引。
建立表的時候指定主鍵索引
CREATE TABLE 表名 (欄位1 資料型別,欄位2 資料型別[,...], PRIMARY KEY (列名));
修改表方式建立主鍵索引
ALTER TABLE 表名 ADD PRIMARY key (列名);
組合索引(單列索引與多列索引)
可以是單列上建立的索到,也可以是在多列上建立的索引。需要滿足最左原則,因為select語句的where 條件是依次從左往右執行的,所以在使用select 語句查詢時 where條件使用的欄位順序必須和組合索引中的排序一致,否則索引將不會生效。
建立表的時候指定組合索引
CREATE TABLE 表名 (列名1 資料型別,列名2 資料型別,列名3 資料型別,INDEX 索引名 (列名1,列名2,列名3));
修改表方式建立組合索引
ALTER TABLE 表名 ADD INDEX 索引名 (列名1,列名2);
注意:使用的時候要注意 where 的最左原則
select * from 表名 where 欄位1=值 and 欄位2=值 and ....;
全文索引(FULLTEXT)
適合在進行模糊查的時候使用可用於在一篇文章中檢索文字資訊。在MySQL5.6版本以前FULLTEXT 索引僅可用於MyISAM引擎,在5.6版本之後innodb引擎也支援FULLTEXT索引。全文索引可以在CHAR、VARCHAR或者TEXT型別的列上建立。每個表只允許有一個全文索引。
直接建立全文索引
ALTER TABLE 表名 ADD FULLTEXT 索引名 (列名);
建立表的時候指定全文索引
CREATE TABLE 表名 (欄位1 資料型別[,...],FULLTEXT 索引名 (列名));
使用全文索引查詢
SELECT * FROM 表名 WHERE MATCH(列名) AGAINST('查詢內容');
檢視索引
show index from 表名;
show keys from 表名;
欄位 | 含義 |
---|---|
Table | 表的名稱 |
Non_unique | 如果索引不能包括重複詞,則為0;如果可以,則為1 |
Key_name | 索引的名稱 |
seq_in_index | 索引中的列序號,從1開始 |
column_name | 列名稱 |
collation | 列以什麼方式儲存在索引中。在 MySQL中,有值'A(升序)或 NULL(無分類) |
Cardinality | 索引中唯一值數目的估計值 |
sub_part | 如果列只是被部分地編入索引,則為被編入索引的字元的數目。如果整列被編入索引,則為NULL |
Packed | 指示關鍵字如何被壓縮。如果沒有被壓縮,則為NULL |
Null | 如果列含有NULL,則含有YES。如果沒有,則該列含有NO |
lndex_type | 用過的索引方法(BTREE,FULLTEXT,HASH,RTREE) |
comment | 備註 |
刪除索引
直接刪除索引
DROP INDEX 索引名 ON 表名;
修改表方式刪除索引
ALTER TABLE 表名 DROP INDEX 索引名;
刪除主鍵索引
ALTER TABLE 表名 DROP PRIMARY KEY;
MySQL事務
事務的概念
- 事務是一種機制、一個操作序列,包含了一組資料庫操作命令,並且把所有的命令作為一個整體一起向系統提交或撤銷操作請求,即這一組資料庫命令要麼都執行,要麼都不執行。
- 事務是一個不可分割的工作邏輯單元,在資料庫系統上執行併發操作時,事務是最小的控制單元。
- 事務適用於多使用者同時操作的資料庫系統的場景,如銀行、保險公司及證券交易系統等等。
- 事務通過事務的整體性以保證資料的一致性。
- 事務能夠提高在向表中更新和插入資訊期間的可靠性。
總的來說,事務就是是一個操作序列,這些操作要麼都執行,要麼都不執行,它是一個不可分割的工作單位。
事務的ACID特點
- ACID,是指在可靠資料庫管理系統(DBMS)中,事務(transaction)應該具有的四個特性:
- 原子性(Atomicity)
- 一致性(Consistency)
- 隔離性(Isolation)
- 永續性(Durability)。這是可靠資料庫所應具備的幾個特性。
原子性
- 指事務是一個不可再分割的工作單位,事務中的操作要麼都發生,要麼都不發生。
- 事務是一個完整的操作,事務的各元素是不可分的。事務中的所有元素必須作為一個整體提交或回滾。
- 如果事務中的任何元素失敗,則整個事務將失敗。
一致性
- 指在事務開始之前和事務結束以後,資料庫的完整性約束沒有被破壞。
- 當事務完成時,資料必須處於一致狀態。
- 在事務開始前,資料庫中儲存的資料處於一致狀態。在正在進行的事務中,資料可能處於不一致的狀態。
- 當事務成功完成時,資料必須再次回到已知的一致狀態。
隔離性
- 指在併發環境中,當不同的事務同時操縱相同的資料時,每個羽務都有各自的完整資料空間。
- 對資料進行修改的所有併發事務是彼此隔離的,表明事務必須是獨立的,它不應以任何方式依賴於或影響其他事務。
- 修改資料的事務可在另一個使用相同資料的事務開始之前訪問這些資料,或者在另一個使用相同資料的事務結束之後訪問這些資料。
- 也就是說併發訪問資料庫時,一個使用者的事務不被其他事務所幹擾,各併發事務之間資料庫是獨立的。
當多個客戶端併發地訪問同一個表時,可能出現下而的一致性問題
髒讀:當一個事務正在訪問資料,並且對資料進行了修改,而這種修改還沒有提交到資料庫中,這時,另外一個事務也訪問這個資料,然後使用了這個資料。
不可重複讀:指在一個事務內,多次讀同一資料。在這個事務還沒有結束時,另外一個事務也訪問該同一資料。那麼,在第一個事務中的兩次讀資料之間,由於第二個事務的修改,那麼第一個事務兩次讀到的的資料可能是不一樣的。這樣就發生了在一個事務內兩次讀到的資料是不一樣的,因此稱為是不可重複讀。(即不能讀到相同的資料內容)
幻讀:一個事務對一個表中的資料進行了修改,這種修改涉及到表中的全部資料行。同時,另一個事務也修改這個表中的資料,這種修改是向表中插入一行新資料。那麼,操作前一個事務的使用者會發現表中還有沒有修改的資料行,就好象發生了幻覺一樣。
丟失更新:兩個事務同時讀取同一條記錄,A先修改記錄,B也修改記錄(B不知道A修改過),B提交資料後B的修改結果覆蓋了A的修改結果。
MySQL事務隔離級別
用以控制事務所做的修改,並將修改通告至其它併發的事務
- read uncommitted : 讀取尚未提交的資料 :不解決髒讀
- read committed:讀取已經提交的資料 :可以解決髒讀
- repeatable read:重讀讀取:可以解決髒讀 和 不可重複讀 —mysql預設的
- serializable:序列化:可以解決 髒讀 不可重複讀 和 虛讀—相當於鎖表
mysq1預設的事務處理級別是repeatable read,而oracle和sQL Server是 read committed。
事務隔離級別 | 髒讀 | 不可重複讀 | 幻讀 | 第一類丟失更新 | 第二類丟失更新 |
---|---|---|---|---|---|
read uncommitted | 允許 | 允許 | 允許 | 禁止 | 允許 |
read committed | 禁止 | 允許 | 允許 | 禁止 | 允許 |
repeatable read | 禁止 | 禁止 | 允許 | 禁止 | 禁止 |
serializable | 禁止 | 禁止 | 禁止 | 禁止 | 禁止 |
事務的級別作用範圍分兩種
- 全域性級:對所有會話有效
- 會話級:只對當前的會話有效
查詢全域性事務隔離級別
show global variables like '%isolation%';
select @@global.tx_isolation;
查詢會話事務隔離級別
show session variables like '%isolation%';
SELECT @@session.tx_isolation;
SELECT @@tx_isolation;
設定全域性事務隔離級別
set global transaction isolation level 級別;
設定當前會話事務隔離級別
set session transaction isolation level 級別;
永續性
在事務完成以後,該事務所對資料庫所作的更改便持久的儲存在資料庫之中,並不會被回滾。
- 指不管系統是否發生故障,事務處理的結果都是永久的。
- 一旦事務被提交,事務的效果會被永久地保留在資料庫中。
小結
- 在事務管理中,原子性是基礎,隔離性是手段,一致性是目的,永續性是結果。
事務控制語句
-
BEGIN 或 START TRANSACTION:顯式地開啟一個事務。
-
COMMIT 或 COMMIT WORK:提交事務,並使已對資料庫進行的所有修改變為永久性的。
-
ROLLBACK 或 ROLLBACK WORK:回滾會結束使用者的事務,並撤銷正在進行的所有未提交的修改。
-
SAVEPOINT S1:使用 SAVEPOINT 允許在事務中建立一個回滾點,一個事務中可以有多個 SAVEPOINT;“S1”代表回滾點名稱。
-
ROLLBACK TO [SAVEPOINT] S1:把事務回滾到標記點。
測試begin和commit(開始事務和提交事務)
開啟另外一個會話
測試事務未提交的回滾
測試建立回滾點並進行回滾
使用 set 設定控制事務
#禁止自動提交(狀態為OFF)
SET AUTOCOMMIT=0;
#開啟自動提交,Mysql預設為1(狀態為ON)
SET AUTOCOMMIT=1;
檢視控制事務
#檢視Mysql中的AUTOCOMMIT值
show variables like 'autocommit';
MySQL儲存引擎
儲存引擎概述
-
MySQL中的資料用各種不同的技術儲存在檔案中,每一種技術都使用不同的儲存機制、索引技巧、鎖定水平並最終提供不同的功能和能力,這些不同的技術以及配套的功能在MySQL中稱為儲存引擎
-
儲存引擎是MySQL將資料儲存在檔案系統中的儲存方式或者儲存格式
-
MySQL常用的儲存引擎
- MyISAM
- InnoDB
-
MySQL資料庫中的元件,負責執行實際的資料I/O操作
-
MySQL系統中,儲存引擎處於檔案系統之上,在資料儲存到資料檔案之前會傳輸到儲存引擎,之後按照各個儲存引擎的儲存格式進行儲存
MyISAM的特點介紹
-
MyISAM不支援事務,也不支援外來鍵約束,只支援全文索引,資料檔案和索引檔案是分開儲存的口訪問速度快,對事務完整性沒有要求
-
MyISAM 適合查詢、插入為主的應用
-
MyISAM在磁碟上儲存成三個檔案,檔名和表名都相同,但是副檔名分別為:
- .frm檔案儲存表結構的定義
- 資料檔案的副檔名為MYD(MYData)
- 索引檔案的副檔名是MYI(MYIndex)
-
表級鎖定形式,資料在更新時鎖定整個表
-
資料庫在讀寫過程中相互阻塞
-
會在資料寫入的過程阻塞使用者資料的讀取
-
也會在資料讀取的過程中阻塞使用者的資料寫入口資料單獨寫入或讀取,速度過程較快且佔用資源相對少
-
MyIAM支援的儲存格式
- 靜態表
- 動態表
- 壓縮表
靜態(固定長度)表
- 靜態表是預設的儲存格式。靜態表中的欄位都是非可變欄位,這樣每個記錄都是固定長度的,這種儲存方式的優點是儲存非常迅速,容易快取,出現故障容易恢復;缺點是佔用的空間通常比動態表多。
動態表
- 動態表包含可變欄位,記錄不是固定長度的,這樣儲存的優點是佔用空間較少,但是頻繁的更新、刪除記錄會產生碎片,需要定期執行OPTIMIZE TABLE 語句或myisamchk-r命令來改善效能,並且出現故障的時候恢復相對比較困難。
壓縮表
- 壓縮表由myisamchk工具建立,佔據非常小的空間,因為每條記錄都是被單獨壓縮的,所以只有非常小的訪問開支。
MyISAM適用的生產場景
- 公司業務不需要事務的支援
- 單方面讀取或寫入資料比較多的業務
- MyISAM儲存引擎資料讀寫都比較頻繁場景不適合
- 使用讀寫併發訪問相對較低的業務
- 資料修改相對較少的業務
- 對資料業務一致性要求不是非常高的業務
- 伺服器硬體資源相對比較差
InnoDB特點介紹
-
支援事務,支援4個事務隔離級別
-
MySQL從5.5.5版本開始,預設的儲存引擎為lnnoDB讀寫阻塞與事務隔離級別相關
-
能非常高效的快取索引和資料
-
表與主鍵以簇的方式儲存
-
支援分割槽、表空間,類似oracle資料庫
-
支援外來鍵約束,5.5前不支援全文索引,5.5後支援全文索引
-
對硬體資源要求還是比較高的場合
-
行級鎖定,但是全表掃描仍然會是表級鎖定,如:
- update table set a=1 where user like"%zhang%';
-
InnoDB中不儲存表的行數,如 select count(*)from table;時,InnoDB 需要掃描一遍整個表來計算有多少行,但是MyISAM只要簡單的讀出儲存好的行數即可。需要注意的是,當count()語句包含where條件時MyISAM 也需要掃描整個表
-
對於自增長的欄位,InnoDB中必須包含只有該欄位的索引,但是在MyISAM表中可以和其他欄位一起建立組合索引
-
清空整個表時,lnnoDB是一行一行的刪除,效率非常慢。
InnoDB適用生產場景
-
業務需要事務的支援
-
行級鎖定對高併發有很好的適應能力,但需確保查詢是通過索引來完成
-
業務資料更新較為頻繁的場景
- 如:論壇,微博等
-
業務資料一致性要求較高
- 如:銀行業務
-
硬體裝置記憶體較大,利用InnoDB較好的快取能力來提高記憶體利用率,減少磁碟IO的壓力
InnoDB與MyISAM 區別
- MyISAM:不支援事務和外來鍵約束,佔用空間較小,訪問速度快,表級鎖定,適用於不需要事務處理,單獨寫入或查詢的應用場景。
- rnnopB:支援事務處理、外來鍵約束、佔用空間比MyISAM大,支援行級鎖定,讀寫併發能力較好,適用於一致性要求高、資料更新頻繁的應用場景。
企業選擇儲存引擎
-
需要考慮每個儲存引擎提供了哪些不同的核心功能及應用場景
-
支援的欄位和資料型別
- 所有引擎都支援通用的資料型別
- 但不是所有的引擎都支援其它的欄位型別,如二進位制物件
-
鎖定型別:不同的儲存引擎支援不同級別的鎖定
- 表鎖定:MyISAM支援
- 行鎖定:InnoDB支援
-
索引的支援
- 建立索引在搜尋和恢復資料庫中的資料時能顯著提高效能
- 不同的儲存引擎提供不同的製作索引的技術
- 有些儲存引擎根本不支援索引
-
事務處理的支援
- 提高在向表中更新和插入資訊期間的可靠性
- 可根據企業業務是否要支援事務選擇儲存引擎
控制語句
檢視系統支援的儲存引擎
show engines;
查看錶使用的儲存引擎
方法一:
show table status from 庫名 where name='表名'\G;
方法二:
use 庫名;
show create table表名;
修改儲存引擎
1.通過alter table修改
use 庫名;
alter table 表名 engine=MyISAM;
2.通過修改/etc/my.cnf 配置檔案,指定預設儲存引擎並重啟服務
vim/etc/my.cnf
[mysqld]
default-storage-engine=myisam
systemctl restart mysql.service
注意:此方法只對修改了配置檔案並重啟mysq1服務後新建立的表有效,已經存在的表不會有變更。
3.通過create table建立表時指定儲存引擎
use庫名;
create table 表名(欄位1資料型別,...)engine=MyISAM;
InnoDB行鎖與索引的關係
- InnoDB行鎖是通過給索引項加鎖來實現的,如果沒有索引,InnoDB將通過隱藏的聚簇索引來對記錄加鎖。
selete frim t1 where id=1;
- 如果id欄位是主鍵,innodb對於主鍵使用了聚簇索引,會直接鎖住整行記錄。
delete from tl where name='aaa';
- 如果name欄位是普通索引,會先鎖住索引的兩行,接著會鎖住相應主鍵對應的記錄。
delete from t1 where age=23;
- 如果age欄位沒有索引,會使用全表掃描過濾,這時表上的各個記錄都將加上鎖。
死鎖
死鎖一般是事務相互等待對方資源,最後形成環路造成的。
案例:
create table t1(id int primary key,name char(4),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);
會話1
begin;
delete from tl where id=5;
會話2
begin;
select * from t1 where id=1 for update;
會話1
delete from tl where id=1;#死鎖發生
會話2
update t1 set name='abc' where id=5; #死鎖發生
注:for update可以為資料庫中的行上一個排它鎖。當一個事務的操作未完成時候,其他事務可以讀取但是不能寫入或更新。
總結
如何儘可能避免死鎖?
- 使用更合理的業務邏輯,以固定的順序訪問表和行。
- 大事務拆小。大事務更傾向於死鎖,如果業務允許,將大事務拆小。
- 在同一個事務中,儘可能做到一次鎖定所需要的所有資源,減少死鎖概率。
- 降低隔離級別。如果業務允許,將隔離級別調低也是較好的選擇,比如將隔離級別從R調整為RC,可以避免掉很多因為gap鎖造成的死鎖。
- 為表新增合理的索引。如果不使用索引將會為表的每一行記錄新增上鎖,死鎖的概率大大增大。