后台开发人员面试内容——数据库(二)
數據庫鎖分類
從數據庫系統角度分為三種:排他鎖、共享鎖、更新鎖。?
從程序員角度分為兩種:一種是悲觀鎖,一種樂觀鎖。
?
1.樂觀鎖和悲觀鎖
1).樂觀鎖:每次不加鎖,假設沒有沖突去完成某項操作,如果因為沖突失敗就重試,直到成功為止。就是當去做某個修改或其他操作的時候它認為不會有其他線程來做同樣的操作(競爭),這是一種樂觀的態度,通常是基于CAS 原子指令來實現的。CAS 通常不會將線程掛起,因此有時性能會好一些。樂觀鎖的一種實現方式——CAS。
2).悲觀鎖:還是像它的名字一樣,對于并發間操作產生的線程安全問題持悲觀狀態,悲觀鎖認為競爭總是會發生,因此每次對某資源進行操作時,都會持有一個獨占的鎖,就像synchronized,不管三七二十一,直接上了鎖就操作資源了
CAS是基于沖突檢測的樂觀鎖(非阻塞)
lock、synchronized是悲觀鎖,屬于搶占式,會引起其他線程阻塞。
volatile提供多線程共享變量可見性和禁止指令重排序優化
?
2.悲觀鎖按使用性質劃分
1)共享鎖(Share Lock)
S鎖,也叫讀鎖。用于所有的只讀數據操作。共享鎖是非獨占的,允許多個并發事務讀取其鎖定的資源
性質?
1. 多個事務可封鎖同一個共享頁;?
2. 任何事務都不能修改該頁;?
3. 通常是該頁被讀取完畢,S鎖立即被釋放
?
2)排他鎖(Exclusive Lock)
X鎖,也叫寫鎖,表示對數據進行寫操作。如果一個事務對對象加了排他鎖,其他事務就不能再給它加任何鎖了。(某個顧客把試衣間從里面反鎖了,其他顧客想要使用這個試衣間,就只有等待鎖從里面打開了。)?
1. 僅允許一個事務封鎖此頁;?
2. 其他任何事務必須等到X鎖被釋放才能對該頁進行訪問;?
3. X鎖一直到事務結束才能被釋放。
?
3)更新鎖
U鎖,在修改操作的初始化階段用來鎖定可能要被修改的資源,這樣可以避免使用共享鎖造成的死鎖現象。
性質?
1. 用來預定要對此頁施加X鎖,它允許其他事務讀,但不允許再施加U鎖或X鎖;?
2. 當被讀取的頁要被更新時,則升級為X鎖;?
3. U鎖一直到事務結束時才能被釋放。
?
3.悲觀鎖按作用范圍劃分為:行鎖、表鎖
1)行鎖
鎖的作用范圍是行級別。
2)表鎖
鎖的作用范圍是整張表。
數據庫能夠確定那些行需要鎖的情況下使用行鎖,如果不知道會影響哪些行的時候就會使用表鎖。
?
數據庫表與表之間關系
1.一對一關系: 兩個表,在第一個表中的某一行只與第二個表中的一行相關,同時第二個表中的某一行,也只與第一個表中的一行相關,我們稱這兩個表為一對一關系。
情況一:一個表包含了太多的數據列
情況二:將數據分離到不同的表,劃分不同的安全級別。
情況三:將常用數據列抽取出來組成一個表
?
2.一對多關系:
定義:有多張表,第一個表中的行可以與第二個表中的一到多個行相關聯,但是第二個表中的一行只能與第一個表中的一行相關聯。
一對多關系是最常見的關系類型。
3.多對多關系:
定義:有兩個表,第一個表的一行可以與第二個表中的一到多個行相關聯,同時,第二個表中的一行可以與第一個表中的一到多個行相關聯
?
數據庫索引分類
1.定義:
沒建立索引:默認的方式是根據搜索條件進行全表掃描,遇到匹配條件的就加入搜索結果集合,時間復雜度為O(N)
建立索引: 通過不斷的縮小想要獲得數據的范圍來篩選出最終想要的結果,同時把隨機的事件變成順序的事件(類似于書目錄), 對某一字段增加索引,查詢時就會先去索引列表中一次定位到特定值的行數,大大減少遍歷匹配的行數,所以能明顯增加查詢的速度。?
首先去索引列表中查詢,而我們的索引列表是B類樹的數據結構,查詢的時間復雜度為O(log2N),定位到特定值得行就會非常快,所以其查詢速度就會非常快。?
索引是一種數據結構。索引本身很大,不可能全部存儲在內存中,因此索引以索引表的形式存儲在磁盤中
作用:提高查詢速度、確保數據的唯一性、可以加速表和表之間的連接,實現表和表之間的參照完整性、使用分組和排序子句進行數據檢索時,可以減少分組和排序的時間、全文檢索字段進行搜素優化
2.分類:
1)主鍵索引(PRIMAY KEY):
PRIMARY KEY (`id`),
數據庫表經常有一列或列組合,其值唯一標識表中的每一行。該列稱為表的主鍵,該索引要求主鍵中的每個值都唯一。當在查詢中使用主鍵索引時,它還允許對數據的快速訪問。
2)唯一索引(UNIQUE):
CREATE UNIQUE INDEX indexName ON table(column(length))
表明此索引的每一個索引值只對應唯一的數據記錄,對于單列惟一性索引,這保證單列不包含重復的值。對于多列惟一性索引,保證多個值的組合不重復。
3)常規索引(INDEX)
CREATE INDEX index_name ON table(column(length))
4)全文索引(FULLTEXT)
CREATE FULLTEXT INDEX index_content ON article(content)
查詢時指定方式:SELECT * FROM tab_name WHERE MATCH (col1,col2) AGAINST (search_word);
5)聚集索引和非聚集索引
聚集索引: 數據按索引順序存儲,中子結點存儲真實的物理數據
非聚集索引:存儲指向真正數據行的指針
3.實現方式:
最常用——B+樹索引
1)B+樹中間節點沒有數據,所以同樣大小的磁盤頁上可以容納更多節點元素
2)B+樹的查詢必須最終找到葉子節點,而B-樹只需要找到匹配的元素即可
3)B-樹只能依靠繁瑣的中序遍歷,而B+樹只需要在鏈表上遍歷即可
次之——hash索引
哈希索引就是采用一定的哈希算法,把鍵值換算成新的哈希值,檢索時不需要類似B+樹那樣從根節點到葉子節點逐級查找,只需一次哈希算法即可立刻定位到相應的位置,速度非常快
區別:
1)Hash 索引僅僅能滿足"=",和"<=>"等值查詢,不能使用范圍查詢。
2)Hash 索引無法被用來避免數據的排序操作。Hash 索引比較的是進行 Hash 運算之后的 Hash 值, 經過相應的 Hash 算法處理之后的 Hash 值的大小關系,并不能保證和Hash運算前完全一樣。
3) Hash 索引不支持多列聯合索引的最左匹配規則
4)在有大量重復鍵值情況下,哈希索引的效率也是極低的,因為存在所謂的哈希碰撞問題
4.索引匹配規則
最左匹配規則
5.索引失效:
1)where語句中帶有or, 但是沒有把or中所有字段加上索引
2)where語句中使用 != 或 <> 操作符
3)where語句中like查詢以‘%’開頭時,不會使用
4)where語句中使用not?in,not?exist會讓索引失效
4)多列索引的第一部分沒有使用索引的話,將不會使用索引,只要第一列使用了索引,后面的列不帶索引也會生效
5) 如果列類型是字符串,那一定要在條件中將數據使用引號引用起來,否則不會使用索引
6)當全表掃描(未使用索引)比使用索引快時,不會使用
7)隱式類型轉換導致索引失效,字符串轉int時
8) 在 where 子句中對字段進行表達式或函數操作,這將導致引擎放棄使用索引而進行全表掃描
?
內連接與外連接
1.內連接,也被稱為自然連接,只有兩個表相匹配的行才能在結果集中出現。返回的結果集選取了兩個表中所有相匹配的數據,舍棄了不匹配的數據。由于內連接是從結果表中刪除與其他連接表中沒有匹配的所有行,所以內連接可能會造成信息的丟失。內連接語法如下:
?
seselect * from t1 inner join t2 on t1.id=t2.id;
?
2.外連接不僅包含符合連接條件的行,還包含左表(左連接時)、右表(右連接時)或兩個邊接表(全外連接)中的所有數據行。 SQL外連接共有三種類型:左外連接(關鍵字為LEFT OUTER JOIN)、右外連接(關鍵字為RIGHT OUTER JOIN)和全外連接(關鍵字為FULL OUTER JOIN)。外連接的用法和內連接一樣,只是將INNER JOIN關鍵字替換為相應的外連接關鍵字即可:
1)左外連接:即以左表為基準,到右表找匹配的數據,找不到匹配的用NULL 補齊
select * from t1 left join t2 on t1.id=t2.id
1)右外連接:即以右表為基準,到左表找匹配的數據,找不到匹配的用NULL 補齊
select * from t1 right join t2 on t1.id=t2.id; ID
3)全外連接(FULL JOIN 或 FULL OUTER JOIN):除了顯示符合連接條件的記錄外,在 2 個表中的其他記錄也顯示出來.
此外,可以用using代替on
a LEFT JOIN b USING (c1,c2,c3)
其作用相當于語句:
a LEFT JOIN b ON a.c1=b.c1 AND a.c2=b.c2 AND a.c3=b.c3
?
存儲過程
SQL語句需要先編譯然后執行,而存儲過程(Stored Procedure)是一組為了完成特定功能的SQL語句集,經編譯后存儲在數據庫中,用戶通過指定存儲過程的名字并給定參數(如果該存儲過程帶有參數)來調用執行它
語法定義:
DELIMITER //
??CREATE PROCEDURE myproc(OUT s int)
????BEGIN
??????SELECT COUNT(*) INTO s FROM students;
????END
????//
DELIMITER ;
優點:
1.存儲過程因為 SQL 語句已經預編譯過了,因此運行的速度比較快
2.存儲過程在服務器端運行,減少客戶端的壓力
3.允許模塊化程序設計,就是說只需要創建一次過程,以后在程序中就可以調用該過程任意次,類似方法的復用
4.減少網絡流量
5. 增強了使用的安全性
缺點:調試麻煩(至少沒有像開發程序那樣容易),可移植性不靈活(因 為存儲過程是依賴于具體的數據庫)
?
數據庫的三級范式
第一范式(1NF):數據表中的每一列(每個字段)必須是不可拆分的最小單元,也就是確保每一列的原子性;
第二范式(2NF):滿足1NF后,要求表中的所有列,都必須依賴于主鍵,而不能有任何一列與主鍵沒有關系,也就是說一個表只描述一件事情;
第三范式(3NF):必須先滿足第二范式(2NF),要求:表中的每一列只與主鍵直接相關而不是間接相關,(表中的每一列只能依賴于主鍵)任何非主屬性不依賴于其它非主屬性
?
事物
1.?原子性:一個事務(transaction)中的所有操作,要么全部完成,要么全部不完成,不會結束在中間某個環節。事務在執行過程中發生錯誤,會被回滾(Rollback)到事務開 始前的狀態,就像這個事務從沒有執行過一樣
2. 一致性:在事務開始和完成時,數據庫中的數據都保持一致的狀態,數據的完整性約束沒有被破壞。(事務的執行使得數據庫從一種正確狀態轉換成另一種正確狀態)。具體 來說就是,比如表與表之間存在外鍵約束關系,那么你對數據庫進行的修改操作就必需要 滿足約束條件,即如果你修改了一張表中的數據,那你還需要修改與之存在外鍵約束關系 的其他表中對應的數據,以達到一致性
3.隔離性:一個事務的執行不能被其他事務干擾。為了防止事務操作間的混淆,必須串行化或序列化請 求,使得在同一時間僅有一個請求用于同一數據。(在事務正確提交之前, 不允許把該事務對數據的任何改變提供給任何其他事務)。(事務處理過程中的中間狀態 對外部是不可見的)。隔離性通過鎖就可以實現
4.持久性:一個事務一旦提交,它對數據庫中數據的改變就應該是永久性的,并不會被回滾
BEGIN 或 START TRANSACTION:顯示地開啟一個事務;?
COMMIT:提交事務,并使已對數據庫進行的所有修改稱為永久性的;
ROLLBACK:回滾會結束用戶的事務,并撤銷正在進行的所有未提交的修改
?
數據庫的隔離性實現
1.臟讀:是指在一個事務處理過程里讀取了另一個未提交的事務中的數據。
2.不可重復讀:是指在對于數據庫中的某個數據,一個事務范圍內多次查詢卻返回了不同的數據值,這是由于在查詢間隔,被另一個事務修改并提交了
3.幻讀:是指當事務不是獨立執行時發生的一種現象,例如第一個事務對一個表中的數據進行了修改,這種修改涉及到表中的全部數據行。同時,第二個事務也修改這個表中的數據,這種修改是向表中插入一行新數據。那么,以后就會發生操作第一個事務的用戶發現表中還有沒有修改的數據行,就好象發生了幻覺一樣
區別:
1.不可重復讀和臟讀的區別是:臟讀是某一事務讀取了另一個事務未提交的臟數據,而不可重復讀則是讀取了前一事務提交的數據
2.幻讀和不可重復讀都是讀取了另一條已經提交的事務(這點就臟讀不同),所不同的是不可重復讀查詢的都是同一個數據項,而幻讀針對的是一批數據整體(比如數據的個數)
?
MySQL數據庫四種隔離級別:
在MySQL數據庫中默認的隔離級別為Repeatable read (可重復讀), 在Oracle數據庫中,只支持Serializable (串行化)級別和Read committed (讀已提交)這兩種級別,其中默認的為Read committed級別
1.Serializable (串行化):可避免臟讀、不可重復讀、幻讀的發生。
2.Repeatable read (可重復讀):可避免臟讀、不可重復讀的發生。
3.Read committed (讀已提交):可避免臟讀的發生。
4.Read uncommitted (讀未提交):最低級別,任何情況都無法保證。
?
判斷表的字段值是否為空
1.查詢字段值為空的語法:where <字段名> is null
2.查詢字段值不為空的語法:where <字段名> is not null 或者where NoT(<字段名> IS?NULL)
?
關鍵字匯總
alter、update、drop、delete、desc、show、use、truncate、insert?into、as、
distinct、group by、order by、desc、limit、LIKE、in、inner join...on、left(right、full) join....on、union
if、between ... and ....、not、
?
?
?
?
?
?
?
?
?
?
?
總結
以上是生活随笔為你收集整理的后台开发人员面试内容——数据库(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 后台开发人员面试内容——操作系统(一)
- 下一篇: 后台开发人员面试内容——Redis非关系