網際網路公司面試必問的mysql題目(下)

table 查詢的數據表,當從衍生表中查數據時會顯示 x 表示對應的執行計劃id partitions

表分區、表創建的時候可以指定通過那個列進行表分區。 舉個例子:

create table tmp (
id int unsigned not null AUTO_INCREMENT,
name varchar(255),
PRIMARY KEY (id)
) engine = innodb
partition by key (id) partitions 5;
複製代碼
互聯網公司面試必問的mysql題目(下)

type(非常重要,可以看到有沒有走索引) 訪問類型

  • ALL 掃描全表數據
  • index 遍歷索引
  • range 索引範圍查找
  • index_subquery 在子查詢中使用 ref
  • unique_subquery 在子查詢中使用 eq_ref
  • ref_or_null 對Null進行索引的優化的 ref
  • fulltext 使用全文索引
  • ref 使用非唯一索引查找數據
  • eq_ref 在join查詢中使用PRIMARY KEYorUNIQUE NOT NULL索引關聯。

possible_keys 可能使用的索引,注意不一定會使用。查詢涉及到的字段上若存在索引,則該索引將被列出來。當該列為 NULL時就要考慮當前的SQL是否需要優化了。

key 顯示MySQL在查詢中實際使用的索引,若沒有使用索引,顯示為NULL。

TIPS:查詢中若使用了覆蓋索引(覆蓋索引:索引的數據覆蓋了需要查詢的所有數據),則該索引僅出現在key列表中

key_length 索引長度

ref 表示上述表的連接匹配條件,即哪些列或常量被用於查找索引列上的值

rows 返回估算的結果集數目,並不是一個準確的值。

extra 的信息非常豐富,常見的有:

  1. Using index 使用覆蓋索引
  2. Using where 使用了用where子句來過濾結果集
  3. Using filesort 使用文件排序,使用非索引列進行排序時出現,非常消耗性能,儘量優化。
  4. Using temporary 使用了臨時表 sql優化的目標可以參考阿里開發手冊
互聯網公司面試必問的mysql題目(下)

某個表有近千萬數據,CRUD比較慢,如何優化?分庫分表了是怎麼做的?分表分庫了有什麼問題?有用到中間件麼?他們的原理知道麼?

數據千萬級別之多,佔用的存儲空間也比較大,可想而知它不會存儲在一塊連續的物理空間上,而是鏈式存儲在多個碎片的物理空間上。可能對於長字符串的比較,就用更多的時間查找與比較,這就導致用更多的時間。

  • 可以做表拆分,減少單表字段數量,優化表結構。
  • 在保證主鍵有效的情況下,檢查主鍵索引的字段順序,使得查詢語句中條件的字段順序和主鍵索引的字段順序保持一致。

主要兩種拆分 垂直拆分,水平拆分。

互聯網公司面試必問的mysql題目(下)

垂直分表

也就是“大表拆小表”,基於列字段進行的。一般是表中的字段較多,將不常用的, 數據較大,長度較長(比如text類型字段)的拆分到“擴展表“。 一般是針對那種幾百列的大表,也避免查詢時,數據量太大造成的“跨頁”問題。

垂直分庫針對的是一個系統中的不同業務進行拆分,比如用戶User一個庫,商品Producet一個庫,訂單Order一個庫。 切分後,要放在多個服務器上,而不是一個服務器上。為什麼? 我們想象一下,一個購物網站對外提供服務,會有用戶,商品,訂單等的CRUD。沒拆分之前, 全部都是落到單一的庫上的,這會讓數據庫的單庫處理能力成為瓶頸。按垂直分庫後,如果還是放在一個數據庫服務器上, 隨著用戶量增大,這會讓單個數據庫的處理能力成為瓶頸,還有單個服務器的磁盤空間,內存,tps等非常吃緊。 所以我們要拆分到多個服務器上,這樣上面的問題都解決了,以後也不會面對單機資源問題。

數據庫業務層面的拆分,和服務的“治理”,“降級”機制類似,也能對不同業務的數據分別的進行管理,維護,監控,擴展等。 數據庫往往最容易成為應用系統的瓶頸,而數據庫本身屬於“有狀態”的,相對於Web和應用服務器來講,是比較難實現“橫向擴展”的。 數據庫的連接資源比較寶貴且單機處理能力也有限,在高併發場景下,垂直分庫一定程度上能夠突破IO、連接數及單機硬件資源的瓶頸。

水平分表

針對數據量巨大的單張表(比如訂單表),按照某種規則(RANGE,HASH取模等),切分到多張表裡面去。 但是這些表還是在同一個庫中,所以庫級別的數據庫操作還是有IO瓶頸。不建議採用。

水平分庫分表

將單張表的數據切分到多個服務器上去,每個服務器具有相應的庫與表,只是表中數據集合不同。 水平分庫分表能夠有效的緩解單機和單庫的性能瓶頸和壓力,突破IO、連接數、硬件資源等的瓶頸。

水平分庫分表切分規則

  1. RANGE從 0到10000一個表,10001到20000一個表;
  2. HASH取模 一個商場系統,一般都是將用戶,訂單作為主表,然後將和它們相關的作為附表,這樣不會造成跨庫事務之類的問題。 取用戶id,然後hash取模,分配到不同的數據庫上。
  3. 地理區域 比如按照華東,華南,華北這樣來區分業務,七牛雲應該就是如此。
  4. 時間 按照時間切分,就是將6個月前,甚至一年前的數據切出去放到另外的一張表,因為隨著時間流逝,這些表的數據 被查詢的概率變小,所以沒必要和“熱數據”放在一起,這個也是“冷熱數據分離”。

分庫分表後面臨的問題

  • 事務支持 分庫分表後,就成了分佈式事務了。如果依賴數據庫本身的分佈式事務管理功能去執行事務,將付出高昂的性能代價; 如果由應用程序去協助控制,形成程序邏輯上的事務,又會造成編程方面的負擔。
  • 跨庫join
  • 只要是進行切分,跨節點Join的問題是不可避免的。但是良好的設計和切分卻可以減少此類情況的發生。解決這一問題的普遍做法是分兩次查詢實現。在第一次查詢的結果集中找出關聯數據的id,根據這些id發起第二次請求得到關聯數據。 分庫分表方案產品
  • 跨節點的count,order by,group by以及聚合函數問題
    這些是一類問題,因為它們都需要基於全部數據集合進行計算。多數的代理都不會自動處理合併工作。解決方案:與解決跨節點join問題的類似,分別在各個節點上得到結果後在應用程序端進行合併。和join不同的是每個結點的查詢可以並行執行,因此很多時候它的速度要比單一大表快很多。但如果結果集很大,對應用程序內存的消耗是一個問題。
  • 數據遷移,容量規劃,擴容等問題 來自淘寶綜合業務平臺團隊,它利用對2的倍數取餘具有向前兼容的特性(如對4取餘得1的數對2取餘也是1)來分配數據,避免了行級別的數據遷移,但是依然需要進行表級別的遷移,同時對擴容規模和分表數量都有限制。總得來說,這些方案都不是十分的理想,多多少少都存在一些缺點,這也從一個側面反映出了Sharding擴容的難度。
  • ID問題
  • 一旦數據庫被切分到多個物理結點上,我們將不能再依賴數據庫自身的主鍵生成機制。一方面,某個分區數據庫自生成的ID無法保證在全局上是唯一的;另一方面,應用程序在插入數據之前需要先獲得ID,以便進行SQL路由. 一些常見的主鍵生成策略

UUID 使用UUID作主鍵是最簡單的方案,但是缺點也是非常明顯的。由於UUID非常的長,除佔用大量存儲空間外,最主要的問題是在索引上,在建立索引和基於索引進行查詢時都存在性能問題。 Twitter的分佈式自增ID算法Snowflake 在分佈式系統中,需要生成全局UID的場合還是比較多的,twitter的snowflake解決了這種需求,實現也還是很簡單的,除去配置信息,核心代碼就是毫秒級時間41位 機器ID 10位 毫秒內序列12位。

  • 跨分片的排序分頁 般來講,分頁時需要按照指定字段進行排序。當排序字段就是分片字段的時候,我們通過分片規則可以比較容易定位到指定的分片,而當排序字段非分片字段的時候,情況就會變得比較複雜了。為了最終結果的準確性,我們需要在不同的分片節點中將數據進行排序並返回,並將不同分片返回的結果集進行彙總和再次排序,最後再返回給用戶。如下圖所示:
互聯網公司面試必問的mysql題目(下)


中間件推薦

互聯網公司面試必問的mysql題目(下)

mysql中in 和exists 區別

mysql中的in語句是把外表和內表作hash 連接,而exists語句是對外表作loop循環,每次loop循環再對內表進行查詢。一直大家都認為exists比in語句的效率要高,這種說法其實是不準確的。這個是要區分環境的。

  1. 如果查詢的兩個表大小相當,那麼用in和exists差別不大。
  2. 如果兩個表中一個較小,一個是大表,則子查詢表大的用exists,子查詢表小的用in。
  3. not in 和not exists如果查詢語句使用了not in 那麼內外表都進行全表掃描,沒有用到索引;而not extsts的子查詢依然能用到表上的索引。所以無論那個表大,用not exists都比not in要快。

現在私信我“資料”即可獲取Java工程化、高性能及分佈式、高性能、高架構。性能調優、Spring,MyBatis,Netty源碼分析和大數據等多個知識點高級進階乾貨的直播免費學習權限及領取思維導圖等相關資料


分享到:


相關文章: