Java關係型數據庫相關面試題

1、手撕sql
有學生表、課程表、成績表,計算平均成績大於等於60的學生id、學生姓名和平均成績。
select s.s_id,s.s_name,avg(sc.score)
from score sc
left join student s on sc.s_id=s.s_id
group by s.s_id having avg(sc.score>=60)

可能引發問題
(1)幾種join的區別
1).以A,B兩張表爲例
A left join B
選出A的所有記錄,B表中沒有的以null 代替
2).right join 同理
3).inner join
A,B的所有記錄都選出,沒有的記錄以null代替
4).cross join (笛卡爾積)
A中的每一條記錄和B中的每一條記錄生成一條記錄
例如A中有4條,B中有4條,cross join 就有16條記錄
(2)常見覆雜sql的語法格式
select column, group_function(column)
from table
[where condition]
[group by group_by_expression]
[order by column];
where -> group by -> having -> order by -> limit (順序不能錯)

2、Mysql中的索引類型

  • index ---- 普通索引,數據可以重複,沒有任何限制。
  • unique ---- 唯一索引,要求索引列的值必須唯一,但允許有空值;如果是組合索引,那麼列值的組合必須唯一。
  • primary key ---- 主鍵索引,是一種特殊的唯一索引,一個表只能有一個主鍵,不允許有空值,一般是在創建表的同時創建主鍵索引。
  • 組合索引 ---- 在多個字段上創建的索引,只有在查詢條件中使用了創建索引時的第一個字段,索引纔會被使用。
  • fulltext ---- 全文索引,是對於大表的文本域:char,varchar,text列才能創建全文索引,主要用於查找文本中的關鍵字,並不是直接與索引中的值進行比較。fulltext更像是一個搜索引擎,配合match against操作使用,而不是一般的where語句加like。

注:全文索引目前只有MyISAM存儲引擎支持全文索引,InnoDB引擎5.6以下版本還不支持全文索引
  所有存儲引擎對每個表至少支持16個索引,總索引長度至少爲256字節,索引有兩種存儲類型,包括B+樹索引和哈希索引。
  索引可以提高查詢的速度,但是創建和維護索引需要耗費時間,同時也會影響插入的速度,如果需要插入大量的數據時,最好是先刪除索引,插入數據後再建立索引。
3、索引失效條件

  • 不在索引列上做任何操作(計算、函數、(自動or手動)類型轉換),會導致索引失效而轉向全表掃描
  • 存儲引擎不能使用索引範圍條件右邊的列
  • 儘量使用覆蓋索引(只訪問索引的查詢(索引列和查詢列一致)),減少select *
  • mysql在使用不等於(!=或者<>)的時候無法使用索引會導致全表掃描
  • is null,is not null也無法使用索引
  • like以通配符開頭(’%abc…’)mysql索引失效會變成全表掃描的操作。

假設
index(a,b,c)

  • 最左前綴匹配:模糊查詢時,使用%匹配時:’a%‘會使用索引,’%a‘不會使用索引
  • 條件中有or,索引不會生效
  • a and c,a生效,c不生效
  • b and c,都不生效
  • a and b > 5 and c, a和b生效,c不生效。

4、覆蓋索引
參考
5、B+樹索引和hash索引的比較

  • Hash 索引僅僅能滿足"=",“IN"和”<=>"查詢,不能使用範圍查詢。
    由於 Hash 索引比較的是進行 Hash 運算之後的 Hash 值,所以它只能用於等值的過濾,不能用於基於範圍的過濾,因爲經過相應的 Hash 算法處理之後的 Hash 值的大小關係,並不能保證和Hash運算前完全一樣。
  • Hash 索引無法被用來避免數據的排序操作。
    由於 Hash 索引中存放的是經過 Hash 計算之後的 Hash 值,而且Hash值的大小關係並不一定和 Hash 運算前的鍵值完全一樣,所以數據庫無法利用索引的數據來避免任何排序運算;
  • Hash索引不能利用部分索引鍵查詢。
    對於組合索引,Hash 索引在計算 Hash 值的時候是組合索引鍵合併後再一起計算 Hash 值,而不是單獨計算 Hash 值,所以通過組合索引的前面一個或幾個索引鍵進行查詢的時候,Hash 索引也無法被利用。
  • Hash 索引在任何時候都不能避免表掃描。
    前面已經知道,Hash 索引是將索引鍵通過 Hash 運算之後,將 Hash運算結果的 Hash 值和所對應的行指針信息存放於一個 Hash 表中,由於不同索引鍵存在相同 Hash 值,所以即使取滿足某個 Hash 鍵值的數據的記錄條數,也無法從 Hash 索引中直接完成查詢,還是要通過訪問表中的實際數據進行相應的比較,並得到相應的結果。
  • Hash索引遇到大量Hash值相等的情況後性能並不一定就會比B-Tree索引高。
    對於選擇性比較低的索引鍵,如果創建 Hash 索引,那麼將會存在大量記錄指針信息存於同一個 Hash 值相關聯。這樣要定位某一條記錄時就會非常麻煩,會浪費多次表數據的訪問,而造成整體性能低下。

6、索引的底層實現(B+樹,爲何不採用紅黑樹,B樹)
在這裏插入圖片描述
索引使用B+樹的原因:

  • 索引查找過程中就要產生磁盤I/O消耗,主要看IO次數,和磁盤存取原理有關。
  • 根據B-Tree的定義,可知檢索一次最多需要訪問h個節點。數據庫系統的設計者巧妙利用了磁盤預讀原理,將一個節點的大小設爲等於一個頁,這樣每個節點只需要一次I/O就可以完全載入
  • 局部性原理與磁盤預讀

7、Mysql存儲引擎 MyISAM 和 InnoDB
MyISAM存儲引擎的特點是:表級鎖、不支持事務和支持全文索引
InnoDB存儲引擎的特點是:行級鎖、事務安全(ACID兼容)、支持外鍵、不支持FULLTEXT類型的索引(5.6.4以後版本開始支持FULLTEXT類型的索引)。InnoDB存儲引擎提供了具有提交、回滾和崩潰恢復能力的事務安全存儲引擎。InnoDB是爲處理巨大量時擁有最大性能而設計的。它的CPU效率可能是任何其他基於磁盤的關係數據庫引擎所不能匹敵的。
注意:
InnoDB表的行鎖也不是絕對的,假如在執行一個SQL語句時MySQL不能確定要掃描的範圍,InnoDB表同樣會鎖全表(鎖完以後,判斷不符合條件的會逐步解鎖),
例如update table set num=1 where name like “a%”。
適用場景
MyISAM適合:
1). 做很多count 的計算;
2). 插入不頻繁,查詢非常頻繁,如果執行大量的SELECT,MyISAM是更好的選擇;
3). 沒有事務。
InnoDB適合:
1). 可靠性要求比較高,或者要求事務;
2). 表更新和查詢都相當的頻繁,並且表鎖定的機會比較大的情況指定數據引擎的創建;
3). 如果你的數據執行大量的INSERT或UPDATE,出於性能方面的考慮,應該使用InnoDB表;
4).DELETE FROM table時,InnoDB不會重新建立表,而是一行一行的 刪除;
5).LOAD TABLE FROM MASTER操作對InnoDB是不起作用的,解決方法是首先把InnoDB表改成MyISAM表,導入數據後再改成InnoDB表,但是對於使用的額外的InnoDB特性(例如外鍵)的表不適用。

8、數據庫三範式
1)、第一範式:
當關系模式R的所有屬性都不能在分解爲更基本的數據單位時,稱R是滿足第一範式的,簡記爲1NF。滿足第一範式是關係模式規範化的最低要求,否則,將有很多基本操作在這樣的關係模式中實現不了。(屬性的原子性約束,不可在分解)
2)、第二範式:
如果關係模式R滿足第一範式,並且R得所有非主屬性都完全依賴於R的每一個候選關鍵屬性,稱R滿足第二範式,簡記爲2NF。(非主鍵屬性完全依賴於主鍵屬性)
3)、第三範式:
設R是一個滿足第一範式條件的關係模式,X是R的任意屬性集,如果X非傳遞依賴於R的任意一個候選關鍵字,稱R滿足第三範式,簡記爲3NF。(非主鍵屬性不能出現依賴傳遞)

9、事務ACID

  • 原子性(Atomic):不可分割的操作單元,事務中所有操作,要麼全部成功;要麼撤回到執行事務之前的狀態
  • 一致性(Consistency):如果在執行事務之前數據庫是一致的,那麼在執行事務之後數據庫也還是一致的;
  • 隔離性(Isolation):事務操作之間彼此獨立和透明互不影響。事務獨立運行。這通常使用鎖來實現。一個事務處理後的結果,影響了其他事務,那麼其他事務會撤回。事務的100%隔離,需要犧牲速度。
  • 持久性(Durability):事務一旦提交,其結果就是永久的。即便發生系統故障,也能恢復。

10、事務隔離級別

  • 未提交讀(Read Uncommitted):允許髒讀,其他事務只要修改了數據,即使未提交,本事務也能看到修改後的數據值。也就是可能讀取到其他會話中未提交事務修改的數據
  • 提交讀(Read Committed):只能讀取到已經提交的數據。Oracle等多數數據庫默認都是該級別 (不重複讀)。
  • 可重複讀(Repeated Read):可重複讀。無論其他事務是否修改並提交了數據,在這個事務中看到的數據值始終不受其他事務影響。存在幻讀問題
  • 串行讀(Serializable):完全串行化的讀,每次讀都需要獲得表級共享鎖,讀寫相互都會阻塞。

MySQL數據庫(InnoDB引擎)默認使用可重複讀( Repeatable read)
在這裏插入圖片描述
事務併發問題:
1)、髒讀:事務A讀取了事務B更新的數據,然後B回滾操作,那麼A讀取到的數據是髒數據
2)、不可重複讀:事務 A 多次讀取同一數據,事務 B 在事務A多次讀取的過程中,對數據作了更新並提交,導致事務A多次讀取同一數據時,結果 不一致。
3)、幻讀:系統管理員A將數據庫中所有學生的成績從具體分數改爲ABCDE等級,但是系統管理員B就在這個時候插入了一條具體分數的記錄,當系統管理員A改結束後發現還有一條記錄沒有改過來,就好像發生了幻覺一樣,這就叫幻讀。
小結:不可重複讀的和幻讀很容易混淆,不可重複讀側重於修改,幻讀側重於新增或刪除。解決不可重複讀的問題只需鎖住滿足條件的行,解決幻讀需要鎖表
  
11、大表優化

  • 限定數據的範圍: 務必禁止不帶任何限制數據範圍條件的查詢語句。比如:我們當用戶在查詢訂單歷史的時候,我們可以控制在一個月的範圍內。
  • 讀/寫分離: 經典的數據庫拆分方案,主庫負責寫,從庫負責讀;
  • 緩存:使用MySQL的緩存,另外對重量級、更新少的數據可以考慮使用應用級別的緩存;
  • 垂直分區:
    根據數據庫裏面數據表的相關性進行拆分。 例如,用戶表中既有用戶的登錄信息又有用戶的基本信息,可以將用戶表拆分成兩個單獨的表,甚至放到單獨的庫做分庫。
    簡單來說垂直拆分是指數據表列的拆分,把一張列比較多的表拆分爲多張表。 如下圖所示,這樣來說大家應該就更容易理解了。
    在這裏插入圖片描述
    垂直拆分的優點: 可以使得行數據變小,在查詢時減少讀取的Block數,減少I/O次數。此外,垂直分區可以簡化表的結構,易於維護。
    垂直拆分的缺點: 主鍵會出現冗餘,需要管理冗餘列,並會引起Join操作,可以通過在應用層進行Join來解決。此外,垂直分區會讓事務變得更加複雜;
  • 水平分區
    保持數據表結構不變,通過某種策略存儲數據分片。這樣每一片數據分散到不同的表或者庫中,達到了分佈式的目的。 水平拆分可以支撐非常大的數據量。
    水平拆分是指數據錶行的拆分,表的行數超過200萬行時,就會變慢,這時可以把一張的表的數據拆成多張表來存放。舉個例子:我們可以將用戶信息表拆分成多個用戶信息表,這樣就可以避免單一表數據量過大對性能造成影響。
    在這裏插入圖片描述
    水平拆分可以支持非常大的數據量。需要注意的一點是:分表僅僅是解決了單一表數據過大的問題,但由於表的數據還是在同一臺機器上,其實對於提升MySQL 併發能力沒有什麼意義,所以水平拆分最好分庫 。
    水平拆分能夠 支持非常大的數據量存儲,應用端改造也少,但 分片事務難以解決 ,跨界點Join 性能較差,邏輯複雜。

12、分庫分錶帶來的問題

  • 事務一致性問題
  • 跨節點關聯查詢 join 問題
  • 跨節點分頁、排序、函數問題
  • 全局主鍵避重問題
    雪花算法
  • 數據遷移、擴容問題

13、慢查詢排查與優化
參考

14、mysql主從複製
MySQL 主從複製是指數據可以從一個MySQL數據庫服務器主節點複製到一個或多個從節點。主服務器對數據庫修改記錄二進制日誌(binlog),從服務器通過主服務器的二進制日誌自動執行更新。
在這裏插入圖片描述
參考

參考資料:
MySQL常見面試題
面試題:索引失效的幾種情況(MySQL)
mysql 聯合索引生效的條件、索引失效的條件
MySQL的btree索引和hash索引的區別
MySQL存儲引擎MyISAM與InnoDB區別總結整理
大表優化
數據庫分庫分表思路

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章