大廠面試超高頻MySQL題目(含答案):基礎+索引+事務+鎖

MySQL基礎篇

公衆號:Java架構師聯盟,每日更新技術好文mysql

說一下 MySQL 執行一條查詢語句的內部執行過程?

  • 客戶端先經過鏈接器鏈接到 MySQL 服務器。面試

  • 鏈接器權限驗證經過以後,先查詢是否有查詢緩存,若是有緩存(以前執行過此語句)則直接返回緩存數據,若是沒有緩存則進入分析器。正則表達式

  • 分析器會對查詢語句進行語法分析和詞法分析,判斷 SQL 語法是否正確,若是查詢語法錯誤會直接返回給客戶端錯誤信息,若是語法正確則進入優化器。redis

  • 優化器是對查詢語句進行優化處理,例如一個表裏面有多個索引,優化器會判別哪一個索引性能更好。算法

  • 優化器執行完就進入執行器,執行器就開始執行語句進行查詢比對了,直到查詢到知足條件的全部數據,而後進行返回。sql

MySQL 提示「不存在此列」是執行到哪一個節點報出的?

此錯誤是執行到分析器階段報出的,由於 MySQL 會在分析器階段檢查 SQL 語句的正確性。數據庫

MySQL 查詢緩存的功能有何優缺點?

MySQL 查詢緩存功能是在鏈接器以後發生的,它的優勢是效率高,若是已經有緩存則會直接返回結果。 查詢緩存的缺點是失效太頻繁致使緩存命中率比較低,任何更新表操做都會清空查詢緩存,所以致使查詢緩存很是容易失效。數組

如何關閉 MySQL 的查詢緩存功能?

MySQL 查詢緩存默認是開啓的,配置 querycachetype 參數爲 DEMAND(按需使用)關閉查詢緩存,MySQL 8.0 以後直接刪除了查詢緩存的功能。緩存

MySQL 的經常使用引擎都有哪些?

MySQL 的經常使用引擎有 InnoDB、MyISAM、Memory 等,從 MySQL 5.5.5 版本開始 InnoDB 就成爲了默認的存儲引擎。安全

MySQL 能夠針對表級別設置數據庫引擎嗎?怎麼設置?

能夠針對不一樣的表設置不一樣的引擎。在 create table 語句中使用 engine=引擎名(好比Memory)來設置此表的存儲引擎。完整代碼以下:

create table student(
 id int primary key auto_increment,
 username varchar(120),
 age int
) ENGINE=Memory

經常使用的存儲引擎 InnoDB 和 MyISAM 有什麼區別?

InnoDB 和 MyISAM 最大的區別是 InnoDB 支持事務,而 MyISAM 不支持事務,它們主要區別以下:

  • InnoDB 支持崩潰後安全恢復,MyISAM 不支持崩潰後安全恢復;

  • InnoDB 支持行級鎖,MyISAM 不支持行級鎖,只支持到表鎖;

  • InnoDB 支持外鍵,MyISAM 不支持外鍵;

  • MyISAM 性能比 InnoDB 高;

  • MyISAM 支持 FULLTEXT 類型的全文索引,InnoDB 不支持 FULLTEXT 類型的全文索引,可是 InnoDB 可使用 sphinx 插件支持全文索引,而且效果更好;

  • InnoDB 主鍵查詢性能高於 MyISAM。

InnoDB 有哪些特性?

1)插入緩衝(insert buffer):對於非彙集索引的插入和更新,不是每一次直接插入索引頁中,而是首先判斷插入的非彙集索引頁是否在緩衝池中,若是在,則直接插入,不然,先放入一個插入緩衝區中。好似欺騙數據庫這個非彙集的索引已經插入到葉子節點了,而後再以必定的頻率執行插入緩衝和非彙集索引頁子節點的合併操做,這時一般能將多個插入合併到一個操做中,這就大大提升了對非彙集索引執行插入和修改操做的性能。

2)兩次寫(double write):兩次寫給 InnoDB 帶來的是可靠性,主要用來解決部分寫失敗(partial page write)。doublewrite 有兩部分組成,一部分是內存中的 doublewrite buffer ,大小爲 2M,另一部分就是物理磁盤上的共享表空間中連續的 128 個頁,即兩個區,大小一樣爲 2M。當緩衝池的做業刷新時,並不直接寫硬盤,而是經過 memcpy 函數將髒頁先拷貝到內存中的 doublewrite buffer,以後經過 doublewrite buffer 再分兩次寫,每次寫入 1M 到共享表空間的物理磁盤上,而後立刻調用 fsync 函數,同步磁盤。以下圖所示

大廠面試超高頻MySQL題目(含答案):基礎+索引+事務+鎖

 

3)自適應哈希索引(adaptive hash index):因爲 InnoDB 不支持 hash 索引,但在某些狀況下 hash 索引的效率很高,因而出現了 adaptive hash index 功能, InnoDB 存儲引擎會監控對錶上索引的查找,若是觀察到創建 hash 索引能夠提升性能的時候,則自動創建 hash 索引。

一張自增表中有三條數據,刪除了兩條數據以後重啓數據庫,再新增一條數據,此時這條數據的 ID 是幾?

若是這張表的引擎是 MyISAM,那麼 ID=4,若是是 InnoDB 那麼 ID=2(MySQL 8 以前的版本)。

MySQL 中什麼狀況會致使自增主鍵不能連續?

如下狀況會致使 MySQL 自增主鍵不能連續:

  • 惟一主鍵衝突會致使自增主鍵不連續;

  • 事務回滾也會致使自增主鍵不連續。

InnoDB 中自增主鍵能不能被持久化?

自增主鍵能不能被持久化,說的是 MySQL 重啓以後 InnoDB 能不能恢復重啓以前的自增列,InnoDB 在 8.0 以前是沒有持久化能力的,但 MySQL 8.0 以後就把自增主鍵保存到 redo log(一種日誌類型,下文會詳細講)中,當 MySQL 重啓以後就會從 redo log 日誌中恢復。

什麼是獨立表空間和共享表空間?它們的區別是什麼?

共享表空間:指的是數據庫的全部的表數據,索引文件所有放在一個文件中,默認這個共享表空間的文件路徑在 data 目錄下。 獨立表空間:每個表都將會生成以獨立的文件方式來進行存儲。 共享表空間和獨立表空間最大的區別是若是把表放再共享表空間,即便表刪除了空間也不會刪除,因此表依然很大,而獨立表空間若是刪除表就會清除空間。

如何設置獨立表空間?

獨立表空間是由參數 innodbfileper_table 控制的,把它設置成 ON 就是獨立表空間了,從 MySQL 5.6.6 版本以後,這個值就默認是 ON 了。

如何進行表空間收縮?

使用重建表的方式能夠收縮表空間,重建表有如下三種方式:

  • alter table t engine=InnoDB

  • optmize table t

  • truncate table t

說一下重建表的執行流程?

  • 創建一個臨時文件,掃描表 t 主鍵的全部數據頁;

  • 用數據頁中表 t 的記錄生成 B+ 樹,存儲到臨時文件中;

  • 生成臨時文件的過程當中,將全部對 t 的操做記錄在一個日誌文件(row log)中;

  • 臨時文件生成後,將日誌文件中的操做應用到臨時文件,獲得一個邏輯數據上與表 t相同的數據文件;

  • 用臨時文件替換表 t 的數據文件。

表的結構信息存在哪裏?

表結構定義佔有的存儲空間比較小,在 MySQL 8 以前,表結構的定義信息存在以 .frm 爲後綴的文件裏,在 MySQL 8 以後,則容許把表結構的定義信息存在系統數據表之中。

什麼是覆蓋索引?

覆蓋索引是指,索引上的信息足夠知足查詢請求,不須要再回到主鍵上去取數據。

若是把一個 InnoDB 表的主鍵刪掉,是否是就沒有主鍵,就沒辦法進行回表查詢了?

能夠回表查詢,若是把主鍵刪掉了,那麼 InnoDB 會本身生成一個長度爲 6 字節的 rowid 做爲主鍵。

執行一個 update 語句之後,我再去執行 hexdump 命令直接查看 ibd 文件內容,爲何沒有看到數據有改變呢?

多是由於 update 語句執行完成後,InnoDB 只保證寫完了 redo log、內存,可能還沒來得及將數據寫到磁盤。

內存表和臨時表有什麼區別?

  • 內存表,指的是使用 Memory 引擎的表,建表語法是 create table … engine=memory。這種表的數據都保存在內存裏,系統重啓的時候會被清空,可是表結構還在。除了這兩個特性看上去比較「奇怪」外,從其餘的特徵上看,它就是一個正常的表。

  • 而臨時表,可使用各類引擎類型 。若是是使用 InnoDB 引擎或者 MyISAM 引擎的臨時表,寫數據的時候是寫到磁盤上的。

併發事務會帶來哪些問題?

  • 髒讀

  • 修改丟失

  • 不可重複讀

  • 幻讀

什麼是髒讀和幻讀?

髒讀是一個事務在處理過程當中讀取了另一個事務未提交的數據;幻讀是指同一個事務內屢次查詢返回的結果集不同(好比增長了或者減小了行記錄)。

爲何會出現幻讀?幻讀會帶來什麼問題?

由於行鎖只能鎖定存在的行,針對新插入的操做沒有限定,因此就有可能產生幻讀。 幻讀帶來的問題以下:

  • 對行鎖語義的破壞;

  • 破壞了數據一致性。

如何避免幻讀?

使用間隙鎖的方式來避免出現幻讀。間隙鎖,是專門用於解決幻讀這種問題的鎖,它鎖的了行與行之間的間隙,可以阻塞新插入的操做 間隙鎖的引入也帶來了一些新的問題,好比:下降併發度,可能致使死鎖。

如何查看 MySQL 的空閒鏈接?

在 MySQL 的命令行中使用 show processlist; 查看全部鏈接,其中 Command 列顯示爲 Sleep 的表示空閒鏈接,以下圖所示:

大廠面試超高頻MySQL題目(含答案):基礎+索引+事務+鎖

 

MySQL 中的字符串類型都有哪些?

MySQL 的字符串類型和取值以下:

類型取值範圍CHAR(N)0~255VARCHAR(N)0~65536TINYBLOB0~255BLOB0~65535MEDUIMBLOB0~167772150LONGBLOB0~4294967295TINYTEXT0~255TEXT0~65535MEDIUMTEXT0~167772150LONGTEXT0~4294967295VARBINARY(N)0~N個字節的變長字節字符集BINARY(N)0~N個字節的定長字節字符集

VARCHAR 和 CHAR 的區別是什麼?分別適用的場景有哪些?

VARCHAR 和 CHAR 最大區別就是,VARCHAR 的長度是可變的,而 CHAR 是固定長度,CHAR 的取值範圍爲1-255,所以 VARCHAR 可能會形成存儲碎片。因爲它們的特性決定了 CHAR 比較適合長度較短的字段和固定長度的字段,如身份證號、手機號等,反之則適合使用 VARCHAR。

MySQL 存儲金額應該使用哪一種數據類型?爲何?

MySQL 存儲金額應該使用 decimal ,由於若是存儲其餘數據類型,好比 float 有致使小數點後數據丟失的風險。

limit 3,2 的含義是什麼?

去除前三條數據以後查詢兩條信息。

now() 和 current_date() 有什麼區別?

now() 返回當前時間包含日期和時分秒,current_date() 只返回當前時間,以下圖所示:

大廠面試超高頻MySQL題目(含答案):基礎+索引+事務+鎖

 

如何去重計算總條數?

使用 distinct 去重,使用 count 統計總條數,具體實現腳本以下:

select count(distinct f) from t

last*insert*id() 函數功能是什麼?有什麼特色?

lastinsertid() 用於查詢最後一次自增表的編號,它的特色是查詢時不須要不須要指定表名,使用 select last_insert_id() 便可查詢,由於不須要指定表名因此它始終以最後一條自增編號爲主,能夠被其它表的自增編號覆蓋。好比 A 表的最大編號是 10,lastinsertid() 查詢出來的值爲 10,這時 B 表插入了一條數據,它的最大編號爲 3,這個時候使用 lastinsertid() 查詢的值就是 3。

刪除表的數據有幾種方式?它們有什麼區別?

刪除數據有兩種方式:delete 和 truncate,它們的區別以下:

  • delete 能夠添加 where 條件刪除部分數據,truncate 不能添加 where 條件只能刪除整張表;

  • delete 的刪除信息會在 MySQL 的日誌中記錄,而 truncate 的刪除信息不被記錄在 MySQL 的日誌中,所以 detele 的信息能夠被找回而 truncate 的信息沒法被找回;

  • truncate 由於不記錄日誌因此執行效率比 delete 快。

delete 和 truncate 的使用腳本以下:

delete from t where username='redis'; truncate table t;

MySQL 中支持幾種模糊查詢?它們有什麼區別?

MySQL 中支持兩種模糊查詢:regexp 和 like,like 是對任意多字符匹配或任意單字符進行模糊匹配,而 regexp 則支持正則表達式的匹配方式,提供比 like 更多的匹配方式。 regexp 和 like 的使用示例以下: select * from person where uname like '%SQL%';> select from person where uname regexp '.SQL*.';

MySQL 支持枚舉嗎?如何實現?它的用途是什麼?

MySQL 支持枚舉,它的實現方式以下:

create table t(
 sex enum('boy','grid') default 'unknown'
);

枚舉的做用是預約義結果值,當插入數據不在枚舉值範圍內,則插入失敗,提示錯誤 Data truncated for column 'xxx' at row n 。

count(column) 和 count(*) 有什麼區別?

count(column) 和 count() 最大區別是統計結果可能不一致,count(column) 統計不會統計列值爲 null 的數據,而 count() 則會統計全部信息,因此最終的統計結果可能會不一樣。

如下關於 count 說法正確的是?

A. count 的查詢性能在各類存儲引擎下的性能都是同樣的。 B. count 在 MyISAM 比 InnoDB 的性能要低。 C. count 在 InnoDB 中是一行一行讀取,而後累計計數的。 D. count 在 InnoDB 中存儲了總條數,查詢的時候直接取出。

答:C

爲何 InnoDB 不把總條數記錄下來,查詢的時候直接返回呢?

由於 InnoDB 使用了事務實現,而事務的設計使用了多版本併發控制,即便是在同一時間進行查詢,獲得的結果也可能不相同,因此 InnoDB 不能把結果直接保存下來,由於這樣是不許確的。

可否使用 show table status 中的錶行數做爲表的總行數直接使用?爲何?

不能,由於 show table status 是經過採樣統計估算出來的,官方文檔說偏差可能在 40% 左右,因此 show table status 中的錶行數不能直接使用。

如下哪一個 SQL 的查詢性能最高?

A. select count(*) from t where time>1000 and time<4500 B. show table status where name='t' C. select count(id) from t where time>1000 and time<4500 D. select count(name) from t where time>1000 and time<4500

答:B 題目解析:由於 show table status 的錶行數是估算出來,而其餘的查詢由於添加了 where 條件,即便是 MyISAM 引擎也不能直接使用已經存儲的總條數,因此 show table status 的查詢性能最高。

InnoDB 和 MyISAM 執行 select count(*) from t,哪一個效率更高?爲何?

MyISAM 效率最高,由於 MyISAM 內部維護了一個計數器,直接返回總條數,而 InnoDB 要逐行統計。

在 MySQL 中有對 count(*) 作優化嗎?作了哪些優化?

count(*) 在不一樣的 MySQL 引擎中的實現方式是不相同的,在沒有 where 條件的狀況下:

  • MyISAM 引擎會把表的總行數存儲在磁盤上,所以在執行 count(*) 的時候會直接返回這個這個行數,執行效率很高;

  • InnoDB 引擎中 count(*) 就比較麻煩了,須要把數據一行一行的從引擎中讀出來,而後累計基數。

但即便這樣,在 InnoDB 中,MySQL 仍是作了優化的,咱們知道對於 count() 這樣的操做,遍歷任意索引樹獲得的結果,在邏輯上都是同樣的,所以,MySQL 優化器會找到最小的那顆索引樹來遍歷,這樣就能在保證邏輯正確的前提下,儘可能少掃描數據量,從而優化了 count() 的執行效率。

在 InnoDB 引擎中 count(*)、count(1)、count(主鍵)、count(字段) 哪一個性能最高?

count(字段)<count(主鍵 id)<count(1)≈count(*) 題目解析:

  • 對於 count(主鍵 id) 來講,InnoDB 引擎會遍歷整張表,把每一行的 id 值都取出來,返回給 server 層。server 層拿到 id 後,判斷是不可能爲空的,就按行累加。

  • 對於 count(1) 來講,InnoDB 引擎遍歷整張表,但不取值。server 層對於返回的每一行,放一個數字「1」進去,判斷是不可能爲空的,按行累加。

  • 對於 count(字段) 來講,若是這個「字段」是定義爲 not null 的話,一行行地從記錄裏面讀出這個字段,判斷不能爲 null,按行累加;若是這個「字段」定義容許爲 null,那麼執行的時候,判斷到有多是 null,還要把值取出來再判斷一下,不是 null 才累加。

  • 對於 count(*) 來講,並不會把所有字段取出來,而是專門作了優化,不取值,直接按行累加。

因此最後得出的結果是:count(字段)<count(主鍵 id)<count(1)≈count(*)。

MySQL 中內鏈接、左鏈接、右鏈接有什麼區別?

  • 內連(inner join)— 把匹配的關聯數據顯示出來;

  • 左鏈接(left join)— 把左邊的表所有顯示出來,右邊的表顯示出符合條件的數據;

  • 右鏈接(right join)— 把右邊的表所有顯示出來,左邊的表顯示出符合條件的數據;

什麼是視圖?如何建立視圖?

視圖是一種虛擬的表,具備和物理表相同的功能,能夠對視圖進行增、改、查操做。視圖一般是一個表或者多個表的行或列的子集。 視圖建立腳本以下:

create view vname as
select column_names
from table_name
where condition

視圖有哪些優勢?

  • 獲取數據更容易,相對於多表查詢來講;

  • 視圖可以對機密數據提供安全保護;

  • 視圖的修改不會影響基本表,提供了獨立的操做單元,比較輕量。

MySQL 中「視圖」的概念有幾個?分別表明什麼含義?

MySQL 中的「視圖」概念有兩個,它們分別是:

  • MySQL 中的普通視圖也是咱們最經常使用的 view,建立語法是 create view …,它的查詢和普通表同樣;

  • InnoDB 實現 MVCC(Multi-Version Concurrency Control)多版本併發控制時用到的一致性讀視圖,它沒有物理結構,做用是事務執行期間定於能夠看到的數據。

使用 delete 誤刪數據怎麼找回?

能夠用 Flashback 工具經過閃回把數據恢復回來。

Flashback 恢復數據的原理是什麼?

Flashback 恢復數據的原理是是修改 binlog 的內容,拿回原庫重放,從而實現數據找回。

MySQL索引篇

###什麼是索引? 索引是一種能幫助 MySQL 提升查詢效率的數據結構。

###索引分別有哪些優勢和缺點? 索引的優勢以下:

  • 快速訪問數據表中的特定信息,提升檢索速度。

  • 建立惟一性索引,保證數據表中每一行數據的惟一性。

  • 加速表與表之間的鏈接。

  • 使用分組和排序進行數據檢索時,能夠顯著減小查詢中分組和排序的時間。

索引的缺點:

  • 雖然提升了的查詢速度,但卻下降了更新表的速度,好比 update、insert,由於更新數據時,MySQL 不只要更新數據,還要更新索引文件;

  • 創建索引會佔用磁盤文件的索引文件。

使用索引注意事項:

  • 使用短索引,短索引不只能夠提升查詢速度,更能節省磁盤空間和 I/O 操做;

  • 索引列排序,MySQL 查詢只使用一個索引,所以若是 where 子句中已經使用了索引的話,那麼 order by 中的列是不會使用索引的,所以數據庫默認排序能夠符合要求的狀況下,不要進行排序操做;儘可能不要包含多個列的排序,若是須要最好給這些列建立複合索引;

  • like 語句操做,通常狀況下不鼓勵使用 like 操做,若是非使用不可, 注意 like "%aaa%" 不會使用索引,而- - like "aaa%"可使用索引;

  • 不要在列上進行運算;

  • 不適用 NOT IN 和 <> 操做。 ###如下 SQL 有什麼問題?該如何優化?

select * from t where f/2=100;

該 SQL 會致使引擎放棄索引而全表掃描,儘可能避免在索引列上計算。可改成:

select * from t where f=100*2;

###爲何 MySQL 官方建議使用自增主鍵做爲表的主鍵? 由於自增主鍵是連續的,在插入過程當中儘可能減小頁分裂,即便要進行頁分裂,也只會分裂不多一部分;而且自增主鍵也能減小數據的移動,每次插入都是插入到最後,因此自增主鍵做爲表的主鍵,對於表的操做來講性能是最高的。

###自增主鍵有哪些優缺點? 優勢:

  • 數據存儲空間很小;

  • 性能最好;

  • 減小頁分裂。 缺點:

  • 數據量過大,可能會超出自增加取值範圍;

  • 沒法知足分佈式存儲,分庫分表的狀況下沒法合併表;

  • 主鍵有自增規律,容易被破解;

綜上所述:是否須要使用自增主鍵,須要根據本身的業務場景來設計。若是是單表單庫,則優先考慮自增主鍵,若是是分佈式存儲,分庫分表,則須要考慮數據合併的業務場景來作數據庫設計方案。

###索引有幾種類型?分別如何建立? MySQL 的索引有兩種分類方式:邏輯分類和物理分類。 按照邏輯分類,索引可分爲:

  • 主鍵索引:一張表只能有一個主鍵索引,不容許重複、不容許爲 NULL;

  • 惟一索引:數據列不容許重複,容許爲 NULL 值,一張表可有多個惟一索引,可是一個惟一索引只能包含一列,好比身份證號碼、卡號等均可以做爲惟一索引;

  • 普通索引:一張表能夠建立多個普通索引,一個普通索引能夠包含多個字段,容許數據重複,容許 NULL 值插入;

  • 全文索引:讓搜索關鍵詞更高效的一種索引。

按照物理分類,索引可分爲:

  • 彙集索引:通常是表中的主鍵索引,若是表中沒有顯示指定主鍵,則會選擇表中的第一個不容許爲 NULL 的惟一索引,若是仍是沒有的話,就採用 Innodb 存儲引擎爲每行數據內置的 6 字節 ROWID 做爲彙集索引。每張表只有一個彙集索引,由於彙集索引的鍵值的邏輯順序決定了表中相應行的物理順序。彙集索引在精確查找和範圍查找方面有良好的性能表現(相比於普通索引和全表掃描),彙集索引就顯得彌足珍貴,彙集索引選擇仍是要慎重的(通常不會讓沒有語義的自增 id 充當彙集索引);

  • 非彙集索引:該索引中索引的邏輯順序與磁盤上行的物理存儲順序不一樣(非主鍵的那一列),一個表中能夠擁有多個非彙集索引。

各類索引的建立腳本以下:

-- 建立主鍵索引
alter table t add primary key add (`id`);
-- 建立惟一索引
alter table t add unique (`username`);
-- 建立普通索引
alter table t add index index_name (`username`);
-- 建立全文索引
alter table t add fulltext (`username`);

###主索引和惟一索引有什麼區別?

  • 主索引不能重複且不能爲空,惟一索引不能重複,但能夠爲空;

  • 一張表只能有一個主索引,但能夠有多個惟一索引;

  • 主索引的查詢性能要高於惟一索引。 ###在 InnDB 中主鍵索引爲何比普通索引的查詢性能高? 由於普通索引的查詢會多執行一次檢索操做。好比主鍵查詢 select * from t where id=10 只須要搜索 id 的這棵 B+ 樹,而普通索引查詢 select * from t where f=3 會先查詢 f 索引樹,獲得 id 的值以後再去搜索 id 的 B+ 樹,由於多執行了一次檢索,因此執行效率就比主鍵索引要低。

###什麼叫回表查詢? 普通索引查詢到主鍵索引後,回到主鍵索引樹搜索的過程,咱們稱爲回表查詢。

參考SQL:

mysql> create table T(
id int primary key, 
k int not null, 
name varchar(16),
index (k))engine=InnoDB;

若是語句是 select * from T where ID=500,即主鍵查詢方式,則只須要檢索主鍵 ID 字段。

mysql>  select * from T where ID=500;
+-----+---+-------+
| id  | k | name  |
+-----+---+-------+
| 500 | 5 | name5 |
+-----+---+-------+

若是語句是 select * from T where k=5,即普通索引查詢方式,則須要先搜索 k 索引樹,獲得 ID 的值爲 500,再到 ID 索引樹搜索一次,這個過程稱爲回表查詢。

mysql> select * from T where k=5;
+-----+---+-------+
| id  | k | name  |
+-----+---+-------+
| 500 | 5 | name5 |
+-----+---+-------+

也就是說,基於非主鍵索引的查詢須要多掃描一棵索引樹。所以,咱們在應用中應該儘可能使用主鍵查詢。

###如何查詢一張表的全部索引? SHOW INDEX FROM T 查詢表 T 全部索引。

###MySQL 最多能夠建立多少個索引列? MySQL 中最多能夠建立 16 個索引列。

###如下 like 查詢會使用索引的是哪個選項?爲何? A.like '%A%' B.like '%A' C.like 'A%' D.以上都不是 答:C 題目解析:like 查詢要走索引,查詢字符不能以通配符(%)開始。

###如何讓 like %abc 走索引查詢? 咱們知道若是要讓 like 查詢要走索引,查詢字符不能以通配符(%)開始,若是要讓 like %abc 也走索引,可使用 REVERSE() 函數來建立一個函數索引,查詢腳本以下:

select * from t where reverse(f) like reverse('%abc');

###MySQL 聯合索引應該注意什麼? 聯合索引又叫複合索引,MySQL 中的聯合索引,遵循最左匹配原則,好比,聯合索引爲 key(a,b,c),則能觸發索引的搜索組合是 a|ab|abc 這三種查詢。

###聯合索引的做用是什麼? 聯合索引的做用以下:

  • 用於多字段查詢,好比,建了一個 key(a,b,c) 的聯合索引,那麼實際等於建了key(a)、key(a,b)、key(a,b,c)等三個索引,咱們知道,每多一個索引,就會多一些寫操做和佔用磁盤空間的開銷,尤爲是對大數據量的表來講,這能夠減小一部分沒必要要的開銷;

  • 覆蓋索引,好比,對於聯合索引 key(a,b,c) 來講,若是使用 SQL:select a,b,c from table where a=1 and b = 1 ,就能夠直接經過遍歷索引取得數據,而無需回表查詢,這就減小了隨機的 IO 操做,減小隨機的 IO 操做,能夠有效的提高數據庫查詢的性能,是很是重要的數據庫優化手段之一;

  • 索引列越多,經過索引篩選出的數據越少。 ###什麼是最左匹配原則?它的生效原則有哪些? 最左匹配原則也叫最左前綴原則,是 MySQL 中的一個重要原則,說的是索引以最左邊的爲起點任何連續的索引都能匹配上,當遇到範圍查詢(>、<、between、like)就會中止匹配。 生效原則來看如下示例,好比表中有一個聯合索引字段 index(a,b,c):

  • where a=1 只使用了索引 a;

  • where a=1 and b=2 只使用了索引 a,b;

  • where a=1 and b=2 and c=3 使用a,b,c;

  • where b=1 or where c=1 不使用索引;

  • where a=1 and c=3 只使用了索引 a;

  • where a=3 and b like 'xx%' and c=3 只使用了索引 a,b。 ###列值爲 NULL 時,查詢會使用到索引嗎? 在 MySQL 5.6 以上的 InnoDB 存儲引擎會正常觸發索引。但爲了兼容低版本的 MySQL 和兼容其餘數據庫存儲引擎,不建議使用 NULL 值來存儲和查詢數據,建議設置列爲 NOT NULL,並設置一個默認值,好比 0 和空字符串等,若是是 datetime 類型,能夠設置成 1970-01-01 00:00:00 這樣的特殊值。

###如下語句會走索引麼?

select * from t where year(date)>2018;

不會,由於在索引列上涉及到了運算。

###可否給手機號的前 6 位建立索引?如何建立? 能夠,建立方式有兩種:

alter table t add index index_phone(phone(6));
create index index_phone on t(phone(6));

###什麼是前綴索引? 前綴索引也叫局部索引,好比給身份證的前 10 位添加索引,相似這種給某列部分信息添加索引的方式叫作前綴索引。

###爲何要用前綴索引? 前綴索引能有效減少索引文件的大小,讓每一個索引頁能夠保存更多的索引值,從而提升了索引查詢的速度。但前綴索引也有它的缺點,不能在 order by 或者 group by 中觸發前綴索引,也不能把它們用於覆蓋索引。

###什麼狀況下適合使用前綴索引? 當字符串自己可能比較長,並且前幾個字符就開始不相同,適合使用前綴索引;相反狀況下不適合使用前綴索引,好比,整個字段的長度爲 20,索引選擇性爲 0.9,而咱們對前 10 個字符創建前綴索引其選擇性也只有 0.5,那麼咱們須要繼續加大前綴字符的長度,可是這個時候前綴索引的優點已經不明顯,就沒有建立前綴索引的必要了。

###什麼是業? 頁是計算機管理存儲器的邏輯塊,硬件及操做系統每每將主存和磁盤存儲區分割爲連續的大小相等的塊,每一個存儲塊稱爲一頁。主存和磁盤以頁爲單位交換數據。數據庫系統的設計者巧妙利用了磁盤預讀原理,將一個節點的大小設爲等於一個頁,這樣每一個節點只須要一次磁盤 IO 就能夠徹底載入。

###索引的常見存儲算法有哪些?

  • 哈希存儲法:以 key、value 方式存儲,把值存入數組中使用哈希值確認數據的位置,若是發生哈希衝突,使用鏈表存儲數據;

  • 有序數組存儲法:按順序存儲,優勢是可使用二分法快速找到數據,缺點是更新效率,適合靜態數據存儲;

  • 搜索樹:以樹的方式進行存儲,查詢性能好,更新速度快。 ###InnoDB 爲何要使用 B+ 樹,而不是 B 樹、Hash、紅黑樹或二叉樹? 由於 B 樹、Hash、紅黑樹或二叉樹存在如下問題:

  • B 樹:無論葉子節點仍是非葉子節點,都會保存數據,這樣致使在非葉子節點中能保存的指針數量變少(有些資料也稱爲扇出),指針少的狀況下要保存大量數據,只能增長樹的高度,致使IO操做變多,查詢性能變低;

  • Hash:雖然能夠快速定位,可是沒有順序,IO 複雜度高;

  • 二叉樹:樹的高度不均勻,不能自平衡,查找效率跟數據有關(樹的高度),而且 IO 代價高;

  • 紅黑樹:樹的高度隨着數據量增長而增長,IO 代價高。 ###爲何 InnoDB 要使用 B+ 誰來存儲索引? B+Tree 中的 B 是 Balance,是平衡的意思,它在經典 B Tree 的基礎上進行了優化,增長了順序訪問指針,在B+Tree 的每一個葉子節點增長一個指向相鄰葉子節點的指針,就造成了帶有順序訪問指針的 B+Tree,這樣就提升了區間訪問性能:若是要查詢 key 爲從 18 到 49 的全部數據記錄,當找到 18 後,只需順着節點和指針順序遍歷就能夠一次性訪問到全部數據節點,極大提到了區間查詢效率(無需返回上層父節點重複遍歷查找減小 IO 操做)。

索引自己也很大,不可能所有存儲在內存中,所以索引每每以索引文件的形式存儲的磁盤上,這樣的話,索引查找過程當中就要產生磁盤 IO 消耗,相對於內存存取,IO 存取的消耗要高几個數量級,因此索引的結構組織要儘可能減小查找過程當中磁盤 IO 的存取次數,從而提高索引效率。 綜合所述,InnDB 只有採起 B+ 樹的數據結構存儲索引,才能提供數據庫總體的操做性能。

###惟一索引和普通索引哪一個性能更好?

  • 對於查詢操做來講:普通索引和惟一索引的性能相近,都是從索引樹中進行查詢;

  • 對於更新操做來講:惟一索引要比普通索引執行的慢,由於惟一索引須要先將數據讀取到內存中,再在內存中進行數據的惟一效驗,因此執行起來要比普通索引更慢。 ###優化器選擇查詢索引的影響因素有哪些? 優化器的目的是使用最小的代價選擇最優的執行方案,影響優化器選擇索引的因素以下:

  • 掃描行數,掃描的行數越少,執行代價就越少,執行效率就會越高;

  • 是否使用了臨時表;

  • 是否排序。 ###MySQL 是如何判斷索引掃描行數的多少? MySQL 的掃描行數是經過索引統計列(cardinality)大體獲得而且判斷的,而索引統計列(cardinality)能夠經過查詢命令 show index 獲得,索引掃描行數的多少就是經過這個值進行判斷的。

###MySQL 是如何獲得索引基數的?它準確嗎? MySQL 的索引基數並不許確,由於 MySQL 的索引基數是經過採樣統計獲得的,好比 InnoDb 默認會有 N 個數據頁,採樣統計會統計這些頁面上的不一樣值獲得一個平均值,而後除以這個索引的頁面數就獲得了這個索引基數。

###MySQL 如何指定查詢的索引? 在 MySQL 中可使用 force index 強行選擇一個索引,具體查詢語句以下:

select * from t force index(index_t)

###在 MySQL 中指定了查詢索引,爲何沒有生效? 咱們知道在 MySQL 中使用 force index 能夠指定查詢的索引,但並非必定會生效,緣由是 MySQL 會根據優化器本身選擇索引,若是 force index 指定的索引出如今候選索引上,這個時候 MySQL 不會在判斷掃描的行數的多少直接使用指定的索引,若是沒在候選索引中,即便 force index 指定了索引也是不會生效的。

###如下 or 查詢有什麼問題嗎?該如何優化?

select * from t where num=10 or num=20;

答:若是使用 or 查詢會使 MySQL 放棄索引而全表掃描,能夠改成:

select * from t where num=10 union select * from t where num=20;

###如下查詢要如何優化? 表中包含索引:

KEY mid (mid)
KEY begintime (begintime)
KEY dg (day,group)

使用如下 SQL 進行查詢:

select f from t where day='2010-12-31' and group=18 and begintime<'2019-12-31 12:14:28' order by begintime limit 1;

答:此查詢理論上是使用 dg 索引效率更高,經過 explain 能夠對比查詢掃描次數。因爲使用了 order by begintime 則使查詢放棄了 dg 索引,而使用 begintime 索引,從側面印證 order by 關鍵字會影響查詢使用索引,這時可使查詢強制使用索引,改成如下SQL:

select f from t use index(dg) where day='2010-12-31' and group=18 and begintime< '2019-12-31 12:14:28' order by begintime limit 1;

###MySQL 會錯選索引嗎? MySQL 會錯選索引,好比 k 索引的速度更快,可是 MySQL 並無使用而是採用了 v 索引,這種就叫錯選索引,由於索引選擇是 MySQL 的服務層的優化器來自動選擇的,但它在複雜狀況下也和人寫程序同樣出現缺陷。

###如何解決 MySQL 錯選索引的問題?

  • 刪除錯選的索引,只留下對的索引;

  • 使用 force index 指定索引;

  • 修改 SQL 查詢語句引導 MySQL 使用咱們指望的索引,好比把 order by b limit 1 改成 order by b,a limit 1 語義是相同的,但 MySQL 查詢的時候會考慮使用 a 鍵上的索引。 ###如何優化身份證的索引? 在中國由於前 6 位表明的是地區,因此不少人的前六位都是相同的,若是咱們使用前綴索引爲 6 位的話,性能提高也並非很明顯,但若是設置的位數過長,那麼佔用的磁盤空間也越大,數據頁能放下的索引值就越少,搜索效率也越低。針對這種狀況優化方案有如下兩種:

  • 使用身份證倒序存儲,這樣設置前六位的意義就很大了;

  • 使用 hash 值,新建立一個字段用於存儲身份證的 hash 值。

MySQL事務篇

事務是什麼?

事務是一系列的數據庫操做,是數據庫應用的基本單位。MySQL 事務主要用於處理操做量大,複雜度高的數據。

事務有哪些特性?

在 MySQL 中只有 InnDB 引擎支持事務,它的四個特性以下:

  • 原子性(Atomic):要麼所有執行,要麼所有不執行;

  • 一致性(Consistency):事務的執行使得數據庫從一種正確狀態轉化爲另外一種正確狀態;

  • 隔離性(Isolation):在事務正確提交以前,不容許把該事務對數據的任何改變提供給其餘事務;

  • 持久性(Durability):事務提交後,其結果永久保存在數據庫中。

MySQL 中有幾種事務隔離級別?分別是什麼?

MySQL 中有四種事務隔離級別,它們分別是:

  • read uncommited:未提交讀,讀到未提交數據;

  • read committed:讀已提交,也叫不可重複讀,兩次讀取到的數據不一致;

  • repetable read:可重複讀;

  • serializable:串行化,讀寫數據都會鎖住整張表,數據操做不會出錯,但併發性能極低,開發中不多用到。

MySQL 默認使用 REPEATABLE-READ 的事務隔離級別。

幻讀和不可重複讀的區別?

  • 不可重複讀的重點是修改:在同一事務中,一樣的條件,第一次讀的數據和第二次讀的數據不同。(由於中間有其餘事務提交了修改)。

  • 幻讀的重點在於新增或者刪除:在同一事務中,一樣的條件,,第一次和第二次讀出來的記錄數不同。(由於中間有其餘事務提交了插入/刪除)。

併發事務通常有哪些問題?

  • 更新丟失(Lost Update):當兩個或多個事務選擇同一行,而後基於最初選定的值更新該行時,因爲每一個事務都不知道其餘事務的存在,就會發生丟失更新問題,最後的更新覆蓋了由其餘事務所作的更新。例如,兩個編輯人員製做了同一文檔的電子副本,每一個編輯人員獨立地更改其副本,而後保存更改後的副本,這樣就覆蓋了原始文檔。 最後保存其更改副本的編輯人員覆蓋另外一個編輯人員所作的更改,若是在前一個編輯人員完成並提交事務以前,另外一個編輯人員不能訪問同一文件,則可避免此問題。

  • 髒讀(Dirty Reads):一個事務正在對一條記錄作修改,在這個事務完成並提交前, 這條記錄的數據就處於不一致狀態; 這時, 另外一個事務也來讀取同一條記錄,若是不加控制,第二個事務讀取了這些髒數據,並據此作進一步的處理,就會產生未提交的數據依賴關係,這種現象被形象地叫作髒讀。

  • 不可重複讀(Non-Repeatable Reads):一個事務在讀取某些數據後的某個時間,再次讀取之前讀過的數據,卻發現其讀出的數據已經發生了改變、或某些記錄已經被刪除了!這種現象就叫作「不可重複讀」 。

  • 幻讀(Phantom Reads): 一個事務按相同的查詢條件從新讀取之前檢索過的數據,卻發現其餘事務插入了知足其查詢條件的新數據,這種現象就稱爲「幻讀」 。

併發事務有什麼什麼問題?應該如何解決?

併發事務可能形成:髒讀、不可重複讀和幻讀等問題 ,這些問題其實都是數據庫讀一致性問題,必須由數據庫提供必定的事務隔離機制來解決,解決方案以下:

  • 加鎖:在讀取數據前,對其加鎖,阻止其餘事務對數據進行修改。

  • 提供數據多版本併發控制(MultiVersion Concurrency Control,簡稱 MVCC 或 MCC),也稱爲多版本數據庫:不用加任何鎖, 經過必定機制生成一個數據請求時間點的一致性數據快照(Snapshot), 並用這個快照來提供必定級別 (語句級或事務級) 的一致性讀取,從用戶的角度來看,好象是數據庫能夠提供同一數據的多個版本。

什麼是 MVCC?

MVCC 全稱是多版本併發控制系統,InnoDB 和 Falcon 存儲引擎經過多版本併發控制(MVCC,Multiversion Concurrency Control)機制解決幻讀問題。

MVCC 是怎麼工做的?

InnoDB 的 MVCC 是經過在每行記錄後面保存兩個隱藏的列來實現,這兩個列一個保存了行的建立時間,一個保存行的過時時間(刪除時間)。固然存儲的並非真實的時間而是系統版本號(system version number)。每開始一個新的事務,系統版本號都會自動新增,事務開始時刻的系統版本號會做爲事務的版本號,用來查詢到每行記錄的版本號進行比較。

REPEATABLE READ(可重讀)隔離級別下 MVCC 如何工做?

  • SELECT:InnoDB 會根據如下條件檢查每一行記錄:第一,InnoDB 只查找版本早於當前事務版本的數據行,這樣能夠確保事務讀取的行要麼是在開始事務以前已經存在要麼是事務自身插入或者修改過的。第二,行的刪除版本號要麼未定義,要麼大於當前事務版本號,這樣能夠確保事務讀取到的行在事務開始以前未被刪除。

  • INSERT:InnoDB 爲新插入的每一行保存當前系統版本號做爲行版本號。

  • DELETE:InnoDB 爲刪除的每一行保存當前系統版本號做爲行刪除標識。

  • UPDATE:InnoDB 爲插入的一行新紀錄保存當前系統版本號做爲行版本號,同時保存當前系統版本號到原來的行做爲刪除標識保存這兩個版本號,使大多數操做都不用加鎖。它不足之處是每行記錄都須要額外的存儲空間,須要作更多的行檢查工做和一些額外的維護工做。

MySQL 事務實現原理是什麼?

事務的實現是基於數據庫的存儲引擎,不一樣的存儲引擎對事務的支持程度不同。MySQL 中支持事務的存儲引擎有InnoDB 和 NDB。 InnoDB 是高版本 MySQL 的默認的存儲引擎,所以就以 InnoDB 的事務實現爲例,InnoDB 是經過多版本併發控制(MVCC,Multiversion Concurrency Control )解決不可重複讀問題,加上間隙鎖(也就是併發控制)解決幻讀問題。所以 InnoDB 的 RR 隔離級別其實實現了串行化級別的效果,並且保留了比較好的併發性能。事務的隔離性是經過鎖實現,而事務的原子性、一致性和持久性則是經過事務日誌實現。

如何設置 MySQL 的事務隔離級別?

MySQL 事務隔離級別 MySQL.cnf 文件裏設置的(默認目錄 /etc/my.cnf),在文件的文末添加配置:

transaction-isolation = REPEATABLE-READ

可用的配置值:READ-UNCOMMITTED、READ-COMMITTED、REPEATABLE-READ、SERIALIZABLE。

InnoDB 默認的事務隔離級別是什麼?如何修改?

InnoDB 默認的事務隔離是 repetable read(可重複讀);能夠經過 set 做用域 transaction isolation level 事務隔離級別 來修改事務的隔離級別,好比:

MySQL> set global transaction isolation level read committed; // 設置全局事務隔離級別爲 read committed MySQL> set session transaction isolation level read committed; // 設置當前會話事務隔離級別爲 read committed

InnoDB 如何開啓手動提交事務?

InnoDB 默認是自動提交事務的,每一次 SQL 操做(非 select 操做)都會自動提交一個事務,若是要手動開啓事務須要設置 set autocommit=0 禁止自動提交事務,至關於開啓手動提交事務。

在 InnoDB 中設置了 autocommit=0,添加一條信息以後沒有手動執行提交操做,請問這條信息能夠被查到嗎?

autocommit=0 表示禁止自動事務提交,在添加操做以後沒有進行手動提交,默認狀況下其餘鏈接客戶端是查詢不到此條新增數據的。

如何手動操做事務?

使用 begin 開啓事務;rollback 回滾事務;commit 提交事務。具體使用示例以下:

begin;
insert person(uname,age) values('laowang',18);
rollback;
commit;

MySQL鎖片

什麼是鎖?MySQL 中提供了幾類鎖?

鎖是實現數據庫併發控制的重要手段,能夠保證數據庫在多人同時操做時可以正常運行。MySQL 提供了全局鎖、行級鎖、表級鎖。其中 InnoDB 支持表級鎖和行級鎖,MyISAM 只支持表級鎖。

什麼是死鎖?

是指兩個或兩個以上的進程在執行過程當中,因爭奪資源而形成的一種互相等待的現象,若無外力做用,它們都將沒法推動下去。此時稱系統處於死鎖狀態或系統產生了死鎖,這些永遠在互相等待的過程稱爲死鎖。

死鎖是指兩個或兩個以上的進程在執行過程當中,因爭奪資源而形成的一種互相等待的現象,若無外力做用,它們都將沒法推動下去。此時稱系統處於死鎖狀態或系統產生了死鎖,這些永遠在互相等待的過程稱爲死鎖。

常見的死鎖案例有哪些?

  • 將投資的錢拆封幾份借給借款人,這時處理業務邏輯就要把若干個借款人一塊兒鎖住 select * from xxx where id in (xx,xx,xx) for update。

  • 批量入庫,存在則更新,不存在則插入。解決方法 insert into tab(xx,xx) on duplicate key update xx='xx'。

如何處理死鎖?

對待死鎖常見的兩種策略:

  • 經過 innodblockwait_timeout 來設置超時時間,一直等待直到超時;

  • 發起死鎖檢測,發現死鎖以後,主動回滾死鎖中的某一個事務,讓其它事務繼續執行。

如何查看死鎖?

  • 使用命令 show engine innodb status 查看最近的一次死鎖。

  • InnoDB Lock Monitor 打開鎖監控,每 15s 輸出一第二天志。使用完畢後建議關閉,不然會影響數據庫性能。

如何避免死鎖?

  • 爲了在單個 InnoDB 表上執行多個併發寫入操做時避免死鎖,能夠在事務開始時經過爲預期要修改的每一個元祖(行)使用 SELECT … FOR UPDATE 語句來獲取必要的鎖,即便這些行的更改語句是在以後才執行的。

  • 在事務中,若是要更新記錄,應該直接申請足夠級別的鎖,即排他鎖,而不該先申請共享鎖、更新時再申請排他鎖,由於這時候當用戶再申請排他鎖時,其餘事務可能又已經得到了相同記錄的共享鎖,從而形成鎖衝突,甚至死鎖

  • 若是事務須要修改或鎖定多個表,則應在每一個事務中以相同的順序使用加鎖語句。在應用中,若是不一樣的程序會併發存取多個表,應儘可能約定以相同的順序來訪問表,這樣能夠大大下降產生死鎖的機會

  • 經過 SELECT … LOCK IN SHARE MODE 獲取行的讀鎖後,若是當前事務再須要對該記錄進行更新操做,則頗有可能形成死鎖。

  • 改變事務隔離級別。

InnoDB 默認是如何對待死鎖的?

InnoDB 默認是使用設置死鎖時間來讓死鎖超時的策略,默認 innodblockwait_timeout 設置的時長是 50s。

如何開啓死鎖檢測?

設置 innodbdeadlockdetect 設置爲 on 能夠主動檢測死鎖,在 Innodb 中這個值默認就是 on 開啓的狀態。

什麼是全局鎖?它的應用場景有哪些?

全局鎖就是對整個數據庫實例加鎖,它的典型使用場景就是作全庫邏輯備份。 這個命令可使整個庫處於只讀狀態。使用該命令以後,數據更新語句、數據定義語句、更新類事務的提交語句等操做都會被阻塞。

什麼是共享鎖?

共享鎖又稱讀鎖 (read lock),是讀取操做建立的鎖。其餘用戶能夠併發讀取數據,但任何事務都不能對數據進行修改(獲取數據上的排他鎖),直到已釋放全部共享鎖。當若是事務對讀鎖進行修改操做,極可能會形成死鎖。

什麼是排它鎖?

排他鎖 exclusive lock(也叫 writer lock)又稱寫鎖。

若某個事物對某一行加上了排他鎖,只能這個事務對其進行讀寫,在此事務結束以前,其餘事務不能對其進行加任何鎖,其餘進程能夠讀取,不能進行寫操做,需等待其釋放。

排它鎖是悲觀鎖的一種實現,在上面悲觀鎖也介紹過。

若事務 1 對數據對象 A 加上 X 鎖,事務 1 能夠讀 A 也能夠修改 A,其餘事務不能再對 A 加任何鎖,直到事物 1 釋放 A 上的鎖。這保證了其餘事務在事物 1 釋放 A 上的鎖以前不能再讀取和修改 A。排它鎖會阻塞全部的排它鎖和共享鎖。

使用全局鎖會致使什麼問題?

若是在主庫備份,在備份期間不能更新,業務停擺,因此更新業務會處於等待狀態。

若是在從庫備份,在備份期間不能執行主庫同步的 binlog,致使主從延遲。

如何處理邏輯備份時,整個數據庫不能插入的狀況?

若是使用全局鎖進行邏輯備份就會讓整個庫成爲只讀狀態,幸虧官方推出了一個邏輯備份工具 MySQLdump 來解決了這個問題,只須要在使用 MySQLdump 時,使用參數 -single-transaction 就會在導入數據以前啓動一個事務來保證數據的一致性,而且這個過程是支持數據更新操做的。

如何設置數據庫爲全局只讀鎖?

使用命令 flush tables with read lock(簡稱 FTWRL)就能夠實現設置數據庫爲全局只讀鎖。

除了 FTWRL 能夠設置數據庫只讀外,還有什麼別的方法?

除了使用 FTWRL 外,還可使用命令 set global readonly=true 設置數據庫爲只讀。

FTWRL 和 set global readonly=true 有什麼區別?

FTWRL 和 set global readonly=true 都是設置整個數據庫爲只讀狀態,但他們最大的區別就是,當執行 FTWRL 的客戶端斷開以後,整個數據庫會取消只讀,而 set global readonly=true 會一直讓數據處於只讀狀態。

如何實現表鎖?

MySQL 裏標記鎖有兩種:表級鎖、元數據鎖(meta data lock)簡稱 MDL。表鎖的語法是 lock tables t read/write。

能夠用 unlock tables 主動釋放鎖,也能夠在客戶端斷開的時候自動釋放。lock tables 語法除了會限制別的線程的讀寫外,也限定了本線程接下來的操做對象。

對於 InnoDB 這種支持行鎖的引擎,通常不使用 lock tables 命令來控制併發,畢竟鎖住整個表的影響面仍是太大。

MDL:不須要顯式使用,在訪問一個表的時候會被自動加上。

MDL 的做用:保證讀寫的正確性。

在對一個表作增刪改查操做的時候,加 MDL 讀鎖;當要對錶作結構變動操做的時候,加 MDL 寫鎖。

讀鎖之間不互斥,讀寫鎖之間,寫鎖之間是互斥的,用來保證變動表結構操做的安全性。

MDL 會直到事務提交纔會釋放,在作表結構變動的時候,必定要當心不要致使鎖住線上查詢和更新。

悲觀鎖和樂觀鎖有什麼區別?

顧名思義,就是很悲觀,每次去拿數據的時候都認爲別人會修改,因此每次在拿數據的時候都會上鎖,這樣別人想拿這個數據就會 block 直到它拿到鎖。正由於如此,悲觀鎖須要耗費較多的時間,另外與樂觀鎖相對應的,悲觀鎖是由數據庫本身實現了的,要用的時候,咱們直接調用數據庫的相關語句就能夠了。

說到這裏,由悲觀鎖涉及到的另外兩個鎖概念就出來了,它們就是共享鎖與排它鎖。共享鎖和排它鎖是悲觀鎖的不一樣的實現,它倆都屬於悲觀鎖的範疇。

樂觀鎖是用數據版本(Version)記錄機制實現,這是樂觀鎖最經常使用的一種實現方式。何謂數據版本?即爲數據增長一個版本標識,通常是經過爲數據庫表增長一個數字類型的 version 字段來實現。當讀取數據時,將 version 字段的值一同讀出,數據每更新一次,對此 version 值加 1。當咱們提交更新的時候,判斷數據庫表對應記錄的當前版本信息與第一次取出來的version值進行比對,若是數據庫表當前版本號與第一次取出來的 version 值相等,則予以更新,不然認爲是過時數據。

好比: 一、數據庫表三個字段,分別是id、value、version select id,value,version from t where id=#{id} 二、每次更新表中的value字段時,爲了防止發生衝突,須要這樣操做

update t
set value=2,version=version+1
where id=#{id} and version=#{version}

樂觀鎖有什麼優勢和缺點?

由於沒有加鎖因此樂觀鎖的優勢就是執行性能高。它的缺點就是有可能產生 ABA 的問題,ABA 問題指的是有一個變量 V 初次讀取的時候是 A 值,而且在準備賦值的時候檢查到它仍然是 A 值,會誤覺得沒有被修改會正常的執行修改操做,實際上這段時間它的值可能被改了其餘值,以後又改回爲 A 值,這個問題被稱爲 ABA 問題。

InnoDB 存儲引擎有幾種鎖算法?

  • Record Lock — 單個行記錄上的鎖;

  • Gap Lock — 間隙鎖,鎖定一個範圍,不包括記錄自己;

  • Next-Key Lock — 鎖定一個範圍,包括記錄自己。

InnoDB 如何實現行鎖?

行級鎖是 MySQL 中粒度最小的一種鎖,他能大大減小數據庫操做的衝突。

INNODB 的行級鎖有共享鎖(S LOCK)和排他鎖(X LOCK)兩種。共享鎖容許事物讀一行記錄,不容許任何線程對該行記錄進行修改。排他鎖容許當前事物刪除或更新一行記錄,其餘線程不能操做該記錄。

共享鎖:SELECT … LOCK IN SHARE MODE,MySQL 會對查詢結果集中每行都添加共享鎖,前提是當前線程沒有對該結果集中的任何行使用排他鎖,不然申請會阻塞。

排他鎖:select * from t where id=1 for update,其中 id 字段必須有索引,MySQL 會對查詢結果集中每行都添加排他鎖,在事物操做中,任何對記錄的更新與刪除操做會自動加上排他鎖。前提是當前沒有線程對該結果集中的任何行使用排他鎖或共享鎖,不然申請會阻塞。

優化鎖方面你有什麼建議?

  • 儘可能使用較低的隔離級別。

  • 精心設計索引, 並儘可能使用索引訪問數據, 使加鎖更精確, 從而減小鎖衝突的機會。

  • 選擇合理的事務大小,小事務發生鎖衝突的概率也更小。

  • 給記錄集顯示加鎖時,最好一次性請求足夠級別的鎖。好比要修改數據的話,最好直接申請排他鎖,而不是先申請共享鎖,修改時再請求排他鎖,這樣容易產生死鎖。

  • 不一樣的程序訪問一組表時,應儘可能約定以相同的順序訪問各表,對一個表而言,儘量以固定的順序存取表中的行。這樣能夠大大減小死鎖的機會。

  • 儘可能用相等條件訪問數據,這樣能夠避免間隙鎖對併發插入的影響。

  • 不要申請超過實際須要的鎖級別。

  • 除非必須,查詢時不要顯示加鎖。 MySQL 的 MVCC 能夠實現事務中的查詢不用加鎖,優化事務性能;MVCC 只在 COMMITTED READ(讀提交)和 REPEATABLE READ(可重複讀)兩種隔離級別下工做。

  • 對於一些特定的事務,可使用表鎖來提升處理速度或減小死鎖的可能。

相關文章
相關標籤/搜索