1. 程式人生 > >面試專題(Mysql及Mongodb)

面試專題(Mysql及Mongodb)

mysql面試題

1.  各個資料庫儲存引擎區別
mysql的儲存引擎是針對表進行設定的,一個庫的不同表可以設定不同的儲存引擎,mysql預設支援多種儲存引擎,以適用不同領域的資料庫應用需要,主要的幾個資料庫引擎如下:
 MyISAM儲存引擎
5.5之前預設的儲存引擎,不支援事務、不支援外來鍵,表級鎖,記憶體和硬碟空間佔用率低,其優勢是訪問速度快,對事務完整性沒有要求,以select、insert為主的應用基本上都可以使用這個引擎;
 InnoDB儲存引擎
5.5之後預設的儲存引擎,提供了具有提交、回滾和奔潰恢復能力的事務安全,支援外來鍵並提供了行級鎖,其劣勢在於寫的處理效率相對較低,並且會佔用更多的磁碟空間以保留資料和索引;

 MEMORY儲存引擎
使用存於記憶體中的內容來建立表,MEMORY型別的表資料存於記憶體訪問非常的快,預設使用HASH索引,一旦資料庫服務重啟或關閉,表中的資料就會丟失;
 MERGE儲存引擎
MERGE儲存引擎是一組MyISAM表組合,這些MyISAM表結構完全相同。MERGE表本身沒有資料,對MERGE表的CRUD操作都是通過內部的MyISAM表進行的;

2. 提高sql 語句效率的技巧
  大批量插入資料
     大批量資料插入空表,可將表設定成為MyISAM,並通過disable keys將唯一索引關閉;
     大批量資料插入非空Innodb表,可採取如下措施提高效率:
        1. 匯入資料時按照主鍵順序排列;
        2. 匯入資料前使用set UNIQUE_CHECKS=0,關閉唯一性校驗,匯入後恢復;
        3. 如果使用了自動提交,建議在匯入前執行SET AUTOCOMMIT=0,關閉自動提交,匯入後恢復;
  優化INSERT 語句


     儘量使用多個值表的insert語句,降低連線、關閉的消耗;
     將索引檔案和資料檔案分在不同的磁碟上存放;
     從一個文字檔案裝入一個表時,使用LOAD DATA INFLIE ,比一般的insert語句快20倍;

  查詢優化
     儘量減少額外的排序,通過索引直接返回有序資料;where條件和order by使用相同的索引,並且order by的順序與索引順序相同,並且order by的欄位都是升序或者都是降序;
     儘量只選擇必要的欄位,提高sql效能;
     能用關聯查詢的不要用子查詢;
     對於包含or的查詢語句,如果要利用索引,則or之間的每個條件都必須用到索引,否則應該考慮增加索引;
     優化分頁
     在索引上完成排序分頁的操作,然後根據主鍵關聯回原表查詢所需的其他列
     把limit查詢轉換為某個位置的查詢;

  注意不使用索引的情況
     如果MySQL估計使用索引比全表掃描更慢,則不使用索引。
     用or分隔開的條件,如果or前的條件中的列有索引,而後面的列沒有索引,那麼涉及到的索引都不會被用到;
     複合索引,如果索引列不是複合索引的第一部分,則不使用索引(即不符合最左字首;
     如果like是以’%’開始的,則該列上的索引不會被使用。
     如果列為字串,則where條件中必須將字元常量值加引號,否則即使該列上存在索引,也不會被使用;
     not in 、 not exists 、 (<> 不等於 !=)這些操作符不走索引
     不要在 where 子句中的“=”左邊進行函式、算術運算或其他表示式運算,否則系統將可能無法正確使用索引;

3. 怎麼樣做執行計劃分析
通過explain命令獲取mysql如何執行select語句的資訊,包括在select語句執行過程中表如何連線和連線的順序;explain分析後的結果解析:
 select_type
    查詢的型別,主要是用於區分普通查詢、聯合查詢、子查詢等複雜的查詢
     SIMPLE:簡單的select查詢,查詢中不包含子查詢或者union
     PRIMARY:查詢中包含任何複雜的子部分,最外層查詢則被標記為primary
     SUBQUERY:在select 或 where列表中包含了子查詢
     UNION:若第二個select出現在union之後,則被標記為union;若union包含在from子句的子查詢中,外層select將被標記為derived

 type
訪問型別,sql查詢優化中一個很重要的指標,結果值從好到壞依次是:system > const > eq_ref > ref > range > index > ALL一般來說,好的sql 查詢至少達到range 級別,最好能達到ref ;
     system:表只有一行記錄(等於系統表),這是const型別的特例,平時不會出現,可以忽略不計
     const:表示通過索引一次就找到了,const用於比較primary key 或者 unique索引。
     eq_ref:唯一性索引掃描,對於每個索引鍵,表中只有一條記錄與之匹配(1對1);
     ref:非唯一性索引掃描,返回匹配某個單獨值的所有行。
     range:索引範圍掃描;
     index:索引全掃描;
     ALL:全表掃描;

possible_keys
查詢涉及到的欄位上存在索引,則該索引將被列出,但不一定被查詢實際使用
key
實際使用的索引,如果為NULL,則沒有使用索引。
key_len
表示索引中使用的位元組數,查詢中使用的索引的長度(最大可能長度),並非實
際使用長度,理論上長度越短越好;
ref
顯示索引的哪些列;
 rows
根據表統計資訊及索引選用情況,大致估算出找到所需的記錄所需要讀取的行數
Extra
不適合在其他欄位中顯示,但是十分重要的額外資訊

優化目標 Tips:
1. 根據需求建立索引
2. 每個查詢都要使用索引以提高查詢效率,至少達到range級別,最好能達到ref;
3. 追求key_len和rows最小;

 

4. mysql 複製的原理
Mysql的複製原理大致如下:
1.主庫在資料提交時會把資料變更作為事件記錄在二進位制日誌檔案Binlog中;可通過sync_binlog控制binlog日誌重新整理到磁碟的頻率;
2.主庫推送二進位制日誌檔案binlog中的事件到從庫的中繼日誌Relay Log,之後從庫根據中繼日誌RelayLog重做資料變更操作,通過邏輯複製達到主從庫的資料一致;
3.MySQL通過3個執行緒來完成主從庫之間的資料同步,其中binlog dump執行緒跑在主庫上,I/O執行緒和sql執行緒跑在從庫上。

當從庫啟動複製時,首先建立I/O執行緒連線主庫,主庫隨後建立binlog dump執行緒讀取資料庫事件併發送給I/O執行緒,I/O執行緒獲取到事件資料後更新到從庫的中繼日誌replay log中去,之後從庫上的sql執行緒讀取中繼日誌中更新的資料庫事件並應用;

 

Mongodb

1. mongodb 與mysql 的區別?
mongodb的本質還是一個數據庫產品,3.0以上版本其穩定性和健壯性有很大提升。它與mysql的區別在於它不會遵循一些約束,比如:sql標準、ACID屬性,表結構等。其主要特性如下:
 面向集合文件的儲存:適合儲存Bson(json的擴充套件)形式的資料;
 格式自由,資料格式不固定,生產環境下修改結構都可以不影響程式執行;
 強大的查詢語句,面向物件的查詢語言,基本覆蓋sql語言所有能力;
 完整的索引支援,支援查詢計劃;
 支援複製和自動故障轉移;
 支援二進位制資料及大型物件(檔案)的高效儲存;
 使用分片叢集提升系統擴充套件性;
 使用記憶體對映儲存引擎,把磁碟的IO操作轉換成為記憶體的操作;

2. mongoDB 主要使用在什麼應用場景?
 MongoDB 的應用已經滲透到各個領域,比如遊戲、物流、電商、內容管理、社交、物聯網、視訊直播等,以下是幾個實際的應用案例:
 遊戲場景,使用 MongoDB 儲存遊戲使用者資訊,使用者的裝備、積分等直接以內嵌文件的形式儲存,方便查詢、更新
 物流場景,使用 MongoDB 儲存訂單資訊,訂單狀態在運送過程中會不斷更新,以MongoDB 內嵌陣列的形式來儲存,一次查詢就能將訂單所有的變更讀取出來。
 社交場景,使用 MongoDB 儲存儲存使用者資訊,以及使用者發表的朋友圈資訊,通過地理位置索引實現附近的人、地點等功能
 物聯網場景,使用 MongoDB 儲存所有接入的智慧裝置資訊,以及裝置彙報的日誌資訊,並對這些資訊進行多維度的分析
 視訊直播,使用 MongoDB 儲存使用者資訊、禮物資訊等

3. 怎麼樣做mongodb 查詢優化
 第一步 找出慢速查詢
1. 開啟內建的查詢分析器,記錄讀寫操作效率:
        db.setProfilingLevel(n,{m}),n的取值可選0,1,2;
     0是預設值表示不記錄;
     1表示記錄慢速操作,如果值為1,m必須賦值單位為ms,用於定義慢速查詢時間的閾值;
     2表示記錄所有的讀寫操作;
        例如:db.setProfilingLevel(1,300)
2. 查詢監控結果
    監控結果儲存在一個特殊的蓋子集合system.profile裡,這個集合分配了128kb的空間,要確保監控分析資料不會消耗太多的系統性資源;蓋子集合維護了自然的插入順序,可以使用$natural操作符進行排序,如:db.system.profile.find().sort({'$natural':-1}).limit(5)

 第二步 分析慢速查詢
找出慢速查詢的原因比較棘手,原因可能有多個:應用程式設計不合理、不正確的資料模型、硬體配置問題,缺少索引等;接下來對於缺少索引的情況進行分析:使用explain分析慢速查詢
    例如:db.orders.find({'price':{'$lt':2000}}).explain('executionStats')
    explain的入參可選值為:
     "queryPlanner" 是預設值,表示僅僅展示執行計劃資訊;
     "executionStats" 表示展示執行計劃資訊同時展示被選中的執行計劃的執行情況資訊;
      "allPlansExecution" 表示展示執行計劃資訊,並展示被選中的執行計劃的執行情況資訊,還展示備選的執行計劃的執行情況資訊;

 第三步 解讀explain結果 
queryPlanner(執行計劃描述)
    winningPlan(被選中的執行計劃)
        stage(可選項:COLLSCAN 沒有走索引;IXSCAN使用了索引)
    rejectedPlans(候選的執行計劃)
executionStats(執行情況描述)
    nReturned (返回的文件個數)
    executionTimeMillis(執行時間ms)
    totalKeysExamined (檢查的索引鍵值個數)
    totalDocsExamined (檢查的文件個數)

優化目標 Tips:
1. 根據需求建立索引
2. 每個查詢都要使用索引以提高查詢效率, winningPlan. stage 必須為IXSCAN ;
3. 追求totalDocsExamined = nReturned

4. mongodb 的索引注意事項?
1. 索引很有用,但是它也是有成本的——它佔記憶體,讓寫入變慢;
2. mongoDB通常在一次查詢裡使用一個索引,所以多個欄位的查詢或者排序需要複合索引才能更加高效;
3. 複合索引的順序非常重要
4. 在生成環境構建索引往往開銷很大,時間也不可以接受,在資料量龐大之前儘量進行查詢優化和構建索引;
5. 避免昂貴的查詢,使用查詢分析器記錄那些開銷很大的查詢便於問題排查;
6. 通過減少掃描文件數量來優化查詢,使用explai對開銷大的查詢進行分析並優化;
7. 索引是用來查詢小範圍資料的,不適合使用索引的情況:
     每次查詢都需要返回大部分資料的文件,避免使用索引
     寫比讀多

5. mongodb 是怎麼實現高可用?

Redis

1. 結合專案經驗,說下 redis  應用場景
 快取:合理使用快取加快資料訪問速度,降低後端資料來源壓力
 排行榜:按照熱度排名,按照發布時間排行,主要用到列表和有序集合
 計數器應用:視訊網站播放數,網站瀏覽數,使用redis計數
 社交網路:贊、踩、粉絲、下拉重新整理
 訊息佇列:釋出和訂閱

2. redis  支援資料型別?各有什麼特點?
 String(字串)
string型別是二進位制安全的。意思是redis的string可以包含任何資料。比如jpg圖片或者序列化的物件 。string型別是Redis最基本的資料型別,一個redis中字串value最多可以是512M
 Hash(雜湊)
Redis hash 是一個鍵值對集合。Redis hash是一個string型別的field和value的對映表,hash特別適合用於儲存物件。類似Java裡面的Map<String,Object>
 List(列表)
Redis 列表是簡單的字串列表,按照插入順序排序。你可以新增一個元素導列表的頭部(左邊)或者尾部(右邊),它的底層實際是個連結串列
 Set(集合)
Redis的Set是string型別的無序集合。它是通過HashTable實現實現的,
 zset(sorted set:有序集合)
Redis zset 和 set 一樣也是string型別元素的集合,且不允許重複的成員。不同的是每個元素都會關聯一個double型別的分數。redis正是通過分數來為集合中的成員進行從小到大的排序。zset的成員是唯一的,但分數(score)卻可以重複。

3. 有什麼持久化策略?各有什麼特點
策略:支援RDB和AOF兩種持久化機制,可以避免因程序退出造成資料丟失,特點如下:
 RDB持久化把當前程序資料生成快照(.rdb)檔案儲存到硬碟的過程,持久化結束後,用這個臨時檔案替換上次持久化的檔案,達到資料恢復。 優點在於使用單獨子程序來進行持久化,主程序不會進行任何IO操作,保證了redis的高效能;缺點在於RDB是間隔一段時間進行持久化,如果持久化之間redis發生故障,會發生資料丟失。所以這種方式更適合資料要求不嚴謹的時候;有手動觸發和自動觸發,手動觸發有save和
bgsave兩命令 ;
     save命令:阻塞當前Redis,直到RDB持久化過程完成為止,若記憶體例項比較大會造成長時間阻塞,線上環境不建議用它
     bgsave命令:redis程序執行fork操作建立子執行緒,由子執行緒完成持久化,阻塞時間很短(微秒級),是save的優化,在執行redis-cli shutdown關閉redis服x務時,如
果沒有開啟AOF持久化,自動執行bgsave; 顯然bgsave是對save的優化

 AOF:針對RDB不適合實時持久化,redis提供了AOF持久化方式來解決,將“操作 +資料”以格式化指令的方式追加到操作日誌檔案的尾部,在append操作返回後(已經寫入到檔案或者即將寫入),才進行實際的資料變更,“日誌檔案”儲存了歷史所有的操作過程;當server需要資料恢復時,可以直接replay此日誌檔案,即可還原所有的操作過程

    開啟:redis.conf設定:appendonly yes (預設不開啟,為no)

    預設檔名:appendfilename "appendonly.aof"

5. 介紹下哨兵機制
redis sentinel是一個分散式架構,其中包含了若干個sentinal節點和Redis節點,每個sentinel節點會對資料節點和sentinel節點進行監控,當它發現節點不可達是,會對節點做下線標識。如果大部分sentinal節點認為主節點不可達,sentinal節點之間會進行“協商” ,選舉出來一個sentinal節點完成故障轉義,並同時把這個故障通知到應用方;

6. 介紹 redis  叢集方案?以及其原理
RedisCluster是redis的分散式解決方案,在3.0版本後推出的方案,有效地解決了Redis分散式的需求,當遇到單機記憶體、併發等瓶頸時,可使用此方案來解決這些問題,一個 redis 叢集包含 16384 個雜湊槽(hash slot),資料庫中的每個資料都屬於這16384個雜湊槽中的一個。叢集使用公式(CRC16[key]&16383)函式來計算鍵 key屬於哪個槽。叢集中的每一個節點負責處理一部分雜湊槽。

7. redis 能做讀寫分離嗎?同步策略是怎麼實現的?
redis提供了主從複製和哨兵機制來提高redis服務的健壯性和高可用,但是從嚴格意義上來講,redis並沒有實現讀寫分離,主從複製架構中,主節點用於響應讀寫請求,從節點用於資料備份,如果需要實現讀從從節點讀,應用需要對客戶端進行改造;但在真實場景下一般不需要做此方案,讀寫分離主要應用在磁碟IO比較大的場景,而redis是快取級別的

同步策略:
redis 2.8版本以上使用psync命令完成同步,過程分“全量”與“部分”複製
a) 全量複製:一般用於初次複製場景(第一次建立SLAVE後全量)
b) 部分複製:網路出現問題,從節佔再次連主時,主節點補發缺少的資料,每次資料增加同步