您好,登錄后才能下訂單哦!
本篇內容介紹了“高頻MySQL的題目有哪些”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
客戶端先通過連接器連接到 MySQL 服務器。
連接器權限驗證通過之后,先查詢是否有查詢緩存,如果有緩存(之前執(zhí)行過此語句)則直接返回緩存數(shù)據,如果沒有緩存則進入分析器。
分析器會對查詢語句進行語法分析和詞法分析,判斷 SQL 語法是否正確,如果查詢語法錯誤會直接返回給客戶端錯誤信息,如果語法正確則進入優(yōu)化器。
優(yōu)化器是對查詢語句進行優(yōu)化處理,例如一個表里面有多個索引,優(yōu)化器會判別哪個索引性能更好。
優(yōu)化器執(zhí)行完就進入執(zhí)行器,執(zhí)行器就開始執(zhí)行語句進行查詢比對了,直到查詢到滿足條件的所有數(shù)據,然后進行返回。
此錯誤是執(zhí)行到分析器階段報出的,因為 MySQL 會在分析器階段檢查 SQL 語句的正確性。
MySQL 查詢緩存功能是在連接器之后發(fā)生的,它的優(yōu)點是效率高,如果已經有緩存則會直接返回結果。 查詢緩存的缺點是失效太頻繁導致緩存命中率比較低,任何更新表操作都會清空查詢緩存,因此導致查詢緩存非常容易失效。
MySQL 查詢緩存默認是開啟的,配置 querycachetype 參數(shù)為 DEMAND(按需使用)關閉查詢緩存,MySQL 8.0 之后直接刪除了查詢緩存的功能。
MySQL 的常用引擎有 InnoDB、MyISAM、Memory 等,從 MySQL 5.5.5 版本開始 InnoDB 就成為了默認的存儲引擎。
可以針對不同的表設置不同的引擎。在 create table 語句中使用 engine=引擎名(比如Memory)來設置此表的存儲引擎。完整代碼如下:
create table student( id int primary key auto_increment, username varchar(120), age int) ENGINE=Memory
InnoDB 和 MyISAM 最大的區(qū)別是 InnoDB 支持事務,而 MyISAM 不支持事務,它們主要區(qū)別如下:
InnoDB 支持崩潰后安全恢復,MyISAM 不支持崩潰后安全恢復;
InnoDB 支持行級鎖,MyISAM 不支持行級鎖,只支持到表鎖;
InnoDB 支持外鍵,MyISAM 不支持外鍵;
MyISAM 性能比 InnoDB 高;
MyISAM 支持 FULLTEXT 類型的全文索引,InnoDB 不支持 FULLTEXT 類型的全文索引,但是 InnoDB 可以使用 sphinx 插件支持全文索引,并且效果更好;
InnoDB 主鍵查詢性能高于 MyISAM。
1)插入緩沖(insert buffer):對于非聚集索引的插入和更新,不是每一次直接插入索引頁中,而是首先判斷插入的非聚集索引頁是否在緩沖池中,如果在,則直接插入,否則,先放入一個插入緩沖區(qū)中。好似欺騙數(shù)據庫這個非聚集的索引已經插入到葉子節(jié)點了,然后再以一定的頻率執(zhí)行插入緩沖和非聚集索引頁子節(jié)點的合并操作,這時通常能將多個插入合并到一個操作中,這就大大提高了對非聚集索引執(zhí)行插入和修改操作的性能。
2)兩次寫(double write):兩次寫給 InnoDB 帶來的是可靠性,主要用來解決部分寫失敗(partial page write)。doublewrite 有兩部分組成,一部分是內存中的 doublewrite buffer ,大小為 2M,另外一部分就是物理磁盤上的共享表空間中連續(xù)的 128 個頁,即兩個區(qū),大小同樣為 2M。當緩沖池的作業(yè)刷新時,并不直接寫硬盤,而是通過 memcpy 函數(shù)將臟頁先拷貝到內存中的 doublewrite buffer,之后通過 doublewrite buffer 再分兩次寫,每次寫入 1M 到共享表空間的物理磁盤上,然后馬上調用 fsync 函數(shù),同步磁盤。如下圖所示
3)自適應哈希索引(adaptive hash index):由于 InnoDB 不支持 hash 索引,但在某些情況下 hash 索引的效率很高,于是出現(xiàn)了 adaptive hash index 功能, InnoDB 存儲引擎會監(jiān)控對表上索引的查找,如果觀察到建立 hash 索引可以提高性能的時候,則自動建立 hash 索引。
如果這張表的引擎是 MyISAM,那么 ID=4,如果是 InnoDB 那么 ID=2(MySQL 8 之前的版本)。
以下情況會導致 MySQL 自增主鍵不能連續(xù):
唯一主鍵沖突會導致自增主鍵不連續(xù);
事務回滾也會導致自增主鍵不連續(xù)。
自增主鍵能不能被持久化,說的是 MySQL 重啟之后 InnoDB 能不能恢復重啟之前的自增列,InnoDB 在 8.0 之前是沒有持久化能力的,但 MySQL 8.0 之后就把自增主鍵保存到 redo log(一種日志類型,下文會詳細講)中,當 MySQL 重啟之后就會從 redo log 日志中恢復。
共享表空間:指的是數(shù)據庫的所有的表數(shù)據,索引文件全部放在一個文件中,默認這個共享表空間的文件路徑在 data 目錄下。 獨立表空間:每一個表都將會生成以獨立的文件方式來進行存儲。 共享表空間和獨立表空間最大的區(qū)別是如果把表放再共享表空間,即使表刪除了空間也不會刪除,所以表依然很大,而獨立表空間如果刪除表就會清除空間。
獨立表空間是由參數(shù) innodbfileper_table 控制的,把它設置成 ON 就是獨立表空間了,從 MySQL 5.6.6 版本之后,這個值就默認是 ON 了。
使用重建表的方式可以收縮表空間,重建表有以下三種方式:
alter table t engine=InnoDB
optmize table t
truncate table t
建立一個臨時文件,掃描表 t 主鍵的所有數(shù)據頁;
用數(shù)據頁中表 t 的記錄生成 B+ 樹,存儲到臨時文件中;
生成臨時文件的過程中,將所有對 t 的操作記錄在一個日志文件(row log)中;
臨時文件生成后,將日志文件中的操作應用到臨時文件,得到一個邏輯數(shù)據上與表 t相同的數(shù)據文件;
用臨時文件替換表 t 的數(shù)據文件。
表結構定義占有的存儲空間比較小,在 MySQL 8 之前,表結構的定義信息存在以 .frm 為后綴的文件里,在 MySQL 8 之后,則允許把表結構的定義信息存在系統(tǒng)數(shù)據表之中。
覆蓋索引是指,索引上的信息足夠滿足查詢請求,不需要再回到主鍵上去取數(shù)據。
可以回表查詢,如果把主鍵刪掉了,那么 InnoDB 會自己生成一個長度為 6 字節(jié)的 rowid 作為主鍵。
可能是因為 update 語句執(zhí)行完成后,InnoDB 只保證寫完了 redo log、內存,可能還沒來得及將數(shù)據寫到磁盤。
內存表,指的是使用 Memory 引擎的表,建表語法是 create table … engine=memory。這種表的數(shù)據都保存在內存里,系統(tǒng)重啟的時候會被清空,但是表結構還在。除了這兩個特性看上去比較“奇怪”外,從其他的特征上看,它就是一個正常的表。
而臨時表,可以使用各種引擎類型 。如果是使用 InnoDB 引擎或者 MyISAM 引擎的臨時表,寫數(shù)據的時候是寫到磁盤上的。
臟讀
修改丟失
不可重復讀
幻讀
臟讀是一個事務在處理過程中讀取了另外一個事務未提交的數(shù)據;幻讀是指同一個事務內多次查詢返回的結果集不一樣(比如增加了或者減少了行記錄)。
因為行鎖只能鎖定存在的行,針對新插入的操作沒有限定,所以就有可能產生幻讀。 幻讀帶來的問題如下:
對行鎖語義的破壞;
破壞了數(shù)據一致性。
使用間隙鎖的方式來避免出現(xiàn)幻讀。間隙鎖,是專門用于解決幻讀這種問題的鎖,它鎖的了行與行之間的間隙,能夠阻塞新插入的操作 間隙鎖的引入也帶來了一些新的問題,比如:降低并發(fā)度,可能導致死鎖。
在 MySQL 的命令行中使用 show processlist; 查看所有連接,其中 Command 列顯示為 Sleep 的表示空閑連接,如下圖所示:
使用 distinct 去重,使用 count 統(tǒng)計總條數(shù),具體實現(xiàn)腳本如下:
select count(distinct f) from t
lastinsertid() 用于查詢最后一次自增表的編號,它的特點是查詢時不需要不需要指定表名,使用 select last_insert_id() 即可查詢,因為不需要指定表名所以它始終以最后一條自增編號為主,可以被其它表的自增編號覆蓋。比如 A 表的最大編號是 10,lastinsertid() 查詢出來的值為 10,這時 B 表插入了一條數(shù)據,它的最大編號為 3,這個時候使用 lastinsertid() 查詢的值就是 3。
刪除數(shù)據有兩種方式:delete 和 truncate,它們的區(qū)別如下:
delete 可以添加 where 條件刪除部分數(shù)據,truncate 不能添加 where 條件只能刪除整張表;
delete 的刪除信息會在 MySQL 的日志中記錄,而 truncate 的刪除信息不被記錄在 MySQL 的日志中,因此 detele 的信息可以被找回而 truncate 的信息無法被找回;
truncate 因為不記錄日志所以執(zhí)行效率比 delete 快。
delete 和 truncate 的使用腳本如下:
delete from t where username='redis'; truncate table t;
MySQL 中支持兩種模糊查詢:regexp 和 like,like 是對任意多字符匹配或任意單字符進行模糊匹配,而 regexp 則支持正則表達式的匹配方式,提供比 like 更多的匹配方式。 regexp 和 like 的使用示例如下: select * from person where uname like '%SQL%';> select from person where uname regexp '.SQL*.';
MySQL 支持枚舉,它的實現(xiàn)方式如下:
create table t( sex enum('boy','grid') default 'unknown');
枚舉的作用是預定義結果值,當插入數(shù)據不在枚舉值范圍內,則插入失敗,提示錯誤 Data truncated for column 'xxx' at row n 。
count(column) 和 count() 最大區(qū)別是統(tǒng)計結果可能不一致,count(column) 統(tǒng)計不會統(tǒng)計列值為 null 的數(shù)據,而 count() 則會統(tǒng)計所有信息,所以最終的統(tǒng)計結果可能會不同。
A. count 的查詢性能在各種存儲引擎下的性能都是一樣的。 B. count 在 MyISAM 比 InnoDB 的性能要低。 C. count 在 InnoDB 中是一行一行讀取,然后累計計數(shù)的。 D. count 在 InnoDB 中存儲了總條數(shù),查詢的時候直接取出。
答:C
因為 InnoDB 使用了事務實現(xiàn),而事務的設計使用了多版本并發(fā)控制,即使是在同一時間進行查詢,得到的結果也可能不相同,所以 InnoDB 不能把結果直接保存下來,因為這樣是不準確的。
不能,因為 show table status 是通過采樣統(tǒng)計估算出來的,官方文檔說誤差可能在 40% 左右,所以 show table status 中的表行數(shù)不能直接使用。
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 的表行數(shù)是估算出來,而其他的查詢因為添加了 where 條件,即使是 MyISAM 引擎也不能直接使用已經存儲的總條數(shù),所以 show table status 的查詢性能最高。
MyISAM 效率最高,因為 MyISAM 內部維護了一個計數(shù)器,直接返回總條數(shù),而 InnoDB 要逐行統(tǒng)計。
count(*) 在不同的 MySQL 引擎中的實現(xiàn)方式是不相同的,在沒有 where 條件的情況下:
MyISAM 引擎會把表的總行數(shù)存儲在磁盤上,因此在執(zhí)行 count(*) 的時候會直接返回這個這個行數(shù),執(zhí)行效率很高;
InnoDB 引擎中 count(*) 就比較麻煩了,需要把數(shù)據一行一行的從引擎中讀出來,然后累計基數(shù)。
但即使這樣,在 InnoDB 中,MySQL 還是做了優(yōu)化的,我們知道對于 count() 這樣的操作,遍歷任意索引樹得到的結果,在邏輯上都是一樣的,因此,MySQL 優(yōu)化器會找到最小的那顆索引樹來遍歷,這樣就能在保證邏輯正確的前提下,盡量少掃描數(shù)據量,從而優(yōu)化了 count() 的執(zhí)行效率。
count(字段)<count(主鍵 id)<count(1)≈count(*) 題目解析:
對于 count(主鍵 id) 來說,InnoDB 引擎會遍歷整張表,把每一行的 id 值都取出來,返回給 server 層。server 層拿到 id 后,判斷是不可能為空的,就按行累加。
對于 count(1) 來說,InnoDB 引擎遍歷整張表,但不取值。server 層對于返回的每一行,放一個數(shù)字“1”進去,判斷是不可能為空的,按行累加。
對于 count(字段) 來說,如果這個“字段”是定義為 not null 的話,一行行地從記錄里面讀出這個字段,判斷不能為 null,按行累加;如果這個“字段”定義允許為 null,那么執(zhí)行的時候,判斷到有可能是 null,還要把值取出來再判斷一下,不是 null 才累加。
對于 count(*) 來說,并不會把全部字段取出來,而是專門做了優(yōu)化,不取值,直接按行累加。
所以最后得出的結果是:count(字段)<count(主鍵 id)<count(1)≈count(*)。
內連(inner join)— 把匹配的關聯(lián)數(shù)據顯示出來;
左連接(left join)— 把左邊的表全部顯示出來,右邊的表顯示出符合條件的數(shù)據;
右連接(right join)— 把右邊的表全部顯示出來,左邊的表顯示出符合條件的數(shù)據;
視圖是一種虛擬的表,具有和物理表相同的功能,可以對視圖進行增、改、查操作。視圖通常是一個表或者多個表的行或列的子集。 視圖創(chuàng)建腳本如下:
create view vname asselect column_namesfrom table_namewhere condition
獲取數(shù)據更容易,相對于多表查詢來說;
視圖能夠對機密數(shù)據提供安全保護;
視圖的修改不會影響基本表,提供了獨立的操作單元,比較輕量。
MySQL 中的“視圖”概念有兩個,它們分別是:
MySQL 中的普通視圖也是我們最常用的 view,創(chuàng)建語法是 create view …,它的查詢和普通表一樣;
InnoDB 實現(xiàn) MVCC(Multi-Version Concurrency Control)多版本并發(fā)控制時用到的一致性讀視圖,它沒有物理結構,作用是事務執(zhí)行期間定于可以看到的數(shù)據。
可以用 Flashback 工具通過閃回把數(shù)據恢復回來。
Flashback 恢復數(shù)據的原理是是修改 binlog 的內容,拿回原庫重放,從而實現(xiàn)數(shù)據找回。
###什么是索引? 索引是一種能幫助 MySQL 提高查詢效率的數(shù)據結構。
###索引分別有哪些優(yōu)點和缺點? 索引的優(yōu)點如下:
快速訪問數(shù)據表中的特定信息,提高檢索速度。
創(chuàng)建唯一性索引,保證數(shù)據表中每一行數(shù)據的唯一性。
加速表與表之間的連接。
使用分組和排序進行數(shù)據檢索時,可以顯著減少查詢中分組和排序的時間。
索引的缺點:
雖然提高了的查詢速度,但卻降低了更新表的速度,比如 update、insert,因為更新數(shù)據時,MySQL 不僅要更新數(shù)據,還要更新索引文件;
建立索引會占用磁盤文件的索引文件。
使用索引注意事項:
使用短索引,短索引不僅可以提高查詢速度,更能節(jié)省磁盤空間和 I/O 操作;
索引列排序,MySQL 查詢只使用一個索引,因此如果 where 子句中已經使用了索引的話,那么 order by 中的列是不會使用索引的,因此數(shù)據庫默認排序可以符合要求的情況下,不要進行排序操作;盡量不要包含多個列的排序,如果需要最好給這些列創(chuàng)建復合索引;
like 語句操作,一般情況下不鼓勵使用 like 操作,如果非使用不可, 注意 like "%aaa%">
不要在列上進行運算;
不適用 NOT IN 和 <> 操作。 ###以下 SQL 有什么問題?該如何優(yōu)化?
select * from t where f/2=100;
該 SQL 會導致引擎放棄索引而全表掃描,盡量避免在索引列上計算??筛臑椋?/p>
select * from t where f=100*2;
###為什么 MySQL 官方建議使用自增主鍵作為表的主鍵? 因為自增主鍵是連續(xù)的,在插入過程中盡量減少頁分裂,即使要進行頁分裂,也只會分裂很少一部分;并且自增主鍵也能減少數(shù)據的移動,每次插入都是插入到最后,所以自增主鍵作為表的主鍵,對于表的操作來說性能是最高的。
###自增主鍵有哪些優(yōu)缺點? 優(yōu)點:
數(shù)據存儲空間很??;
性能最好;
減少頁分裂。 缺點:
數(shù)據量過大,可能會超出自增長取值范圍;
無法滿足分布式存儲,分庫分表的情況下無法合并表;
主鍵有自增規(guī)律,容易被破解;
綜上所述:是否需要使用自增主鍵,需要根據自己的業(yè)務場景來設計。如果是單表單庫,則優(yōu)先考慮自增主鍵,如果是分布式存儲,分庫分表,則需要考慮數(shù)據合并的業(yè)務場景來做數(shù)據庫設計方案。
###索引有幾種類型?分別如何創(chuàng)建? MySQL 的索引有兩種分類方式:邏輯分類和物理分類。 按照邏輯分類,索引可分為:
主鍵索引:一張表只能有一個主鍵索引,不允許重復、不允許為 NULL;
唯一索引:數(shù)據列不允許重復,允許為 NULL 值,一張表可有多個唯一索引,但是一個唯一索引只能包含一列,比如身份證號碼、卡號等都可以作為唯一索引;
普通索引:一張表可以創(chuàng)建多個普通索引,一個普通索引可以包含多個字段,允許數(shù)據重復,允許 NULL 值插入;
全文索引:讓搜索關鍵詞更高效的一種索引。
按照物理分類,索引可分為:
聚集索引:一般是表中的主鍵索引,如果表中沒有顯示指定主鍵,則會選擇表中的第一個不允許為 NULL 的唯一索引,如果還是沒有的話,就采用 Innodb 存儲引擎為每行數(shù)據內置的 6 字節(jié) ROWID 作為聚集索引。每張表只有一個聚集索引,因為聚集索引的鍵值的邏輯順序決定了表中相應行的物理順序。聚集索引在精確查找和范圍查找方面有良好的性能表現(xiàn)(相比于普通索引和全表掃描),聚集索引就顯得彌足珍貴,聚集索引選擇還是要慎重的(一般不會讓沒有語義的自增 id 充當聚集索引);
非聚集索引:該索引中索引的邏輯順序與磁盤上行的物理存儲順序不同(非主鍵的那一列),一個表中可以擁有多個非聚集索引。
各種索引的創(chuàng)建腳本如下:
-- 創(chuàng)建主鍵索引alter table t add primary key add (`id`);-- 創(chuàng)建唯一索引alter table t add unique (`username`);-- 創(chuàng)建普通索引alter table t add index index_name (`username`);-- 創(chuàng)建全文索引alter table t add fulltext (`username`);
###主索引和唯一索引有什么區(qū)別?
主索引不能重復且不能為空,唯一索引不能重復,但可以為空;
一張表只能有一個主索引,但可以有多個唯一索引;
主索引的查詢性能要高于唯一索引。 ###在 InnDB 中主鍵索引為什么比普通索引的查詢性能高? 因為普通索引的查詢會多執(zhí)行一次檢索操作。比如主鍵查詢 select * from t where id=10 只需要搜索 id 的這棵 B+ 樹,而普通索引查詢 select * from t where f=3 會先查詢 f 索引樹,得到 id 的值之后再去搜索 id 的 B+ 樹,因為多執(zhí)行了一次檢索,所以執(zhí)行效率就比主鍵索引要低。
###什么叫回表查詢? 普通索引查詢到主鍵索引后,回到主鍵索引樹搜索的過程,我們稱為回表查詢。
參考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 最多可以創(chuàng)建多少個索引列? MySQL 中最多可以創(chuàng)建 16 個索引列。
###以下 like 查詢會使用索引的是哪一個選項?為什么? A.like '%A%' B.like '%A' C.like 'A%' D.以上都不是 答:C 題目解析:like 查詢要走索引,查詢字符不能以通配符(%)開始。
###如何讓 like %abc 走索引查詢? 我們知道如果要讓 like 查詢要走索引,查詢字符不能以通配符(%)開始,如果要讓 like %abc 也走索引,可以使用 REVERSE() 函數(shù)來創(chuàng)建一個函數(shù)索引,查詢腳本如下:
select * from t where reverse(f) like reverse('%abc');
###MySQL 聯(lián)合索引應該注意什么? 聯(lián)合索引又叫復合索引,MySQL 中的聯(lián)合索引,遵循最左匹配原則,比如,聯(lián)合索引為 key(a,b,c),則能觸發(fā)索引的搜索組合是 a|ab|abc 這三種查詢。
###聯(lián)合索引的作用是什么? 聯(lián)合索引的作用如下:
用于多字段查詢,比如,建了一個 key(a,b,c) 的聯(lián)合索引,那么實際等于建了key(a)、key(a,b)、key(a,b,c)等三個索引,我們知道,每多一個索引,就會多一些寫操作和占用磁盤空間的開銷,尤其是對大數(shù)據量的表來說,這可以減少一部分不必要的開銷;
覆蓋索引,比如,對于聯(lián)合索引 key(a,b,c) 來說,如果使用 SQL:select a,b,c from table where a=1 and b = 1 ,就可以直接通過遍歷索引取得數(shù)據,而無需回表查詢,這就減少了隨機的 IO 操作,減少隨機的 IO 操作,可以有效的提升數(shù)據庫查詢的性能,是非常重要的數(shù)據庫優(yōu)化手段之一;
索引列越多,通過索引篩選出的數(shù)據越少。 ###什么是最左匹配原則?它的生效原則有哪些? 最左匹配原則也叫最左前綴原則,是 MySQL 中的一個重要原則,說的是索引以最左邊的為起點任何連續(xù)的索引都能匹配上,當遇到范圍查詢(>、<、between、like)就會停止匹配。 生效原則來看以下示例,比如表中有一個聯(lián)合索引字段 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 存儲引擎會正常觸發(fā)索引。但為了兼容低版本的 MySQL 和兼容其他數(shù)據庫存儲引擎,不建議使用 NULL 值來存儲和查詢數(shù)據,建議設置列為 NOT NULL,并設置一個默認值,比如 0 和空字符串等,如果是 datetime 類型,可以設置成 1970-01-01 00:00:00 這樣的特殊值。
###以下語句會走索引么?
select * from t where year(date)>2018;
不會,因為在索引列上涉及到了運算。
###能否給手機號的前 6 位創(chuàng)建索引?如何創(chuàng)建? 可以,創(chuàng)建方式有兩種:
alter table t add index index_phone(phone(6)); create index index_phone on t(phone(6));
###什么是前綴索引? 前綴索引也叫局部索引,比如給身份證的前 10 位添加索引,類似這種給某列部分信息添加索引的方式叫做前綴索引。
###為什么要用前綴索引? 前綴索引能有效減小索引文件的大小,讓每個索引頁可以保存更多的索引值,從而提高了索引查詢的速度。但前綴索引也有它的缺點,不能在 order by 或者 group by 中觸發(fā)前綴索引,也不能把它們用于覆蓋索引。
###什么情況下適合使用前綴索引? 當字符串本身可能比較長,而且前幾個字符就開始不相同,適合使用前綴索引;相反情況下不適合使用前綴索引,比如,整個字段的長度為 20,索引選擇性為 0.9,而我們對前 10 個字符建立前綴索引其選擇性也只有 0.5,那么我們需要繼續(xù)加大前綴字符的長度,但是這個時候前綴索引的優(yōu)勢已經不明顯,就沒有創(chuàng)建前綴索引的必要了。
###什么是業(yè)? 頁是計算機管理存儲器的邏輯塊,硬件及操作系統(tǒng)往往將主存和磁盤存儲區(qū)分割為連續(xù)的大小相等的塊,每個存儲塊稱為一頁。主存和磁盤以頁為單位交換數(shù)據。數(shù)據庫系統(tǒng)的設計者巧妙利用了磁盤預讀原理,將一個節(jié)點的大小設為等于一個頁,這樣每個節(jié)點只需要一次磁盤 IO 就可以完全載入。
###索引的常見存儲算法有哪些?
哈希存儲法:以 key、value 方式存儲,把值存入數(shù)組中使用哈希值確認數(shù)據的位置,如果發(fā)生哈希沖突,使用鏈表存儲數(shù)據;
有序數(shù)組存儲法:按順序存儲,優(yōu)點是可以使用二分法快速找到數(shù)據,缺點是更新效率,適合靜態(tài)數(shù)據存儲;
搜索樹:以樹的方式進行存儲,查詢性能好,更新速度快。 ###InnoDB 為什么要使用 B+ 樹,而不是 B 樹、Hash、紅黑樹或二叉樹? 因為 B 樹、Hash、紅黑樹或二叉樹存在以下問題:
B 樹:不管葉子節(jié)點還是非葉子節(jié)點,都會保存數(shù)據,這樣導致在非葉子節(jié)點中能保存的指針數(shù)量變少(有些資料也稱為扇出),指針少的情況下要保存大量數(shù)據,只能增加樹的高度,導致IO操作變多,查詢性能變低;
Hash:雖然可以快速定位,但是沒有順序,IO 復雜度高;
二叉樹:樹的高度不均勻,不能自平衡,查找效率跟數(shù)據有關(樹的高度),并且 IO 代價高;
紅黑樹:樹的高度隨著數(shù)據量增加而增加,IO 代價高。 ###為什么 InnoDB 要使用 B+ 誰來存儲索引? B+Tree 中的 B 是 Balance,是平衡的意思,它在經典 B Tree 的基礎上進行了優(yōu)化,增加了順序訪問指針,在B+Tree 的每個葉子節(jié)點增加一個指向相鄰葉子節(jié)點的指針,就形成了帶有順序訪問指針的 B+Tree,這樣就提高了區(qū)間訪問性能:如果要查詢 key 為從 18 到 49 的所有數(shù)據記錄,當找到 18 后,只需順著節(jié)點和指針順序遍歷就可以一次性訪問到所有數(shù)據節(jié)點,極大提到了區(qū)間查詢效率(無需返回上層父節(jié)點重復遍歷查找減少 IO 操作)。
索引本身也很大,不可能全部存儲在內存中,因此索引往往以索引文件的形式存儲的磁盤上,這樣的話,索引查找過程中就要產生磁盤 IO 消耗,相對于內存存取,IO 存取的消耗要高幾個數(shù)量級,所以索引的結構組織要盡量減少查找過程中磁盤 IO 的存取次數(shù),從而提升索引效率。 綜合所述,InnDB 只有采取 B+ 樹的數(shù)據結構存儲索引,才能提供數(shù)據庫整體的操作性能。
###唯一索引和普通索引哪個性能更好?
對于查詢操作來說:普通索引和唯一索引的性能相近,都是從索引樹中進行查詢;
對于更新操作來說:唯一索引要比普通索引執(zhí)行的慢,因為唯一索引需要先將數(shù)據讀取到內存中,再在內存中進行數(shù)據的唯一效驗,所以執(zhí)行起來要比普通索引更慢。 ###優(yōu)化器選擇查詢索引的影響因素有哪些? 優(yōu)化器的目的是使用最小的代價選擇最優(yōu)的執(zhí)行方案,影響優(yōu)化器選擇索引的因素如下:
掃描行數(shù),掃描的行數(shù)越少,執(zhí)行代價就越少,執(zhí)行效率就會越高;
是否使用了臨時表;
是否排序。 ###MySQL 是如何判斷索引掃描行數(shù)的多少? MySQL 的掃描行數(shù)是通過索引統(tǒng)計列(cardinality)大致得到并且判斷的,而索引統(tǒng)計列(cardinality)可以通過查詢命令 show index 得到,索引掃描行數(shù)的多少就是通過這個值進行判斷的。
###MySQL 是如何得到索引基數(shù)的?它準確嗎? MySQL 的索引基數(shù)并不準確,因為 MySQL 的索引基數(shù)是通過采樣統(tǒng)計得到的,比如 InnoDb 默認會有 N 個數(shù)據頁,采樣統(tǒng)計會統(tǒng)計這些頁面上的不同值得到一個平均值,然后除以這個索引的頁面數(shù)就得到了這個索引基數(shù)。
###MySQL 如何指定查詢的索引? 在 MySQL 中可以使用 force index 強行選擇一個索引,具體查詢語句如下:
select * from t force index(index_t)
###在 MySQL 中指定了查詢索引,為什么沒有生效? 我們知道在 MySQL 中使用 force index 可以指定查詢的索引,但并不是一定會生效,原因是 MySQL 會根據優(yōu)化器自己選擇索引,如果 force index 指定的索引出現(xiàn)在候選索引上,這個時候 MySQL 不會在判斷掃描的行數(shù)的多少直接使用指定的索引,如果沒在候選索引中,即使 force index 指定了索引也是不會生效的。
###以下 or 查詢有什么問題嗎?該如何優(yōu)化?
select * from t where num=10 or num=20;
答:如果使用 or 查詢會使 MySQL 放棄索引而全表掃描,可以改為:
select * from t where num=10 union select * from t where num=20;
###以下查詢要如何優(yōu)化? 表中包含索引:
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 可以對比查詢掃描次數(shù)。由于使用了 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 的服務層的優(yōu)化器來自動選擇的,但它在復雜情況下也和人寫程序一樣出現(xiàn)缺陷。
###如何解決 MySQL 錯選索引的問題?
刪除錯選的索引,只留下對的索引;
使用 force index 指定索引;
修改 SQL 查詢語句引導 MySQL 使用我們期望的索引,比如把 order by b limit 1 改為 order by b,a limit 1 語義是相同的,但 MySQL 查詢的時候會考慮使用 a 鍵上的索引。 ###如何優(yōu)化身份證的索引? 在中國因為前 6 位代表的是地區(qū),所以很多人的前六位都是相同的,如果我們使用前綴索引為 6 位的話,性能提升也并不是很明顯,但如果設置的位數(shù)過長,那么占用的磁盤空間也越大,數(shù)據頁能放下的索引值就越少,搜索效率也越低。針對這種情況優(yōu)化方案有以下兩種:
使用身份證倒序存儲,這樣設置前六位的意義就很大了;
使用 hash 值,新創(chuàng)建一個字段用于存儲身份證的 hash 值。
事務是一系列的數(shù)據庫操作,是數(shù)據庫應用的基本單位。MySQL 事務主要用于處理操作量大,復雜度高的數(shù)據。
在 MySQL 中只有 InnDB 引擎支持事務,它的四個特性如下:
原子性(Atomic):要么全部執(zhí)行,要么全部不執(zhí)行;
一致性(Consistency):事務的執(zhí)行使得數(shù)據庫從一種正確狀態(tài)轉化為另一種正確狀態(tài);
隔離性(Isolation):在事務正確提交之前,不允許把該事務對數(shù)據的任何改變提供給其他事務;
持久性(Durability):事務提交后,其結果永久保存在數(shù)據庫中。
MySQL 中有四種事務隔離級別,它們分別是:
read uncommited:未提交讀,讀到未提交數(shù)據;
read committed:讀已提交,也叫不可重復讀,兩次讀取到的數(shù)據不一致;
repetable read:可重復讀;
serializable:串行化,讀寫數(shù)據都會鎖住整張表,數(shù)據操作不會出錯,但并發(fā)性能極低,開發(fā)中很少用到。
MySQL 默認使用 REPEATABLE-READ 的事務隔離級別。
不可重復讀的重點是修改:在同一事務中,同樣的條件,第一次讀的數(shù)據和第二次讀的數(shù)據不一樣。(因為中間有其他事務提交了修改)。
幻讀的重點在于新增或者刪除:在同一事務中,同樣的條件,,第一次和第二次讀出來的記錄數(shù)不一樣。(因為中間有其他事務提交了插入/刪除)。
更新丟失(Lost Update):當兩個或多個事務選擇同一行,然后基于最初選定的值更新該行時,由于每個事務都不知道其他事務的存在,就會發(fā)生丟失更新問題,最后的更新覆蓋了由其他事務所做的更新。例如,兩個編輯人員制作了同一文檔的電子副本,每個編輯人員獨立地更改其副本,然后保存更改后的副本,這樣就覆蓋了原始文檔。 最后保存其更改副本的編輯人員覆蓋另一個編輯人員所做的更改,如果在前一個編輯人員完成并提交事務之前,另一個編輯人員不能訪問同一文件,則可避免此問題。
臟讀(Dirty Reads):一個事務正在對一條記錄做修改,在這個事務完成并提交前, 這條記錄的數(shù)據就處于不一致狀態(tài); 這時, 另一個事務也來讀取同一條記錄,如果不加控制,第二個事務讀取了這些臟數(shù)據,并據此做進一步的處理,就會產生未提交的數(shù)據依賴關系,這種現(xiàn)象被形象地叫做臟讀。
不可重復讀(Non-Repeatable Reads):一個事務在讀取某些數(shù)據后的某個時間,再次讀取以前讀過的數(shù)據,卻發(fā)現(xiàn)其讀出的數(shù)據已經發(fā)生了改變、或某些記錄已經被刪除了!這種現(xiàn)象就叫做“不可重復讀” 。
幻讀(Phantom Reads): 一個事務按相同的查詢條件重新讀取以前檢索過的數(shù)據,卻發(fā)現(xiàn)其他事務插入了滿足其查詢條件的新數(shù)據,這種現(xiàn)象就稱為“幻讀” 。
并發(fā)事務可能造成:臟讀、不可重復讀和幻讀等問題 ,這些問題其實都是數(shù)據庫讀一致性問題,必須由數(shù)據庫提供一定的事務隔離機制來解決,解決方案如下:
加鎖:在讀取數(shù)據前,對其加鎖,阻止其他事務對數(shù)據進行修改。
提供數(shù)據多版本并發(fā)控制(MultiVersion Concurrency Control,簡稱 MVCC 或 MCC),也稱為多版本數(shù)據庫:不用加任何鎖, 通過一定機制生成一個數(shù)據請求時間點的一致性數(shù)據快照(Snapshot), 并用這個快照來提供一定級別 (語句級或事務級) 的一致性讀取,從用戶的角度來看,好象是數(shù)據庫可以提供同一數(shù)據的多個版本。
MVCC 全稱是多版本并發(fā)控制系統(tǒng),InnoDB 和 Falcon 存儲引擎通過多版本并發(fā)控制(MVCC,Multiversion Concurrency Control)機制解決幻讀問題。
InnoDB 的 MVCC 是通過在每行記錄后面保存兩個隱藏的列來實現(xiàn),這兩個列一個保存了行的創(chuàng)建時間,一個保存行的過期時間(刪除時間)。當然存儲的并不是真實的時間而是系統(tǒng)版本號(system version number)。每開始一個新的事務,系統(tǒng)版本號都會自動新增,事務開始時刻的系統(tǒng)版本號會作為事務的版本號,用來查詢到每行記錄的版本號進行比較。
SELECT:InnoDB 會根據以下條件檢查每一行記錄:第一,InnoDB 只查找版本早于當前事務版本的數(shù)據行,這樣可以確保事務讀取的行要么是在開始事務之前已經存在要么是事務自身插入或者修改過的。第二,行的刪除版本號要么未定義,要么大于當前事務版本號,這樣可以確保事務讀取到的行在事務開始之前未被刪除。
INSERT:InnoDB 為新插入的每一行保存當前系統(tǒng)版本號作為行版本號。
DELETE:InnoDB 為刪除的每一行保存當前系統(tǒng)版本號作為行刪除標識。
UPDATE:InnoDB 為插入的一行新紀錄保存當前系統(tǒng)版本號作為行版本號,同時保存當前系統(tǒng)版本號到原來的行作為刪除標識保存這兩個版本號,使大多數(shù)操作都不用加鎖。它不足之處是每行記錄都需要額外的存儲空間,需要做更多的行檢查工作和一些額外的維護工作。
事務的實現(xiàn)是基于數(shù)據庫的存儲引擎,不同的存儲引擎對事務的支持程度不一樣。MySQL 中支持事務的存儲引擎有InnoDB 和 NDB。 InnoDB 是高版本 MySQL 的默認的存儲引擎,因此就以 InnoDB 的事務實現(xiàn)為例,InnoDB 是通過多版本并發(fā)控制(MVCC,Multiversion Concurrency Control )解決不可重復讀問題,加上間隙鎖(也就是并發(fā)控制)解決幻讀問題。因此 InnoDB 的 RR 隔離級別其實實現(xiàn)了串行化級別的效果,而且保留了比較好的并發(fā)性能。事務的隔離性是通過鎖實現(xiàn),而事務的原子性、一致性和持久性則是通過事務日志實現(xiàn)。
MySQL 事務隔離級別 MySQL.cnf 文件里設置的(默認目錄 /etc/my.cnf),在文件的文末添加配置:
transaction-isolation = REPEATABLE-READ
可用的配置值:READ-UNCOMMITTED、READ-COMMITTED、REPEATABLE-READ、SERIALIZABLE。
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 默認是自動提交事務的,每一次 SQL 操作(非 select 操作)都會自動提交一個事務,如果要手動開啟事務需要設置 set autocommit=0 禁止自動提交事務,相當于開啟手動提交事務。
autocommit=0 表示禁止自動事務提交,在添加操作之后沒有進行手動提交,默認情況下其他連接客戶端是查詢不到此條新增數(shù)據的。
使用 begin 開啟事務;rollback 回滾事務;commit 提交事務。具體使用示例如下:
begin; insert person(uname,age) values('laowang',18); rollback; commit;
鎖是實現(xiàn)數(shù)據庫并發(fā)控制的重要手段,可以保證數(shù)據庫在多人同時操作時能夠正常運行。MySQL 提供了全局鎖、行級鎖、表級鎖。其中 InnoDB 支持表級鎖和行級鎖,MyISAM 只支持表級鎖。
是指兩個或兩個以上的進程在執(zhí)行過程中,因爭奪資源而造成的一種互相等待的現(xiàn)象,若無外力作用,它們都將無法推進下去。此時稱系統(tǒng)處于死鎖狀態(tài)或系統(tǒng)產生了死鎖,這些永遠在互相等待的過程稱為死鎖。
死鎖是指兩個或兩個以上的進程在執(zhí)行過程中,因爭奪資源而造成的一種互相等待的現(xiàn)象,若無外力作用,它們都將無法推進下去。此時稱系統(tǒng)處于死鎖狀態(tài)或系統(tǒng)產生了死鎖,這些永遠在互相等待的過程稱為死鎖。
將投資的錢拆封幾份借給借款人,這時處理業(yè)務邏輯就要把若干個借款人一起鎖住 select * from xxx where id in (xx,xx,xx) for update。
批量入庫,存在則更新,不存在則插入。解決方法 insert into tab(xx,xx) on duplicate key update xx='xx'。
對待死鎖常見的兩種策略:
通過 innodblockwait_timeout 來設置超時時間,一直等待直到超時;
發(fā)起死鎖檢測,發(fā)現(xiàn)死鎖之后,主動回滾死鎖中的某一個事務,讓其它事務繼續(xù)執(zhí)行。
使用命令 show engine innodb status 查看最近的一次死鎖。
InnoDB Lock Monitor 打開鎖監(jiān)控,每 15s 輸出一次日志。使用完畢后建議關閉,否則會影響數(shù)據庫性能。
為了在單個 InnoDB 表上執(zhí)行多個并發(fā)寫入操作時避免死鎖,可以在事務開始時通過為預期要修改的每個元祖(行)使用 SELECT … FOR UPDATE 語句來獲取必要的鎖,即使這些行的更改語句是在之后才執(zhí)行的。
在事務中,如果要更新記錄,應該直接申請足夠級別的鎖,即排他鎖,而不應先申請共享鎖、更新時再申請排他鎖,因為這時候當用戶再申請排他鎖時,其他事務可能又已經獲得了相同記錄的共享鎖,從而造成鎖沖突,甚至死鎖
如果事務需要修改或鎖定多個表,則應在每個事務中以相同的順序使用加鎖語句。在應用中,如果不同的程序會并發(fā)存取多個表,應盡量約定以相同的順序來訪問表,這樣可以大大降低產生死鎖的機會
通過 SELECT … LOCK IN SHARE MODE 獲取行的讀鎖后,如果當前事務再需要對該記錄進行更新操作,則很有可能造成死鎖。
改變事務隔離級別。
InnoDB 默認是使用設置死鎖時間來讓死鎖超時的策略,默認 innodblockwait_timeout 設置的時長是 50s。
設置 innodbdeadlockdetect 設置為 on 可以主動檢測死鎖,在 Innodb 中這個值默認就是 on 開啟的狀態(tài)。
全局鎖就是對整個數(shù)據庫實例加鎖,它的典型使用場景就是做全庫邏輯備份。 這個命令可以使整個庫處于只讀狀態(tài)。使用該命令之后,數(shù)據更新語句、數(shù)據定義語句、更新類事務的提交語句等操作都會被阻塞。
共享鎖又稱讀鎖 (read lock),是讀取操作創(chuàng)建的鎖。其他用戶可以并發(fā)讀取數(shù)據,但任何事務都不能對數(shù)據進行修改(獲取數(shù)據上的排他鎖),直到已釋放所有共享鎖。當如果事務對讀鎖進行修改操作,很可能會造成死鎖。
排他鎖 exclusive lock(也叫 writer lock)又稱寫鎖。
若某個事物對某一行加上了排他鎖,只能這個事務對其進行讀寫,在此事務結束之前,其他事務不能對其進行加任何鎖,其他進程可以讀取,不能進行寫操作,需等待其釋放。
排它鎖是悲觀鎖的一種實現(xiàn),在上面悲觀鎖也介紹過。
若事務 1 對數(shù)據對象 A 加上 X 鎖,事務 1 可以讀 A 也可以修改 A,其他事務不能再對 A 加任何鎖,直到事物 1 釋放 A 上的鎖。這保證了其他事務在事物 1 釋放 A 上的鎖之前不能再讀取和修改 A。排它鎖會阻塞所有的排它鎖和共享鎖。
如果在主庫備份,在備份期間不能更新,業(yè)務停擺,所以更新業(yè)務會處于等待狀態(tài)。
如果在從庫備份,在備份期間不能執(zhí)行主庫同步的 binlog,導致主從延遲。
如果使用全局鎖進行邏輯備份就會讓整個庫成為只讀狀態(tài),幸好官方推出了一個邏輯備份工具 MySQLdump 來解決了這個問題,只需要在使用 MySQLdump 時,使用參數(shù) -single-transaction 就會在導入數(shù)據之前啟動一個事務來保證數(shù)據的一致性,并且這個過程是支持數(shù)據更新操作的。
使用命令 flush tables with read lock(簡稱 FTWRL)就可以實現(xiàn)設置數(shù)據庫為全局只讀鎖。
除了使用 FTWRL 外,還可以使用命令 set global readonly=true 設置數(shù)據庫為只讀。
FTWRL 和 set global readonly=true 都是設置整個數(shù)據庫為只讀狀態(tài),但他們最大的區(qū)別就是,當執(zhí)行 FTWRL 的客戶端斷開之后,整個數(shù)據庫會取消只讀,而 set global readonly=true 會一直讓數(shù)據處于只讀狀態(tài)。
MySQL 里標記鎖有兩種:表級鎖、元數(shù)據鎖(meta data lock)簡稱 MDL。表鎖的語法是 lock tables t read/write。
可以用 unlock tables 主動釋放鎖,也可以在客戶端斷開的時候自動釋放。lock tables 語法除了會限制別的線程的讀寫外,也限定了本線程接下來的操作對象。
對于 InnoDB 這種支持行鎖的引擎,一般不使用 lock tables 命令來控制并發(fā),畢竟鎖住整個表的影響面還是太大。
MDL:不需要顯式使用,在訪問一個表的時候會被自動加上。
MDL 的作用:保證讀寫的正確性。
在對一個表做增刪改查操作的時候,加 MDL 讀鎖;當要對表做結構變更操作的時候,加 MDL 寫鎖。
讀鎖之間不互斥,讀寫鎖之間,寫鎖之間是互斥的,用來保證變更表結構操作的安全性。
MDL 會直到事務提交才會釋放,在做表結構變更的時候,一定要小心不要導致鎖住線上查詢和更新。
顧名思義,就是很悲觀,每次去拿數(shù)據的時候都認為別人會修改,所以每次在拿數(shù)據的時候都會上鎖,這樣別人想拿這個數(shù)據就會 block 直到它拿到鎖。正因為如此,悲觀鎖需要耗費較多的時間,另外與樂觀鎖相對應的,悲觀鎖是由數(shù)據庫自己實現(xiàn)了的,要用的時候,我們直接調用數(shù)據庫的相關語句就可以了。
說到這里,由悲觀鎖涉及到的另外兩個鎖概念就出來了,它們就是共享鎖與排它鎖。共享鎖和排它鎖是悲觀鎖的不同的實現(xiàn),它倆都屬于悲觀鎖的范疇。
樂觀鎖是用數(shù)據版本(Version)記錄機制實現(xiàn),這是樂觀鎖最常用的一種實現(xiàn)方式。何謂數(shù)據版本?即為數(shù)據增加一個版本標識,一般是通過為數(shù)據庫表增加一個數(shù)字類型的 version 字段來實現(xiàn)。當讀取數(shù)據時,將 version 字段的值一同讀出,數(shù)據每更新一次,對此 version 值加 1。當我們提交更新的時候,判斷數(shù)據庫表對應記錄的當前版本信息與第一次取出來的version值進行比對,如果數(shù)據庫表當前版本號與第一次取出來的 version 值相等,則予以更新,否則認為是過期數(shù)據。
比如: 1、數(shù)據庫表三個字段,分別是id、value、version select id,value,version from t where id=#{id} 2、每次更新表中的value字段時,為了防止發(fā)生沖突,需要這樣操作
update t set value=2,version=version+1 where id=#{id} and version=#{version}
因為沒有加鎖所以樂觀鎖的優(yōu)點就是執(zhí)行性能高。它的缺點就是有可能產生 ABA 的問題,ABA 問題指的是有一個變量 V 初次讀取的時候是 A 值,并且在準備賦值的時候檢查到它仍然是 A 值,會誤以為沒有被修改會正常的執(zhí)行修改操作,實際上這段時間它的值可能被改了其他值,之后又改回為 A 值,這個問題被稱為 ABA 問題。
Record Lock — 單個行記錄上的鎖;
Gap Lock — 間隙鎖,鎖定一個范圍,不包括記錄本身;
Next-Key Lock — 鎖定一個范圍,包括記錄本身。
行級鎖是 MySQL 中粒度最小的一種鎖,他能大大減少數(shù)據庫操作的沖突。
INNODB 的行級鎖有共享鎖(S LOCK)和排他鎖(X LOCK)兩種。共享鎖允許事物讀一行記錄,不允許任何線程對該行記錄進行修改。排他鎖允許當前事物刪除或更新一行記錄,其他線程不能操作該記錄。
共享鎖:SELECT … LOCK IN SHARE MODE,MySQL 會對查詢結果集中每行都添加共享鎖,前提是當前線程沒有對該結果集中的任何行使用排他鎖,否則申請會阻塞。
排他鎖:select * from t where id=1 for update,其中 id 字段必須有索引,MySQL 會對查詢結果集中每行都添加排他鎖,在事物操作中,任何對記錄的更新與刪除操作會自動加上排他鎖。前提是當前沒有線程對該結果集中的任何行使用排他鎖或共享鎖,否則申請會阻塞。
盡量使用較低的隔離級別。
精心設計索引, 并盡量使用索引訪問數(shù)據, 使加鎖更精確, 從而減少鎖沖突的機會。
選擇合理的事務大小,小事務發(fā)生鎖沖突的幾率也更小。
給記錄集顯示加鎖時,最好一次性請求足夠級別的鎖。比如要修改數(shù)據的話,最好直接申請排他鎖,而不是先申請共享鎖,修改時再請求排他鎖,這樣容易產生死鎖。
不同的程序訪問一組表時,應盡量約定以相同的順序訪問各表,對一個表而言,盡可能以固定的順序存取表中的行。這樣可以大大減少死鎖的機會。
盡量用相等條件訪問數(shù)據,這樣可以避免間隙鎖對并發(fā)插入的影響。
不要申請超過實際需要的鎖級別。
除非必須,查詢時不要顯示加鎖。 MySQL 的 MVCC 可以實現(xiàn)事務中的查詢不用加鎖,優(yōu)化事務性能;MVCC 只在 COMMITTED READ(讀提交)和 REPEATABLE READ(可重復讀)兩種隔離級別下工作。
對于一些特定的事務,可以使用表鎖來提高處理速度或減少死鎖的可能。
“高頻MySQL的題目有哪些”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。