java面試總結之三

前言html

數據庫是java開發過程必不可少的數據存儲工具,一般咱們分爲關係型數據庫和非關係型數據庫,上一篇中已經簡單的介紹了redis,這裏說一說關係型數據庫mysql。java

一、mysql引擎mysql

  這裏只說咱們常見的兩種引擎,MyISAM和Innodb,其餘相關的引擎有興趣的能夠自行了解。首先咱們簡單的說說這兩種引擎的區別。redis

  1)MyISAM,不支持事務,支持全文索引、表鎖,在磁盤上有三個與表名相同的文件,.FRM文件存儲表結構,.MYD文件存儲表數據,.MYI文件存儲表索引,MyISAM不緩存數據,只緩存索引。算法

  2)InnoDB,支持事務、外鍵、行鎖和非鎖定讀,即默認狀況下讀不產生鎖。InnoDB由一系列後臺線程和一大塊內存組成。默認狀況下,後臺線程有7個,4個IO線程,1個master thread,1個lock監控線程,1個error監控線程。sql

  在實際開發中,因爲事務和行級鎖等機制的緣由,Innodb可能接觸的更多一些。MyISAM更多用於查詢,尤爲是select * from tableName,能夠直接獲取到數值,不須要全表掃描。數據庫

二、mysql結構編程

  mysql的結構以下圖所示,我的十分喜歡這張圖,經過這張圖還能夠大體瞭解一條SQL語句的執行過程
後端

  1)Connectors,與其餘編程語言(java等)中的sql語句進行交互
  2)Connection pool,鏈接池,管理緩存用戶鏈接、線程處理等須要緩存的數據
  3)Management services&Utilities,系統管理和控制工具
  4)SQL interface,SQL接口,接收用戶的sql命令,並返回用戶須要的結果
  5)parser,解析器,驗證並解析用戶傳來的sql語句,將sql語句解析成數據結構,並將這個數據結構傳遞到後續步驟,若是解析過程須要錯誤,說明sql語句是錯誤的,中止執行
  6)Optimlzer,優化器,產生多種執行計劃,數據庫選擇最優的方案執行
  7)cache&buffer,緩存,若是查詢緩存有命中,則直接返回結果。cache是讀緩存,buffer是寫緩存。
  8)Engines,存儲引擎
  SQL語句執行過程:
  1)請求與mysql的connectors進行交互,請求到達後會暫時存放在鏈接池(connection pool)中,並由處理器(management services&utilities)管理。當請求從等待隊列進入處理隊列後,管理器會將請求交給SQL接口(SQL interface)。
  2)SQL接口接收到請求後,會將請求進行hash處理並和緩存(cache&buffer)中的結果進行比較,若是徹底匹配,則直接返回緩存數據。
  3)若是緩存未命中,由SQL接口將請求交給解析器(parser),解析器將sql語言解析成數據結構
  4)解析器處理完畢,請求便來到優化器(optimizer),優化器會產生多個執行計劃,數據庫會選擇一個最優方案來執行
  5)肯定最優方案以後,sql語句即可以由存儲引擎處理(engines),存儲引擎將會到後端的存儲設備中獲取數據並原路返回
三、索引
  mysql中的索引包括主鍵索引(默認自動爲主鍵添加)、普通索引、惟一索引(字段的值不能重複)、組合索引和全文索引(不建議使用,並且Innodb也不支持,建議使用solr等代替)。其中組合索引須要額外說明一下,組合索引知足最左原則,即假如在A、B、C三列上添加索引,實際上會額外在A和A,B上建立索引,至關於建立了三個索引。另外能夠經過show index from tableName查詢該表上的索引。索引的算法包括B-Tree和Hash兩種,在此強調一下Innodb不支持Hash,即便設置成Hash,索引依然使用B-Tree。
  一般咱們會在常用的查詢語句的where和join字段上添加索引,這裏須要注意的是join的兩個字段必須類型一致,若是是字符串類型,編碼格式也要同樣,不然將沒法使用索引,另外,在like中,以_%通配符開頭的查詢沒法使用索引,如:
select * from tableName where name like '_zhang'
select * from tableName where name like '%zhang'

  上述兩個sql沒法使用name列上的索引緩存

select * from tableName where name like 'zhang_'
select * from tableName where name like 'zhang%'

  上述兩個sql可使用name列上的索引

  還有一點須要注意的是,對於變化較少的字段不建議添加索引,如性別的列,一般的值是0和1或者true和false,此列添加索引不會有太大的速度提高。一個表的索引個數也不建議過多,增刪改數據的同時還要維護索引,過多的索引會下降數據庫的效率。

四、mysql優化

  mysql的優化從三個方面入手,包括建立表時的優化,索引的建立以及sql的優化

  1)建立表時的優化

    a)爲表添加主鍵ID,最好使用無符號的int類型,設置成自增(注意分表時id重複的狀況)

    b)針對字典表能夠考慮使用ENUM類型代替字符串,若是插入的值不在ENUM規定值內,則自動使用''空字符串代替

    c)儘可能使用NOT NULL,使用NULL須要額外的空間,並且NULL沒法使用索引

    d)使用PROCEDURE ANALYSE()函數取得建議,根據表中數據進行分析,因此須要數據庫中有必定的數據作基礎,如:

SELECT * FROM sys_user PROCEDURE ANALYSE();

    越小的列越快,在考慮往後數據擴展的前提下,儘可能使用較小存儲單元的類型,如字典表中數據較少時,主鍵能夠放棄使用INT,用MEDIUMINT、SMALLINT來代替,甚至使用更小的TINYINT,若是不須要記錄時間,可使用DATE代替DATETIME

    e)使用固定長度的表,若是表中全部的列都是固定長度的,表會被認爲是「static」的,會加快查詢速度,若是列中包含varchar、text或blog之一,則表不是固定長度的。固定長度的表因爲定長,能夠根據偏移量計算下一條數據的位置,而變長的表只能經過尋找下一條數據的主鍵。固定長度的表的缺點就是會形成空間浪費,由於不管存儲數據大小,都會分配定長的空間。注:mysql字段佔用空間與類型有關,如int(11)和int(3)都佔用四個字節的長度,區別是根據存儲數據的長度自動補全零位的個數,存儲1111時,因爲長度是4,int(3)不須要補零,int(11)會自動補全7個0

    f)表分割,表分割能夠分爲水平分割和垂直分割。水平分割就是創建結構相同可是表名不一樣的表,將數據按照hash運算以後存儲在對應的表中,如sys_user_1,sys_user_2等;垂直分割是將表中一些不經常使用的或者會常常更新致使查詢緩存失效的列分割出來,如家庭住址,最後登陸時間等字段。注:被分割的字段不能常常被JOIN,不然會極大下降性能

    g)數據庫讀寫分離

  2)索引的建立

    索引的建立就是在適合的列上添加索引,從而達到加快查詢速度的效果,上面已經說起,這裏再也不累述。

  3)SQL的優化

    a)使用explain關鍵字解析sql語句,如:

EXPLAIN SELECT * FROM (SELECT user_sex,COUNT(*) AS counts FROM sys_user u GROUP BY u.user_sex) count_t WHERE count_t.counts > 1

    結果以下所示:

    一般咱們關注的是type這一列,這裏不要求記住全部,只須要記住幾個典型的,而且瞭解哪一個更優便可,如system、const、eq_ref、ref、range、index、all等。這裏有一篇文章,你們能夠參考瞭解一下:《mysql explain 的type解釋》

    b)在查詢結果明確只有一條的狀況下,且該列上沒有索引,使用LIMIT 1能夠在查詢到數據以後直接返回,避免全表掃描;判斷一條數據是否存在時,使用SELECT 1能夠提升查詢速度,SELECT 1 > SELECT any column > SELECT *

    c)避免SELECT *,用什麼數據取什麼列,減小網絡數據傳輸

    d)儘可能少用having、in、not in、is null等關鍵字或判斷,對於having,可使用子查詢來代替;in和not in可使用exists和not exists代替,若是數據連續,也可使用between and代替。

五、Innodb文件結構

  InnoDB表由共享表空間或獨立表空間、日誌文件組和表結構文件組成。可使用show variables like 'innodb_file_per_table'查看是否開啓了獨立表空間,結果爲ON時表示開啓獨立表空間;OFF時表示使用共享共享表空間。

  1)表結構文件(.frm)mysql會爲每一個表在其數據目錄下建立一個tablename.frm文件來存儲表結構定義,與引擎無關,用來恢復表結構
  2)表空間文件,表空間(tablespace)由分散的段(segment)組成,一個段包含多個區(extent),一個區由64個連續的頁(page)組成,每一個頁的大小爲16K,因此一個區的大小爲1M,區包含行(row)。
  3)共享表空間將全部的數據存儲在一個單獨的表空間裏面;獨立表空間爲每個表建立一個表空間文件(.ibd),存儲表的數據、索引等數據,撤銷(undo)信息、系統事務信息等存放在原來的共享表空間中。在mysql5.6.5及以前默認是共享表空間,以後默認是獨立表空間。可使用 SHOW VARIABLES like 'innodb_data%'命令來查看共享表空間文件信息,文件默認的名稱是ibdata1,初始大小爲10M,可自動擴展,如:ibdata1:10M:autoextend
  4)共享表空間的優劣勢
    優點:能夠將表空間分紅多個文件存儲在不一樣的磁盤上,一個表的數據能夠存放在不一樣的表空間文件上,表空間文件大小不受表大小限制;數據和文件放在一塊兒,方便管理
    劣勢:大量刪除數據時,表空間會出現空隙
  5)獨立表空間的優劣勢
    優點:每一個表有獨立的表空間,表數據和索引存儲在獨立的表空間中,能夠實現單表在數據庫中的轉移(數據文件複製);大量刪除數據的時候,能夠壓縮表空間文件,回收空間
    劣勢:單個表空間文件很大
六、事務隔離級別
  說到數據庫就不得不說一下事務,簡單的ACID原則你們都知道,講的是原子性、隔離性、一致性和永久性,但願你能用實際狀況描述一下這四種特性。另外就是事務的隔離級別,以下:
    1)Read uncommitted,讀取未提交內容,最低級別,任何狀況均可能發生
    2)Read committed,讀取已提交內容,可避免髒讀
    3)Repeatable read,可重複讀,可避免髒讀、不可重複讀
    4)Serializable,串行化,避免髒讀、不可重複讀、幻讀
  以上四種隔離級別最高的是Serializable級別,最低的是Read uncommitted級別,固然級別越高,執行效率就越低。像Serializable這樣的級別,就是以鎖表的方式(相似於Java多線程中的鎖)使得其餘的線程只能在鎖外等待,因此平時選用何種隔離級別應該根據實際狀況。在MySQL數據庫中,支持上面四種隔離級別,默認的爲Repeatable read (可重複讀);而在Oracle數據庫中,只支持Serializable (串行化)級別和Read committed (讀已提交)這兩種級別,其中默認的爲Read committed級別。
  順帶提一下數據異常的狀況:
    1)髒讀,一個事務在執行過程當中讀取了另外一個事務未提交的數據。
    2)不可重複讀,一個事務範圍內的屢次查詢返回不一樣結果,因爲在查詢間隔中,數據被其餘事務修改並提交了。
    3)幻讀,一個事務對一批數據進行修改,另外一個事務插入一條新數據,此時新插入的數據並未被第一個事務修改,產生幻讀。
   髒讀是讀取另外一個事務未提交的數據產生的,而不可重複讀和幻讀是讀取另外一個事務已提交的數據產生的;不可重複讀是針對一條數據產生的,幻讀是針對一批數據產生的。
七、Innodb鎖
  針對鎖的粒度大小不一樣,mysql分爲行級鎖、表鎖、頁鎖,這裏咱們只討論行級鎖和表鎖。Innodb支持行級鎖,MyISAM使用的是表鎖。根據鎖的性質不一樣,又可分爲讀鎖(共享鎖)、寫鎖(排它鎖)和意向鎖。只有讀鎖與讀鎖是兼容的,也就是說多個線程能夠同時讀取同一數據,可是當有一個線程寫數據時,其餘線程不管是讀取仍是寫該數據均被阻塞。意向鎖是一種虛擬的鎖,當一個線程對錶結構進行修改時,須要對整個表進行加鎖,再獲取到表鎖以後還須要判斷是否存在行級鎖,傳統的方式就是一行一行的判斷,這樣是極其低效的方法。意向鎖的思想是,在添加行級鎖時,對錶添加意向鎖,當有其餘線程對錶加鎖以後,只須要判斷是否存在乎向鎖就能夠知道是否存在行級鎖了。
  添加讀鎖的方式爲:
select * from tableName where id =1 lock in share mode
  添加寫鎖的方式爲:
select * from tableName where id =1 for update
  這裏須要說明一下,添加寫鎖時,必須明確id且id存在,不然將添加表鎖。
  死鎖只會出如今行級鎖的狀況下,即兩個進程都持有一部分數據的鎖,可是再釋放鎖以前又想獲取對方的持有的鎖,從而形成無限等待下去的狀況。這裏有一篇文章,你們能夠參考一下: 《Mysql併發時經典常見的死鎖緣由及解決方法》
關於mysql的總結大體就這麼,還有不少東西等待咱們去探索和學習,但願這篇文章能幫助你們對mysql有一個簡單的瞭解。

本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接,不然保留追究法律責任的權利。

原文連接:http://www.cnblogs.com/1ning/p/6705129.html

相關文章
相關標籤/搜索