1. 程式人生 > 資料庫 >Java面試彙總-MySQL篇

Java面試彙總-MySQL篇

1、資料庫的三正規化是什麼

第一正規化:列不可再分
第二正規化:行可以唯一區分,主鍵約束
第三正規化:表的非主屬性不能依賴與其他表的非主屬性 外來鍵約束
且三大正規化是一級一級依賴的,第二正規化建立在第一正規化上,第三正規化建立第一第二正規化上。

2、資料庫引擎有哪些

如何檢視mysql提供的所有儲存引擎

mysql> show engines;

mysql常用引擎包括:MYISAM、Innodb、Memory、MERGE

  • MYISAM:全表鎖,擁有較高的執行速度,不支援事務,不支援外來鍵,併發效能差,佔用空間相對較小,對事務完整性沒有要求,以select、insert為主的應用基本上可以使用這引擎
  • Innodb:行級鎖,提供了具有提交、回滾和崩潰回覆能力的事務安全,支援自動增長列,支援外來鍵約束,併發能力強,佔用空間是MYISAM的2.5倍,處理效率相對會差一些
  • Memory:全表鎖,儲存在內容中,速度快,但會佔用和資料量成正比的記憶體空間且資料在mysql重啟時會丟失,預設使用HASH索引,檢索效率非常高,但不適用於精確查詢,主要用於那些內容變化不頻繁的程式碼表
  • MERGE:是一組MYISAM表的組合

3、InnoDB與MyISAM的區別

1. InnoDB支援事務,MyISAM不支援,對於InnoDB每一條SQL語言都預設封裝成事務,自動提交,這樣會影響速度,所以最好把多條SQL語言放在begin和commit之間,組成一個事務;

2. InnoDB支援外來鍵,而MyISAM不支援。對一個包含外來鍵的InnoDB錶轉為MYISAM會失敗;
3. InnoDB是聚集索引,資料檔案是和索引綁在一起的,必須要有主鍵,通過主鍵索引效率很高。但是輔助索引需要兩次查詢,先查詢到主鍵,然後再通過主鍵查詢到資料。因此,主鍵不應該過大,因為主鍵太大,其他索引也都會很大。而MyISAM是非聚集索引,資料檔案是分離的,索引儲存的是資料檔案的指標。主鍵索引和輔助索引是獨立的。
4. InnoDB不儲存表的具體行數,執行select count(*) from table時需要全表掃描。而MyISAM用一個變數儲存了整個表的行數,執行上述語句時只需要讀出該變數即可,速度很快;
5. Innodb不支援全文索引,而MyISAM支援全文索引,查詢效率上MyISAM要高;

如何選擇引擎?
如果沒有特別的需求,使用預設的Innodb 即可。
MyISAM:以讀寫插入為主的應用程式,比如部落格系統、新聞入口網站。
Innodb:更新(刪除)操作頻率也高,或者要保證資料的完整性;併發量高,支援事務和外來鍵。比如OA自動化辦公系統。

4、資料庫的事務

什麼是事務?: 多條sql語句,要麼全部成功,要麼全部失敗。
事務的特性:
資料庫事務特性:原子性(Atomic)、一致性(Consistency)、隔離性(Isolation)、永續性(Durabiliy)。簡稱ACID。

  • 原子性:組成一個事務的多個數據庫操作是一個不可分割的原子單元,只有所有操作都成功,整個事務才會提交。任何一個操作失敗,已經執行的任何操作都必須撤銷,讓資料庫返回初始狀態。
  • 一致性:事務操作成功後,資料庫所處的狀態和它的業務規則是一致的。即資料不會被破壞。如A轉賬100元給B,不管操作是否成功,A和B的賬戶總額是不變的。
  • 隔離性:在併發資料操作時,不同的事務擁有各自的資料空間,它們的操作不會對彼此產生干擾。
  • 永續性:一旦事務提交成功,事務中的所有操作都必須持久化到資料庫中。

5、索引問題

索引是對資料庫表中一個或多個列的值進行排序的結構,建立索引有助於快速獲取資訊。

你也可以這樣理解:索引就是加快檢索表中資料的方法。資料庫的索引類似於書籍的索引。在書籍中,索引允許使用者不必翻閱完整個書就能迅速地找到所需要的資訊。在資料庫中,索引也允許資料庫程式迅速地找到表中的資料,而不必掃描整個資料庫。
mysql 有4種不同的索引:

主鍵索引(PRIMARY)

資料列不允許重複,不允許為NULL,一個表只能有一個主鍵。
唯一索引(UNIQUE)
資料列不允許重複,允許為NULL值,一個表允許多個列建立唯一索引。
可以通過 ALTER TABLE table_name ADD UNIQUE (column); 建立唯一索引
可以通過 ALTER TABLE table_name ADD UNIQUE (column1,column2); 建立唯一組合索引
普通索引(INDEX)
可以通過ALTER TABLE table_name ADD INDEX index_name (column); 建立普通索引
可以通過ALTER TABLE table_name ADD INDEX index_name(column1, column2,column3); 建立組合索引
全文索引(FULLTEXT)
可以通過ALTER TABLE table_name ADD FULLTEXT (column); 建立全文索引
索引並非是越多越好,建立索引也需要耗費資源,一是增加了資料庫的儲存空間,二是在插入和刪除時要花費較多的時間維護索引

  • 索引加快資料庫的檢索速度
  • 索引降低了插入、刪除、修改等維護任務的速度
  • 唯一索引可以確保每一行資料的唯一性
  • 通過使用索引,可以在查詢的過程中使用優化隱藏器,提高系統的效能
  • 索引需要佔物理和資料空間

6、SQL優化

1、查詢語句中不要使用select *
2、儘量減少子查詢,使用關聯查詢(left join,right join,inner join)替代
3、減少使用IN或者NOT IN ,使用exists,not exists或者關聯查詢語句替代
4、or 的查詢儘量用 union或者union all 代替(在確認沒有重複資料或者不用剔除重複資料時,union all會更好)
5、應儘量避免在 where 子句中使用!=或<>操作符,否則將引擎放棄使用索引而進行全表掃描。
6、應儘量避免在 where 子句中對欄位進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描,如: select id from t where num is null 可以在num上設定預設值0,確保表中num列沒有null值,然後這樣查詢: select id from t where num=0

7、簡單說一說drop、delete與truncate的區別

SQL中的drop、delete、truncate都表示刪除,但是三者有一些差別
delete和truncate只刪除表的資料不刪除表的結構
速度,一般來說: drop> truncate >delete
delete語句是dml,這個操作會放到rollback segement中,事務提交之後才生效;
如果有相應的trigger,執行的時候將被觸發. truncate,drop是ddl, 操作立即生效,原資料不放到rollback segment中,不能回滾. 操作不觸發trigger.

8、什麼是檢視

檢視是一種虛擬的表,具有和物理表相同的功能。可以對檢視進行增,改,查,操作,試圖通常是有一個表或者多個表的行或列的子集。對檢視的修改不影響基本表。它使得我們獲取資料更容易,相比多表查詢。

9、 什麼是內聯接、左外聯接、右外聯接

  • 內聯接(Inner Join):匹配2張表中相關聯的記錄。
  • 左外聯接(Left Outer Join):除了匹配2張表中相關聯的記錄外,還會匹配左表中剩餘的記錄,右表中未匹配到的欄位用NULL表示。
  • 右外聯接(Right Outer Join):除了匹配2張表中相關聯的記錄外,還會匹配右表中剩餘的記錄,左表中未匹配到的欄位用NULL表示。在判定左表和右表時,要根據表名出現在Outer Join的左右位置關係。

10、併發事務帶來哪些問題

在典型的應用程式中,多個事務併發執行,經常會操作相同的資料來完成各自的任務(多個使用者對同一資料進行操作)。併發雖然是必須的,但可能會導致以下的問題。

  • 髒讀(Dirty read): 當一個事務正在訪問資料並且對資料進行了修改,而這種修改還沒有提交到資料庫中,這時另外一個事務也訪問了這個資料,然後使用了這個資料。因為這個資料是還沒有提交的資料,那麼另外一個事務讀到的這個資料是“髒資料”,依據“髒資料”所做的操作可能是不正確的。
  • 丟失修改(Lost to modify): 指在一個事務讀取一個數據時,另外一個事務也訪問了該資料,那麼在第一個事務中修改了這個資料後,第二個事務也修改了這個資料。這樣第一個事務內的修改結果就被丟失,因此稱為丟失修改。 例如:事務1讀取某表中的資料A=20,事務2也讀取A=20,事務1修改A=A-1,事務2也修改A=A-1,最終結果A=19,事務1的修改被丟失。
  • 不可重複讀(Unrepeatableread): 指在一個事務內多次讀同一資料。在這個事務還沒有結束時,另一個事務也訪問該資料。那麼,在第一個事務中的兩次讀資料之間,由於第二個事務的修改導致第一個事務兩次讀取的資料可能不太一樣。這就發生了在一個事務內兩次讀到的資料是不一樣的情況,因此稱為不可重複讀。
  • 幻讀(Phantom read): 幻讀與不可重複讀類似。它發生在一個事務(T1)讀取了幾行資料,接著另一個併發事務(T2)插入了一些資料時。在隨後的查詢中,第一個事務(T1)就會發現多了一些原本不存在的記錄,就好像發生了幻覺一樣,所以稱為幻讀。

不可重複讀和幻讀區別:
不可重複讀的重點是修改比如多次讀取一條記錄發現其中某些列的值被修改,幻讀的重點在於新增或者刪除比如多次讀取一條記錄發現記錄增多或減少了。

11、事務隔離級別有哪些?MySQL的預設隔離級別是?

SQL 標準定義了四個隔離級別:

  • READ-UNCOMMITTED(讀取未提交): 最低的隔離級別,允許讀取尚未提交的資料變更,可能會導致髒讀、幻讀或不可重複讀。
  • READ-COMMITTED(讀取已提交): 允許讀取併發事務已經提交的資料,可以阻止髒讀,但是幻讀或不可重複讀仍有可能發生。
  • REPEATABLE-READ(可重複讀): 對同一欄位的多次讀取結果都是一致的,除非資料是被本身事務自己所修改,可以阻止髒讀和不可重複讀,但幻讀仍有可能發生。
  • SERIALIZABLE(可序列化): 最高的隔離級別,完全服從ACID的隔離級別。所有的事務依次逐個執行,這樣事務之間就完全不可能產生干擾,也就是說,該級別可以防止髒讀、不可重複讀以及幻讀
隔離級別髒讀不可重複讀幻讀
READ-UNCOMMITTED
READ-COMMITTED×
REPEATABLE-READ××
SERIALIZABLE×××

MySQL InnoDB 儲存引擎的預設支援的隔離級別是 REPEATABLE-READ(可重讀)。我們可以通過SELECT @@tx_isolation; 命令來檢視

mysql> SELECT @@tx_isolation;
+-----------------+
| @@tx_isolation  |
+-----------------+
| REPEATABLE-READ |
+-----------------+

這裡需要注意的是:與 SQL 標準不同的地方在於 InnoDB 儲存引擎在 REPEATABLE-READ(可重讀)事務隔離級別下使用的是Next-Key Lock 鎖演算法,因此可以避免幻讀的產生,這與其他資料庫系統(如SQL Server) 是不同的。所以說InnoDB 儲存引擎的預設支援的隔離級別是 REPEATABLE-READ(可重讀) 已經可以完全保證事務的隔離性要求,即達到了 SQL標準的 SERIALIZABLE(可序列化) 隔離級別。因為隔離級別越低,事務請求的鎖越少,所以大部分資料庫系統的隔離級別都是 READCOMMITTED(讀取提交內容) ,但是你要知道的是InnoDB 儲存引擎預設使用 REPEAaTABLEREAD(可重讀) 並不會有任何效能損失。
InnoDB 儲存引擎在 分散式事務 的情況下一般會用到 SERIALIZABLE(可序列化) 隔離級別。

12、大表如何優化?

當MySQL單表記錄數過大時,資料庫的CRUD效能會明顯下降,一些常見的優化措施如下:
1. 限定資料的範圍
務必禁止不帶任何限制資料範圍條件的查詢語句。比如:我們當用戶在查詢訂單歷史的時候,我們可以控制在一個月的範圍內;
2. 讀/寫分離
經典的資料庫拆分方案,主庫負責寫,從庫負責讀;
3. 垂直分割槽
根據資料庫裡面資料表的相關性進行拆分。 例如,使用者表中既有使用者的登入資訊又有使用者的基本資訊,可以將使用者表拆分成兩個單獨的表,甚至放到單獨的庫做分庫。
簡單來說垂直拆分是指資料表列的拆分,把一張列比較多的表拆分為多張表。 如下圖所示,這樣來說大家應該就更容易理解了

垂直拆分的優點: 可以使得列資料變小,在查詢時減少讀取的Block數,減少I/O次數。此外,垂直分割槽可以簡化表的結構,易於維護。
垂直拆分的缺點: 主鍵會出現冗餘,需要管理冗餘列,並會引起Join操作,可以通過在應用層進行Join來解決。此外,垂直分割槽會讓事務變得更加複雜;
4. 水平分割槽

保持資料表結構不變,通過某種策略儲存資料分片。這樣每一片資料分散到不同的表或者庫中,達到了分散式的目的。 水平拆分可以支撐非常大的資料量。
水平拆分是指資料錶行的拆分,表的行數超過200萬行時,就會變慢,這時可以把一張的表的資料拆成多張表來存放。舉個例子:我們可以將使用者資訊表拆分成多個使用者資訊表,這樣就可以避免單一表資料量過大對效能造成影響。

水平拆分可以支援非常大的資料量。需要注意的一點是:分表僅僅是解決了單一表資料過大的問題,但由於表的資料還是在同一臺機器上,其實對於提升MySQL併發能力沒有什麼意義,所以 水平拆分最好分庫
水平拆分能夠 支援非常大的資料量儲存,應用端改造也少,但 分片事務難以解決 ,跨節點Join效能較差,邏輯複雜。《Java工程師修煉之道》的作者推薦 儘量不要對資料進行分片,因為拆分會帶來邏輯、部署、運維的各種複雜度 ,一般的資料表在優化得當的情況下支撐千萬以下的資料量是沒有太大問題的。如果實在要分片,儘量選擇客戶端分片架構,這樣可以減少一次和中介軟體的網路I/O。
下面補充一下資料庫分片的兩種常見方案:

  • 客戶端代理: 分片邏輯在應用端,封裝在jar包中,通過修改或者封裝JDBC層來實現。 噹噹網的Sharding-JDBC 、阿里的TDDL是兩種比較常用的實現。
  • 中介軟體代理: 在應用和資料中間加了一個代理層。分片邏輯統一維護在中介軟體服務中。 我們現在談的 Mycat 、360的Atlas、網易的DDB等等都是這種架構的實現。

詳細內容可以參考:

13、分庫分表之後,id 主鍵如何處理?

因為要是分成多個表之後,每個表都是從 1 開始累加,這樣是不對的,我們需要一個全域性唯一的 id 來支援。
生成全域性 id 有下面這幾種方式:

  • UUID:不適合作為主鍵,因為太長了,並且無序不可讀,查詢效率低。比較適合用於生成唯一的名字的標示比如檔案的名字。
  • 資料庫自增 id : 兩臺資料庫分別設定不同步長,生成不重複ID的策略來實現高可用。這種方式生成的 id 有序,但是需要獨立部署資料庫例項,成本高,還會有效能瓶頸。
  • 利用 redis 生成 id : 效能比較好,靈活方便,不依賴於資料庫。但是,引入了新的元件造成系統更加複雜,可用性降低,編碼更加複雜,增加了系統成本。
  • Twitter的snowflake演算法 :。
  • 美團的Leaf分散式ID生成系統 :Leaf 是美團開源的分散式ID生成器,能保證全域性唯一性、趨勢遞增、單調遞增、資訊保安,裡面也提到了幾種分散式方案的對比,但也需要依賴關係資料庫、Zookeeper等中介軟體。感覺還不錯。 。

14、mysql有關許可權的表都有哪幾個

MySQL伺服器通過許可權表來控制使用者對資料庫的訪問,許可權表存放在mysql資料庫裡,由mysql_install_db指令碼初始化。這些許可權表分別user,db,table_priv,columns_priv和host。下面分別介紹一下這些表的結構和內容:

  • user許可權表:記錄允許連線到伺服器的使用者帳號資訊,裡面的許可權是全域性級的。
  • db許可權表:記錄各個帳號在各個資料庫上的操作許可權。
  • table_priv許可權表:記錄資料表級的操作許可權。
  • columns_priv許可權表:記錄資料列級的操作許可權。
  • host許可權表:配合db許可權表對給定主機上資料庫級操作許可權作更細緻的控制。這個許可權表不受GRANT和REVOKE語句的影響。

15、mysql有哪些資料型別

1、整數型別 ,包括TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT,分別表示1位元組、2位元組、3位元組、4位元組、8位元組整數。任何整數型別都可以加上UNSIGNED屬性,表示資料是無符號的,即非負整數。
長度:整數型別可以被指定長度,例如:INT(11)表示長度為11的INT型別。長度在大多數場景是沒有意義的,它不會限制值的合法範圍,只會影響顯示字元的個數,而且需要和UNSIGNED ZEROFILL屬性配合使用才有意義。
例子,假定型別設定為INT(5),屬性為UNSIGNED ZEROFILL,如果使用者插入的資料為12的話,那麼資料庫實際儲存資料為00012。
2、實數型別,包括FLOAT、DOUBLE、DECIMAL。
DECIMAL可以用於儲存比BIGINT還大的整型,能儲存精確的小數。
而FLOAT和DOUBLE是有取值範圍的,並支援使用標準的浮點進行近似計算。
計算時FLOAT和DOUBLE相比DECIMAL效率更高一些,DECIMAL你可以理解成是用字串進行處理。
3、字串型別,包括VARCHAR、CHAR、TEXT、BLOB
VARCHAR用於儲存可變長字串,它比定長型別更節省空間。
VARCHAR使用額外1或2個位元組儲存字串長度。列長度小於255位元組時,使用1位元組表示,否則使用2位元組表示。
VARCHAR儲存的內容超出設定的長度時,內容會被截斷。
CHAR是定長的,根據定義的字串長度分配足夠的空間。
CHAR會根據需要使用空格進行填充方便比較。
CHAR適合儲存很短的字串,或者所有值都接近同一個長度。
CHAR儲存的內容超出設定的長度時,內容同樣會被截斷。
使用策略:
對於經常變更的資料來說,CHAR比VARCHAR更好,因為CHAR不容易產生碎片。
對於非常短的列,CHAR比VARCHAR在儲存空間上更有效率。
使用時要注意只分配需要的空間,更長的列排序時會消耗更多記憶體。
儘量避免使用TEXT/BLOB型別,查詢時會使用臨時表,導致嚴重的效能開銷。
4、列舉型別(ENUM),把不重複的資料儲存為一個預定義的集合。
有時可以使用ENUM代替常用的字串型別。
ENUM儲存非常緊湊,會把列表值壓縮到一個或兩個位元組。
ENUM在內部儲存時,其實存的是整數。
儘量避免使用數字作為ENUM列舉的常量,因為容易混亂。
排序是按照內部儲存的整數

5、日期和時間型別,儘量使用timestamp,空間效率高於datetime,
用整數儲存時間戳通常不方便處理。
如果需要儲存微妙,可以使用bigint儲存。
看到這裡,這道真題是不是就比較容易回答了。

16、建立索引的三種方式,刪除索引

第一種方式:在執行CREATE TABLE時建立索引

CREATE TABLE user_index2 (
id INT auto_increment PRIMARY KEY,
first_name VARCHAR (16),
last_name VARCHAR (16),
id_card VARCHAR (18),
information text,
KEY name (first_name, last_name),
FULLTEXT KEY (information),
UNIQUE KEY (id_card)
);

第二種方式:使用ALTER TABLE命令去增加索引

ALTER TABLE table_name ADD INDEX index_name (column_list);

ALTER TABLE用來建立普通索引、UNIQUE索引或PRIMARY KEY索引。
其中table_name是要增加索引的表名,column_list指出對哪些列進行索引,多列時各列之間用逗號分隔。
索引名index_name可自己命名,預設時,MySQL將根據第一個索引列賦一個名稱。另外,ALTER TABLE允許在單個語句中更改多個表,因此可以在同時建立多個索引。
第三種方式:使用CREATE INDEX命令建立

CREATE INDEX index_name ON table_name (column_list);

CREATE INDEX可對錶增加普通索引或UNIQUE索引。(但是,不能建立PRIMARY KEY索引)
刪除索引
根據索引名刪除普通索引、唯一索引、全文索引: alter table 表名 drop KEY 索引名

alter table user_index drop KEY name;
alter table user_index drop KEY id_card;
alter table user_index drop KEY information;

刪除主鍵索引: alter table 表名 drop primary key (因為主鍵只有一個)。這裡值得注意的是,如果主鍵自增長,那麼不能直接執行此操作(自增長依賴於主鍵索引):

需要取消自增長再行刪除:

alter table user_index
-- 重新定義欄位
MODIFY id int,
drop PRIMARY KEY

但通常不會刪除主鍵,因為設計主鍵一定與業務邏輯無關。