真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

mysql行級別怎么實(shí)現(xiàn) mysql 行級權(quán)限

MySQL 是如何實(shí)現(xiàn)四大隔離級別的

SQL標(biāo)準(zhǔn)定義了4類隔離級別,包括了一些具體規(guī)則,用來限定事務(wù)內(nèi)外的哪些改變是可見的,哪些是不可見的。低級別的隔離級一般支持更高的并發(fā)處理,并擁有更低的系統(tǒng)開銷。

彝良網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)!從網(wǎng)頁設(shè)計(jì)、網(wǎng)站建設(shè)、微信開發(fā)、APP開發(fā)、響應(yīng)式網(wǎng)站等網(wǎng)站項(xiàng)目制作,到程序開發(fā),運(yùn)營維護(hù)。創(chuàng)新互聯(lián)成立于2013年到現(xiàn)在10年的時(shí)間,我們擁有了豐富的建站經(jīng)驗(yàn)和運(yùn)維經(jīng)驗(yàn),來保證我們的工作的順利進(jìn)行。專注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)

Read Uncommitted(讀取未提交內(nèi)容)

在該隔離級別,所有事務(wù)都可以看到其他未提交事務(wù)的執(zhí)行結(jié)果。本隔離級別很少用于實(shí)際應(yīng)用,因?yàn)樗男阅芤膊槐绕渌墑e好多少。讀取未提交的數(shù)據(jù),也被稱之為臟讀(Dirty Read)。

Read Committed(讀取提交內(nèi)容)

這是大多數(shù)數(shù)據(jù)庫系統(tǒng)的默認(rèn)隔離級別(但不是MySQL默認(rèn)的)。它滿足了隔離的簡單定義:一個(gè)事務(wù)只能看見已經(jīng)提交事務(wù)所做的改變。這種隔離級別 也支持所謂的不可重復(fù)讀(Nonrepeatable Read),因?yàn)橥皇聞?wù)的其他實(shí)例在該實(shí)例處理其間可能會有新的commit,所以同一select可能返回不同結(jié)果。

Repeatable Read(可重讀)

這是MySQL的默認(rèn)事務(wù)隔離級別,它確保同一事務(wù)的多個(gè)實(shí)例在并發(fā)讀取數(shù)據(jù)時(shí),會看到同樣的數(shù)據(jù)行。不過理論上,這會導(dǎo)致另一個(gè)棘手的問題:幻讀 (Phantom Read)。簡單的說,幻讀指當(dāng)用戶讀取某一范圍的數(shù)據(jù)行時(shí),另一個(gè)事務(wù)又在該范圍內(nèi)插入了新行,當(dāng)用戶再讀取該范圍的數(shù)據(jù)行時(shí),會發(fā)現(xiàn)有新的“幻影” 行。InnoDB和Falcon存儲引擎通過多版本并發(fā)控制(MVCC,Multiversion Concurrency Control)機(jī)制解決了該問題。

Serializable(可串行化)

這是最高的隔離級別,它通過強(qiáng)制事務(wù)排序,使之不可能相互沖突,從而解決幻讀問題。簡言之,它是在每個(gè)讀的數(shù)據(jù)行上加上共享鎖。在這個(gè)級別,可能導(dǎo)致大量的超時(shí)現(xiàn)象和鎖競爭。

這四種隔離級別采取不同的鎖類型來實(shí)現(xiàn),若讀取的是同一個(gè)數(shù)據(jù)的話,就容易發(fā)生問題。例如:

臟讀(Drity Read):某個(gè)事務(wù)已更新一份數(shù)據(jù),另一個(gè)事務(wù)在此時(shí)讀取了同一份數(shù)據(jù),由于某些原因,前一個(gè)RollBack了操作,則后一個(gè)事務(wù)所讀取的數(shù)據(jù)就會是不正確的。

不可重復(fù)讀(Non-repeatable read):在一個(gè)事務(wù)的兩次查詢之中數(shù)據(jù)不一致,這可能是兩次查詢過程中間插入了一個(gè)事務(wù)更新的原有的數(shù)據(jù)。

幻讀(Phantom Read):在一個(gè)事務(wù)的兩次查詢中數(shù)據(jù)筆數(shù)不一致,例如有一個(gè)事務(wù)查詢了幾列(Row)數(shù)據(jù),而另一個(gè)事務(wù)卻在此時(shí)插入了新的幾列數(shù)據(jù),先前的事務(wù)在接下來的查詢中,就會發(fā)現(xiàn)有幾列數(shù)據(jù)是它先前所沒有的。

在MySQL中,實(shí)現(xiàn)了這四種隔離級別,分別有可能產(chǎn)生問題如下所示:

MySQL簡單介紹——換個(gè)角度認(rèn)識MySQL

1、InnoDB存儲引擎

Mysql版本=5.5 默認(rèn)的存儲引擎,MySQL推薦使用的存儲引擎。支持事務(wù),行級鎖定,外鍵約束。事務(wù)安全型存儲引擎。更加注重?cái)?shù)據(jù)的完整性和安全性。

存儲格式 : 數(shù)據(jù),索引集中存儲,存儲于同一個(gè)表空間文件中。

InnoDB的行鎖模式及其加鎖方法: InnoDB中有以下兩種類型的行鎖:共享鎖(讀鎖: 允許事務(wù)對一條行數(shù)據(jù)進(jìn)行讀?。┖?互斥鎖(寫鎖: 允許事務(wù)對一條行數(shù)據(jù)進(jìn)行刪除或更新), 對于update,insert,delete語句,InnoDB會自動(dòng)給設(shè)計(jì)的數(shù)據(jù)集加互斥鎖,對于普通的select語句,InnoDB不會加任何鎖。

InnoDB行鎖的實(shí)現(xiàn)方式: InnoDB行鎖是通過給索引上的索引項(xiàng)加鎖來實(shí)現(xiàn)的,如果沒有索引,InnoDB將通過隱藏的聚簇索引來對記錄加鎖。InnoDB這種行鎖實(shí)現(xiàn)特點(diǎn)意味著:如果不通過索引條件檢索數(shù)據(jù),那么InnoDB將對表中的所有記錄加鎖,實(shí)際效果跟表鎖一樣。

(1)在不通過索引條件查詢時(shí),InnoDB會鎖定表中的所有記錄。

(2)Mysql的行鎖是針對索引加的鎖,不是針對記錄加的鎖,所以雖然是訪問不同行的記錄,但是如果使用相同的索引鍵,是會出現(xiàn)沖突的。

(3)當(dāng)表有多個(gè)索引的時(shí)候,不同的事務(wù)可以使用不同的索引鎖定不同的行,但都是通過行鎖來對數(shù)據(jù)加鎖。

優(yōu)點(diǎn):

1、支持事務(wù)處理、ACID事務(wù)特性;

2、實(shí)現(xiàn)了SQL標(biāo)準(zhǔn)的四種隔離級別( 原子性( Atomicity )、一致性( Consistency )、隔離性(Isolation )和持續(xù)性(Durability ));

3、支持行級鎖和外鍵約束;

4、可以利用事務(wù)日志進(jìn)行數(shù)據(jù)恢復(fù)。

5、鎖級別為行鎖,行鎖優(yōu)點(diǎn)是適用于高并發(fā)的頻繁表修改,高并發(fā)是性能優(yōu)于 MyISAM。缺點(diǎn)是系統(tǒng)消耗較大。

6、索引不僅緩存自身,也緩存數(shù)據(jù),相比 MyISAM 需要更大的內(nèi)存。

缺點(diǎn):

因?yàn)樗鼪]有保存表的行數(shù),當(dāng)使用COUNT統(tǒng)計(jì)時(shí)會掃描全表。

使用場景:

(1)可靠性要求比較高,或者要求事務(wù);(2)表更新和查詢都相當(dāng)?shù)念l繁,并且表鎖定的機(jī)會比較大的情況。

2、 MyISAM存儲引擎

MySQL= 5.5 MySQL默認(rèn)的存儲引擎。ISAM:Indexed Sequential Access Method(索引順序存取方法)的縮寫,是一種文件系統(tǒng)。擅長與處理,高速讀與寫。

功能:

(1)支持?jǐn)?shù)據(jù)壓縮存儲,但壓縮后的表變成了只讀表,不可寫;如果需要更新數(shù)據(jù),則需要先解壓后更新。

(2)支持表級鎖定,不支持高并發(fā);

(3)支持并發(fā)插入。寫操作中的插入操作,不會阻塞讀操作(其他操作);

優(yōu)點(diǎn):

1.高性能讀??;

2.因?yàn)樗4媪吮淼男袛?shù),當(dāng)使用COUNT統(tǒng)計(jì)時(shí)不會掃描全表;

缺點(diǎn):

1、鎖級別為表鎖,表鎖優(yōu)點(diǎn)是開銷小,加鎖快;缺點(diǎn)是鎖粒度大,發(fā)生鎖沖動(dòng)概率較高,容納并發(fā)能力低,這個(gè)引擎適合查詢?yōu)橹鞯臉I(yè)務(wù)。

2、此引擎不支持事務(wù),也不支持外鍵。

3、INSERT和UPDATE操作需要鎖定整個(gè)表;

使用場景:

(1)做很多count 的計(jì)算;(2)插入不頻繁,查詢非常頻繁;(3)沒有事務(wù)。

InnoDB和MyISAM一些細(xì)節(jié)上的差別:

1、InnoDB不支持FULLTEXT類型的索引,MySQL5.6之后已經(jīng)支持(實(shí)驗(yàn)性)。

2、InnoDB中不保存表的 具體行數(shù),也就是說,執(zhí)行select count() from table時(shí),InnoDB要掃描一遍整個(gè)表來計(jì)算有多少行,但是MyISAM只要簡單的讀出保存好的行數(shù)即可。注意的是,當(dāng)count()語句包含 where條件時(shí),兩種表的操作是一樣的。

3、對于AUTO_INCREMENT類型的字段,InnoDB中必須包含只有該字段的索引,但是在MyISAM表中,可以和其他字段一起建立聯(lián)合索引。

4、DELETE FROM table時(shí),InnoDB不會重新建立表,而是一行一行的刪除。

5、LOAD TABLE FROM MASTER操作對InnoDB是不起作用的,解決方法是首先把InnoDB表改成MyISAM表,導(dǎo)入數(shù)據(jù)后再改成InnoDB表,但是對于使用的額外的InnoDB特性(例如外鍵)的表不適用。

6、另外,InnoDB表的行鎖也不是絕對的,如果在執(zhí)行一個(gè)SQL語句時(shí)MySQL不能確定要掃描的范圍,InnoDB表同樣會鎖全表。

1.索引概述

利用關(guān)鍵字,就是記錄的部分?jǐn)?shù)據(jù)(某個(gè)字段,某些字段,某個(gè)字段的一部分),建立與記錄位置的對應(yīng)關(guān)系,就是索引。索引的關(guān)鍵字一定是排序的。索引本質(zhì)上是表字段的有序子集,它是提高查詢速度最有效的方法。一個(gè)沒有建立任何索引的表,就相當(dāng)于一本沒有目錄的書,在每次查詢時(shí)就會進(jìn)行全表掃描,這樣會導(dǎo)致查詢效率極低、速度也極慢。如果建立索引,那么就好比一本添加的目錄,通過目錄的指引,迅速翻閱到指定的章節(jié),提升的查詢性能,節(jié)約了查詢資源。

2.索引種類

從索引的定義方式和用途中來看:主鍵索引,唯一索引,普通索引,全文索引。

無論任何類型,都是通過建立關(guān)鍵字與位置的對應(yīng)關(guān)系來實(shí)現(xiàn)的。索引是通過關(guān)鍵字找對應(yīng)的記錄的地址。

以上類型的差異:對索引關(guān)鍵字的要求不同。

關(guān)鍵字:記錄的部分?jǐn)?shù)據(jù)(某個(gè)字段,某些字段,某個(gè)字段的一部分)。

普通索引,index:對關(guān)鍵字沒有要求。

唯一索引,unique index:要求關(guān)鍵字不能重復(fù)。同時(shí)增加唯一約束。

主鍵索引,primary key:要求關(guān)鍵字不能重復(fù),也不能為NULL。同時(shí)增加主鍵約束。

全文索引,fulltext key:關(guān)鍵字的來源不是所有字段的數(shù)據(jù),而是從字段中提取的特別關(guān)鍵詞。

PS:這里主鍵索引和唯一索引的區(qū)別在于:主鍵索引不能為空值,唯一索引允許空值;主鍵索引在一張表內(nèi)只能創(chuàng)建一個(gè),唯一索引可以創(chuàng)建多個(gè)。主鍵索引肯定是唯一索引,但唯一索引不一定是主鍵索引。

3.索引原則

如果索引不遵循使用原則,則可能導(dǎo)致索引無效。

(1)列獨(dú)立

如果需要某個(gè)字段上使用索引,則需要在字段參與的表達(dá)中,保證字段獨(dú)立在一側(cè)。否則索引不會用到索引, 例如這條sql就不會用到索引:select * from A where id+1=10;

(2)左原則

Like:匹配模式必須要左邊確定不能以通配符開頭。例如:select * from A where name like '%小明%' ,不會用到索引,而select * from A where name like '小明%' 就可以用到索引(name字段有建立索引),如果業(yè)務(wù)上需要用到'%小明%'這種方式,有兩種方法:1.可以考慮全文索引,但mysql的全文索引不支持中文;2.只查詢索引列或主鍵列,例如:select name from A where name like '%小明%' 或 select id from A where name like '%小明%' 或 select id,name from A where name like '%小明%' 這三種情況都會用到name的索引;

復(fù)合索引:一個(gè)索引關(guān)聯(lián)多個(gè)字段,僅僅針對左邊字段有效果,添加復(fù)合索引時(shí),第一個(gè)字段很重要,只有包含第一個(gè)字段作為查詢條件的情況才會使用復(fù)合索引(必須用到建索引時(shí)選擇的第一個(gè)字段作為查詢條件,其他字段的順序無關(guān)),而且查詢條件只能出現(xiàn)and拼接,不能用or,否則則無法使用索引.

(3)OR的使用

必須要保證 OR 兩端的條件都存在可以用的索引,該查詢才可以使用索引。

(4)MySQL智能選擇

即使?jié)M足了上面說原則,MySQL也能棄用索引,例如:select * from A where id 1;這里棄用索引的主要原因:查詢即使使用索引,會導(dǎo)致出現(xiàn)大量的隨機(jī)IO,相對于從數(shù)據(jù)記錄的第一條遍歷到最后一條的順序IO開銷,還要大。

4.索引的使用場景

(1)索引檢索:檢索數(shù)據(jù)時(shí)使用索引。

(2)索引排序: 如果order by 排序需要的字段上存在索引,則可能使用到索引。

(3)索引覆蓋: 索引擁有的關(guān)鍵字內(nèi)容,覆蓋了查詢所需要的全部數(shù)據(jù),此時(shí),就不需要在數(shù)據(jù)區(qū)獲取數(shù)據(jù),僅僅在索引區(qū)即可。覆蓋就是直接在索引區(qū)獲取內(nèi)容,而不需要在數(shù)據(jù)區(qū)獲取。例如: select name from A where name like '小明%';

建立索引索引時(shí),不能僅僅考慮where檢索,同時(shí)考慮其他的使用場景。(在所有的where字段上增加索引,就是不合理的)

5.前綴索引

前綴索引是建立索引關(guān)鍵字一種方案。通常會使用字段的整體作為索引關(guān)鍵字。有時(shí),即使使用字段前部分?jǐn)?shù)據(jù),也可以去識別某些記錄。就比如一個(gè)班級里,我要找王xx,假如姓王的只有1個(gè)人,那么就可以建一個(gè)關(guān)鍵字為'王'的前綴索引。語法:Index `index_name` (`index_field`(N))使用index_name前N個(gè)字符建立的索引。

6.索引失效

(1) 應(yīng)盡量避免在 where 子句中使用 != 或 操作符,否則將引擎放棄使用索引而進(jìn)行全表掃描;

(2) 應(yīng)盡量避免在 where 子句中使用 or 來連接條件,如果一個(gè)字段有索引,一個(gè)字段沒有索引,將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描;

(3) 應(yīng)盡量避免在 where 子句中對字段進(jìn)行 null 值判斷,否則將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描;

(4)應(yīng)盡量避免在 where 子句中對字段進(jìn)行表達(dá)式操作,這將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描;如select id from t where num/2 = 100;

(5) 應(yīng)盡量避免在where子句中對字段進(jìn)行函數(shù)操作,這將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描;如:select id from t where substring(name,1,3) = ’abc’ ;

(6)應(yīng)盡量避免在where子句中對字段進(jìn)行類型轉(zhuǎn)換,這將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描; 如果列類型是字符串,那一定要在條件中將數(shù)據(jù)使用引號引用起來,如select id from t where id = 1;如果id字段在表設(shè)計(jì)中是varchar類型,那么即使id列上存的是數(shù)字,在查詢時(shí)也一定要用varchar去匹配,sql應(yīng)改為select id from t where id = '1';

(7)應(yīng)盡量避免在where子句中單獨(dú)引用復(fù)合索引里非第一位置的索引;

join 的兩種算法:BNL 和 NLJ

NLJ(Nested Loop Join)嵌套循環(huán)算法;以如下 SQL 為例:

select * from t1 join t2 on t1.a=t2.a

SQL 執(zhí)行時(shí)內(nèi)部流程是這樣的:

1. 先從 t1(假設(shè)這里 t1 被選為驅(qū)動(dòng)表)中取出一行數(shù)據(jù) X;

2. 從 X 中取出關(guān)聯(lián)字段 a 值,去 t2 中進(jìn)行查找,滿足條件的行取出;

3. 重復(fù)1、2步驟,直到表 t1 最后一行循環(huán)結(jié)束。

這就是一個(gè)嵌套循環(huán)的過程,如果在被驅(qū)動(dòng)表上查找數(shù)據(jù)時(shí)可以使用索引,總的對比計(jì)算次數(shù)等于驅(qū)動(dòng)表滿足 where 條件的行數(shù)。假設(shè)這里 t1、t2都是1萬行,則只需要 1萬次計(jì)算,這里用到的是Index Nested-Loops Join(INLJ,基于索引的嵌套循環(huán)聯(lián)接)。

如果 t1、t2 的 a 字段都沒有索引,還按照上述的嵌套循環(huán)流程查找數(shù)據(jù)呢?每次在被驅(qū)動(dòng)表上查找數(shù)據(jù)時(shí)都是一次全表掃描,要做1萬次全表掃描,掃描行數(shù)等于 1萬+1萬*1萬,這個(gè)效率很低,如果表行數(shù)更多,掃描行數(shù)動(dòng)輒幾百億,所以優(yōu)化器肯定不會使用這樣的算法,而是選擇 BNL 算法;

BNLJ(Block Nested Loop Join)塊嵌套循環(huán)算法;

1. 把 t1 表(假設(shè)這里 t1 被選為驅(qū)動(dòng)表)滿足條件的數(shù)據(jù)全部取出放到線程的 join buffer 中;

2. 每次取 t2 表一行數(shù)據(jù),去 joinbuffer 中進(jìn)行查找,滿足條件的行取出,直到表 t2 最后一行循環(huán)結(jié)束。

這個(gè)算法下,執(zhí)行計(jì)劃的 Extra 中會出現(xiàn) Using join buffer(Block Nested Loop),t1、t2 都做了一次全表掃描,總的掃描行數(shù)等于 1萬+1萬。但是由于 joinbuffer 維護(hù)的是一個(gè)無序數(shù)組,每次在 joinbuffer 中查找都要遍歷所有行,總的內(nèi)存計(jì)算次數(shù)等于1萬*1萬。另外如果 joinbuffer 不夠大放不下驅(qū)動(dòng)表的數(shù)據(jù),則要分多次執(zhí)行上面的流程,會導(dǎo)致被驅(qū)動(dòng)表也做多次全表掃描。

BNLJ相對于NLJ的優(yōu)點(diǎn)在于,驅(qū)動(dòng)層可以先將部分?jǐn)?shù)據(jù)加載進(jìn)buffer,這種方法的直接影響就是將大大減少內(nèi)層循環(huán)的次數(shù),提高join的效率。

例如:

如果內(nèi)層循環(huán)有100條記錄,外層循環(huán)也有100條記錄,這樣的話,每次外層循環(huán)先將10條記錄放到buffer中,內(nèi)層循環(huán)的100條記錄每條與這個(gè)buffer中的10條記錄進(jìn)行匹配,只需要匹配內(nèi)層循環(huán)總記錄數(shù)次即可結(jié)束一次循環(huán)(在這里,即只需要匹配100次即可結(jié)束),然后將匹配成功的記錄連接后放入結(jié)果集中,接著,外層循環(huán)繼續(xù)向buffer中放入10條記錄,同理進(jìn)行匹配,并將成功的記錄連接后放入結(jié)果集。后續(xù)循環(huán)以此類推,直到循環(huán)結(jié)束,將結(jié)果集發(fā)給client為止。

可以發(fā)現(xiàn),若用NLJ,則需要100 * 100次才可結(jié)束,BNLJ則需要100 / block_size * 100 = 10 * 100次就可結(jié)束,大大減少了循環(huán)次數(shù)。

JOIN 按照功能大致分為如下三類:

JOIN、STRAIGHT_JOIN、INNER JOIN(內(nèi)連接,或等值連接):取得兩個(gè)表中存在連接匹配關(guān)系的記錄。

LEFT JOIN(左連接):取得左表(table1)完全記錄,即是右表(table2)并無對應(yīng)匹配記錄。

RIGHT JOIN(右連接):與 LEFT JOIN 相反,取得右表(table2)完全記錄,即是左表(table1)并無匹配對應(yīng)記錄。

注意:mysql不支持Full join,不過可以通過UNION 關(guān)鍵字來合并 LEFT JOIN 與 RIGHT JOIN來模擬FULL join。

mysql 多表連接查詢方式,因?yàn)閙ysql只支持NLJ算法,所以如果是小表驅(qū)動(dòng)大表則效率更高;反之則效率下降;因此mysql對內(nèi)連接或等值連接的方式做了一個(gè)優(yōu)化,會去判斷join表的數(shù)據(jù)行大小,然后取數(shù)據(jù)行小的表為驅(qū)動(dòng)表。

INNER JOIN、JOIN、WHERE等值連接和STRAIGHT_JOIN都能表示內(nèi)連接,那平時(shí)如何選擇呢?一般情況下用INNER JOIN、JOIN或者WHERE等值連接,因?yàn)镸ySQL 會按照"小表驅(qū)動(dòng)大表的策略"進(jìn)行優(yōu)化。當(dāng)出現(xiàn)需要排序時(shí),才考慮用STRAIGHT_JOIN指定某張表為驅(qū)動(dòng)表。

兩表JOIN優(yōu)化

a.當(dāng)無order by條件時(shí),根據(jù)實(shí)際情況,使用left/right/inner join即可,根據(jù)explain優(yōu)化 ;

b.當(dāng)有order by條件時(shí),如select * from a inner join b where 1=1 and other condition order by a.col;使用explain解釋語句;

1)如果第一行的驅(qū)動(dòng)表為a,則效率會非常高,無需優(yōu)化;

2)否則,因?yàn)橹荒軐︱?qū)動(dòng)表字段直接排序的緣故,會出現(xiàn)using temporary,所以此時(shí)需要使用STRAIGHT_JOIN明確a為驅(qū)動(dòng)表,來達(dá)到使用a.col上index的優(yōu)化目的;或者使用left join且Where條件中不含b的過濾條件,此時(shí)的結(jié)果集為a的全集,而STRAIGHT_JOIN為inner join且使用a作為驅(qū)動(dòng)表。注:使用STRAIGHT_JOIN雖然不會using temporary,但也不是一定就能提高效率,如果a表數(shù)據(jù)遠(yuǎn)遠(yuǎn)超過b表,那么有可能使用STRAIGHT_JOIN時(shí)比原來的sql效率更低,所以怎么使用STRAIGHT_JOIN,還是要視情況而定。

在使用left join(或right join)時(shí),應(yīng)該清楚的知道以下幾點(diǎn):

(1). on與 where的執(zhí)行順序

ON 條件(“A LEFT JOIN B ON 條件表達(dá)式”中的ON)用來決定如何從 B 表中檢索數(shù)據(jù)行。如果 B 表中沒有任何一行數(shù)據(jù)匹配 ON 的條件,將會額外生成一行所有列為 NULL 的數(shù)據(jù),在匹配階段 WHERE 子句的條件都不會被使用。僅在匹配階段完成以后,WHERE 子句條件才會被使用。它將從匹配階段產(chǎn)生的數(shù)據(jù)中檢索過濾。

所以我們要注意:在使用Left (right) join的時(shí)候,一定要在先給出盡可能多的匹配滿足條件,減少Where的執(zhí)行。

(2).注意ON 子句和 WHERE 子句的不同

即使右表的數(shù)據(jù)不滿足ON后面的條件,也會在結(jié)果集拼接一條為NULL的數(shù)據(jù)行,但WHERE后面的條件不一樣,右表不滿足WHERE的條件,左表關(guān)聯(lián)的數(shù)據(jù)也會被過濾掉。

(3).盡量避免子查詢,而用join

往往性能這玩意兒,更多時(shí)候體現(xiàn)在數(shù)據(jù)量比較大的時(shí)候,此時(shí),我們應(yīng)該避免復(fù)雜的子查詢。

(1)in 和 not in 要慎用,如:select id from t where num in(1,2,3)對于連續(xù)的數(shù)值,能用 between 就不要用 in:select id from t where num between 1 and 3很多時(shí)候用 exists 代替 in 是一個(gè)好的選擇:select num from a where num in(select num from b)用下面的語句替換:select num from a where exists(select 1 from b where num=a.num)

(2)Update 語句,如果只更改1、2個(gè)字段,不要Update全部字段,否則頻繁調(diào)用會引起明顯的性能消耗,同時(shí)帶來大量日志。

(3)join語句,MySQL里面的join是用小表去驅(qū)動(dòng)大表,而由于MySQL join實(shí)現(xiàn)的原理就是做循環(huán),比如left join就是對左邊的數(shù)據(jù)進(jìn)行循環(huán)去驅(qū)動(dòng)右邊的表,左邊有m條記錄匹配,右邊有n條記錄那么就是做m次循環(huán),每次掃描n行數(shù)據(jù),總掃面行數(shù)是m*n行數(shù)據(jù)。左邊返回的結(jié)果集的大小就決定了循環(huán)的次數(shù),故單純的用小表去驅(qū)動(dòng)大表不一定的正確的,小表的結(jié)果集可能也大于大表的結(jié)果集,所以寫join的時(shí)候盡可能的先估計(jì)兩張表的可能結(jié)果集,用小結(jié)果集去驅(qū)動(dòng)大結(jié)果集.值得注意的是在使用left/right join的時(shí)候,從表的條件應(yīng)寫在on之后,主表應(yīng)寫在where之后.否則MySQL會當(dāng)作普通的連表查詢;

(4)select count(*) from table;這樣不帶任何條件的count會引起全表掃描,并且沒有任何業(yè)務(wù)意義,是一定要杜絕的;

(5)select * from t 這種語句要盡量避免,使用具體的字段代替*,更有實(shí)際意義,需要什么字段就返回什么字段;

(6)數(shù)據(jù)量大的情況下,limit要慎用,因?yàn)槭褂胠imit m,n方式分頁時(shí),mysql每次都是查詢前m+n條,然后舍棄前m條,所以m越大,偏移量越大,性能就越差。比如:select * from A limit 1000000,20這鐘,查詢效率就會非常低,當(dāng)分頁的頁數(shù)大于一定的數(shù)量之后,就可以換種方式來分頁:select * from A a join (select id from A limit 1000000,20) b on a.id=b.id;

Mysql到底是怎么實(shí)現(xiàn)MVCC的

Mysql到底是怎么實(shí)現(xiàn)MVCC的

Mysql到底是怎么實(shí)現(xiàn)MVCC的?這個(gè)問題無數(shù)人都在問,但google中并無答案,本文嘗試從Mysql源碼中尋找答案。

在Mysql中MVCC是在Innodb存儲引擎中得到支持的,Innodb為每行記錄都實(shí)現(xiàn)了三個(gè)隱藏字段:

6字節(jié)的事務(wù)ID(DB_TRX_ID )

7字節(jié)的回滾指針(DB_ROLL_PTR)

隱藏的ID

6字節(jié)的事物ID用來標(biāo)識該行所述的事務(wù),7字節(jié)的回滾指針需要了解下Innodb的事務(wù)模型。

1. Innodb的事務(wù)相關(guān)概念

為了支持事務(wù),Innbodb引入了下面幾個(gè)概念:

redo log

redo log就是保存執(zhí)行的SQL語句到一個(gè)指定的Log文件,當(dāng)Mysql執(zhí)行recovery時(shí)重新執(zhí)行redo log記錄的SQL操作即可。當(dāng)客戶端執(zhí)行每條SQL(更新語句)時(shí),redo log會被首先寫入log buffer;當(dāng)客戶端執(zhí)行COMMIT命令時(shí),log buffer中的內(nèi)容會被視情況刷新到磁盤。redo log在磁盤上作為一個(gè)獨(dú)立的文件存在,即Innodb的log文件。

undo log

與redo log相反,undo log是為回滾而用,具體內(nèi)容就是copy事務(wù)前的數(shù)據(jù)庫內(nèi)容(行)到undo buffer,在適合的時(shí)間把undo buffer中的內(nèi)容刷新到磁盤。undo buffer與redo buffer一樣,也是環(huán)形緩沖,但當(dāng)緩沖滿的時(shí)候,undo buffer中的內(nèi)容會也會被刷新到磁盤;與redo log不同的是,磁盤上不存在單獨(dú)的undo log文件,所有的undo log均存放在主ibd數(shù)據(jù)文件中(表空間),即使客戶端設(shè)置了每表一個(gè)數(shù)據(jù)文件也是如此。

rollback segment

回滾段這個(gè)概念來自O(shè)racle的事物模型,在Innodb中,undo log被劃分為多個(gè)段,具體某行的undo log就保存在某個(gè)段中,稱為回滾段??梢哉J(rèn)為undo log和回滾段是同一意思。

Innodb提供了基于行的鎖,如果行的數(shù)量非常大,則在高并發(fā)下鎖的數(shù)量也可能會比較大,據(jù)Innodb文檔說,Innodb對鎖進(jìn)行了空間有效優(yōu)化,即使并發(fā)量高也不會導(dǎo)致內(nèi)存耗盡。

對行的鎖有分兩種:排他鎖、共享鎖。共享鎖針對對,排他鎖針對寫,完全等同讀寫鎖的概念。如果某個(gè)事務(wù)在更新某行(排他鎖),則其他事物無論是讀還是寫本行都必須等待;如果某個(gè)事物讀某行(共享鎖),則其他讀的事物無需等待,而寫事物則需等待。通過共享鎖,保證了多讀之間的無等待性,但是鎖的應(yīng)用又依賴Mysql的事務(wù)隔離級別。

隔離級別

隔離級別用來限制事務(wù)直接的交互程度,目前有幾個(gè)工業(yè)標(biāo)準(zhǔn):

- READ_UNCOMMITTED:臟讀

- READ_COMMITTED:讀提交

- REPEATABLE_READ:重復(fù)讀

- SERIALIZABLE:串行化

Innodb對四種類型都支持,臟讀和串行化應(yīng)用場景不多,讀提交、重復(fù)讀用的比較廣泛,后面會介紹其實(shí)現(xiàn)方式。

2. 行的更新過程

下面演示下事務(wù)對某行記錄的更新過程:

1. 初始數(shù)據(jù)行

F1~F6是某行列的名字,1~6是其對應(yīng)的數(shù)據(jù)。后面三個(gè)隱含字段分別對應(yīng)該行的事務(wù)號和回滾指針,假如這條數(shù)據(jù)是剛INSERT的,可以認(rèn)為ID為1,其他兩個(gè)字段為空。

2.事務(wù)1更改該行的各字段的值

當(dāng)事務(wù)1更改該行的值時(shí),會進(jìn)行如下操作:

用排他鎖鎖定該行

php+mysql怎么實(shí)現(xiàn)無限級別分類,數(shù)據(jù)庫怎么設(shè)計(jì)?只用一條SQL語句讀出數(shù)據(jù),怎么解決+新聞- |—國際新聞

數(shù)據(jù)庫中給多個(gè)父級ID字段,例如:國內(nèi)新聞的PID(父級ID)是新聞的ID,體育新聞的PID是國內(nèi)新聞的ID,這樣通過查找PID就可以找到上一級別。

mysql 核心內(nèi)容-上

1、SQL語句執(zhí)行流程

MySQL大體上可分為Server層和存儲引擎層兩部分。

Server層:

連接器:TCP握手后服務(wù)器來驗(yàn)證登陸用戶身份,A用戶創(chuàng)建連接后,管理員對A用戶權(quán)限修改了也不會影響到已經(jīng)創(chuàng)建的鏈接權(quán)限,必須重新登陸。

查詢緩存:查詢后的結(jié)果存儲位置,MySQL8.0版本以后已經(jīng)取消,因?yàn)椴樵兙彺媸l繁,得不償失。

分析器:根據(jù)語法規(guī)則,判斷你輸入的這個(gè)SQL語句是否滿足MySQL語法。

優(yōu)化器:多種執(zhí)行策略可實(shí)現(xiàn)目標(biāo),系統(tǒng)自動(dòng)選擇最優(yōu)進(jìn)行執(zhí)行。

執(zhí)行器:判斷是否有權(quán)限,將最終任務(wù)提交到存儲引擎。

存儲引擎層

負(fù)責(zé)數(shù)據(jù)的存儲和提取。其架構(gòu)模式是插件式的,支持InnoDB、MyISAM、Memory等多個(gè)存儲引擎?,F(xiàn)在最常用的存儲引擎是InnoDB,它從MySQL 5.5.5版本開始成為了默認(rèn)存儲引擎(經(jīng)常用的也是這個(gè))。

SQL執(zhí)行順序

2、BinLog、RedoLog、UndoLog

BinLog

BinLog是記錄所有數(shù)據(jù)庫表結(jié)構(gòu)變更(例如create、alter table)以及表數(shù)據(jù)修改(insert、update、delete)的二進(jìn)制日志,主從數(shù)據(jù)庫同步用到的都是BinLog文件。BinLog日志文件有三種模式。

STATEMENT 模式

內(nèi)容:binlog 記錄可能引起數(shù)據(jù)變更的 sql 語句

優(yōu)勢:該模式下,因?yàn)闆]有記錄實(shí)際的數(shù)據(jù),所以日志量很少 IO 都消耗很低,性能是最優(yōu)的

劣勢:但有些操作并不是確定的,比如 uuid() 函數(shù)會隨機(jī)產(chǎn)生唯一標(biāo)識,當(dāng)依賴 binlog 回放時(shí),該操作生成的數(shù)據(jù)與原數(shù)據(jù)必然是不同的,此時(shí)可能造成無法預(yù)料的后果。

ROW 模式

內(nèi)容:在該模式下,binlog 會記錄每次操作的源數(shù)據(jù)與修改后的目標(biāo)數(shù)據(jù),StreamSets就要求該模式。

優(yōu)勢:可以絕對精準(zhǔn)的還原,從而保證了數(shù)據(jù)的安全與可靠,并且復(fù)制和數(shù)據(jù)恢復(fù)過程可以是并發(fā)進(jìn)行的

劣勢:缺點(diǎn)在于 binlog 體積會非常大,同時(shí),對于修改記錄多、字段長度大的操作來說,記錄時(shí)性能消耗會很嚴(yán)重。閱讀的時(shí)候也需要特殊指令來進(jìn)行讀取數(shù)據(jù)。

MIXED 模式

內(nèi)容:是對上述STATEMENT 跟 ROW 兩種模式的混合使用。

細(xì)節(jié):對于絕大部分操作,都是使用 STATEMENT 來進(jìn)行 binlog 沒有記錄,只有以下操作使用 ROW 來實(shí)現(xiàn):表的存儲引擎為 NDB,使用了uuid() 等不確定函數(shù),使用了 insert delay 語句,使用了臨時(shí)表

主從同步流程:

1、主節(jié)點(diǎn)必須啟用二進(jìn)制日志,記錄任何修改了數(shù)據(jù)庫數(shù)據(jù)的事件。

2、從節(jié)點(diǎn)開啟一個(gè)線程(I/O Thread)把自己扮演成 mysql 的客戶端,通過 mysql 協(xié)議,請求主節(jié)點(diǎn)的二進(jìn)制日志文件中的事件 。

3、主節(jié)點(diǎn)啟動(dòng)一個(gè)線程(dump Thread),檢查自己二進(jìn)制日志中的事件,跟對方請求的位置對比,如果不帶請求位置參數(shù),則主節(jié)點(diǎn)就會從第一個(gè)日志文件中的第一個(gè)事件一個(gè)一個(gè)發(fā)送給從節(jié)點(diǎn)。

4、從節(jié)點(diǎn)接收到主節(jié)點(diǎn)發(fā)送過來的數(shù)據(jù)把它放置到中繼日志(Relay log)文件中。并記錄該次請求到主節(jié)點(diǎn)的具體哪一個(gè)二進(jìn)制日志文件內(nèi)部的哪一個(gè)位置(主節(jié)點(diǎn)中的二進(jìn)制文件會有多個(gè))。

5、從節(jié)點(diǎn)啟動(dòng)另外一個(gè)線程(sql Thread ),把 Relay log 中的事件讀取出來,并在本地再執(zhí)行一次。

mysql默認(rèn)的復(fù)制方式是異步的,并且復(fù)制的時(shí)候是有并行復(fù)制能力的。主庫把日志發(fā)送給從庫后不管了,這樣會產(chǎn)生一個(gè)問題就是假設(shè)主庫掛了,從庫處理失敗了,這時(shí)候從庫升為主庫后,日志就丟失了。由此產(chǎn)生兩個(gè)概念。

全同步復(fù)制

主庫寫入binlog后強(qiáng)制同步日志到從庫,所有的從庫都執(zhí)行完成后才返回給客戶端,但是很顯然這個(gè)方式的話性能會受到嚴(yán)重影響。

半同步復(fù)制

半同步復(fù)制的邏輯是這樣,從庫寫入日志成功后返回ACK確認(rèn)給主庫,主庫收到至少一個(gè)從庫的確認(rèn)就認(rèn)為寫操作完成。

還可以延伸到由于主從配置不一樣、主庫大事務(wù)、從庫壓力過大、網(wǎng)絡(luò)震蕩等造成主備延遲,如何避免這個(gè)問題?主備切換的時(shí)候用可靠性優(yōu)先原則還是可用性優(yōu)先原則?如何判斷主庫Crash了?互為主備的情況下如何避免主備循環(huán)復(fù)制?被刪庫跑路了如何正確恢復(fù)?( o )… 感覺越來越扯到DBA的活兒上去了。

RedoLog

可以先通過下面demo理解:

飯點(diǎn)記賬可以把賬單寫在賬本上也可以寫在粉板上。有人賒賬或者還賬的話,一般有兩種做法:

1、直接把賬本翻出來,把這次賒的賬加上去或者扣除掉。

2、先在粉板上記下這次的賬,等打烊以后再把賬本翻出來核算。

生意忙時(shí)選后者,因?yàn)榍罢咛闊┝?。得在密密麻麻的記錄中找到這個(gè)人的賒賬總額信息,找到之后再拿出算盤計(jì)算,最后再將結(jié)果寫回到賬本上。

同樣在MySQL中如果每一次的更新操作都需要寫進(jìn)磁盤,然后磁盤也要找到對應(yīng)的那條記錄,然后再更新,整個(gè)過程IO成本、查找成本都很高。而粉板和賬本配合的整個(gè)過程就是MySQL用到的是Write-Ahead Logging 技術(shù),它的關(guān)鍵點(diǎn)就是先寫日志,再寫磁盤。此時(shí)賬本 = BinLog,粉板 = RedoLog。

1、 記錄更新時(shí),InnoDB引擎就會先把記錄寫到RedoLog(粉板)里面,并更新內(nèi)存。同時(shí),InnoDB引擎會在空閑時(shí)將這個(gè)操作記錄更新到磁盤里面。

2、 如果更新太多RedoLog處理不了的時(shí)候,需先將RedoLog部分?jǐn)?shù)據(jù)寫到磁盤,然后擦除RedoLog部分?jǐn)?shù)據(jù)。RedoLog類似轉(zhuǎn)盤。

RedoLog有write pos 跟checkpoint

write pos :是當(dāng)前記錄的位置,一邊寫一邊后移,寫到第3號文件末尾后就回到0號文件開頭。

check point:是當(dāng)前要擦除的位置,也是往后推移并且循環(huán)的,擦除記錄前要把記錄更新到數(shù)據(jù)文件。

write pos和check point之間的是粉板上還空著的部分,可以用來記錄新的操作。如果write pos追上checkpoint,表示粉板滿了,這時(shí)候不能再執(zhí)行新的更新,得停下來先擦掉一些記錄,把checkpoint推進(jìn)一下。

有了redo log,InnoDB就可以保證即使數(shù)據(jù)庫發(fā)生異常重啟,之前提交的記錄都不會丟失,這個(gè)能力稱為crash-safe。 redolog兩階段提交:為了讓binlog跟redolog兩份日志之間的邏輯一致。提交流程大致如下:

1 prepare階段 -- 2 寫binlog -- 3 commit

當(dāng)在2之前崩潰時(shí),重啟恢復(fù)后發(fā)現(xiàn)沒有commit,回滾。備份恢復(fù):沒有binlog 。一致

當(dāng)在3之前崩潰時(shí),重啟恢復(fù)發(fā)現(xiàn)雖沒有commit,但滿足prepare和binlog完整,所以重啟后會自動(dòng)commit。備份:有binlog. 一致

binlog跟redolog區(qū)別:

redo log是InnoDB引擎特有的;binlog是MySQL的Server層實(shí)現(xiàn)的,所有引擎都可以使用。

redo log是物理日志,記錄的是在某個(gè)數(shù)據(jù)頁上做了什么修改;binlog是邏輯日志,記錄的是這個(gè)語句的原始邏輯,比如給ID=2這一行的c字段加1。

redo log是循環(huán)寫的,空間固定會用完;binlog是可以追加寫入的。追加寫是指binlog文件寫到一定大小后會切換到下一個(gè),并不會覆蓋以前的日志。

UndoLog

UndoLog 一般是邏輯日志,主要分為兩種:

insert undo log

代表事務(wù)在insert新記錄時(shí)產(chǎn)生的undo log, 只在事務(wù)回滾時(shí)需要,并且在事務(wù)提交后可以被立即丟棄

update undo log

事務(wù)在進(jìn)行update或delete時(shí)產(chǎn)生的undo log; 不僅在事務(wù)回滾時(shí)需要,在快照讀時(shí)也需要;所以不能隨便刪除,只有在快速讀或事務(wù)回滾不涉及該日志時(shí),對應(yīng)的日志才會被purge線程統(tǒng)一清除

3、MySQL中的索引

索引的常見模型有哈希表、有序數(shù)組和搜索樹。

哈希表:一種以KV存儲數(shù)據(jù)的結(jié)構(gòu),只適合等值查詢,不適合范圍查詢。

有序數(shù)組:只適用于靜態(tài)存儲引擎,涉及到插入的時(shí)候比較麻煩??梢詤⒖糐ava中的ArrayList。

搜索樹:按照數(shù)據(jù)結(jié)構(gòu)中的二叉樹來存儲數(shù)據(jù),不過此時(shí)是N叉樹(B+樹)。廣泛應(yīng)用在存儲引擎層中。

B+樹比B樹優(yōu)勢在于:

B+ 樹非葉子節(jié)點(diǎn)存儲的只是索引,可以存儲的更多。B+樹比B樹更加矮胖,IO次數(shù)更少。

B+ 樹葉子節(jié)點(diǎn)前后管理,更加方便范圍查詢。同時(shí)結(jié)果都在葉子節(jié)點(diǎn),查詢效率穩(wěn)定。

B+樹中更有利于對數(shù)據(jù)掃描,可以避免B樹的回溯掃描。

索引的優(yōu)點(diǎn):

1、唯一索引可以保證每一行數(shù)據(jù)的唯一性

2、提高查詢速度

3、加速表與表的連接

4、顯著的減少查詢中分組和排序的時(shí)間

5、通過使用索引,可以在查詢的過程中,使用優(yōu)化隱藏器,提高系統(tǒng)的性能。

索引的缺點(diǎn):

1、創(chuàng)建跟維護(hù)都需要耗時(shí)

2、創(chuàng)建索引時(shí),需要對表加鎖,在鎖表的同時(shí),可能會影響到其他的數(shù)據(jù)操作

3、 索引需要磁盤的空間進(jìn)行存儲,磁盤占用也很快。

4、當(dāng)對表中的數(shù)據(jù)進(jìn)行CRUD的時(shí),也會觸發(fā)索引的維護(hù),而維護(hù)索引需要時(shí)間,可能會降低數(shù)據(jù)操作性能

索引設(shè)計(jì)的原則不應(yīng)該:

1、索引不是越多越好。索引太多,維護(hù)索引需要時(shí)間跟空間。

2、 頻繁更新的數(shù)據(jù),不宜建索引。

3、數(shù)據(jù)量小的表沒必要建立索引。

應(yīng)該:

1、重復(fù)率小的列建議生成索引。因?yàn)橹貜?fù)數(shù)據(jù)少,索引樹查詢更有效率,等價(jià)基數(shù)越大越好。

2、數(shù)據(jù)具有唯一性,建議生成唯一性索引。在數(shù)據(jù)庫的層面,保證數(shù)據(jù)正確性

3、頻繁group by、order by的列建議生成索引??梢源蠓岣叻纸M和排序效率

4、經(jīng)常用于查詢條件的字段建議生成索引。通過索引查詢,速度更快

索引失效的場景

1、模糊搜索:左模糊或全模糊都會導(dǎo)致索引失效,比如'%a'和'%a%'。但是右模糊是可以利用索引的,比如'a%' 。

2、隱式類型轉(zhuǎn)換:比如select * from t where name = xxx , name是字符串類型,但是沒有加引號,所以是由MySQL隱式轉(zhuǎn)換的,所以會讓索引失效 3、當(dāng)語句中帶有or的時(shí)候:比如select * from t where name=‘sw’ or age=14

4、不符合聯(lián)合索引的最左前綴匹配:(A,B,C)的聯(lián)合索引,你只where了C或B或只有B,C

關(guān)于索引的知識點(diǎn):

主鍵索引:主鍵索引的葉子節(jié)點(diǎn)存的是整行數(shù)據(jù)信息。在InnoDB里,主鍵索引也被稱為聚簇索引(clustered index)。主鍵自增是無法保證完全自增的哦,遇到唯一鍵沖突、事務(wù)回滾等都可能導(dǎo)致不連續(xù)。

唯一索引:以唯一列生成的索引,該列不允許有重復(fù)值,但允許有空值(NULL)

普通索引跟唯一索引查詢性能:InnoDB的數(shù)據(jù)是按數(shù)據(jù)頁為單位來讀寫的,默認(rèn)每頁16KB,因此這兩種索引查詢數(shù)據(jù)性能差別微乎其微。

change buffer:普通索引用在更新過程的加速,更新的字段如果在緩存中,如果是普通索引則直接更新即可。如果是唯一索引需要將所有數(shù)據(jù)讀入內(nèi)存來確保不違背唯一性,所以盡量用普通索引。

非主鍵索引:非主鍵索引的葉子節(jié)點(diǎn)內(nèi)容是主鍵的值。在InnoDB里,非主鍵索引也被稱為二級索引(secondary index)

回表:先通過數(shù)據(jù)庫索引掃描出數(shù)據(jù)所在的行,再通過行主鍵id取出索引中未提供的數(shù)據(jù),即基于非主鍵索引的查詢需要多掃描一棵索引樹。

覆蓋索引:如果一個(gè)索引包含(或者說覆蓋)所有需要查詢的字段的值,我們就稱之為覆蓋索引。

聯(lián)合索引:相對單列索引,組合索引是用多個(gè)列組合構(gòu)建的索引,一次性最多聯(lián)合16個(gè)。

最左前綴原則:對多個(gè)字段同時(shí)建立的組合索引(有順序,ABC,ACB是完全不同的兩種聯(lián)合索引) 以聯(lián)合索引(a,b,c)為例,建立這樣的索引相當(dāng)于建立了索引a、ab、abc三個(gè)索引。另外組合索引實(shí)際還是一個(gè)索引,并非真的創(chuàng)建了多個(gè)索引,只是產(chǎn)生的效果等價(jià)于產(chǎn)生多個(gè)索引。

索引下推:MySQL 5.6引入了索引下推優(yōu)化,可以在索引遍歷過程中,對索引中包含的字段先做判斷,過濾掉不符合條件的記錄,減少回表字?jǐn)?shù)。

索引維護(hù):B+樹為了維護(hù)索引有序性涉及到頁分裂跟頁合并。增刪數(shù)據(jù)時(shí)需考慮頁空間利用率。

自增主鍵:一般會建立與業(yè)務(wù)無關(guān)的自增主鍵,不會觸發(fā)葉子節(jié)點(diǎn)分裂。

延遲關(guān)聯(lián):通過使用覆蓋索引查詢返回需要的主鍵,再根據(jù)主鍵關(guān)聯(lián)原表獲得需要的數(shù)據(jù)。

InnoDB存儲: * .frm文件是一份定義文件,也就是定義數(shù)據(jù)庫表是一張?jiān)趺礃拥谋怼?.ibd文件則是該表的索引,數(shù)據(jù)存儲文件,既該表的所有索引樹,所有行記錄數(shù)據(jù)都存儲在該文件中。

MyISAM存儲:* .frm文件是一份定義文件,也就是定義數(shù)據(jù)庫表是一張?jiān)趺礃拥谋怼? .MYD文件是MyISAM存儲引擎表的所有行數(shù)據(jù)的文件。* .MYI文件存放的是MyISAM存儲引擎表的索引相關(guān)數(shù)據(jù)的文件。MyISAM引擎下,表數(shù)據(jù)和表索引數(shù)據(jù)是分開存儲的。

MyISAM查詢:在MyISAM下,主鍵索引和輔助鍵索引都屬于非聚簇索引。查詢不管是走主鍵索引,還是非主鍵索引,在葉子結(jié)點(diǎn)得到的都是目的數(shù)據(jù)的地址,還需要通過該地址,才能在數(shù)據(jù)文件中找到目的數(shù)據(jù)。

PS:InnoDB支持聚簇索引,MyISAM不支持聚簇索引

4、SQL事務(wù)隔離級別

ACID的四個(gè)特性

原子性(Atomicity):把多個(gè)操作放到一個(gè)事務(wù)中,保證這些操作要么都成功,要么都不成功

一致性(Consistency):理解成一串對數(shù)據(jù)進(jìn)行操作的程序執(zhí)行下來,不會對數(shù)據(jù)產(chǎn)生不好的影響,比如憑空產(chǎn)生,或消失

隔離性(Isolation,又稱獨(dú)立性):隔離性的意思就是多個(gè)事務(wù)之間互相不干擾,即使是并發(fā)事務(wù)的情況下,他們只是兩個(gè)并發(fā)執(zhí)行沒有交集,互不影響的東西;當(dāng)然實(shí)現(xiàn)中,也不一定需要這么完整隔離性,即不一定需要這么的互不干擾,有時(shí)候還是允許有部分干擾的。所以MySQL可以支持4種事務(wù)隔離性

持久性(Durability):當(dāng)某個(gè)操作操作完畢了,那么結(jié)果就是這樣了,并且這個(gè)操作會持久化到日志記錄中

PS:ACID中C與CAP定理中C的區(qū)別

ACID的C著重強(qiáng)調(diào)單數(shù)據(jù)庫事務(wù)操作時(shí),要保證數(shù)據(jù)的完整和正確性,數(shù)據(jù)不會憑空消失跟增加。CAP 理論中的C指的是對一個(gè)數(shù)據(jù)多個(gè)備份的讀寫一致性

事務(wù)操作可能會出現(xiàn)的數(shù)據(jù)問題

1、臟讀(dirty read):B事務(wù)更改數(shù)據(jù)還未提交,A事務(wù)已經(jīng)看到并且用了。B事務(wù)如果回滾,則A事務(wù)做錯(cuò)了

2、 不可重復(fù)讀(non-repeatable read):不可重復(fù)讀的重點(diǎn)是修改: 同樣的條件, 你讀取過的數(shù)據(jù), 再次讀取出來發(fā)現(xiàn)值不一樣了,只需要鎖住滿足條件的記錄

3、 幻讀(phantom read):事務(wù)A先修改了某個(gè)表的所有紀(jì)錄的狀態(tài)字段為已處理,未提交;事務(wù)B也在此時(shí)新增了一條未處理的記錄,并提交了;事務(wù)A隨后查詢記錄,卻發(fā)現(xiàn)有一條記錄是未處理的造成幻讀現(xiàn)象,幻讀僅專指新插入的行?;米x會造成語義上的問題跟數(shù)據(jù)一致性問題。

4、 在可重復(fù)讀RR隔離級別下,普通查詢是快照讀,是不會看到別的事務(wù)插入的數(shù)據(jù)的。因此,幻讀在當(dāng)前讀下才會出現(xiàn)。要用間隙鎖解決此問題。

在說隔離級別之前,你首先要知道,你隔離得越嚴(yán)實(shí),效率就會越低。因此很多時(shí)候,我們都要在二者之間尋找一個(gè)平衡點(diǎn)。SQL標(biāo)準(zhǔn)的事務(wù)隔離級別由低到高如下: 上圖從上到下的模式會導(dǎo)致系統(tǒng)的并行性能依次降低,安全性依次提高。

讀未提交:別人改數(shù)據(jù)的事務(wù)尚未提交,我在我的事務(wù)中也能讀到。

讀已提交(Oracle默認(rèn)):別人改數(shù)據(jù)的事務(wù)已經(jīng)提交,我在我的事務(wù)中才能讀到。

可重復(fù)讀(MySQL默認(rèn)):別人改數(shù)據(jù)的事務(wù)已經(jīng)提交,我在我的事務(wù)中也不去讀,以此保證重復(fù)讀一致性。

串行:我的事務(wù)尚未提交,別人就別想改數(shù)據(jù)。

標(biāo)準(zhǔn)跟實(shí)現(xiàn):上面都是關(guān)于事務(wù)的標(biāo)準(zhǔn),但是每一種數(shù)據(jù)庫都有不同的實(shí)現(xiàn),比如MySQL InnDB 默認(rèn)為RR級別,但是不會出現(xiàn)幻讀。因?yàn)楫?dāng)事務(wù)A更新了所有記錄的某個(gè)字段,此時(shí)事務(wù)A會獲得對這個(gè)表的表鎖,因?yàn)槭聞?wù)A還沒有提交,所以事務(wù)A獲得的鎖沒有釋放,此時(shí)事務(wù)B在該表插入新記錄,會因?yàn)闊o法獲得該表的鎖,則導(dǎo)致插入操作被阻塞。只有事務(wù)A提交了事務(wù)后,釋放了鎖,事務(wù)B才能進(jìn)行接下去的操作。所以可以說 MySQL的RR級別的隔離是已經(jīng)實(shí)現(xiàn)解決了臟讀,不可重復(fù)讀和幻讀的。

5、MySQL中的鎖

無論是Java的并發(fā)編程還是數(shù)據(jù)庫的并發(fā)操作都會涉及到鎖,研發(fā)人員引入了悲觀鎖跟樂觀鎖這樣一種鎖的設(shè)計(jì)思想。

悲觀鎖:

優(yōu)點(diǎn):適合在寫多讀少的并發(fā)環(huán)境中使用,雖然無法維持非常高的性能,但是在樂觀鎖無法提更好的性能前提下,可以做到數(shù)據(jù)的安全性

缺點(diǎn):加鎖會增加系統(tǒng)開銷,雖然能保證數(shù)據(jù)的安全,但數(shù)據(jù)處理吞吐量低,不適合在讀書寫少的場合下使用

樂觀鎖:

優(yōu)點(diǎn):在讀多寫少的并發(fā)場景下,可以避免數(shù)據(jù)庫加鎖的開銷,提高DAO層的響應(yīng)性能,很多情況下ORM工具都有帶有樂觀鎖的實(shí)現(xiàn),所以這些方法不一定需要我們?nèi)藶榈娜?shí)現(xiàn)。

缺點(diǎn):在寫多讀少的并發(fā)場景下,即在寫操作競爭激烈的情況下,會導(dǎo)致CAS多次重試,沖突頻率過高,導(dǎo)致開銷比悲觀鎖更高。

實(shí)現(xiàn):數(shù)據(jù)庫層面的樂觀鎖其實(shí)跟CAS思想類似, 通數(shù)據(jù)版本號或者時(shí)間戳也可以實(shí)現(xiàn)。

數(shù)據(jù)庫并發(fā)場景主要有三種:

讀-讀:不存在任何問題,也不需要并發(fā)控制

讀-寫:有隔離性問題,可能遇到臟讀,幻讀,不可重復(fù)讀

寫-寫:可能存更新丟失問題,比如第一類更新丟失,第二類更新丟失

兩類更新丟失問題:

第一類更新丟失:事務(wù)A的事務(wù)回滾覆蓋了事務(wù)B已提交的結(jié)果 第二類更新丟失:事務(wù)A的提交覆蓋了事務(wù)B已提交的結(jié)果

為了合理貫徹落實(shí)鎖的思想,MySQL中引入了雜七雜八的各種鎖:

鎖分類

MySQL支持三種層級的鎖定,分別為

表級鎖定

MySQL中鎖定粒度最大的一種鎖,最常使用的MYISAM與INNODB都支持表級鎖定。

頁級鎖定

是MySQL中鎖定粒度介于行級鎖和表級鎖中間的一種鎖,表級鎖速度快,但沖突多,行級沖突少,但速度慢。所以取了折衷的頁級,一次鎖定相鄰的一組記錄。

行級鎖定

Mysql中鎖定粒度最細(xì)的一種鎖,表示只針對當(dāng)前操作的行進(jìn)行加鎖。行級鎖能大大減少數(shù)據(jù)庫操作的沖突。其加鎖粒度最小,但加鎖的開銷也最大行級鎖不一定比表級鎖要好:鎖的粒度越細(xì),代價(jià)越高,相比表級鎖在表的頭部直接加鎖,行級鎖還要掃描找到對應(yīng)的行對其上鎖,這樣的代價(jià)其實(shí)是比較高的,所以表鎖和行鎖各有所長。

MyISAM中的鎖

雖然MySQL支持表,頁,行三級鎖定,但MyISAM存儲引擎只支持表鎖。所以MyISAM的加鎖相對比較開銷低,但數(shù)據(jù)操作的并發(fā)性能相對就不高。但如果寫操作都是尾插入,那還是可以支持一定程度的讀寫并發(fā)

從MyISAM所支持的鎖中也可以看出,MyISAM是一個(gè)支持讀讀并發(fā),但不支持通用讀寫并發(fā),寫寫并發(fā)的數(shù)據(jù)庫引擎,所以它更適合用于讀多寫少的應(yīng)用場合,一般工程中也用的較少。

InnoDB中的鎖

該模式下支持的鎖實(shí)在是太多了,具體如下:

共享鎖和排他鎖 (Shared and Exclusive Locks)

意向鎖(Intention Locks)

記錄鎖(Record Locks)

間隙鎖(Gap Locks)

臨鍵鎖 (Next-Key Locks)

插入意向鎖(Insert Intention Locks)

主鍵自增鎖 (AUTO-INC Locks)

空間索引斷言鎖(Predicate Locks for Spatial Indexes)

舉個(gè)栗子,比如行鎖里的共享鎖跟排它鎖:lock in share modle 共享讀鎖:

為了確保自己查到的數(shù)據(jù)沒有被其他的事務(wù)正在修改,也就是說確保查到的數(shù)據(jù)是最新的數(shù)據(jù),并且不允許其他人來修改數(shù)據(jù)。但是自己不一定能夠修改數(shù)據(jù),因?yàn)橛锌赡芷渌氖聞?wù)也對這些數(shù)據(jù)使用了 in share mode 的方式上了S 鎖。如果不及時(shí)的commit 或者rollback 也可能會造成大量的事務(wù)等待。

for update排它寫鎖:

為了讓自己查到的數(shù)據(jù)確保是最新數(shù)據(jù),并且查到后的數(shù)據(jù)只允許自己來修改的時(shí)候,需要用到for update。相當(dāng)于一個(gè) update 語句。在業(yè)務(wù)繁忙的情況下,如果事務(wù)沒有及時(shí)的commit或者rollback 可能會造成其他事務(wù)長時(shí)間的等待,從而影響數(shù)據(jù)庫的并發(fā)使用效率。

Gap Lock間隙鎖:

1、行鎖只能鎖住行,如果在記錄之間的間隙插入數(shù)據(jù)就無法解決了,因此MySQL引入了間隙鎖(Gap Lock)。間隙鎖是左右開區(qū)間。間隙鎖之間不會沖突。

2、間隙鎖和行鎖合稱NextKeyLock,每個(gè)NextKeyLock是前開后閉區(qū)間。

間隙鎖加鎖原則(學(xué)完忘那種):

1、加鎖的基本單位是 NextKeyLock,是前開后閉區(qū)間。

2、查找過程中訪問到的對象才會加鎖。

3、索引上的等值查詢,給唯一索引加鎖的時(shí)候,NextKeyLock退化為行鎖。

4、索引上的等值查詢,向右遍歷時(shí)且最后一個(gè)值不滿足等值條件的時(shí)候,NextKeyLock退化為間隙鎖。

5、唯一索引上的范圍查詢會訪問到不滿足條件的第一個(gè)值為止。

“mysql”達(dá)到1億級別如何設(shè)計(jì)優(yōu)化?

“mysql”達(dá)到1億級別如何設(shè)計(jì)優(yōu)化?

1.首先可以考慮業(yè)務(wù)層面優(yōu)化,即垂直分表。

垂直分表就是把一個(gè)數(shù)據(jù)量很大的表,可以按某個(gè)字段的屬性或使用頻繁程度分類,拆分為多個(gè)表。

如有多種業(yè)務(wù)類型,每種業(yè)務(wù)類型入不同的表,table1,table2,table3.

如果日常業(yè)務(wù)不需要使用所有數(shù)據(jù),可以按時(shí)間分表,比如說月表。每個(gè)表只存一個(gè)月記錄。

2.架構(gòu)上的優(yōu)化,即水平分表。

水平分表就是根據(jù)一列或多列數(shù)據(jù)的值把數(shù)據(jù)行放到多個(gè)獨(dú)立的表里,這里不具備業(yè)務(wù)意義。

如按照id分表,末尾是0-9的數(shù)據(jù)分別插入到10個(gè)表里面。

可能你要問,這樣看起來和剛才說的垂直分表沒什么區(qū)別。只不過是否具備業(yè)務(wù)意義的差異,都是按字段的值來分表。

實(shí)際上,水平分表現(xiàn)在最流行的實(shí)現(xiàn)方式,是通過水平分庫來實(shí)現(xiàn)的。即剛才所說的10個(gè)表,分布在10個(gè)mysql數(shù)據(jù)庫上。這樣可以通過多個(gè)低配置主機(jī)整合起來,實(shí)現(xiàn)高性能。

最常見的解決方案是cobar,這個(gè)帖子介紹的比較完善,可以看看。


文章標(biāo)題:mysql行級別怎么實(shí)現(xiàn) mysql 行級權(quán)限
標(biāo)題路徑:http://weahome.cn/article/doddcdi.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部