本文做者 TomorrowWu,原創文章,轉載註明出處,博客地址 https://segmentfault.com/u/to... 第一時間看後續精彩文章。以爲好的話,順手分享到朋友圈吧,感謝支持。mysql
筆者最近在準備面試,以爲學習最好的方式就是把知道的東西經過博客寫出來,一方面考察本身對某個知識點的理解,一方面督促本身查閱更多資料深刻學習面試
我會總結出我在網上看到的面試題以及相應的答案,而且儘量的講原理,有錯誤的地方但願有大神基給予指正,讀者若是有好的題目,也能夠評論中提出,我將後續更新上去,謝謝sql
固然學習MySQL不只僅是看一些面試題,最好仍是看一些相關的書籍,好比比較好的就是<<高性能MySQL>>中文版,很詳細,很厚,還未看完,還有簡朝陽先生的<<MySQL性能調優與架構設計>>一書,當初泛讀了一遍,等待深刻研究中數據庫
1.經常使用的方法是explainSQL查看執行計劃,根據查詢計劃知道是否使用了索引,以及是否進行全表掃描,以及查詢的順序等等全過程,依次咱們能夠創建適當的索引和鏈接查詢調優、SQL語句拆分等segmentfault
2.開啓慢查詢,記錄執行時間長的SQL語句後端
解決方案:
在建立表時,字段儘可能指定默認值,或者設置not null,不要給數據庫留null安全
優化案例服務器
select id from t where num=10 or Name = 'admin' //優化後 select id from t where num = 10 union all select id from t where Name = 'admin'
- 前置模糊索引 like '%abc' 勢必會進行全表掃描; 2. like 'abc%'依舊有可能進行全表掃描,當部分DBMD中返回結果超過該表的80%時,就失去使用索引的意義數據庫會自動改用全表掃描.(例如: where mobile like '1%')
原理:SQL只有在運行時纔會解析局部變量,優化程序必須在編譯時選擇訪問計劃,可是編譯時變量值還未知,所以沒法做爲索引選擇的輸入項網絡
//全表掃描 select id from t where num = @num //強制使用索引 select id from t with(index(索引名)) where num = @num
select id from t where num/2 = 100 //修改成 select id from t where num = 100*2
select id from t where substring(name,1,3) = ’abc’ //修改後 select id from t where name like 'abc%'
引擎在逐個比較字符串中每個字符,對於數字只須要比較一次session
引擎在找到第一個記錄後就中止掃描記錄,而不是遍歷整個表或索引
少許state使用enum,方便遷移數據庫以及維護,使用int和varchar
缺點:級聯查詢
InnoDB,MyISAM,Archive,Blackhole,CSV,Federated,Memory,Merge,NDB集羣引擎等,還有一些第三方存儲引擎
引擎 | 存儲結構 | 存儲空間 | 可移植性、備份及恢復 | 事務支持 | AUTO_INCREMENT | 表鎖差別 | 全文索引 | 表主鍵 | 表的具體行數 | CRUD操做 | 外鍵 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
InnoDB | 全部的表都保存在同一個數據文件中(也多是多個文件,或者是獨立的表空間文件),InnoDB表的大小隻受限於操做系統文件的大小,通常爲2GB | 須要更多的內存和存儲,它會在主內存中創建其專用的緩衝池用於高速緩衝數據和索引 | 免費的方案能夠是拷貝數據文件、備份binlog,或者用mysqldump,在數據量達到幾十G時就相對痛苦了 | 支持事務,外部鍵等高級數據庫功能;具備事務(commit)、回滾(rollback)和崩潰修復能力(crash recovery capabilities)的事務安全型表(transaction-safe ACID compliant) | 必須包含只有該字段的索引;自動增加列必須是索引;若是是組合索引也必須是組合索引的第一列 | 行級鎖;行鎖大幅度提升了多用戶併發操做性能;只有在where的主鍵時有效,非主鍵的where鎖全表 | 5.6.4之後開始支持fulltext類型的全文索引 | 若是沒有設定主鍵或者非空惟一索引,就會自動生成一個6字節的主鍵(用戶不可見),數據是主索引的一部分,附加索引保存的是主索引的值 | 沒有保存表的總行數,若是使用select count() from table;就會遍歷整個表,消耗至關大,可是在加了wehre條件後,myisam和innodb處理的方式都同樣 | 適合大量insert或update;delete從性能上InnoDB更優,但DELETE FROM table時,InnoDB不會從新創建表,而是一行一行的刪除,在innodb上若是要清空保存有大量數據的表,最好使用truncate table這個命令 | 支持外鍵 | |
MyISAM | 在磁盤上存儲成三個文件,第一個文件的名字以表的名字開始,擴展名指出文件類型;.frm文件存儲表定義;數據文件的擴展名爲.MYD(MYData);索引文件的擴展名是.MYI(MYIndex) | 可被壓縮,存儲空間較小;支持三種存儲格式:靜態表(默認,注意數據末尾不能有空格,會被去掉)、動態表、壓縮表 | 數據是以文件的形式存儲,跨平臺的數據轉移中很方便,在備份和恢復時可單獨針對某個表進行操做 | 不支持事務,不支持外鍵;強調性能,每次查詢具備原子性,執行速度比InnoDB快 | 能夠和其餘字段一塊兒創建聯合索引;自動增加列必須是索引,若是是組合索引,自動增加列能夠不是第一列,它能夠根據前面幾列進行排序後遞增 | 表級鎖;select,update,delete,insert語句都會給表自動加鎖,若是加鎖後,表知足insert併發的狀況下,能夠在表尾部插入新數據 | 支持fulltext類型的全文索引 | 容許沒有任何索引和主鍵的表存在,索引都是保存行的地址 | 保存有表的總行數,select count() from table;會直接取出出該值 | 適合有大量select | 不支持外鍵 |
引擎 | 原則 |
---|---|
採用MyISAM引擎 | 1. R/W > 100:1,且update相對較少; 2,併發不高 3, 表數據量小 4, 硬件資源有限 |
採用InnoDB引擎 | 1, R/W比較小,頻繁update大字段 2, 表數據量超過1000萬,併發高 3,安全性和可用性要求高 |
採用Memory引擎 | 1,有足夠的內存 2,對數據一致性要求不高,如在線人數和session等應用3, 須要按期歸檔數據 |
例如電話號碼等字段,空值表示不知道對方的手機號碼,空字符表示後來取消了這個號碼,等等
簡單來講,避免數據量大時掃描過多的記錄
解決方案:
方案 | 具體過程 | 原理 | 缺點 | |
---|---|---|---|---|
基於id分頁 | 帶上前一頁最後一條記錄的id去請求下一頁數據,後端在去MySQL查詢時,where條件加上 id>last_id limit 10,order by id | 能夠少去聚簇索引中拿不少數據,只拿須要的10條 | 須要產品上作一些妥協,沒法進行指定頁的跳轉,加載數據時使用更多按鈕 | |
基於offset(偏移量)分頁 | 先去二級索引中找出知足條件的offset+limit行記錄的id,而後根據id去聚簇索引中找到對應的行記錄,取出offset+limit行數據,最後丟掉offset行,只保留limit行,效率不好 | 由於去聚簇索引中訪問了太多沒必要要的數據 | 效率差 |
優化案例:
select * from news order by id desc limit 1000000,10 耗時7.28秒 //方案1 0.365秒 select * from news where id > (select id from news order by id desc limit 1000000, 1) order by id desc limit 0,10 方案2 ,適合id連續的系統,速度極快 select * from news where id between 1000000 and 1000010 order by id desc
類型 | 如何實現 | 使用場景 | 優勢 | 缺點 | |
---|---|---|---|---|---|
延遲加載 | 分頁SQL拆成兩句,第一句先查詢符合條件的id(查詢的列都在二級索引中,不用訪問聚簇索引中的數據行,效率很高) 第二個sql根據id去聚簇索引拿數據 | 解決offset過大致使的分頁性能問題 | 8s變50ms,避免加載多餘數據,浪費內存,網絡傳輸 | sql語句被屢次發送執行,對DB性能有影響 |
案例:
SELECT * FROM table_A USE INDEX (index_A) WHERE A = xxx AND B = xxx AND C IN (xxx) ORDER BY D DESC LIMIT 33380, 11 KEY `index_A` (`A`,`B`,`D`,`C`) // 延遲加載後: 1. SELECT table_A.id FROM table_A USE INDEX (index_A) WHERE A = xxx AND B = xxx AND C IN (xxx) ORDER BY D DESC LIMIT 33380, 11; 2. Select * from table_A where id in (ids)
慢查詢日誌
一個事務包含多個操做,這些操做要麼所有執行,要麼全都不執行。實現事務的原子性,要支持回滾操做,在某個操做失敗後,回滾到事務執行以前的狀態。
事務使得系統從一個一致的狀態轉換到另外一個一致狀態。事務的一致性決定了一個系統設計和實現的複雜度
程度 | 詳解 |
---|---|
強一致性 | 讀操做能夠當即讀到提交的更新操做 |
弱一致性 | 提交的更新操做,不必定當即會被讀操做讀到 |
最終一致性 | 是弱一致性的特例。事務更新一份數據,最終一致性保證在沒有其餘事務更新一樣的值的話,最終全部的事務都會讀到以前事務更新的最新值 |
單調一致性 | 若是一個進程已經讀到一個值,那麼後續不會讀到更早的值 |
會話一致性 | 保證客戶端和服務器交互的會話過程當中,讀操做能夠讀到更新操做後的最新值 |
併發事務之間互相影響的程度,好比一個事務會不會讀取到另外一個未提交的事務修改的數據
最多見的一個性能問題
舉個例子,咱們數據庫中有兩張表,一個是Customers,一個是Orders。Orders中含有一個外鍵customer_id,指向了Customers的主鍵id,想要獲得全部Customer以及其分別對應的Order
// N+1方式 SELECT * FROM Customers; SELECT * FROM Orders WHERE Orders.customer_id = #{customer.id} //left join SELECT * FROM Customers LEFT JOIN Orders on Customers.id = Orders.customer_id;
前者的讀寫責任分離,責任是根據具體業務來的,讀不只僅是指的數據庫意義上的讀操做,而是根據業務需求,爲複雜業務時的讀操做,專門創建數據庫以供直接讀取去展現界面;後者讀寫分離是針對數據庫層次的,主數據庫寫,從數據庫讀