?????? 博主個(gè)人介紹
辛苦牛,掌握主流技術(shù)棧,包括前端后端,已經(jīng)7年時(shí)間,曾在稅務(wù)機(jī)關(guān)從事開發(fā)工作,目前在國企任職。希望通過自己的不斷分享,可以幫助各位想或者已經(jīng)走在這條路上的朋友一定的幫助
前言
??金九銀十馬上就要來啦,各位小伙伴們有計(jì)劃跳槽的要開始準(zhǔn)備了,博主接下來一段時(shí)間會(huì)給大家持續(xù)更新面試題目,大家持續(xù)關(guān)注一下,感謝??????
之前有寫過一篇mysql優(yōu)化的文章,鏈接放給大家,有需要可以查看
一文看懂Mysql優(yōu)化問題【純肝貨、面試必備】
內(nèi)容
MySQL 的邏輯架構(gòu)了解嗎?
第一層是服務(wù)器層,主要提供連接處理、授權(quán)認(rèn)證、安全等功能。
第二層實(shí)現(xiàn)了 MySQL 核心服務(wù)功能,包括查詢解析、分析、優(yōu)化、緩存以及日期和時(shí)間等所有內(nèi)置函 數(shù),所有跨存儲(chǔ)引擎的功能都在這一層實(shí)現(xiàn),例如存儲(chǔ)過程、觸發(fā)器、視圖等。
第三層是存儲(chǔ)引擎層,存儲(chǔ)引擎負(fù)責(zé) MySQL 中數(shù)據(jù)的存儲(chǔ)和提取。服務(wù)器通過 API 與存儲(chǔ)引擎通信, 這些接口屏蔽了不同存儲(chǔ)引擎的差異,使得差異對(duì)上層查詢過程透明。除了會(huì)解析外鍵定義的 InnoDB 外,存儲(chǔ)引擎不會(huì)解析 SQL,不同存儲(chǔ)引擎之間也不會(huì)相互通信,只是簡單響應(yīng)上層服務(wù)器請求。
Q2:談一談 MySQL 的讀寫鎖
在處理并發(fā)讀或?qū)憰r(shí),可以通過實(shí)現(xiàn)一個(gè)由兩種類型組成的鎖系統(tǒng)來解決問題。這兩種類型的鎖通常被 稱為共享鎖和排它鎖,也叫讀鎖和寫鎖。讀鎖是共享的,相互不阻塞,多個(gè)客戶在同一時(shí)刻可以同時(shí)讀 取同一個(gè)資源而不相互干擾。寫鎖則是排他的,也就是說一個(gè)寫鎖會(huì)阻塞其他的寫鎖和讀鎖,確保在給 定時(shí)間內(nèi)只有一個(gè)用戶能執(zhí)行寫入并防止其他用戶讀取正在寫入的同一資源。
在實(shí)際的數(shù)據(jù)庫系統(tǒng)中,每時(shí)每刻都在發(fā)生鎖定,當(dāng)某個(gè)用戶在修改某一部分?jǐn)?shù)據(jù)時(shí),MySQL 會(huì)通過 鎖定防止其他用戶讀取同一數(shù)據(jù)。寫鎖比讀鎖有更高的優(yōu)先級(jí),一個(gè)寫鎖請求可能會(huì)被插入到讀鎖隊(duì)列 的前面,但是讀鎖不能插入到寫鎖前面。
Q3:MySQL 的鎖策略有什么?
表鎖是MySQL中最基本的鎖策略,并且是開銷最小的策略。表鎖會(huì)鎖定整張表,一個(gè)用戶在對(duì)表進(jìn)行寫 操作前需要先獲得寫鎖,這會(huì)阻塞其他用戶對(duì)該表的所有讀寫操作。只有沒有寫鎖時(shí),其他讀取的用戶 才能獲取讀鎖,讀鎖之間不相互阻塞。
行鎖可以最大程度地支持并發(fā),同時(shí)也帶來了最大開銷。InnoDB 和 XtraDB 以及一些其他存儲(chǔ)引擎實(shí) 現(xiàn)了行鎖。行鎖只在存儲(chǔ)引擎層實(shí)現(xiàn),而服務(wù)器層沒有實(shí)現(xiàn)。
Q4:數(shù)據(jù)庫死鎖如何解決?
死鎖是指多個(gè)事務(wù)在同一資源上相互占用并請求鎖定對(duì)方占用的資源而導(dǎo)致惡性循環(huán)的現(xiàn)象。當(dāng)多個(gè)事
務(wù)試圖以不同順序鎖定資源時(shí)就可能會(huì)產(chǎn)生死鎖,多個(gè)事務(wù)同時(shí)鎖定同一個(gè)資源時(shí)也會(huì)產(chǎn)生死鎖。
為了解決死鎖問題,數(shù)據(jù)庫系統(tǒng)實(shí)現(xiàn)了各種死鎖檢測和死鎖超時(shí)機(jī)制。越復(fù)雜的系統(tǒng),例如InnoDB 存 儲(chǔ)引擎,越能檢測到死鎖的循環(huán)依賴,并立即返回一個(gè)錯(cuò)誤。這種解決方式很有效,否則死鎖會(huì)導(dǎo)致出 現(xiàn)非常慢的查詢。還有一種解決方法,就是當(dāng)查詢的時(shí)間達(dá)到鎖等待超時(shí)的設(shè)定后放棄鎖請求,這種方 式通常來說不太好。InnoDB 目前處理死鎖的方法是將持有最少行級(jí)排它鎖的事務(wù)進(jìn)行回滾。
死鎖發(fā)生之后,只有部分或者完全回滾其中一個(gè)事務(wù),才能打破死鎖。對(duì)于事務(wù)型系統(tǒng)這是無法避免 的,所以應(yīng)用程序在設(shè)計(jì)時(shí)必須考慮如何處理死鎖。大多數(shù)情況下只需要重新執(zhí)行因死鎖回滾的事務(wù)即 可。
Q5:事務(wù)是什么?
事務(wù)是一組原子性的 SQL 查詢,或者說一個(gè)獨(dú)立的工作單元。如果數(shù)據(jù)庫引擎能夠成功地對(duì)數(shù)據(jù)庫應(yīng)用 該組查詢的全部語句,那么就執(zhí)行該組查詢。如果其中有任何一條語句因?yàn)楸罎⒒蚱渌驘o法執(zhí)行, 那么所有的語句都不會(huì)執(zhí)行。也就是說事務(wù)內(nèi)的語句要么全部執(zhí)行成功,要么全部執(zhí)行失敗。
Q6:事務(wù)有什么特性?
- 原子性 atomicity
一個(gè)事務(wù)在邏輯上是必須不可分割的最小工作單元,整個(gè)事務(wù)中的所有操作要么全部提交成功,要么全 部失敗回滾,對(duì)于一個(gè)事務(wù)來說不可能只執(zhí)行其中的一部分。 - 一致性 consistency
數(shù)據(jù)庫總是從一個(gè)一致性的狀態(tài)轉(zhuǎn)換到另一個(gè)一致性的狀態(tài)。 - 隔離性 isolation
針對(duì)并發(fā)事務(wù)而言,隔離性就是要隔離并發(fā)運(yùn)行的多個(gè)事務(wù)之間的相互影響,一般來說一個(gè)事務(wù)所做的 修改在最終提交以前,對(duì)其他事務(wù)是不可?的。 - 持久性 durability 一旦事務(wù)提交成功,其修改就會(huì)永久保存到數(shù)據(jù)庫中,此時(shí)即使系統(tǒng)崩潰,修改的數(shù)據(jù)也不會(huì)丟失。
Q7:MySQL 的隔離級(jí)別有哪些?
- 未提交讀 READ UNCOMMITTED
在該級(jí)別事務(wù)中的修改即使沒有被提交,對(duì)其他事務(wù)也是可?的。事務(wù)可以讀取其他事務(wù)修改完但未提 交的數(shù)據(jù),這種問題稱為臟讀。這個(gè)級(jí)別還會(huì)導(dǎo)致不可重復(fù)讀和幻讀,性能沒有比其他級(jí)別好很多,很 少使用。 - 提交讀 READ COMMITTED
多數(shù)數(shù)據(jù)庫系統(tǒng)默認(rèn)的隔離級(jí)別。提交讀滿足了隔離性的簡單定義:一個(gè)事務(wù)開始時(shí)只能"看?"已經(jīng)提 交的事務(wù)所做的修改。換句話說,一個(gè)事務(wù)從開始直到提交之前的任何修改對(duì)其他事務(wù)都是不可?的。 也叫不可重復(fù)讀,因?yàn)閮纱螆?zhí)行同樣的查詢可能會(huì)得到不同結(jié)果。 - 可重復(fù)讀 REPEATABLE READ(MySQL默認(rèn)的隔離級(jí)別)
可重復(fù)讀解決了不可重復(fù)讀的問題,保證了在同一個(gè)事務(wù)中多次讀取同樣的記錄結(jié)果一致。但還是無法 解決幻讀,所謂幻讀指的是當(dāng)某個(gè)事務(wù)在讀取某個(gè)范圍內(nèi)的記錄時(shí),會(huì)產(chǎn)生幻行。InnoDB 存儲(chǔ)引擎通 過多版本并發(fā)控制MVCC 解決幻讀的問題。 - 可串行化 SERIALIZABLE
最高的隔離級(jí)別,通過強(qiáng)制事務(wù)串行執(zhí)行,避免幻讀??纱谢瘯?huì)在讀取的每一行數(shù)據(jù)上都加鎖,可能 導(dǎo)致大量的超時(shí)和鎖爭用的問題。實(shí)際應(yīng)用中很少用到這個(gè)隔離級(jí)別,只有非常需要確保數(shù)據(jù)一致性且 可以接受沒有并發(fā)的情況下才考慮該級(jí)別。
Q8:MVCC 是什么?
MVCC 是多版本并發(fā)控制,在很多情況下避免加鎖,大都實(shí)現(xiàn)了非阻塞的讀操作,寫操作也只鎖定必要
的行。
InnoDB 的MVCC 通過在每行記錄后面保存兩個(gè)隱藏的列來實(shí)現(xiàn),這兩個(gè)列一個(gè)保存了行的創(chuàng)建時(shí)間, 一個(gè)保存行的過期時(shí)間間。不過存儲(chǔ)的不是實(shí)際的時(shí)間值而是系統(tǒng)版本號(hào),每開始一個(gè)新的事務(wù)系統(tǒng)版 本號(hào)都會(huì)自動(dòng)遞增,事務(wù)開始時(shí)刻的系統(tǒng)版本號(hào)會(huì)作為事務(wù)的版本號(hào),用來和查詢到的每行記錄的版本 號(hào)進(jìn)行比較。
MVCC 只能在 READ COMMITTED 和 REPEATABLE READ 兩個(gè)隔離級(jí)別下工作,因?yàn)?READ UNCOMMITTED 總是讀取最新的數(shù)據(jù)行,而不是符合當(dāng)前事務(wù)版本的數(shù)據(jù)行,而 SERIALIZABLE 則會(huì)對(duì) 所有讀取的行都加鎖。
Q9:談一談 InnoDB
InnoDB 是 MySQL 的默認(rèn)事務(wù)型引擎,用來處理大量短期事務(wù)。InnoDB 的性能和自動(dòng)崩潰恢復(fù)特性使
得它在非事務(wù)型存儲(chǔ)需求中也很流行,除非有特別原因否則應(yīng)該優(yōu)先考慮 InnoDB。
InnoDB 的數(shù)據(jù)存儲(chǔ)在表空間中,表空間由一系列數(shù)據(jù)文件組成。MySQL4.1 后 InnoDB 可以將每個(gè)表
的數(shù)據(jù)和索引放在單獨(dú)的文件中。
InnoDB采用MVCC來支持高并發(fā),并且實(shí)現(xiàn)了四個(gè)標(biāo)準(zhǔn)的隔離級(jí)別。其默認(rèn)級(jí)別是 REPEATABLE READ ,并通過間隙鎖策略防止幻讀,間隙鎖使 InnoDB 不僅僅鎖定查詢涉及的行,還會(huì)對(duì)索引中的間 隙進(jìn)行鎖定防止幻行的插入。
InnoDB 表是基于聚簇索引建立的,InnoDB 的索引結(jié)構(gòu)和其他存儲(chǔ)引擎有很大不同,聚簇索引對(duì)主鍵 查詢有很高的性能,不過它的二級(jí)索引中必須包含主鍵列,所以如果主鍵很大的話其他所有索引都會(huì)很
大,因此如果表上索引較多的話主鍵應(yīng)當(dāng)盡可能小。
InnoDB 的存儲(chǔ)格式是平***立的,可以將數(shù)據(jù)和索引文件從一個(gè)平臺(tái)復(fù)制到另一個(gè)平臺(tái)。
InnoDB 內(nèi)部做了很多優(yōu)化,包括從磁盤讀取數(shù)據(jù)時(shí)采用的可預(yù)測性預(yù)讀,能夠自動(dòng)在內(nèi)存中創(chuàng)建加速 讀操作的自適應(yīng)哈希索引,以及能夠加速插入操作的插入緩沖區(qū)等。
Q10:談一談 MyISAM
MySQL5.1及之前,MyISAM 是默認(rèn)存儲(chǔ)引擎,MyISAM 提供了大量的特性,包括全文索引、壓縮、空
間函數(shù)等,但不支持事務(wù)和行鎖,最大的缺陷就是崩潰后無法安全恢復(fù)。對(duì)于只讀的數(shù)據(jù)或者表比較 小、可以忍受修復(fù)操作的情況仍然可以使用 MyISAM。
MyISAM 將表存儲(chǔ)在數(shù)據(jù)文件和索引文件中,分別以 .MYD 和 .MYI 作為擴(kuò)展名。MyISAM 表可以包 含動(dòng)態(tài)或者靜態(tài)行,MySQL 會(huì)根據(jù)表的定義決定行格式。MyISAM 表可以存儲(chǔ)的行記錄數(shù)一般受限于 可用磁盤空間或者操作系統(tǒng)中單個(gè)文件的最大尺寸。
MyISAM 對(duì)整張表進(jìn)行加鎖,讀取時(shí)會(huì)對(duì)需要讀到的所有表加共享鎖,寫入時(shí)則對(duì)表加排它鎖。但是在 表有讀取查詢的同時(shí),也支持并發(fā)往表中插入新的記錄。
對(duì)于MyISAM 表,MySQL 可以手動(dòng)或自動(dòng)執(zhí)行檢查和修復(fù)操作,這里的修復(fù)和事務(wù)恢復(fù)以及崩潰恢復(fù) 的概念不同。執(zhí)行表的修復(fù)可能導(dǎo)致一些數(shù)據(jù)丟失,而且修復(fù)操作很慢。
對(duì)于 MyISAM 表,即使是 BLOB 和 TEXT 等?字段,也可以基于其前 500 個(gè)字符創(chuàng)建索引。MyISAM 也支持全文索引,這是一種基于分詞創(chuàng)建的索引,可以支持復(fù)雜的查詢。
MyISAM 設(shè)計(jì)簡單,數(shù)據(jù)以緊密格式存儲(chǔ),所以在某些場景下性能很好。MyISAM 最典型的性能問題還 是表鎖問題,如果所有的查詢?期處于 Locked 狀態(tài),那么原因毫無疑問就是表鎖。
Q11:談一談 Memory
如果需要快速訪問數(shù)據(jù)且這些數(shù)據(jù)不會(huì)被修改,重啟以后丟失也沒有關(guān)系,那么使用 Memory 表是非 常有用的。Memory 表至少要比 MyISAM 表快一個(gè)數(shù)量級(jí),因?yàn)樗袛?shù)據(jù)都保存在內(nèi)存,不需要磁盤 IO,Memory 表的結(jié)構(gòu)在重啟后會(huì)保留,但數(shù)據(jù)會(huì)丟失。
Memory 表適合的場景:查找或者映射表、緩存周期性聚合數(shù)據(jù)的結(jié)果、保存數(shù)據(jù)分析中產(chǎn)生的中間數(shù) 據(jù)。
Memory 表支持哈希索引,因此查找速度極快。雖然速度很快但還是無法取代傳統(tǒng)的基于磁盤的表, Memory 表使用表級(jí)鎖,因此并發(fā)寫入的性能較低。它不支持 BLOB 和 TEXT 類型的列,并且每行的? 度是固定的,所以即使指定了 VARCHAR 列,實(shí)際存儲(chǔ)時(shí)也會(huì)轉(zhuǎn)換成CHAR,這可能導(dǎo)致部分內(nèi)存的浪 費(fèi)。
如果 MySQL 在執(zhí)行查詢的過程中需要使用臨時(shí)表來保持中間結(jié)果,內(nèi)部使用的臨時(shí)表就是 Memory 表。如果中間結(jié)果太大超出了Memory 表的限制,或者含有 BLOB 或 TEXT 字段,臨時(shí)表會(huì)轉(zhuǎn)換成 MyISAM 表。
Q12:查詢執(zhí)行流程是什么?
簡單來說分為五步:1 客戶端發(fā)送一條查詢給服務(wù)器。2 服務(wù)器先檢查查詢緩存,如果命中了緩存則
立刻返回存儲(chǔ)在緩存中的結(jié)果,否則進(jìn)入下一階段。3 服務(wù)器端進(jìn)行 SQL 解析、預(yù)處理,再由優(yōu)化器 生成對(duì)應(yīng)的執(zhí)行計(jì)劃。4 MySQL 根據(jù)優(yōu)化器生成的執(zhí)行計(jì)劃,調(diào)用存儲(chǔ)引擎的 API 來執(zhí)行查詢。5 將 結(jié)果返回給客戶端。
Q13:VARCHAR 和 CHAR 的區(qū)別?
VARCHAR 用于存儲(chǔ)可變字符串,是最常?的字符串?dāng)?shù)據(jù)類型。它比 CHAR 更節(jié)省空間,因?yàn)樗鼉H使用 必要的空間。VARCHAR 需要 1 或 2 個(gè)額外字節(jié)記錄字符串?度,如果列的最大?度不大于 255 字節(jié)則 只需要 1 字節(jié)。VARCHAR 不會(huì)刪除末尾空格。
VARCHAR 適用場景:字符串列的最大?度比平均?度大很多、列的更新很少、使用了 UTF8 這種復(fù)雜 字符集,每個(gè)字符都使用不同的字節(jié)數(shù)存儲(chǔ)。
CHAR 是定?的,根據(jù)定義的字符串?度分配足夠的空間。CHAR 會(huì)刪除末尾空格。
CHAR 適合存儲(chǔ)很短的字符串,或所有值都接近同一個(gè)?度,例如存儲(chǔ)密碼的 MD5 值。對(duì)于經(jīng)常變更 的數(shù)據(jù),CHAR 也比 VARCHAR更好,因?yàn)槎?的 CHAR 不容易產(chǎn)生碎片。對(duì)于非常短的列,CHAR 在 存儲(chǔ)空間上也更有效率,例如用 CHAR 來存儲(chǔ)只有 Y 和 N 的值只需要一個(gè)字節(jié),但是 VARCHAR 需要 兩個(gè)字節(jié),因?yàn)檫€有一個(gè)記錄?度的額外字節(jié)。
Q14:DATETIME 和 TIMESTAMP 的區(qū)別?
DATETIME 能保存大范圍的值,從 1001~9999 年,精度為秒。把日期和時(shí)間封裝到了一個(gè)整數(shù)中,與 時(shí)區(qū)無關(guān),使用 8 字節(jié)存儲(chǔ)空間。
TIMESTAMP 和 UNIX 時(shí)間戳相同,只使用 4 字節(jié)的存儲(chǔ)空間,范圍比 DATETIME 小得多,只能表示 1970 ~2038 年,并且依賴于時(shí)區(qū)。
Q15:數(shù)據(jù)類型有哪些優(yōu)化策略?
- 更小的通常更好
一般情況下盡量使用可以正確存儲(chǔ)數(shù)據(jù)的最小數(shù)據(jù)類型,更小的數(shù)據(jù)類型通常也更快,因?yàn)樗鼈冋加酶?少的磁盤、內(nèi)存和 CPU 緩存。 - 盡可能簡單
簡單數(shù)據(jù)類型的操作通常需要更少的 CPU 周期,例如整數(shù)比字符操作代價(jià)更低,因?yàn)樽址托?duì)規(guī) 則使字符相比整形更復(fù)雜。應(yīng)該使用 MySQL 的內(nèi)建類型 date、time 和 datetime 而不是字符串來存儲(chǔ)
日期和時(shí)間,另一點(diǎn)是應(yīng)該使用整形存儲(chǔ) IP 地址。 - 盡量避免 NULL
通常情況下最好指定列為 NOT NULL,除非需要存儲(chǔ) NULL值。因?yàn)槿绻樵冎邪蔀?NULL 的列對(duì) MySQL 來說更難優(yōu)化,可為 NULL 的列使索引、索引統(tǒng)計(jì)和值比較都更復(fù)雜,并且會(huì)使用更多存儲(chǔ)空 間。當(dāng)可為 NULL 的列被索引時(shí),每個(gè)索引記錄需要一個(gè)額外字節(jié),在MyISAM 中還可能導(dǎo)致固定大小 的索引變成可變大小的索引。
如果計(jì)劃在列上建索引,就應(yīng)該盡量避免設(shè)計(jì)成可為 NULL 的列。
Q16:索引有什么作用?
索引也叫鍵,是存儲(chǔ)引擎用于快速找到記錄的一種數(shù)據(jù)結(jié)構(gòu)。索引對(duì)于良好的性能很關(guān)鍵,尤其是當(dāng)表 中數(shù)據(jù)量越來越大時(shí),索引對(duì)性能的影響愈發(fā)重要。在數(shù)據(jù)量較小且負(fù)載較低時(shí),不恰當(dāng)?shù)乃饕龑?duì)性能 的影響可能還不明顯,但數(shù)據(jù)量逐漸增大時(shí),性能會(huì)急劇下降。
索引大大減少了服務(wù)器需要掃描的數(shù)據(jù)量、可以幫助服務(wù)器避免排序和臨時(shí)表、可以將隨機(jī) IO 變成順
序 IO。但索引并不總是最好的工具,對(duì)于非常小的表,大部分情況下會(huì)采用全表掃描。對(duì)于中到大型的表, 索引就非常有效。但對(duì)于特大型的表,建立和使用索引的代價(jià)也隨之增?,這種情況下應(yīng)該使用分 區(qū)技 術(shù)。
在MySQL中,首先在索引中找到對(duì)應(yīng)的值,然后根據(jù)匹配的索引記錄找到對(duì)應(yīng)的數(shù)據(jù)行。索引可以包括 一個(gè)或多個(gè)列的值,如果索引包含多個(gè)列,那么列的順序也十分重要,因?yàn)?MySQL 只能使用索引的最 左前綴。
Q17:談一談 MySQL 的 B-Tree 索引
大多數(shù) MySQL 引擎都支持這種索引,但底層的存儲(chǔ)引擎可能使用不同的存儲(chǔ)結(jié)構(gòu),例如 NDB 使用 T- Tree,而 InnoDB 使用 B+ Tree。
B-Tree 通常意味著所有的值都是按順序存儲(chǔ)的,并且每個(gè)葉子?到根的距離相同。B-Tree 索引能夠加 快訪問數(shù)據(jù)的速度,因?yàn)榇鎯?chǔ)引擎不再需要進(jìn)行全表掃描來獲取需要的數(shù)據(jù),取而代之的是從索引的根 節(jié)點(diǎn)開始進(jìn)行搜索。根節(jié)點(diǎn)的槽中存放了指向子節(jié)點(diǎn)的指針,存儲(chǔ)引擎根據(jù)這些指針向下層查找。通過 比較節(jié)點(diǎn)?的值和要查找的值可以找到合適的指針進(jìn)入下層子節(jié)點(diǎn),這些指針實(shí)際上定義了子節(jié)點(diǎn)?中 值的上限和下限。最終存儲(chǔ)引擎要么找到對(duì)應(yīng)的值,要么該記錄不存在。葉子節(jié)點(diǎn)的指針指向的是被索 引的數(shù)據(jù),而不是其他的節(jié)點(diǎn)?。
B-Tree索引的限制:
如果不是按照索引的最左列開始查找,則無法使用索引。
不能跳過索引中的列,例如索引為 (id,name,sex),不能只使用 id 和 sex 而跳過 name。
如果查詢中有某個(gè)列的范圍查詢,則其右邊的所有列都無法使用索引。
Q18:了解 Hash 索引嗎?
哈希索引基于哈希表實(shí)現(xiàn),只有精確匹配索引所有列的查詢才有效。對(duì)于每一行數(shù)據(jù),存儲(chǔ)引擎都會(huì)對(duì) 所有的索引列計(jì)算一個(gè)哈希碼,哈希碼是一個(gè)較小的值,并且不同鍵值的行計(jì)算出的哈希碼也不一樣。 哈希索引將所有的哈希碼存儲(chǔ)在索引中,同時(shí)在哈希表中保存指向每個(gè)數(shù)據(jù)行的指針。
只有 Memory 引擎顯式支持哈希索引,這也是 Memory 引擎的默認(rèn)索引類型。 因?yàn)樗饕陨碇恍璐鎯?chǔ)對(duì)應(yīng)的哈希值,所以索引的結(jié)構(gòu)十分緊湊,這讓哈希索引的速度非???,但它也
有一些限制:
哈希索引數(shù)據(jù)不是按照索引值順序存儲(chǔ)的,無法用于排序。 哈希索引不支持部分索引列匹配查找,因?yàn)楣K饕冀K是使用索引列的全部內(nèi)容來計(jì)算哈希值 的。例如在數(shù)據(jù)列(a,b)上建立哈希索引,如果查詢的列只有a就無法使用該索引。
哈希索引只支持等值比較查詢,不支持任何范圍查詢。
Q19:什么是自適應(yīng)哈希索引?
自適應(yīng)哈希索引是 InnoDB 引擎的一個(gè)特殊功能,當(dāng)它注意到某些索引值被使用的非常頻繁時(shí),會(huì)在內(nèi) 存中基于 B-Tree 索引之上再創(chuàng)鍵一個(gè)哈希索引,這樣就讓 B-Tree 索引也具有哈希索引的一些優(yōu)點(diǎn),比 如快速哈希查找。這是一個(gè)完全自動(dòng)的內(nèi)部行為,用戶無法控制或配置,但如果有必要可以關(guān)閉該功 能。
Q20 :什么是空間索引?
MyISAM 表支持空間索引,可以用作地理數(shù)據(jù)存儲(chǔ)。和 B-Tree 索引不同,這類索引無需前綴查詢???間索引會(huì)從所有維度來索引數(shù)據(jù),查詢時(shí)可以有效地使用任意維度來組合查詢。必須使用 MySQL 的 GIS 即地理信息系統(tǒng)的相關(guān)函數(shù)來維護(hù)數(shù)據(jù),但 MySQL 對(duì) GIS 的支持并不完善,因此大部分人都不會(huì) 使用這個(gè)特性。
Q21:什么是全文索引? 通過數(shù)值比較、范圍過濾等就可以完成絕大多數(shù)需要的查詢,但如果希望通過關(guān)鍵字匹配進(jìn)行查詢,就
需要基于相似度的查詢,而不是精確的數(shù)值比較,全文索引就是為這種場景設(shè)計(jì)的。
MyISAM 的全文索引是一種特殊的 B-Tree 索引,一共有兩層。第一層是所有關(guān)鍵字,然后對(duì)于每一個(gè) 關(guān)鍵字的第二層,包含的是一組相關(guān)的"文檔指針"。全文索引不會(huì)索引文檔對(duì)象中的所有詞語,它會(huì)根 據(jù)規(guī)則過濾掉一些詞語,例如停用詞列表中的詞都不會(huì)被索引。
Q22:什么是聚簇索引?
聚簇索引不是一種索引類型,而是一種數(shù)據(jù)存儲(chǔ)方式。InnoDB 的聚簇索引實(shí)際上在同一個(gè)結(jié)構(gòu)中保存 了 B-Tree 索引和數(shù)據(jù)行。當(dāng)表有聚餐索引時(shí),它的行數(shù)據(jù)實(shí)際上存放在索引的葉子?中,因?yàn)闊o法同 時(shí)把數(shù)據(jù)行存放在兩個(gè)不同的地方,所以一個(gè)表只能有一個(gè)聚簇索引。
優(yōu)點(diǎn):1 可以把相關(guān)數(shù)據(jù)保存在一起。2 數(shù)據(jù)訪問更快,聚簇索引將索引和數(shù)據(jù)保存在同一個(gè) B-Tree 中,因此獲取數(shù)據(jù)比非聚簇索引要更快。3 使用覆蓋索引掃描的查詢可以直接使用?節(jié)點(diǎn)中的主鍵值。
缺點(diǎn):1 聚簇索引最大限度提高了 IO 密集型應(yīng)用的性能,如果數(shù)據(jù)全部在內(nèi)存中將會(huì)失去優(yōu)勢。2 更 新聚簇索引列的代價(jià)很高,因?yàn)闀?huì)強(qiáng)制每個(gè)被更新的行移動(dòng)到新位置。3 基于聚簇索引的表插入新行或主 鍵被更新導(dǎo)致行移動(dòng)時(shí),可能導(dǎo)致?分裂,表會(huì)占用更多磁盤空間。4 當(dāng)行稀疏或由于?分裂導(dǎo)致數(shù)據(jù)存 儲(chǔ)不連續(xù)時(shí),全表掃描可能很慢。
Q23:什么是覆蓋索引?
覆蓋索引指一個(gè)索引包含或覆蓋了所有需要查詢的字段的值,不再需要根據(jù)索引回表查詢數(shù)據(jù)。覆蓋索
引必須要存儲(chǔ)索引列的值,因此 MySQL 只能使用 B-Tree 索引做覆蓋索引。
優(yōu)點(diǎn):1 索引條目通常遠(yuǎn)小于數(shù)據(jù)行大小,可以極大減少數(shù)據(jù)訪問量。2 因?yàn)樗饕凑樟兄淀樞虼鎯?chǔ), 所以對(duì)于 IO 密集型防偽查詢回避隨機(jī)從磁盤讀取每一行數(shù)據(jù)的 IO 少得多。3 由于 InnoDB 使用聚簇 索引,覆蓋索引對(duì) InnoDB 很有幫助。InnoDB 的二級(jí)索引在葉子節(jié)點(diǎn)保存了行的主鍵值,如果二級(jí)主 鍵能覆蓋查詢那么可以避免對(duì)主鍵索引的二次查詢。
Q24:你知道哪些索引使用原則?
- 建立索引
對(duì)查詢頻次較高且數(shù)據(jù)量比較大的表建立索引。索引字段的選擇,最佳候選列應(yīng)當(dāng)從 WHERE 子句的條 件中提取,如果 WHERE 子句中的組合比較多,應(yīng)當(dāng)挑選最常用、過濾效果最好的列的組合。業(yè)務(wù)上具 有唯一特性的字段,即使是多個(gè)字段的組合,也必須建成唯一索引。 - 使用前綴索引
索引列開始的部分字符,索引創(chuàng)建后也是使用硬盤來存儲(chǔ)的,因此短索引可以提升索引訪問的 IO 效率。 對(duì)于 BLOB、TEXT 或很?的 VARCHAR 列必須使用前綴索引,MySQL 不允許索引這些列的完整?度。 前綴索引是一種能使索引更小更快的有效方法,但缺點(diǎn)是 MySQL 無法使用前綴索引做 ORDER BY 和 GROUP BY,也無法使用前綴索引做覆蓋掃描。 - 選擇合適的索引順序
當(dāng)不需要考慮排序和分組時(shí),將選擇性最高的列放在前面。索引的選擇性是指不重復(fù)的索引值和數(shù)據(jù)表 的記錄總數(shù)之比,索引的選擇性越高則查詢效率越高,唯一索引的選擇性是 1,因此也可以使用唯一索引 提升查詢效率。 - 刪除無用索引
MySQL 允許在相同列上創(chuàng)建多個(gè)索引,重復(fù)的索引需要單獨(dú)維護(hù),并且優(yōu)化器在優(yōu)化查詢時(shí)也需要逐 個(gè)考慮,這會(huì)影響性能。重復(fù)索引是指在相同的列上按照相同的順序創(chuàng)建的相同類型的索引,應(yīng)該避免 創(chuàng)建重復(fù)索引。如果創(chuàng)建了索引 (A,B) 再創(chuàng)建索引 (A) 就是冗余索引,因?yàn)檫@只是前一個(gè)索引的前綴索 引,對(duì)于 B-Tree 索引來說是冗余的。解決重復(fù)索引和冗余索引的方法就是刪除這些索引。除了重復(fù)索 引和冗余索引,可能還會(huì)有一些服務(wù)器永遠(yuǎn)不用的索引,也應(yīng)該考慮刪除。
Q25:索引失效的情況有哪些?
如果索引列出現(xiàn)了隱式類型轉(zhuǎn)換,則 MySQL 不會(huì)使用索引。常?的情況是在 SQL 的 WHERE 條件中字
段類型為字符串,其值為數(shù)值,如果沒有加引號(hào)那么 MySQL 不會(huì)使用索引。
如果 WHERE 條件中含有 OR,除非 OR 前使用了索引列而 OR 之后是非索引列,索引會(huì)失效。
MySQL 不能在索引中執(zhí)行 LIKE 操作,這是底層存儲(chǔ)引擎 API 的限制,最左匹配的 LIKE 比較會(huì)被轉(zhuǎn)換 為簡單的比較操作,但如果是以通配符開頭的 LIKE 查詢,存儲(chǔ)引擎就無法做比較。這種情況下 MySQL 只能提取數(shù)據(jù)行的值而不是索引值來做比較。
如果查詢中的列不是獨(dú)立的,則 MySQL 不會(huì)使用索引。獨(dú)立的列是指索引列不能是表達(dá)式的一部分, 也不能是函數(shù)的參數(shù)。
對(duì)于多個(gè)范圍條件查詢,MySQL 無法使用第一個(gè)范圍列后面的其他索引列,對(duì)于多個(gè)等值查詢則沒有 這種限制。
如果 MySQL 判斷全表掃描比使用索引查詢更快,則不會(huì)使用索引。
索引文件具有 B-Tree 的最左前綴匹配特性,如果左邊的值未確定,那么無法使用此索引。
Q26:如何定位低效 SQL?
可以通過兩種方式來定位執(zhí)行效率較低的 SQL 語句。一種是通過慢查詢?nèi)罩径ㄎ?,可以通過慢查詢?nèi)罩?定位那些已經(jīng)執(zhí)行完畢的 SQL 語句。另一種是使用 SHOW PROCESSLIST 查詢,慢查詢?nèi)罩驹诓樵兘Y(jié)束 以后才記錄,所以在應(yīng)用反應(yīng)執(zhí)行效率出現(xiàn)問題的時(shí)候查詢慢查詢?nèi)罩静荒芏ㄎ粏栴},此時(shí)可以使用 SHOW PROCESSLIST 命令查看當(dāng)前 MySQL 正在進(jìn)行的線程,包括線程的狀態(tài)、是否鎖表等,可以實(shí)時(shí) 查看 SQL 的執(zhí)行情況,同時(shí)對(duì)一些鎖表操作進(jìn)行優(yōu)化。找到執(zhí)行效率低的 SQL 語句后,就可以通過 SHOW PROFILE、EXPLAIN 或 trace 等豐富來繼續(xù)優(yōu)化語句。
Q27:SHOW PROFILE 的作用?
通過 SHOW PROFILE 可以分析 SQL 語句性能消耗,例如查詢到 SQL 會(huì)執(zhí)行多少時(shí)間,并顯示 CPU、
內(nèi)存使用量,執(zhí)行過程中系統(tǒng)鎖及表鎖的花費(fèi)時(shí)間等信息。例如SHOW PROFILE CPU/MEMORY/BLOCK
IO FOR QUERY N 分別查詢 id 為 N 的 SQL 語句的 CPU、內(nèi)存以及 IO 的消耗情況。
Q28:trace 是干什么的?
從 MySQL5.6 開始,可以通過 trace 文件進(jìn)一步獲取優(yōu)化器是是如何選擇執(zhí)行計(jì)劃的,在使用時(shí)需要先 打開設(shè)置,然后執(zhí)行一次 SQL,最后查看 information_schema.optimizer_trace 表而都內(nèi)容,該表為 聯(lián)合i表,只能在當(dāng)前會(huì)話進(jìn)行查詢,每次查詢后返回的都是最近一次執(zhí)行的 SQL 語句。
Q29:EXPLAIN 的字段有哪些,具有什么含義?
執(zhí)行計(jì)劃是 SQL 調(diào)優(yōu)的一個(gè)重要依據(jù),可以通過 EXPLAIN 命令查看 SQL 語句的執(zhí)行計(jì)劃,如果作用在 表上,那么該命令相當(dāng)于 DESC。EXPLAIN 的指標(biāo)及含義如下:
指標(biāo)名 | 含義 |
---|---|
id | 表示 SELECT 子句或操作表的順序,執(zhí)行順序從大到小執(zhí)行,當(dāng) id 一樣時(shí),執(zhí) 行順序從上往下。 |
select_type | 表示查詢中每個(gè) SELECT 子句的類型,例如 SIMPLE 表示不包含子查詢、表連接 或其他復(fù)雜語法的簡單查詢,PRIMARY 表示復(fù)雜查詢的最外層查詢, SUBQUERY 表示在 SELECT 或 WHERE 列表中包含了子查詢。 |
type | 表示訪問類型,性能由差到好為:ALL 全表掃描、index 索引全掃描、range 索 引范圍掃描、ref 返回匹配某個(gè)單獨(dú)值得所有行,常?于使用非唯一索引或唯一 索引的非唯一前綴進(jìn)行的查找,也經(jīng)常出現(xiàn)在 join 操作中、eq_ref 唯一性索引 掃描,對(duì)于每個(gè)索引鍵只有一條記錄與之匹配、const 當(dāng) MySQL 對(duì)查詢某部分 進(jìn)行優(yōu)化,并轉(zhuǎn)為一個(gè)常量時(shí),使用這些訪問類型,例如將主鍵或唯一索引置 于 WHERE 列表就能將該查詢轉(zhuǎn)為一個(gè) const、system 表中只有一行數(shù)據(jù)或空 表,只能用于 MyISAM 和 Memory 表、NULL 執(zhí)行時(shí)不用訪問表或索引就能得 到結(jié)果。SQL 性能優(yōu)化的目標(biāo):至少要達(dá)到 range 級(jí)別,要求是 ref 級(jí)別,如 果可以是consts 最好。 |
possible_keys | 表示查詢時(shí)可能用到的索引,但不一定使用。列出大量可能索引時(shí)意味著備選 索引數(shù)量太多了。 |
key | 顯示 MySQL 在查詢時(shí)實(shí)際使用的索引,如果沒有使用則顯示為 NULL。 |
key_len | 表示使用到索引字段的?度,可通過該列計(jì)算查詢中使用的索引的?度,對(duì)于 確認(rèn)索引有效性以及多列索引中用到的列數(shù)目很重要。 |
ref | 表示上述表的連接匹配條件,即哪些列或常量被用于查找索引列上的值。 |
rows | 表示 MySQL 根據(jù)表統(tǒng)計(jì)信息及索引選用情況,估算找到所需記錄所需要讀取的 行數(shù)。 |
Extra | 表示額外信息,例如 Using temporary 表示需要使用臨時(shí)表存儲(chǔ)結(jié)果集,常? 于排序和分組查詢。Using filesort 表示無法利用索引完成的文件排序,這是 ORDER BY 的結(jié)果,可以通過合適的索引改進(jìn)性能。Using index 表示只需要使用索引就可以滿足查詢表得要求,說明表正在使用覆蓋索引。 |
Q30:有哪些優(yōu)化 SQL 的策略?
- 優(yōu)化 COUNT 查詢
COUNT 是一個(gè)特殊的函數(shù),它可以統(tǒng)計(jì)某個(gè)列值的數(shù)量,在統(tǒng)計(jì)列值時(shí)要求列值是非空的,不會(huì)統(tǒng)計(jì) NULL 值。如果在 COUNT 中指定了列或列的表達(dá)式,則統(tǒng)計(jì)的就是這個(gè)表達(dá)式有值的結(jié)果數(shù),而不是 NULL。
COUNT 的另一個(gè)作用是統(tǒng)計(jì)結(jié)果集的行數(shù),當(dāng) MySQL 確定括號(hào)內(nèi)的表達(dá)式不可能為 NULL 時(shí),實(shí)際 上就是在統(tǒng)計(jì)行數(shù)。當(dāng)使用 COUNT() 時(shí), 不會(huì)擴(kuò)展成所有列,它會(huì)忽略所有的列而直接統(tǒng)計(jì)所有的
行數(shù)。
某些業(yè)務(wù)場景并不要求完全精確的 COUNT 值,此時(shí)可以使用近似值來代替,EXPLAIN 出來的優(yōu)化器估 算的行數(shù)就是一個(gè)不錯(cuò)的近似值,因?yàn)閳?zhí)行 EXPLAIN 并不需要真正地執(zhí)行查詢。
通常來說 COUNT 都需要掃描大量的行才能獲取精確的結(jié)果,因此很難優(yōu)化。在 MySQL 層還能做的就 只有覆蓋掃描了,如果還不夠就需要修改應(yīng)用的架構(gòu),可以增加匯總表或者外部緩存系統(tǒng)。 - 優(yōu)化關(guān)聯(lián)查詢
確保 ON 或 USING 子句中的列上有索引,在創(chuàng)建索引時(shí)就要考慮到關(guān)聯(lián)的順序。
確保任何 GROUP BY 和 ORDER BY 的表達(dá)式只涉及到一個(gè)表中的列,這樣 MySQL 才有可能使用索引
來優(yōu)化這個(gè)過程。
在 MySQL 5.5 及以下版本盡量避免子查詢,可以用關(guān)聯(lián)查詢代替,因?yàn)閳?zhí)行器會(huì)先執(zhí)行外部的 SQL 再
執(zhí)行內(nèi)部的 SQL。 - 優(yōu)化 GROUP BY
如果沒有通過 ORDER BY 子句顯式指定要排序的列,當(dāng)查詢使用 GROUP BY 時(shí),結(jié)果***自動(dòng)按照分組 的字段進(jìn)行排序,如果不關(guān)心結(jié)果集的順序,可以使用 ORDER BY NULL 禁止排序。 - 優(yōu)化 LIMIT 分?
在偏移量非常大的時(shí)候,需要查詢很多條數(shù)據(jù)再舍棄,這樣的代價(jià)非常高。要優(yōu)化這種查詢,要么是在 ?面中限制分?的數(shù)量,要么是優(yōu)化大偏移量的性能。最簡單的辦法是盡可能地使用覆蓋索引掃描,而 不是查詢所有的列,然后根據(jù)需要做一次關(guān)聯(lián)操作再返回所需的列。
還有一種方法是從上一次取數(shù)據(jù)的位置開始掃描,這樣就可以避免使用 OFFSET。其他優(yōu)化方法還包括 使用預(yù)先計(jì)算的匯總表,或者關(guān)聯(lián)到一個(gè)冗余表,冗余表只包含主鍵列和需要做排序的數(shù)據(jù)列。 - 優(yōu)化 UNION 查詢
MySQL 通過創(chuàng)建并填充臨時(shí)表的方式來執(zhí)行 UNION 查詢,除非確實(shí)需要服務(wù)器消除重復(fù)的行,否則一 定要使用 UNION ALL,如果沒有 ALL 關(guān)鍵字,MySQL 會(huì)給臨時(shí)表加上 DISTINCT 選項(xiàng),這會(huì)導(dǎo)致對(duì)整 個(gè)臨時(shí)表的數(shù)據(jù)做唯一性檢查,這樣做的代價(jià)非常高。 - 使用用戶自定義變量
在查詢中混合使用過程化和關(guān)系化邏輯的時(shí)候,自定義變量可能會(huì)非常有用。用戶自定義變量是一個(gè)用 來存儲(chǔ)內(nèi)容的臨時(shí)容器,在連接 MySQL 的整個(gè)過程中都存在,可以在任何可以使用表達(dá)式的地方使用
自定義變量。例如可以使用變量來避免重復(fù)查詢剛剛更新過的數(shù)據(jù)、統(tǒng)計(jì)更新和插入的數(shù)量等。 - 優(yōu)化 INSERT
需要對(duì)一張表插入很多行數(shù)據(jù)時(shí),應(yīng)該盡量使用一次性插入多個(gè)值的 INSERT 語句,這種方式將縮減客
戶端與數(shù)據(jù)庫之間的連接、關(guān)閉等消耗,效率比多條插入單個(gè)值的 INSERT 語句高。也可以關(guān)閉事務(wù)的 自動(dòng)提交,在插入完數(shù)據(jù)后提交。當(dāng)插入的數(shù)據(jù)是按主鍵的順序插入時(shí),效率更高。
Q31:MySQL 主從復(fù)制的作用?
復(fù)制解決的基本問題是讓一臺(tái)服務(wù)器的數(shù)據(jù)與其他服務(wù)器保持同步,一臺(tái)主庫的數(shù)據(jù)可以同步到多臺(tái)備 庫上,備庫本身也可以被配置成另外一臺(tái)服務(wù)器的主庫。主庫和備庫之間可以有多種不同的組合方式。
MySQL 支持兩種復(fù)制方式:基于行的復(fù)制和基于語句的復(fù)制,基于語句的復(fù)制也稱為邏輯復(fù)制,從 MySQL 3.23 版本就已存在,基于行的復(fù)制方式在 5.1 版本才被加進(jìn)來。這兩種方式都是通過在主庫上 記錄二進(jìn)制日志、在備庫重放日志的方式來實(shí)現(xiàn)異步的數(shù)據(jù)復(fù)制。因此同一時(shí)刻備庫的數(shù)據(jù)可能與主庫 存在不一致,并且無法包裝主備之間的延遲。
MySQL 復(fù)制大部分是向后兼容的,新版本的服務(wù)器可以作為老版本服務(wù)器的備庫,但是老版本不能作 為新版本服務(wù)器的備庫,因?yàn)樗赡軣o法解析新版本所用的新特性或語法,另外所使用的二進(jìn)制文件格 式也可能不同。
復(fù)制解決的問題:數(shù)據(jù)分布、負(fù)載均衡、備份、高可用性和故障切換、MySQL 升級(jí)測試。
Q32:MySQL 主從復(fù)制的步驟?
1 在主庫上把數(shù)據(jù)更改記錄到二進(jìn)制日志中。 2 備庫將主庫的日志復(fù)制到自己的中繼日志中。 3 備庫讀 取中繼日志中的事件,將其重放到備庫數(shù)據(jù)之上。
第一步是在主庫上記錄二進(jìn)制日志,每次準(zhǔn)備提交事務(wù)完成數(shù)據(jù)更新前,主庫將數(shù)據(jù)更新的事件記錄到 二進(jìn)制日志中。MySQL 會(huì)按事務(wù)提交的順序而非每條語句的執(zhí)行順序來記錄二進(jìn)制日志,在記錄二進(jìn) 制日志后,主庫會(huì)告訴存儲(chǔ)引擎可以提交事務(wù)了。
下一步,備庫將主庫的二進(jìn)制日志復(fù)制到其本地的中繼日志中。備庫首先會(huì)啟動(dòng)一個(gè)工作的 IO 線程, IO 線程跟主庫建立一個(gè)普通的客戶端連接,然后在主庫上啟動(dòng)一個(gè)特殊的二進(jìn)制轉(zhuǎn)儲(chǔ)線程,這個(gè)線程會(huì)讀 取主庫上二進(jìn)制日志中的事件。它不會(huì)對(duì)事件進(jìn)行輪詢。如果該線程追趕上了主庫將進(jìn)入睡眠狀態(tài), 直 到主庫發(fā)送信號(hào)量通知其有新的事件產(chǎn)生時(shí)才會(huì)被喚醒,備庫 IO 線程會(huì)將接收到的事件記錄到中繼
日志中。
備庫的 SQL 線程執(zhí)行最后一步,該線程從中繼日志中讀取事件并在備庫執(zhí)行,從而實(shí)現(xiàn)備庫數(shù)據(jù)的更 新。當(dāng) SQL 線程追趕上 IO 線程時(shí),中繼日志通常已經(jīng)在系統(tǒng)緩存中,所以中繼日志的開銷很低。SQL 線程執(zhí)行的時(shí)間也可以通過配置選項(xiàng)來決定是否寫入其自己的二進(jìn)制日志中。文章來源:http://www.zghlxwxcb.cn/news/detail-588671.html
寫在最后
希望博主收集的內(nèi)容能幫到大家,祝大家能找到一個(gè)好的工作,過好的生活,如有錯(cuò)誤歡迎指正。 ??????文章來源地址http://www.zghlxwxcb.cn/news/detail-588671.html
到了這里,關(guān)于金九銀十面試題之《Mysql》的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!