1. 程式人生 > >能避開很多坑的mysql面試題,你知道嗎?

能避開很多坑的mysql面試題,你知道嗎?

最近有一些朋友問我一些mysql相關的面試題,有一些比較基礎,有些比較偏。這裡就總結一些常見的mysql面試題吧,都是自己平時工作的總結以及經驗。大家看完,能避開很多坑。而且很多問題,都是面試中也經常問到!希望能對大家的面試有一些幫助!!!

 

比如,下面這些問題:

  • 1、為什麼一定要設一個主鍵?
  • 2、你們主鍵是用自增還是UUID?
  • 3、自增主機用完了怎麼辦?
  • 4、主鍵為什麼不推薦有業務含義?
  • 5、貨幣欄位用什麼型別??
  • 6、時間欄位用什麼型別?
  • 7、為什麼不直接儲存圖片、音訊、視訊等大容量內容?
  • 8、表中有大欄位X(例如:text型別),且欄位X不會經常更新,以讀為為主,那麼是拆成子表好?還是放一起好?
  • 9、欄位為什麼要定義為NOT NULL?
  • 10、where執行順序是怎樣的
  • 11、應該在這些列上建立索引?
  • 12、mysql聯合索引?
  • 13、什麼是最左字首原則?
  • 14、什麼情況下應不建或少建索引?
  • 15、MySQL資料庫cpu飆升到100%的話他怎麼處理?

其實要想把這些問題具體的原理原因將清楚,那每一個問題都可以囉嗦出一篇文章來。所以,在這裡我可能不會深入的說明mysql底層的原理。只會把工作中,我們的經驗總結,有可能你會覺得,就是這樣的做的,不這麼做可餓能就會掉坑裡去。當然,我給的回答可能並非標準答案,畢竟是自己的一些工作總結。各位讀者有更好的回答,也歡迎交流!

 

1:為什麼要一定要設定主鍵?

其實這個不是一定的,有些場景下,小系統或者沒什麼用的表,不設定主鍵也沒關係,mysql最好是用自增主鍵,主要是以下兩個原因:果定義了主鍵,那麼InnoDB會選擇主鍵作為聚集索引、如果沒有顯式定義主鍵,則innodb 會選擇第一個不包含有NULL值的唯一索引作為主鍵索引、如果也沒有這樣的唯一索引,則innodb 會選擇內建6位元組長的ROWID作為隱含的聚集索引。所以,反正都要生成一個主鍵,那你還不如自己指定一個主鍵,提高查詢效率!

 

2:主鍵是用自增還是UUID?

最好是用自增主鍵,主要是以下兩個原因:

  1. 如果表使用自增主鍵,那麼每次插入新的記錄,記錄就會順序新增到當前索引節點的後續位置,當一頁寫滿,就會自動開闢一個新的頁。
  2. 如果使用非自增主鍵(如uuid),由於每次插入主鍵的值近似於隨機,因此每次新紀錄都要被插到索引頁的隨機某個位置,此時MySQL為了將新記錄插到合適位置而移動資料,甚至目標頁面可能已經被回寫到磁碟上而從快取中清掉,此時又要從磁碟上讀回來,這增加了很多開銷,同時頻繁的移動、分頁操作造成索引碎片,得到了不夠緊湊的索引結構,後續不得不通過OPTIMIZE TABLE來重建表並優化填充頁面。

不過,也不是所有的場景下都得使用自增主鍵,可能場景下,主鍵必須自己生成,不在乎那些效能的開銷。那也沒有問題。

 

3:自增主機用完了怎麼辦?

在mysql中,Int整型的範圍(-2147483648~2147483648),約20億!因此不用考慮自增ID達到最大值這個問題。而且資料達到千萬級的時候就應該考慮分庫分表了。

 

4:主鍵為什麼不推薦有業務含義?

最好是主鍵是無意義的自增ID,然後另外建立一個業務主鍵ID,

因為任何有業務含義的列都有改變的可能性,主鍵一旦帶上了業務含義,那麼主鍵就有可能發生變更。主鍵一旦發生變更,該資料在磁碟上的儲存位置就會發生變更,有可能會引發頁分裂,產生空間碎片。

還有就是,帶有業務含義的主鍵,不一定是順序自增的。那麼就會導致資料的插入順序,並不能保證後面插入資料的主鍵一定比前面的資料大。如果出現了,後面插入資料的主鍵比前面的小,就有可能引發頁分裂,產生空間碎片。

 

5:貨幣欄位用什麼型別?
貨幣欄位一般都用 Decimal型別,
float和double是以二進位制儲存的,資料大的時候,可能存在誤差。看下面這個圖就明白了:

 

6:時間欄位用什麼型別?

這個看具體情況和實際場景,timestamp ,datatime ,bigint 都行!把理由講清楚就行!

timestamp,該型別是四個位元組的整數,它能表示的時間範圍為1970-01-01 08:00:01到2038-01-19 11:14:07。2038年以後的時間,是無法用timestamp型別儲存的。
但是它有一個優勢,timestamp型別是帶有時區資訊的。一旦你係統中的時區發生改變,例如你修改了時區,該欄位的值會自動變更。這個特性用來做一些國際化大專案,跨時區的應用時,特別注意!

datetime,佔用8個位元組,它儲存的時間範圍為1000-01-01 00:00:00 ~ 9999-12-31 23:59:59。顯然,儲存時間範圍更大。但是它坑的地方在於,他儲存的是時間絕對值,不帶有時區資訊。如果你改變資料庫的時區,該項的值不會自己發生變更!

bigint,也是8個位元組,自己維護一個時間戳,查詢效率高,不過資料寫入,顯示都需要做轉換。

 

7:為什麼不直接儲存圖片、音訊、視訊等大容量內容?

我們在實際應用中,都是檔案形式儲存的。mysql中,只存檔案的存放路徑。雖然mysql中blob型別可以用來存放大容量檔案,但是,我們在生產中,基本不用!
主要有如下幾個原因:

  1. Mysql記憶體臨時表不支援TEXT、BLOB這樣的大資料型別,如果查詢中包含這樣的資料,查詢效率會非常慢。

  2. 資料庫特別大,記憶體佔用高,維護也比較麻煩。

  3. binlog太大,如果是主從同步的架構,會導致主從同步效率問題!

因此,不推薦使用blob等型別!

 

8:表中有大欄位X(例如:text型別),且欄位X不會經常更新,以讀為為主,那麼是拆成子表好?還是放一起好?

其實各有利弊,拆開帶來的問題:連線消耗;不拆可能帶來的問題:查詢效能,所以要看你的實際情況,如果表資料量比較大,最好還是拆開為好。這樣查詢速度更快。

9:欄位為什麼要定義為NOT NULL?

一般情況,都會設定一個預設值,不會出現欄位裡面有null,又有空的情況。主要有以下幾個原:

1. 索引效能不好,Mysql難以優化引用可空列查詢,它會使索引、索引統計和值更加複雜。可空列需要更多的儲存空間,還需要mysql內部進行特殊處理。可空列被索引後,每條記錄都需要一個額外的位元組,還能導致MYisam 中固定大小的索引變成可變大小的索引。

2. 如果某列存在null的情況,可能導致count() 等函式執行不對的情況。看一下2個圖就明白了:

 

3. sql 語句寫著也麻煩,既要判斷是否為空,又要判斷是否為null等。

 

10:where執行順序是怎樣的?

where 條件從左往右執行的,在資料量小的時候不用考慮,但資料量多的時候要考慮條件的先後順序,此時應遵守一個原則:排除越多的條件放在第一個。

 


11:應該在這些列上建立索引:

在經常需要搜尋的列上,可以加快搜索的速度;在作為主鍵的列上,強制該列的唯一性和組織表中資料的排列結構;在經常用在連線的列上,這些列主要是一些外來鍵,可以加快連線的速度;在經常需要根據範圍進行搜尋的列上建立索引,因為索引已經排序,其指定的範圍是連續的;在經常需要排序的列上建立索引,因為索引已經排序,這樣查詢可以利用索引的排序,加快排序查詢時間;在經常使用在WHERE子句中的列上面建立索引,加快條件的判斷速度。

 

12:mysql聯合索引

聯合索引是兩個或更多個列上的索引。對於聯合索引:Mysql從左到右的使用索引中的欄位,一個查詢可以只使用索引中的一部份,但只能是最左側部分。例如索引是key index (a,b,c). 可以支援a 、 a,b 、 a,b,c 3種組合進行查詢,但不支援 b,c進行查詢 .當最左側欄位是常量引用時,索引就十分有效。
利用索引中的附加列,您可以縮小搜尋的範圍,但使用一個具有兩列的索引 不同於使用兩個單獨的索引。複合索引的結構與電話簿類似,人名由姓和名構成,電話簿首先按姓氏對進行排序,然後按名字對有相同姓氏的人進行排序。如果您知 道姓,電話簿將非常有用;如果您知道姓和名,電話簿則更為有用,但如果您只知道名不姓,電話簿將沒有用處。

 

13:什麼是最左字首原則?

最左字首原則指的是,如果查詢的時候查詢條件精確匹配索引的左邊連續一列或幾列,則此列就可以被用到。如下:

select * from user where name=xx and city=xx ; //可以命中索引
select * from user where name=xx ; // 可以命中索引
select * from user where city=xx ; // 無法命中索引

這裡需要注意的是,查詢的時候如果兩個條件都用上了,但是順序不同,如 city= xx and name =xx,那麼現在的查詢引擎會自動優化為匹配聯合索引的順序,這樣是能夠命中索引的。

由於最左字首原則,在建立聯合索引時,索引欄位的順序需要考慮欄位值去重之後的個數,較多的放前面。ORDER BY子句也遵循此規則。


14:什麼情況下應不建或少建索引

表記錄太少
經常插入、刪除、修改的表
資料重複且分佈平均的表字段,假如一個表有10萬行記錄,有一個欄位A只有T和F兩種值,且每個值的分佈概率大約為50%,那麼對這種表A欄位建索引一般不會提高資料庫的查詢速度。
經常和主欄位一塊查詢但主欄位索引值比較多的表字段


15:問了下MySQL資料庫cpu飆升到100%的話他怎麼處理?

1. 列出所有程序 show processlist 觀察所有程序 多秒沒有狀態變化的(幹掉)

2. 檢視慢查詢,找出執行時間長的sql;explain分析sql是否走索引,sql優化;

3. 檢查其他子系統是否正常,是否快取失效引起,需要檢視buffer命中率;

 

總結

以上就是一些最基礎的總結,希望大家有所收穫吧!