天天看點

Java面試題 第五部分 資料庫相關

Redis

1 Redis有哪些資料結構?底層的編碼有哪些?有序連結清單采用了哪些不同的編碼?

資料結構

  1. String(Key,Value) function:get,set,del
  2. List(Key,List) function:rpush,lrange,lindex,lpop
  3. Set(Key,Set) function:sadd,smembers,sismember,srem
  4. Hash(Key,Map) function:hset,hget(key,mapkey),hgetall,hdel
  5. Zset(Key,Set) function:zadd,zrange,zrangebyscore,zrem (Zset和Set的差別在于每個Set每個元素都有一個分值,實作有序set的目的)

底層編碼

Redis資料編碼:

defineOBJ_ENCODING_RAW 0

有序連結清單采用的編碼:ziplist和skiplist

2 redis的hash資料結構最多能存儲多少個元素

Every hash can store up to 2^32 - 1 field-value pairs (more than 4 billion).

3 Redis的高可用方案(todo)

4 什麼是一緻性hash算法

key個數為2的32次方的圓環
  1. 求出每個伺服器的IP獲得hash值,将其配置到一個 0~2^n 的圓環上(n通常取32)稱為Node。
  2. 用同樣的方法求出待存儲對象的主鍵 hash值,也将其配置到這個圓環上,然後從資料映射到的位置開始順時針查找,找到第一個Node進行存儲。
    Java面試題 第五部分 資料庫相關
    節點增删,需要對目前操作節點和逆時針找到的第一個節點之間的資料進行資料遷移 節點雪崩,對熱點Node添加虛拟節點,減少節點的壓力

5 Redis為什麼使用單線程模型,為什麼不用多線程達到高并發的目的

差別并發和并行的關系

單線程減少了線程上下文的切換&采用IO多路複用的政策,提升了讀寫效率

6 Redis資料熱點問題

如何發現資料熱點

(1)資料通路量日志記錄進行推算

(2)利用redis4.x自身特性,LFU機制發現熱點資料(LFU:最近最少使用算法,每個對象包含24bit空間記錄通路資訊,高16位通路時間,低8位通路頻次)

資料熱點問題的解決

(1)請求進入隊列,等待熱點redis節點重建完成 (2)添加分布式鎖,隻允許一個線程通路db資源 (3)主從分離,主節點負責讀寫,從節點負責讀操作

7 redis實作的消息隊列

兩種消息隊列的實作方式

  1. redis支援key-List存儲,通過lpush對list添加,lpop從list讀取,完成消息隊列的功能,blpop實作阻塞讀取的作用,隊列為空的時候阻塞等待
  2. redis支援釋出訂閱模型,通過主題釋出資料,通過訂閱擷取釋出的資料

兩者的差別

lpush-lpop:1對1(pop一次資料就沒了) 釋出訂閱:1對多

lpush-lpop:拉模式 釋出訂閱:推模式

Mysql

1 mysql存儲引擎

預設存儲引擎

v5.1之前是MyISAM,V5.1之後是MyISAN

存儲引擎的分類

MyISAM存儲引擎:靜态型、動态型、壓縮型存儲結構,并發插入的表鎖(針對select量大的情況)

InnoDB存儲引擎:事務,自增列,外鍵,mvcc,行鎖

MEMORY存儲引擎:資料存儲在記憶體,表結構存儲磁盤frm檔案,hash索引,資料安全性不高

2 資料庫垂直和水準拆分依據(單表資料量多大拆)

通俗了解:水準拆分行,行資料拆分到不同表中 (表記錄條數太多)垂直拆分列,表資料拆分到不同表中,單表資料達到千萬級(表記錄複雜,每條記錄内容太多)

3 Mysql的事務操作問題和事務隔離級别

事務操作讀寫不一緻問題問題

髒讀

一個事務對資料進行了修改,而這種修改還沒有送出到資料庫中,這時,另外一個事務也通路這個資料,然後使用了這個資料。(一讀一修改)

不可重複讀

一個事務多次讀同一資料,(前後讀取結果不一緻),針對單行資料變化産生的錯誤。(多讀一修改)

幻讀

例如事務在插入已經檢查過不存在的記錄時,發生資料插入的沖突。針對的資料行數發生的變化。(多讀一增删)

事務隔離級别

READ UNCOMMITTED(未送出讀):事務修改使沒有送出,對其他事務也都是可見的。事務可以讀取未送出的資料,這也被稱為髒讀(DirtyRead)。

READ COMMITTED(送出讀):一個事務開始時,隻能“看見”已經送出的事務所做的修改。不可重複讀。

REPEATABLEREAD(可重複讀):同一個事務中多次讀取相同的資料傳回的結果是一樣的。其避免了髒讀和不可重複讀問題,但幻讀依然存在。

SERIALIZABLE(可串行化):通過強制事務串行執行,SERIALIZABLE會在讀取的每一行資料上都加鎖,是以可能導緻大量的逾時和鎖争用的問題

隔離級别原理 (todo)

4 資料庫主從同步資料一緻性如何解決

  1. 半同步複制辦法就是等主從同步完成之後,等主庫上的寫請求再傳回,這就是常說的“半同步複制”。

    優點:利用資料庫原生功能,比較簡單 缺點:主庫的寫請求時延會增長,吞吐量會降低

  2. 資料庫中間件(讀寫直接請求中間件,中間件承擔請求路由的作用)

    1)所有的讀寫都走資料庫中間件,通常情況下,寫請求路由到主庫,讀請求路由到從庫

    2)記錄路由到寫庫的key,主從同步時間視窗内(假設是500ms),如果有讀請求通路就把這個key上的讀請求路由到主庫。

    3)在主從同步時間過完後,對應key的讀請求繼續路由到從庫。

半同步複制的原理&同步方法

  1. 基于SQL語句的複制(statement-based replication, SBR):sql語句寫入binllog,binlog小,從伺服器版本可能大于主伺服器,行鎖更多
  2. 基于行的複制(row-based replication, RBR): 每一條行資料寫入binlog,資料安全可靠,可以采用多線程複制,binlog檔案大 混合模式複制(mixed-based replication, MBR);
  3. 混合模式 12

主從延時長的優化方案

mysql通過主從架構實作讀寫分離,資料量大高并發場景下主從同步延時較長,原因在于mysql使用單線程重放Relaylog,通過多線程重放可以提升效率,但是多線程操作不能保證請求的順序性,是以多線程的操作的前提是請求的隔離性,請求在不同的庫上執 行,互相之間不存在順序影響,相同庫上的寫操作使用相同線程,不同庫上的寫操作使用不同的線程(針對多庫情況) 針對單庫多表的情況,mysql5.7開始,将可以同步并行執行的事務分組,同組事務可以并行執行,mysqlbinlog中可以發現在原始的binlog中新增了兩個字段,分别為lastcommited(上次送出事務編号)和sequence_number

5 什麼叫做目前讀&快照讀?

在可重複讀級别下,快照讀是通過MVVC(多版本控制)和undo log來實作的,目前讀是通過加record lock(記錄鎖)和gap lock(間隙鎖)來實作的。
  1. 快照讀(snapshot read) 簡單的select操作(不包括 select … lock in share mode, select … for update)
  2. 目前讀讀(current read) select … lock in share mode&select … for update&insert&update&delete

6 寫sql

有學生成績表(存在重複資料)

問題1:删除重複資料,保留ID最小的記錄

問題2:計算每個學生的全學科平均分

找出重複資料的最小id

(A) select min(peopleid) from people group by peopleName having count(peopleName)>1

找出全部存在重複資料的所有記錄的Name

(B) select peopleName from people group by peopleName having count(peopleName)>1

删除除去id最小記錄的全部重複資料

© delete from people where peoName in B and peopleId not in (A)

算平均數

select name,avg(score) from(slect * from A left join C where A.Name =C.Name) group by Name

事務

事務

1 事務特性以及實作原理

ACID

Atomic:原子性:成功或者失敗 實作原理:復原日志(undo log) Duration:持久性:一旦事務被送出,那麼資料一定會被寫入到資料庫中并持久存儲起來(redo log)

Isolation:隔離性:事務的隔離級别,并發控制機制(鎖/時間戳/多版本/快照) Consistency:一緻性:更改便持久的儲存在資料庫之中,并不會被復原,前三個都是為了保證最終的一緻性

CAP

C:Consistency一緻性

A:Availability可用性

P:Partition tolerance分區容錯性

一緻性解決方案:串行化,單個資料集(單個資料集意味着一旦資料丢失就是導緻可用性降低的問題)

可用性解決方案:備援副本,故障自動遷移(備援就會産生一緻性問題)

分區容錯性解決方案:可擴充,機器擴容增減不影響資料一緻性

CA: 一緻性和可用性,為什麼不可能同時成立

因為可能通信失敗(即出現分區容錯)。如果保證 G2 的一緻性,那麼 G1 必須在寫操作時,鎖定 G2 的讀操作和寫操作。隻有資料同步後,才能重新開放讀寫。鎖定期間,G2 不能讀寫,沒有可用性不。如果保證 G2 的可用性,那麼勢必不能鎖定 G2,是以一緻性不成立。 綜上所述,G2 無法同時做到一緻性和可用性。系統設計時隻能選擇一個目标。如果追求一緻性,那麼無法保證所有節點的可用性;如果追求所有節點的可用性,那就沒法做到一緻性。

因為AC隻能滿足一個(C[單庫水準切分] A[雙主庫同步高可用],一般采用的方案還是說AP+最終一緻性

分布式事務(多資料庫情況)

在同一個資料庫上的事務操作叫做單機事務,在不同資料庫上的事務操作叫做分布式事務

舉例:餘額、訂單、流水可能分布在不同的資料庫上,甚至不同的資料庫執行個體上,此時就不能用資料庫原生事務來保證資料的一緻性了。

分布式事務解決方案

  1. 添加補償事務,即事務本身的逆向操作,在一系列事務的組合操作存在某一事務操作失敗的情況下,對已經執行成功事務執行逆操作補償事務

    問題:

    補償事務需要針對每一個事務單獨編寫,不具有通用性;補償事務本身也可能會失敗;業務流程複雜時會有很多if/else邏輯判斷

  2. 後置送出優化:事務先執行,最後一起送出,curd執行階段耗時較長,commit階段時間短,curd階段有問題則直接終止事務,全部不再送出。産生不一緻的問題轉移到送出階段,因為送出階段時間短,也就是說,不一緻情況發生機率減小。

    問題:

    因為送出 commit階段延時到最慢事務的執行時間截止,是以整體的資料庫連接配接時間變長,減少了系統吞吐量。

  3. 兩階段送出(分布式RPC調用環境下的分布式事務) 它通過引入一個協調者(Coordinator)來統一掌控所有參與者(Participant)的操作結果,并訓示它們是否要把操作結果進行真正的送出(commit)或者復原(rollback)

    問題:

    (1)某一個參與者回複消息之前,所有參與者以及協調者都處于阻塞狀态;

    (2)在協調者發出消息之前,所有參與者都處于阻塞狀态;]

  4. 在6的基礎上添加逾時機制

10 資料庫不同次元的查詢請求如何滿足,采用備援資料後如何保證正反資料的一緻性

網際網路資料量大的業務場景,常常: 使用水準切分來降低單庫資料量 使用資料備援的反範式設計來滿足不同次元的查詢需求

備援資料三種方案:

(1)服務同步雙寫法能夠很容易的實作資料備援

(2)為了降低延遲時間,可以優化為服務異步雙寫法

(3)為了屏蔽“備援資料”對服務帶來的複雜性,可以優化為線下異步雙寫法

保證資料一緻性的方案:

(1)最簡單的方式,線下腳本掃全量資料比對

(2)提高效率的方式,線下腳本掃增量資料比對

(3)最實時的方式,線上檢測“消息對”

索引

1 資料庫索引

什麼是索引

索引是對資料庫表中一列或多列的值進行排序的一種結構

_使用索引的原因)

加快對表中記錄的查查找找或排排序序

索引的字段選擇

表的主鍵,外鍵,非外鍵的連接配接字段(用于關聯查詢的字段),枚舉類型的資料(有限的變化區間),數值類型的資料

2 聚集索引和非聚集索引

差別

實體記憶體連續性&表能建立個數 讀取聚集快,增删聚集慢,大資料集合查詢,範圍查詢優

1、聚集索引一個表隻能有一個,而非聚集索引一個表可以存在多個,這個跟沒問題沒差别,一般人都知道。

2、聚集索引存儲記錄是實體上連續存在,而非聚集索引是邏輯上的連續,實體存儲并不連續,這個大家也都知道。

聚集索引像拼音查字典,拼音的順序和漢字在字典中存在的位置順序保持一緻,A找到啊,啊在第一頁第一個,B找到比,比在第10頁,a在b前,a在比前非聚集索引像是筆畫查字典,筆畫靠前不一定筆畫對應的漢字也靠前 聚集索引對應的葉子節點存放最終資料 非聚集索引的葉子節點存放的對應資料行的記憶體位址和索引的字段,不包含資料行的全部資料

使用場景

使用聚集索引的查詢效率要比非聚集索引的效率要高,但是如果需要頻繁去改變聚集索引的值,寫入性能并不高,因為需要移動對應資料的實體位置。 非聚集索引在查詢的時候可以的話就避免二次查詢,這樣性能會大幅提升。

如何解決非聚集索引的二次查詢問題(非聚查主鍵,聚集主鍵查内容)

複合索引(覆寫索引)多列索引 PS:在非聚集索引中可以直接查到非聚集索引的索引列内容

非聚集索引分類

普通索引:最基本的索引,無限制索引。

唯一索引:索引列的值唯一允許有空值。

主鍵索引:不允許有空值的唯一索引。

全文索引:僅可用于 MyISAM表,針對較大的資料,生成全文索引很耗時好空間。

組合索引:多列索引的組合,遵循”最左字首“原則。

複合索引的最左字首原則(判斷使用index&ref(掃全索引)查詢)

mysql建立複合索引的規則是首先會對複合索引的最左邊的,也就是第一個name字段的資料進行排序,在第一個字段的排序基礎上,然後再對後面第二個的cid字段進行排序。其實就相當于實作了類似 order by name cid這樣一種排序規則。

1.索引左字首性的第一層意思:必須用到索引的第一個字段。

2. 索引字首性的第二層意思:對于索引的第一個字段,用like時左邊必須是固定值,通配符隻能出現在右邊。

3.索引字首性的第三層意思:如果在字段前加了函數,則索引會被抑制 (a,b,c) 查詢(a,c)隻有a走索引,c需要走index掃描

3 資料庫索引,底層是怎樣實作的(todo)

4 索引有什麼用?如何建索引?(加快查詢效率)

  1. 選擇區分度高的字段作為 索引 字段
  2. 範圍 ,條件不明确的 有索引 速度也會很慢
  3. 索引字段 不能 通過 *10 avg() 等公式計算
  4. 最左字首 --聯合索引 (a,b,c,d)

5 存在慢查詢日志但是線上查詢explain發現走索引的原因?

1)資料後置處理groupby

2)傳回的資料集太大

3)使用多列索引的查詢語句

6 什麼叫做反向索引

由于不是由記錄來确定屬性值,而是由屬性值來确定記錄的位置,因而稱為反向索引(inverted index)。帶有反向索引的檔案我們稱為反向索引檔案,簡稱倒排檔案(inverted file)。全文檢索就是反向索引。

7 一條SQL語句執行得很慢的原因

(1)大多數情況是正常的,隻是偶爾會出現很慢的情況。
  1. 資料庫在重新整理髒頁 redo log打滿,請求等待redo log同步磁盤完成,任何一條sql都有可能
  2. 語句涉及到的表加鎖了(mysql可以使用showprocesslist)
(2)在資料量不變的情況下,這條SQL語句一直以來都執行的很慢。
  1. 沒用到索引(字段沒有索引||字段有索引,但卻沒有用索引)

緩存

1 緩存失效如何解決?

  1. 大面積的緩存key失效(緩存的時間分散分布)
  2. 熱點key失效(加鎖重構緩存,備份緩存,緩存降級提示等待重試)

2 緩存問題(擊穿和雪崩都是緩存失效問題)

緩存穿透

緩存和資料庫都查詢不到這條資料

緩存中存儲這些空資料的key&布隆過濾器

緩存擊穿(實質上是熱點資料的緩存失效問題)

大量的請求同時查詢一個key時,此時這個key正好失效了,就會導緻大量的請求都打到資料庫上面,第一個查詢資料的請求上使用一個互斥鎖來鎖住它

緩存雪崩(緩緩存存大大規規模模失失效效問問題題)

某一時刻發生大規模的緩存失效的情況

使用叢集緩存,保證緩存服務的高可用,緩存失效時間分散

熱點資料集中失效(就就是是緩緩存存擊擊穿穿問問題題)

熱點的資料來說,當緩存失效以後會存在大量的請求 備份緩存&緩存降級&重構加鎖

資料庫和Redis資料一緻性問題

資料庫和redis資料一緻性問題(分布式多節點環境 & 單機環境)

單機場景下:寫庫成功寫緩存失敗導緻資料不一緻

解決方案:讀緩存再讀庫,删緩存寫庫再寫緩存

分布式環境:寫讀并發,
  1. 目标更新資料A為B
  2. 目标讀取資料A 1删緩緩存A——2讀取緩存(null)——2讀取資料庫(A)——1修改資料庫(B)——1更新緩存(B)——2更新緩存(A) 導緻緩存資料庫不一緻最終庫中存B,緩存存A

    解決方案:采用隊列同步并發操作,根據ID配置隊列,保證單個資料的查詢修改行為是同步的,

    優化點,緩存未命中多個查詢時,後續的查詢不進入隊列,自旋等待隊列其他查詢任務刷緩存

小結(資料庫之間的對比)

1 Nosql和關系型資料庫的差別 (存儲方式表&文檔-圖-鍵值對,存儲是否結構化,存儲擴充方式,事務規範,性能)

1.目标:應付超大規模,超大流量以及高并發的場景

2.存儲方式(關系型-表格型,Nosql-資料集中,就像文檔、鍵值對或者圖結構)

3.存儲結構(關系型-結構化資料,Nosql-動态結構,非結構化資料)

4.存儲規範(關系型-資料分割到最小的關系表,Nosql-平面資料集,存在重複)

5.存儲擴充(關系型-提升節點機器性能,Nosql-分布式叢集規模擴張)

6.查詢方式(關系型-結構化sql查詢,Nosql-非結構化查詢語言unql)

7.事務(關系型-ACID原子一緻隔離持久原則,Nosql-Base原則基本可用柔性一緻)

8.性能 (關系型-海量資料讀寫性能差,Nosql-記憶體級key-value效率高)

ps:圖資料庫:Neo4J ·節點與邊線可以被賦予屬性(鍵-值對); ·隻有邊線能夠與類别相關聯,例如“KNOWS”; ·邊線可以指定為有指向或無指向。

2 solr和mongodb的差別,存資料為什麼不用solr?

都可以做非結構化文檔存儲。mongodb是典型的nosql,相對于mysql等傳統的關系型資料庫出現的,側重于存儲非結構化資料,基于這些非結構化資料提供一些簡單的查詢。 solr是典型的搜尋系統,支援結構化資料的搜尋,也支援非結構化資料的搜尋,側重點在于搜尋。
我的了解:solr是以luence為基礎的搜尋引擎,solr中存儲的資料Field會作為索引項存在,但是作為存儲項,很多并不需要作為索引項,僅作存儲展示使用,是以存資料不适合使用solr

3 Redis和memcache有什麼差別?Redis為什麼比memcache有優勢?(存儲方式,存儲格式,叢集管理方式)

  1. 存儲方式:(memcache純記憶體,redis是記憶體+硬碟,快照或者AOF檔案的方式持久化)
  2. 資料支援類型:(redis比memcache支援的存儲類型更多,memcache僅僅支援String)
  3. 叢集管理方式不同:(redis支援分布式,memcache需要用戶端自定義一緻性hash算法來實作分布式的memcache叢集)

PS:mongodb支援豐富的資料表達,索引,最類似關系型資料庫,支援的查詢語言非常豐富。mongoDB支援master-slave,replicaset(内部采用paxos選舉算法,自動故障恢複),auto sharding機制,對用戶端屏蔽了故障轉移和切分機制。 MongoDB從1.8版本開始采用binlog方式支援持久化的可靠性。mongoDB不支援事務。mongoDB内置了資料分析的功能(mapreduce),其他兩者不支援。MongoDB:主要解決海量資料的通路效率問題。