數據庫常見面試題

事務四大特性(ACID)原子性、一致性、隔離性、持久性?

原子性(Atomicity)

原子性是指事務包含的所有操作要麼全部成功,要麼全部失敗回滾,因此事務的操作如果成功就必須要完全應用到數據庫,如果操作失敗則不能對數據庫有任何影響。

一致性(Consistency)

事務開始前和結束後,數據庫的完整性約束沒有被破壞。比如A向B轉賬,不可能A扣了錢,B卻沒收到。

隔離性(Isolation)

隔離性是當多個用戶併發訪問數據庫時,比如操作同一張表時,數據庫爲每一個用戶開啓的事務,不能被其他事務的操作所幹擾,多個併發事務之間要相互隔離。

同一時間,只允許一個事務請求同一數據,不同的事務之間彼此沒有任何干擾。比如A正在從一張銀行卡中取錢,在A取錢的過程結束前,B不能向這張卡轉賬。

關於事務的隔離性數據庫提供了多種隔離級別,稍後會介紹到。   持久性(Durability)

持久性是指一個事務一旦被提交了,那麼對數據庫中的數據的改變就是永久性的,即便是在數據庫系統遇到故障的情況下也不會丟失提交事務的操作.

事務的併發?事務隔離級別,每個級別會引發什麼問題,MySQL默認是哪個級別?

從理論上來說, 事務應該彼此完全隔離, 以避免併發事務所導致的問題,然而, 那樣會對性能產生極大的影響, 因爲事務必須按順序運行, 在實際開發中, 爲了提升性能, 事務會以較低的隔離級別運行, 事務的隔離級別可以通過隔離事務屬性指定。
事務的併發問題

1、髒讀:事務A讀取了事務B更新的數據,然後B回滾操作,那麼A讀取到的數據是髒數據

2、不可重複讀:事務 A 多次讀取同一數據,事務 B 在事務A多次讀取的過程中,對數據作了更新並提交,導致事務A多次讀取同一數據時,結果因此本事務先後兩次讀到的數據結果會不一致。

3、幻讀:幻讀解決了不重複讀,保證了同一個事務裏,查詢的結果都是事務開始時的狀態(一致性)。

例如:事務T1對一個表中所有的行的某個數據項做了從“1”修改爲“2”的操作 這時事務T2又對這個表中插入了一行數據項,而這個數據項的數值還是爲“1”並且提交給數據庫。 而操作事務T1的用戶如果再查看剛剛修改的數據,會發現還有跟沒有修改一樣,其實這行是從事務T2中添加的,就好像產生幻覺一樣,這就是發生了幻讀。

小結:不可重複讀的和幻讀很容易混淆,不可重複讀側重於修改,幻讀側重於新增或刪除。解決不可重複讀的問題只需鎖住滿足條件的行,解決幻讀需要鎖表。
事務的隔離級別
事務隔離級別 髒讀 不可重複讀 幻讀
讀未提交 read-uncommitted 是 是 是
不可重複讀 read-committed 否 是 是
可重複讀 repeatable-read 否 否 是
串行化 serializable 否 否 否

讀未提交:另一個事務修改了數據,但尚未提交,而本事務中的SELECT會讀到這些未被提交的數據髒讀
不可重複讀:事務 A 多次讀取同一數據,事務 B 在事務A多次讀取的過程中,對數據作了更新並提交,導致事務A多次讀取同一數據時,結果因此本事務先後兩次讀到的數據結果會不一致。
可重複讀:在同一個事務裏,SELECT的結果是事務開始時時間點的狀態,因此,同樣的SELECT操作讀到的結果會是一致的。但是,會有幻讀現象
串行化:最高的隔離級別,在這個隔離級別下,不會產生任何異常。併發的事務,就像事務是在一個個按照順序執行一樣

MySQL默認的事務隔離級別爲repeatable-read

MySQL 支持 4 中事務隔離級別.
事務的隔離級別要得到底層數據庫引擎的支持, 而不是應用程序或者框架的支持.
Oracle 支持的 2 種事務隔離級別:READ_COMMITED , SERIALIZABLE

補充:

SQL規範所規定的標準,不同的數據庫具體的實現可能會有些差異
MySQL中默認事務隔離級別是“可重複讀”時並不會鎖住讀取到的行

事務隔離級別:未提交讀時,寫數據只會鎖住相應的行。
事務隔離級別爲:可重複讀時,寫數據會鎖住整張表。
事務隔離級別爲:串行化時,讀寫數據都會鎖住整張表。

隔離級別越高,越能保證數據的完整性和一致性,但是對併發性能的影響也越大,魚和熊掌不可兼得啊。對於多數應用程序,可以優先考慮把數據庫系統的隔離級別設爲Read Committed,它能夠避免髒讀取,而且具有較好的併發性能。儘管它會導致不可重複讀、幻讀這些併發問題,在可能出現這類問題的個別場合,可以由應用程序採用悲觀鎖或樂觀鎖來控制。
MySQL常見的三種存儲引擎(InnoDB、MyISAM、MEMORY)的區別?
MySQL存儲引擎MyISAM與InnoDB如何選擇

MySQL有多種存儲引擎,每種存儲引擎有各自的優缺點,可以擇優選擇使用:MyISAM、InnoDB、MERGE、MEMORY(HEAP)、BDB(BerkeleyDB)、EXAMPLE、FEDERATED、ARCHIVE、CSV、BLACKHOLE。

雖然MySQL裏的存儲引擎不只是MyISAM與InnoDB這兩個,但常用的就是兩個。

兩種存儲引擎的大致區別表現在:

InnoDB支持事務,MyISAM不支持,這一點是非常之重要。事務是一種高級的處理方式,如在一些列增刪改中只要哪個出錯還可以回滾還原,而MyISAM就不可以了。
MyISAM適合查詢以及插入爲主的應用。
InnoDB適合頻繁修改以及涉及到安全性較高的應用。
InnoDB支持外鍵,MyISAM不支持。
從MySQL5.5.5以後,InnoDB是默認引擎。
InnoDB不支持FULLTEXT類型的索引。
InnoDB中不保存表的行數,如select count(*) from table時,InnoDB需要掃描一遍整個表來計算有多少行,但是MyISAM只要簡單的讀出保存好的行數即可。注意的是,當count(*)語句包含where條件時MyISAM也需要掃描整個表。
對於自增長的字段,InnoDB中必須包含只有該字段的索引,但是在MyISAM表中可以和其他字段一起建立聯合索引。
DELETE FROM table時,InnoDB不會重新建立表,而是一行一行的 刪除,效率非常慢。MyISAM則會重建表。
InnoDB支持行鎖(某些情況下還是鎖整表,如 update table set a=1 where user like '%lee%'。

關於MySQL數據庫提供的兩種存儲引擎,MyISAM與InnoDB選擇使用:

INNODB會支持一些關係數據庫的高級功能,如事務功能和行級鎖,MyISAM不支持。
MyISAM的性能更優,佔用的存儲空間少,所以,選擇何種存儲引擎,視具體應用而定。
如果你的應用程序一定要使用事務,毫無疑問你要選擇INNODB引擎。但要注意,INNODB的行級鎖是有條件的。在where條件沒有使用主鍵時,照樣會鎖全表。比如DELETE FROM mytable這樣的刪除語句。
如果你的應用程序對查詢性能要求較高,就要使用MyISAM了。MyISAM索引和數據是分開的,而且其索引是壓縮的,可以更好地利用內存。所以它的查詢性能明顯優於INNODB。壓縮後的索引也能節約一些磁盤空間。MyISAM擁有全文索引的功能,這可以極大地優化LIKE查詢的效率。

有人說MyISAM只能用於小型應用,其實這只是一種偏見。如果數據量比較大,這是需要通過升級架構來解決,比如分表分庫,而不是單純地依賴存儲引擎。

現在一般都是選用innodb了,主要是MyISAM的全表鎖,讀寫串行問題,併發效率鎖表,效率低,MyISAM對於讀寫密集型應用一般是不會去選用的。
MEMORY存儲引擎

MEMORY是MySQL中一類特殊的存儲引擎。它使用存儲在內存中的內容來創建表,而且數據全部放在內存中。這些特性與前面的兩個很不同。

每個基於MEMORY存儲引擎的表實際對應一個磁盤文件。該文件的文件名與表名相同,類型爲frm類型。該文件中只存儲表的結構。而其數據文件,都是存儲在內存中,這樣有利於數據的快速處理,提高整個表的效率。值得注意的是,服務器需要有足夠的內存來維持MEMORY存儲引擎的表的使用。如果不需要了,可以釋放內存,甚至刪除不需要的表。

MEMORY默認使用哈希索引。速度比使用B型樹索引快。當然如果你想用B型樹索引,可以在創建索引時指定。

注意,MEMORY用到的很少,因爲它是把數據存到內存中,如果內存出現異常就會影響數據。如果重啓或者關機,所有數據都會消失。因此,基於MEMORY的表的生命週期很短,一般是一次性的。
MySQL的MyISAM與InnoDB兩種存儲引擎在,事務、鎖級別,各自的適用場景?

事務處理上方面

MyISAM:強調的是性能,每次查詢具有原子性,其執行數度比InnoDB類型更快,但是不提供事務支持。
InnoDB:提供事務支持事務,外部鍵等高級數據庫功能。 具有事務(commit)、回滾(rollback)和崩潰修復能力(crash recovery capabilities)的事務安全(transaction-safe (ACID compliant))型表。

鎖級別

MyISAM:只支持表級鎖,用戶在操作MyISAM表時,select,update,delete,insert語句都會給表自動加鎖,如果加鎖以後的表滿足insert併發的情況下,可以在表的尾部插入新的數據。
InnoDB:支持事務和行級鎖,是innodb的最大特色。行鎖大幅度提高了多用戶併發操作的新能。但是InnoDB的行鎖,只是在WHERE的主鍵是有效的,非主鍵的WHERE都會鎖全表的。

查詢語句不同元素(where、jion、limit、group by、having等等)執行先後順序?

1.查詢中用到的關鍵詞主要包含六個,並且他們的順序依次爲 select–from–where–group by–having–order by

其中select和from是必須的,其他關鍵詞是可選的,這六個關鍵詞的執行順序 與sql語句的書寫順序並不是一樣的,而是按照下面的順序來執行

from:需要從哪個數據表檢索數據
where:過濾表中數據的條件
group by:如何將上面過濾出的數據分組
having:對上面已經分組的數據進行過濾的條件
select:查看結果集中的哪個列,或列的計算結果
order by :按照什麼樣的順序來查看返回的數據

2.from後面的表關聯,是自右向左解析 而where條件的解析順序是自下而上的。

也就是說,在寫SQL文的時候,儘量把數據量小的表放在最右邊來進行關聯(用小表去匹配大表),而把能篩選出小量數據的條件放在where語句的最左邊 (用小表去匹配大表)
什麼是臨時表,臨時表什麼時候刪除?

時表可以手動刪除:
DROP TEMPORARY TABLE IF EXISTS temp_tb;

臨時表只在當前連接可見,當關閉連接時,MySQL會自動刪除表並釋放所有空間。因此在不同的連接中可以創建同名的臨時表,並且操作屬於本連接的臨時表。

創建臨時表的語法與創建表語法類似,不同之處是增加關鍵字TEMPORARY,如:
CREATE TEMPORARY TABLE tmp_table (
NAME VARCHAR (10) NOT NULL,
time date NOT NULL
);

select * from tmp_table;
MySQL B+Tree索引和Hash索引的區別?

Hash索引結構的特殊性,其檢索效率非常高,索引的檢索可以一次定位;
B+樹索引需要從根節點到枝節點,最後才能訪問到頁節點這樣多次的IO訪問;

那爲什麼大家不都用Hash索引而還要使用B+樹索引呢?
Hash索引

Hash索引僅僅能滿足"=","IN"和"<=>"查詢,不能使用範圍查詢,因爲經過相應的Hash算法處理之後的Hash值的大小關係,並不能保證和Hash運算前完全一樣;
Hash索引無法被用來避免數據的排序操作,因爲Hash值的大小關係並不一定和Hash運算前的鍵值完全一樣;
Hash索引不能利用部分索引鍵查詢,對於組合索引,Hash索引在計算Hash值的時候是組合索引鍵合併後再一起計算Hash值,而不是單獨計算Hash值,所以通過組合索引的前面一個或幾個索引鍵進行查詢的時候,Hash索引也無法被利用;
Hash索引在任何時候都不能避免表掃描,由於不同索引鍵存在相同Hash值,所以即使取滿足某個Hash鍵值的數據的記錄條數,也無法從Hash索引中直接完成查詢,還是要回表查詢數據;
Hash索引遇到大量Hash值相等的情況後性能並不一定就會比B+樹索引高。

B+Tree索引

MySQL中,只有HEAP/MEMORY引擎才顯示支持Hash索引。

常用的InnoDB引擎中默認使用的是B+樹索引,它會實時監控表上索引的使用情況,如果認爲建立哈希索引可以提高查詢效率,則自動在內存中的“自適應哈希索引緩衝區”建立哈希索引(在InnoDB中默認開啓自適應哈希索引),通過觀察搜索模式,MySQL會利用index key的前綴建立哈希索引,如果一個表幾乎大部分都在緩衝池中,那麼建立一個哈希索引能夠加快等值查詢。
B+樹索引和哈希索引的明顯區別是:

如果是等值查詢,那麼哈希索引明顯有絕對優勢,因爲只需要經過一次算法即可找到相應的鍵值;當然了,這個前提是,鍵值都是唯一的。如果鍵值不是唯一的,就需要先找到該鍵所在位置,然後再根據鏈表往後掃描,直到找到相應的數據;

如果是範圍查詢檢索,這時候哈希索引就毫無用武之地了,因爲原先是有序的鍵值,經過哈希算法後,有可能變成不連續的了,就沒辦法再利用索引完成範圍查詢檢索;

同理,哈希索引沒辦法利用索引完成排序,以及like ‘xxx%’ 這樣的部分模糊查詢(這種部分模糊查詢,其實本質上也是範圍查詢);

哈希索引也不支持多列聯合索引的最左匹配規則;

B+樹索引的關鍵字檢索效率比較平均,不像B樹那樣波動幅度大,在有大量重複鍵值情況下,哈希索引的效率也是極低的,因爲存在所謂的哈希碰撞問題。

在大多數場景下,都會有範圍查詢、排序、分組等查詢特徵,用B+樹索引就可以了。
sql查詢語句確定創建哪種類型的索引,如何優化查詢

性能優化過程中,選擇在哪個列上創建索引是最重要的步驟之一,可以考慮使用索引的主要有兩種類型的列:在where子句中出現的列,在join子句中出現的列。
考慮列中值的分佈,索引的列的基數越大,索引的效果越好。
使用短索引,如果對字符串列進行索引,應該指定一個前綴長度,可節省大量索引空間,提升查詢速度。
利用最左前綴,顧名思義,就是最左優先,在多列索引,有體現:(ALTER TABLE people ADD INDEX lname_fname_age (lame,fname,age);),所謂最左前綴原則就是先要看第一列,在第一列滿足的條件下再看左邊第二列,以此類推
不要過度建索引,只保持所需的索引。每個額外的索引都要佔用額外的磁盤空間,並降低寫操作的性能。
在修改表的內容時,索引必須進行更新,有時可能需要重構,因此,索引越多,所花的時間越長。
MySQL只對一下操作符才使用索引:<,<=,=,>,>=,between,in
以及某些時候的like(不以通配符%或_開頭的情形)。

聚集索引和非聚集索引區別?

聚合索引(clustered index) / 非聚合索引(nonclustered index)

根本區別

聚集索引和非聚集索引的根本區別是表記錄的排列順序和與索引的排列順序是否一致。

聚集索引

聚集索引表記錄的排列順序和索引的排列順序一致,所以查詢效率快,只要找到第一個索引值記錄,其餘就連續性的記錄在物理也一樣連續存放。聚集索引對應的缺點就是修改慢,因爲爲了保證表中記錄的物理和索引順序一致,在記錄插入的時候,會對數據頁重新排序。

聚集索引類似於新華字典中用拼音去查找漢字,拼音檢索表於書記順序都是按照a~z排列的,就像相同的邏輯順序於物理順序一樣,當你需要查找a,ai兩個讀音的字,或是想一次尋找多個傻(sha)的同音字時,也許向後翻幾頁,或緊接着下一行就得到結果了。

非聚集索引

非聚集索引制定了表中記錄的邏輯順序,但是記錄的物理和索引不一定一致,兩種索引都採用B+樹結構,非聚集索引的葉子層並不和實際數據頁相重疊,而採用葉子層包含一個指向表中的記錄在數據頁中的指針方式。非聚集索引層次多,不會造成數據重排。

非聚集索引類似在新華字典上通過偏旁部首來查詢漢字,檢索表也許是按照橫、豎、撇來排列的,但是由於正文中是a~z的拼音順序,所以就類似於邏輯地址於物理地址的不對應。同時適用的情況就在於分組,大數目的不同值,頻繁更新的列中,這些情況即不適合聚集索引。
有哪些鎖(樂觀鎖悲觀鎖),select 時怎麼加排它鎖?
悲觀鎖(Pessimistic Lock)

悲觀鎖的特點是先獲取鎖,再進行業務操作,即“悲觀”的認爲獲取鎖是非常有可能失敗的,因此要先確保獲取鎖成功再進行業務操作。通常所說的“一鎖二查三更新”即指的是使用悲觀鎖。通常來講在數據庫上的悲觀鎖需要數據庫本身提供支持,即通過常用的select … for update操作來實現悲觀鎖。當數據庫執行select for update時會獲取被select中的數據行的行鎖,因此其他併發執行的select for update如果試圖選中同一行則會發生排斥(需要等待行鎖被釋放),因此達到鎖的效果。select for update獲取的行鎖會在當前事務結束時自動釋放,因此必須在事務中使用。

這裏需要注意的一點是不同的數據庫對select for update的實現和支持都是有所區別的,例如oracle支持select for update no wait,表示如果拿不到鎖立刻報錯,而不是等待,MySQL就沒有no wait這個選項。另外MySQL還有個問題是select for update語句執行中所有掃描過的行都會被鎖上,這一點很容易造成問題。因此如果在MySQL中用悲觀鎖務必要確定走了索引,而不是全表掃描。
樂觀鎖(Optimistic Lock)

樂觀鎖,也叫樂觀併發控制,它假設多用戶併發的事務在處理時不會彼此互相影響,各事務能夠在不產生鎖的情況下處理各自影響的那部分數據。在提交數據更新之前,每個事務會先檢查在該事務讀取數據後,有沒有其他事務又修改了該數據。如果其他事務有更新的話,那麼當前正在提交的事務會進行回滾。

樂觀鎖的特點先進行業務操作,不到萬不得已不去拿鎖。即“樂觀”的認爲拿鎖多半是會成功的,因此在進行完業務操作需要實際更新數據的最後一步再去拿一下鎖就好。

樂觀鎖在數據庫上的實現完全是邏輯的,不需要數據庫提供特殊的支持。一般的做法是在需要鎖的數據上增加一個版本號,或者時間戳,然後按照如下方式實現:

樂觀鎖(給表加一個版本號字段) 這個並不是樂觀鎖的定義,給表加版本號,是數據庫實現樂觀鎖的一種方式。
1. SELECT data AS old_data, version AS old_version FROM …;
2. 根據獲取的數據進行業務操作,得到new_data和new_version
3. UPDATE SET data = new_data, version = new_version WHERE version = old_version
if (updated row > 0) {
// 樂觀鎖獲取成功,操作完成
} else {
// 樂觀鎖獲取失敗,回滾並重試
}

樂觀鎖在不發生取鎖失敗的情況下開銷比悲觀鎖小,但是一旦發生失敗回滾開銷則比較大,因此適合用在取鎖失敗概率比較小的場景,可以提升系統併發性能

樂觀鎖還適用於一些比較特殊的場景,例如在業務操作過程中無法和數據庫保持連接等悲觀鎖無法適用的地方。
總結

悲觀鎖和樂觀鎖是數據庫用來保證數據併發安全防止更新丟失的兩種方法,例子在select … for update前加個事務就可以防止更新丟失。悲觀鎖和樂觀鎖大部分場景下差異不大,一些獨特場景下有一些差別,一般我們可以從如下幾個方面來判斷。

響應速度:如果需要非常高的響應速度,建議採用樂觀鎖方案,成功就執行,不成功就失敗,不需要等待其他併發去釋放鎖。

衝突頻率:如果衝突頻率非常高,建議採用悲觀鎖,保證成功率,如果衝突頻率大,樂觀鎖會需要多次重試才能成功,代價比較大。

重試代價:如果重試代價大,建議採用悲觀鎖。

非關係型數據庫和關係型數據庫區別,優勢比較?
非關係型數據庫的優勢:

  1. 性能

NOSQL是基於鍵值對的,可以想象成表中的主鍵和值的對應關係,而且不需要經過SQL層的解析,所以性能非常高。

  1. 可擴展性

同樣也是因爲基於鍵值對,數據之間沒有耦合性,所以非常容易水平擴展。
關係型數據庫的優勢:

  1. 複雜查詢

可以用SQL語句方便的在一個表以及多個表之間做非常複雜的數據查詢。

  1. 事務支持

使得對於安全性能很高的數據訪問要求得以實現。
總結

對於這兩類數據庫,對方的優勢就是自己的弱勢,反之亦然。

NOSQL數據庫慢慢開始具備SQL數據庫的一些複雜查詢功能,比如MongoDB。

對於事務的支持也可以用一些系統級的原子操作來實現例如樂觀鎖之類的方法來曲線救國,比如Redis set nx。
數據庫三範式,根據某個場景設計數據表?

所有字段值都是不可分解的原子值。
在一個數據庫表中,一個表中只能保存一種數據,不可以把多種數據保存在同一張數據庫表中。
數據表中的每一列數據都和主鍵直接相關,而不能間接相關。

第一範式(確保每列保持原子性)

第一範式是最基本的範式。如果數據庫表中的所有字段值都是不可分解的原子值,就說明該數據庫表滿足了第一範式。

第一範式的合理遵循需要根據系統的實際需求來定。比如某些數據庫系統中需要用到“地址”這個屬性,本來直接將“地址”屬性設計成一個數據庫表的字段就行。但是如果系統經常會訪問“地址”屬性中的“城市”部分,那麼就非要將“地址”這個屬性重新拆分爲省份、城市、詳細地址等多個部分進行存儲,這樣在對地址中某一部分操作的時候將非常方便。這樣設計纔算滿足了數據庫的第一範式,如下表所示。

上表所示的用戶信息遵循了第一範式的要求,這樣在對用戶使用城市進行分類的時候就非常方便,也提高了數據庫的性能。
第二範式(確保表中的每列都和主鍵相關)

第二範式在第一範式的基礎之上更進一層。第二範式需要確保數據庫表中的每一列都和主鍵相關,而不能只與主鍵的某一部分相關(主要針對聯合主鍵而言)。也就是說在一個數據庫表中,一個表中只能保存一種數據,不可以把多種數據保存在同一張數據庫表中。

比如要設計一個訂單信息表,因爲訂單中可能會有多種商品,所以要將訂單編號和商品編號作爲數據庫表的聯合主鍵。
第三範式(確保每列都和主鍵列直接相關,而不是間接相關)

第三範式需要確保數據表中的每一列數據都和主鍵直接相關,而不能間接相關。

比如在設計一個訂單數據表的時候,可以將客戶編號作爲一個外鍵和訂單表建立相應的關係。而不可以在訂單表中添加關於客戶其它信息(比如姓名、所屬公司等)的字段。
數據庫的讀寫分離、主從複製,主從複製分析的 7 個問題?
主從複製的幾種方式

同步複製

所謂的同步複製,意思是master的變化,必須等待slave-1,slave-2,...,slave-n完成後才能返回。 這樣,顯然不可取,也不是MySQL複製的默認設置。比如,在WEB前端頁面上,用戶增加了條記錄,需要等待很長時間。

異步複製

如同AJAX請求一樣。master只需要完成自己的數據庫操作即可。至於slaves是否收到二進制日誌,是否完成操作,不用關心,MySQL的默認設置。

半同步複製

master只保證slaves中的一個操作成功,就返回,其他slave不管。 這個功能,是由google爲MySQL引入的。

主從複製分析的 7 個問題

問題1:master的寫操作,slaves被動的進行一樣的操作,保持數據一致性,那麼slave是否可以主動的進行寫操作?

假設slave可以主動的進行寫操作,slave又無法通知master,這樣就導致了master和slave數據不一致了。因此slave不應該進行寫操作,至少是slave上涉及到複製的數據庫不可以寫。實際上,這裏已經揭示了讀寫分離的概念。

問題2:主從複製中,可以有N個slave,可是這些slave又不能進行寫操作,要他們幹嘛?

以實現數據備份。

類似於高可用的功能,一旦master掛了,可以讓slave頂上去,同時slave提升爲master。

異地容災,比如master在北京,地震掛了,那麼在上海的slave還可以繼續。

主要用於實現scale out,分擔負載,可以將讀的任務分散到slaves上。

【很可能的情況是,一個系統的讀操作遠遠多於寫操作,因此寫操作發向master,讀操作發向slaves進行操作】

問題3:主從複製中有master,slave1,slave2,…等等這麼多MySQL數據庫,那比如一個JAVA WEB應用到底應該連接哪個數據庫?

當 然,我們在應用程序中可以這樣,insert/delete/update這些更新數據庫的操作,用connection(for master)進行操作,select用connection(for slaves)進行操作。那我們的應用程序還要完成怎麼從slaves選擇一個來執行select,例如使用簡單的輪循算法。

這樣的話,相當於應用程序完成了SQL語句的路由,而且與MySQL的主從複製架構非常關聯,一旦master掛了,某些slave掛了,那麼應用程序就要修改了。能不能讓應用程序與MySQL的主從複製架構沒有什麼太多關係呢?

找一個組件,application program只需要與它打交道,用它來完成MySQL的代理,實現SQL語句的路由。

MySQL proxy並不負責,怎麼從衆多的slaves挑一個?可以交給另一個組件(比如haproxy)來完成。

這就是所謂的MySQL READ WRITE SPLITE,MySQL的讀寫分離。

問題4:如果MySQL proxy , direct , master他們中的某些掛了怎麼辦?

總統一般都會弄個副總統,以防不測。同樣的,可以給這些關鍵的節點來個備份。

問題5:當master的二進制日誌每產生一個事件,都需要發往slave,如果我們有N個slave,那是發N次,還是隻發一次?

如果只發一次,發給了slave-1,那slave-2,slave-3,…它們怎麼辦?

顯 然,應該發N次。實際上,在MySQL master內部,維護N個線程,每一個線程負責將二進制日誌文件發往對應的slave。master既要負責寫操作,還的維護N個線程,負擔會很重。可以這樣,slave-1是master的從,slave-1又是slave-2,slave-3,…的主,同時slave-1不再負責select。 slave-1將master的複製線程的負擔,轉移到自己的身上。這就是所謂的多級複製的概念。

問題6:當一個select發往MySQL proxy,可能這次由slave-2響應,下次由slave-3響應,這樣的話,就無法利用查詢緩存了。

應該找一個共享式的緩存,比如memcache來解決。將slave-2,slave-3,…這些查詢的結果都緩存至mamcache中。

問題7:隨着應用的日益增長,讀操作很多,我們可以擴展slave,但是如果master滿足不了寫操作了,怎麼辦呢?

scale on ?更好的服務器? 沒有最好的,只有更好的,太貴了。。。

scale out ? 主從複製架構已經滿足不了。

可以分庫【垂直拆分】,分表【水平拆分】。
使用explain優化sql和索引?

對於複雜、效率低的sql語句,我們通常是使用explain sql 來分析sql語句,這個語句可以打印出,語句的執行。這樣方便我們分析,進行優化

table:顯示這一行的數據是關於哪張表的
type:這是重要的列,顯示連接使用了何種類型。從最好到最差的連接類型爲const、eq_reg、ref、range、index和ALL
all: full table scan ;MySQL將遍歷全表以找到匹配的行;
index : index scan; index 和 all的區別在於index類型只遍歷索引;
range:索引範圍掃描,對索引的掃描開始於某一點,返回匹配值的行,常見與between ,< ,>等查詢;
ref:非唯一性索引掃描,返回匹配某個單獨值的所有行,常見於使用非唯一索引即唯一索引的非唯一前綴進行查找;
eq_ref:唯一性索引掃描,對於每個索引鍵,表中只有一條記錄與之匹配,常用於主鍵或者唯一索引掃描;
const,system:當MySQL對某查詢某部分進行優化,並轉爲一個常量時,使用這些訪問類型。如果將主鍵置於where列表中,MySQL就能將該查詢轉化爲一個常量。
possible_keys:顯示可能應用在這張表中的索引。如果爲空,沒有可能的索引。可以爲相關的域從WHERE語句中選擇一個合適的語句
key: 實際使用的索引。如果爲NULL,則沒有使用索引。很少的情況下,MySQL會選擇優化不足的索引。這種情況下,可以在SELECT語句中使用USE INDEX(indexname)來強制使用一個索引或者用IGNORE INDEX(indexname)來強制MySQL忽略索引
key_len:使用的索引的長度。在不損失精確性的情況下,長度越短越好
ref:顯示索引的哪一列被使用了,如果可能的話,是一個常數
rows:MySQL認爲必須檢查的用來返回請求數據的行數
Extra:關於MySQL如何解析查詢的額外信息。將在表4.3中討論,但這裏可以看到的壞的例子是Using temporary和Using filesort,意思MySQL根本不能使用索引,結果是檢索會很慢。

MySQL慢查詢怎麼解決?

slow_query_log 慢查詢開啓狀態。
slow_query_log_file 慢查詢日誌存放的位置(這個目錄需要MySQL的運行帳號的可寫權限,一般設置爲MySQL的數據存放目錄)。
long_query_time 查詢超過多少秒才記錄。

什麼是 內連接、外連接、交叉連接、笛卡爾積等?
內連接

內連接查詢操作列出與連接條件匹配的數據行,它使用比較運算符比較被連接列的 列值。

內連接分三種:

等值連接:在連接條件中使用等於號(=)運算符比較被連接列的列值,其查詢結 果中列出被連接表中的所有列,包括其中的重複列。

例,下面使用等值連接列出authors和publishers表中位於同一城市的作者和出版社:
SELECT * FROM authors AS a INNER JOIN publishers AS p ON a.city=p.city

不等連接: 在連接條件使用除等於運算符以外的其它比較運算符比較被連接的 列的列值。這些運算符包括>、>=、<=、<、!>、!<和<>。

自然連接:在連接條件中使用等於(=)運算符比較被連接列的列值,但它使用選 擇列表指出查詢結果集合中所包括的列,並刪除連接表中的重複列。

例,在選擇列表中刪除authors 和publishers 表中重複列(city和state):
SELECT a.*,p.pub_id,p.pub_name,p.country FROM authors AS a INNER JOIN publishers AS p ON a.city=p.city
外連接

外連接,返回到查詢結果集合中的不僅包含符合連接條件的行,而且還包括左表(左外連接或左連接)、右表(右外連接或右連接)或兩個邊接表(全外連接)中的所有數據行。

left join(左聯接) 返回包括左表中的所有記錄和右表中聯結字段相等的記錄。
right join(右聯接) 返回包括右表中的所有記錄和左表中聯結字段相等的記錄。

例如1:
SELECT a.,b. FROM luntan LEFT JOIN usertable as b ON a.username=b.username

例如2:
SELECT a.,b. FROM city as a FULL OUTER JOIN user as b ON a.username=b.username
交叉連接

交叉連接不帶 WHERE 子句,它返回被連接的兩個表所有數據行的“笛卡爾積”,返回到結果集合中的數據行數等於第一個表中符合查詢條件的數據行數乘以第二個表中符合查詢條件的數據行數。

例,titles表中有6類圖書,而publishers表中有8家出版社,則下 列交叉連接檢索到的記錄數將等於6*8=48行。

例如:
SELECT type,pub_name FROM titles CROSS JOIN publishers ORDER BY type
笛卡爾積

笛卡爾積是兩個表每一個字段相互匹配,去掉where 或者inner join的等值 得出的結果就是笛卡爾積。笛卡爾積也等同於交叉連接。
總結

內連接: 只連接匹配的行。
左外連接: 包含左邊表的全部行(不管右邊的表中是否存在與它們匹配的行),以及右邊表中全部匹配的行。
右外連接: 包含右邊表的全部行(不管左邊的表中是否存在與它們匹配的行),以及左邊表中全部匹配的行。
全外連接: 包含左、右兩個表的全部行,不管另外一邊的表中是否存在與它們匹配的行。
交叉連接 生成笛卡爾積-它不使用任何匹配或者選取條件,而是直接將一個數據源中的每個行與另一個數據源的每個行都一一匹配。

MySQL都有什麼鎖,死鎖判定原理和具體場景,死鎖怎麼解決?
MySQL都有什麼鎖

MySQL有三種鎖的級別:頁級、表級、行級。

表級鎖:開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖衝突的概率最高,併發度最低。
行級鎖:開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖衝突的概率最低,併發度也最高。
頁面鎖:開銷和加鎖時間界於表鎖和行鎖之間;會出現死鎖;鎖定粒度界於表鎖和行鎖之間,併發度一般

什麼情況下會造成死鎖

所謂死鎖: 是指兩個或兩個以上的進程在執行過程中。
因爭奪資源而造成的一種互相等待的現象,若無外力作用,它們都將無法推進下去。
此時稱系統處於死鎖狀態或系統產生了死鎖,這些永遠在互相等竺的進程稱爲死鎖進程。
表級鎖不會產生死鎖.所以解決死鎖主要還是針對於最常用的InnoDB。

死鎖的關鍵在於:兩個(或以上)的Session加鎖的順序不一致。

那麼對應的解決死鎖問題的關鍵就是:讓不同的session加鎖有次序。
死鎖的解決辦法

查出的線程殺死 kill

SELECT trx_MySQL_thread_id FROM information_schema.INNODB_TRX;

設置鎖的超時時間

Innodb 行鎖的等待時間,單位秒。可在會話級別設置,RDS 實例該參數的默認值爲 50(秒)。

生產環境不推薦使用過大的 innodb_lock_wait_timeout參數值

該參數支持在會話級別修改,方便應用在會話級別單獨設置某些特殊操作的行鎖等待超時時間,如下:
set innodb_lock_wait_timeout=1000; —設置當前會話 Innodb 行鎖等待超時時間,單位秒。
varchar和char的使用場景?

char的長度是不可變的,而varchar的長度是可變的。

定義一個char[10]和varchar[10]。

如果存進去的是‘csdn’,那麼char所佔的長度依然爲10,除了字符‘csdn’外,後面跟六個空格,varchar就立馬把長度變爲4了,取數據的時候,char類型的要用trim()去掉多餘的空格,而varchar是不需要的。

char的存取數度還是要比varchar要快得多,因爲其長度固定,方便程序的存儲與查找。

char也爲此付出的是空間的代價,因爲其長度固定,所以難免會有多餘的空格佔位符佔據空間,可謂是以空間換取時間效率。

varchar是以空間效率爲首位。

char的存儲方式是:對英文字符(ASCII)佔用1個字節,對一個漢字佔用兩個字節。

varchar的存儲方式是:對每個英文字符佔用2個字節,漢字也佔用2個字節。

兩者的存儲數據都非unicode的字符數據。
MySQL 高併發環境解決方案?

MySQL 高併發環境解決方案 分庫 分表 分佈式 增加二級緩存。。。。。

需求分析:互聯網單位 每天大量數據讀取,寫入,併發性高。

現有解決方式:水平分庫分表,由單點分佈到多點數據庫中,從而降低單點數據庫壓力。
集羣方案:解決DB宕機帶來的單點DB不能訪問問題。
讀寫分離策略:極大限度提高了應用中Read數據的速度和併發量。無法解決高寫入壓力。

數據庫崩潰時事務的恢復機制(REDO日誌和UNDO日誌)?
Undo Log

Undo Log是爲了實現事務的原子性,在MySQL數據庫InnoDB存儲引擎中,還用了Undo Log來實現多版本併發控制(簡稱:MVCC)。

事務的原子性(Atomicity)事務中的所有操作,要麼全部完成,要麼不做任何操作,不能只做部分操作。如果在執行的過程中發生了錯誤,要回滾(Rollback)到事務開始前的狀態,就像這個事務從來沒有執行過。

原理Undo Log的原理很簡單,爲了滿足事務的原子性,在操作任何數據之前,首先將數據備份到一個地方(這個存儲數據備份的地方稱爲UndoLog)。然後進行數據的修改。如果出現了錯誤或者用戶執行了ROLLBACK語句,系統可以利用Undo Log中的備份將數據恢復到事務開始之前的狀態。

之所以能同時保證原子性和持久化,是因爲以下特點:

更新數據前記錄Undo log。
爲了保證持久性,必須將數據在事務提交前寫到磁盤。只要事務成功提交,數據必然已經持久化。
Undo log必須先於數據持久化到磁盤。如果在G,H之間系統崩潰,undo log是完整的, 可以用來回滾事務。
如果在A-F之間系統崩潰,因爲數據沒有持久化到磁盤。所以磁盤上的數據還是保持在事務開始前的狀態。

缺陷:每個事務提交前將數據和Undo Log寫入磁盤,這樣會導致大量的磁盤IO,因此性能很低。

如果能夠將數據緩存一段時間,就能減少IO提高性能。但是這樣就會喪失事務的持久性。因此引入了另外一種機制來實現持久化,即Redo Log。
Redo Log

原理和Undo Log相反,Redo Log記錄的是新數據的備份。在事務提交前,只要將Redo Log持久化即可,不需要將數據持久化。當系統崩潰時,雖然數據沒有持久化,但是Redo Log已經持久化。系統可以根據Redo Log的內容,將所有數據恢復到最新的狀態。
發佈了44 篇原創文章 · 獲贊 60 · 訪問量 9282
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章