mysql數據庫面試題

數據庫優化
建表優化
1)數據庫範式
l 第一範式(1NF):強調的是列的原子性,即列不能夠再分成其他幾列。

如電話列可進行拆分---家庭電話、公司電話

l 第二範式(2NF):首先是 1NF,另外包含兩部分內容,一是表必須有主鍵;二是沒有包含在主鍵中的列必須完全依賴於主鍵,而不能只依賴於主鍵的一部分。

clipboard.png

clipboard.png

clipboard.png

l 第三範式(3NF):首先是 2NF,另外非主鍵列必須直接依賴於主鍵,不能存在傳遞依賴。

比如Student表(學號,姓名,年齡,性別,所在院校,院校地址,院校電話)

這樣一個表結構,就存在上述關係。 學號--> 所在院校 --> (院校地址,院校電話)

這樣的表結構,我們應該拆開來,如下。

(學號,姓名,年齡,性別,所在院校)--(所在院校,院校地址,院校電話)

滿足這些規範的數據庫是簡潔的、結構明晰的;同時,不會發生插入(insert)、刪除(delete)和更新(update)操作異常。

2)數據類型選擇
l 數字類型

Float和double選擇(儘量選擇float)

區分開TINYINT / INT / BIGINT,能確定不會使用負數的字段,建議添加 unsigned定義

能夠用數字類型的字段儘量選擇數字類型而不用字符串類型的

l 字符類型

char,varchar,TEXT的選擇:非萬不得已不要使用 TEXT 數據類型,定長字段,建議使用 CHAR 類型(填空格),不定長字段儘量使用 VARCHAR(自動適應長度,超過階段),且僅僅設定適當的最大長度

l 時間類型

按選擇優先級排序DATE(精確到天)、TIMESTAMP、DATETIME(精確到時間)

l ENUM

對於狀態字段,可以嘗試使用 ENUM 來存放

l 避免使用NULL字段,很難查詢優化且佔用額外索引空間

3)字符編碼
同樣的內容使用不同字符集表示所佔用的空間大小會有較大的差異,所以通過使用合適的字符集,可以幫助我們儘可能減少數據量,進而減少IO操作次數。

1.純拉丁字符能表示的內容,選擇 latin1 字符編碼

2.中文可選用utf-8

3.MySQL的數據類型可以精確到字段,所以當我們需要大型數據庫中存放多字節數據的時候,可以通過對不同表不同字段使用不同的數據類型來較大程度減小數據存儲量,進而降低 IO 操作次數並提高緩存命中率

Sql優化
1) 只返回需要的數據

a) 不要寫SELECT *的語句

b) 合理寫WHERE子句,不要寫沒有WHERE的SQL語句。

2) 儘量少做重複的工作

可以合併一些sql語句

3) 適當建立索引(不是越多越好)但以下幾點會進行全表掃描

a) 左模糊查詢’%...’

b) 使用了不等操作符!=

c) Or使用不當,or兩邊都必須有索引才行

d) In 、not in

e) Where子句對字段進行表達式操作

f) 對於創建的複合索引(從最左邊開始組合),查詢條件用到的列必須從左邊開始不能間隔。否則無效,複合索引的結構與電話簿類似

g) 全文索引:當於對文件建立了一個以詞庫爲目錄的索引(文件大全文索引比模糊匹配效果好)

能在char、varchar、text類型的列上面創建全文索引

MySQL 5.6 Innodb引擎也能進行全文索引

搜索語法:MATCH (列名1, 列名2,…) AGAINST (搜索字符串 [搜索修飾符])

如果列類型是字符串,但在查詢時把一個數值型常量賦值給了一個字符型的列名name,那麼雖然在name列上有索引,但是也沒有用到。

4) 使用join代替子查詢

5) 使用union代替手動創建臨時表

索引優化
一、 創建索引,以下情況不適合建立索引

l 表記錄太少

l 經常插入、刪除、修改的表

l 數據重複且分佈平均的表字段

二、 複合索引

如果一個表中的數據在查詢時有多個字段總是同時出現則這些字段就可以作爲複合索引

索引
索引是對數據庫表中一列或多列的值進行排序的一種結構。

優點:

l 大大加快數據的檢索速度

l 創建唯一性索引,保證數據庫表中每一行數據的唯一性

l 可以加速表和表之間的連接

缺點:

l 索引需要佔物理空間。

l 當對錶中的數據進行增加、刪除和修改的時候,索引也要動態的維護,

降低了數據的維護速度。

索引分類:

l 普通索引

create index zjj_temp_index_1 on zjj_temp_1(first_name);

drop index zjj_temp_index_1;

l 唯一索引,索引列的值必須唯一,但允許有空值

create unique index zjj_temp_1 on zjj_temp_1(id);

l 主鍵索引,它是一種特殊的唯一索引,不允許有空值。

l 組合索引

事務
數據庫事務(Database Transaction) ,是指作爲單個邏輯工作單元執行的一系列操作,要麼完全地執行,要麼完全地不執行。

四大特徵:
(1)原子性

事務必須是原子工作單元;對於其數據修改,要麼全都執行,要麼全都不執行。

(2)一致性

事務的一致性指的是在一個事務執行之前和執行之後數據庫都必須處於一致性狀態。事務執行的結果必須是使數據庫從一個一致性狀態變到另一個一致性狀態。

(3) 隔離性(關於事務的隔離性數據庫提供了多種隔離級別)

一個事務的執行不能干擾其它事務。即一個事務內部的操作及使用的數據對其它併發事務是隔離的,併發執行的各個事務之間不能互相干擾。

(4)持久性

事務完成之後,它對於數據庫中的數據改變是永久性的。該修改即使出現系統故障也將一

直保持。

在介紹數據庫提供的各種隔離級別之前,我們先看看如果不考慮事務的隔離性,會發生的幾種問題:

l 髒讀

髒讀是指在一個事務處理過程裏讀取了另一個未提交的事務中的數據。

l 不可重複讀

l 幻讀

幻讀和不可重複讀都是讀取了另一條已經提交的事務,不可重複讀重點在於update和delete,而幻讀的重點在於insert。

在可重複讀中,該sql第一次讀取到數據後,就將這些數據加鎖,其它事務無法修改這些數據,就可以實現可重複 讀了。但這種方法卻無法鎖住insert的數據,所以當事務A先前讀取了數據,或者修改了全部數據,事務B還是可以insert數據提交,這時事務A就會 發現莫名其妙多了一條之前沒有的數據,這就是幻讀,不能通過行鎖來避免。需要Serializable隔離級別 ,讀用讀鎖,寫用寫鎖,讀鎖和寫鎖互斥,這麼做可以有效的避免幻讀、不可重複讀、髒讀等問題,但會極大的降低數據庫的併發能力。

現在來看看MySQL數據庫爲我們提供的四種隔離級別:

  ① Serializable (串行化):可避免髒讀、不可重複讀、幻讀的發生。

  ② Repeatable read (可重複讀):可避免髒讀、不可重複讀的發生。

  ③ Read committed (讀已提交):可避免髒讀的發生。

④ Read uncommitted (讀未提交):最低級別,任何情況都無法保證。

在MySQL數據庫中默認的隔離級別爲Repeatable read (可重複讀)。

鎖模式包括:

l 共享鎖:(讀取)操作創建的鎖。其他用戶可以併發讀取數據,但任何事物都不能獲取數據上的排它鎖,直到已釋放所有共享鎖。

l 排他鎖(X鎖):對數據A加上排他鎖後,則其他事務不能再對A加任任何類型的封鎖。獲准排他鎖的事務既能讀數據,又能修改數據。

l 更新鎖:
更新 (U) 鎖可以防止通常形式的死鎖。如果兩個事務獲得了資源上的共享模式鎖,然後試圖同時更新數據,則兩個事務需都要轉換共享鎖爲排它 (X) 鎖,並且每個事務都等待另一個事務釋放共享模式鎖,因此發生死鎖。
若要避免這種潛 在的死鎖問題,請使用更新 (U) 鎖。一次只有一個事務可以獲得資源的更新 (U) 鎖。如果事務修改資源,則更新 (U) 鎖轉換爲排它 (X) 鎖。否則,鎖轉換爲共享鎖。

鎖的粒度主要有以下幾種類型:

l 行鎖: 粒度最小,併發性最高

l 頁鎖:一次鎖定一頁。25個行鎖可升級爲一個頁鎖。

l 表鎖:粒度大,併發性低

l 數據庫鎖:控制整個數據庫操作

樂觀鎖:相對悲觀鎖而言,樂觀鎖假設認爲數據一般情況下不會造成衝突,所以在數據進行提交更新的時候,纔會正式對數據的衝突與否進行檢測,如果發現衝突了,則讓返回用戶錯誤的信息,讓用戶決定如何去做。一般的實現樂觀鎖的方式就是記錄數據版本。

悲觀鎖:顧名思義,就是很悲觀,每次去拿數據的時候都認爲別人會修改,所以每次在拿數據的時候都會上鎖,這樣別人想拿這個數據就會block直到它拿到鎖。傳統的關係型數據庫裏邊就用到了很多這種鎖機制,比如行鎖,表鎖等,讀鎖,寫鎖等,都是在做操作之前先上鎖。

索引
MyISAM、InnoDB區別

l MyISAM類型不支持事務處理等高級處理,而InnoDB類型支持。

l MyISAM表不支持外鍵,InnoDB支持

l MyISAM鎖的粒度是表級,而InnoDB支持行級鎖定。

l MyISAM支持全文類型索引,而InnoDB不支持全文索引。(mysql 5.6後innodb支持全文索引)

MyISAM相對簡單,所以在效率上要優於InnoDB,小型應用可以考慮使用MyISAM。當你的數據庫有大量的寫入、更新操作而查詢比較少或者數據完整性要求比較高的時

候就選擇innodb表。當你的數據庫主要以查詢爲主,相比較而言更新和寫 入比較少,並且業務方面數據完整性要求不那麼嚴格,就選擇mysiam表。

MyISAM和InnoDB索引實現:
MyISAM索引實現

MyISAM索引文件和數據文件是分離的,索引文件僅保存數據記錄的地址。

l 主索引

MyISAM引擎使用B+Tree作爲索引結構,葉節點的data域存放的是數據記錄的地址。

clipboard.png

l 輔助索引

在MyISAM中,主索引和輔助索引(Secondary key)在結構上沒有任何區別,只是主索引要求key是唯一的,而輔助索引的key可以重複。

clipboard.png

MyISAM中索引檢索的算法爲首先按照B+Tree搜索算法搜索索引,如果指定的Key存在,則取出其data域的值,然後以data域的值爲地址,讀取相應數據記錄。

MyISAM的索引方式也叫做“非聚集”的,之所以這麼稱呼是爲了與InnoDB的聚集索引區分。

InnoDB索引實現
然InnoDB也使用B+Tree作爲索引結構,但具體實現方式卻與MyISAM截然不同.

l 主索引

InnoDB表數據文件本身就是主索引。

clipboard.png

InnoDB主索引(同時也是數據文件)的示意圖,可以看到葉節點包含了完整的數據記錄。這種索引叫做聚集索引。因爲InnoDB的數據文件本身要按主鍵聚集,所以InnoDB要求表必須有主鍵(MyISAM可以沒有),如果沒有顯式指定,則MySQL系統會自動選擇一個可以唯一標識數據記錄的列作爲主鍵,如果不存在這種列,則MySQL自動爲InnoDB表生成一個隱含字段作爲主鍵,這個字段長度爲6個字節,類型爲長整形。

l 輔助索引

InnoDB的所有輔助索引都引用主鍵作爲data域。

clipboard.png

聚集索引這種實現方式使得按主鍵的搜索十分高效,但是輔助索引搜索需要檢索兩遍索引:首先檢索輔助索引獲得主鍵,然後用主鍵到主索引中檢索獲得記錄。

不同存儲引擎的索引實現方式對於正確使用和優化索引都非常有幫助,例如知道了InnoDB的索引實現後,就很容易明白

1、爲什麼不建議使用過長的字段作爲主鍵,因爲所有輔助索引都引用主索引,過長的主索引會令輔助索引變得過大。再例如,

2、用非單調的字段作爲主鍵在InnoDB中不是個好主意,因爲InnoDB數據文件本身是一顆B+Tree,非單調的主鍵會造成在插入新記錄時數據文件爲了維持B+Tree的特性而頻繁的分裂調整,十分低效,而使用自增字段作爲主鍵則是一個很好的選擇。

InnoDB索引和MyISAM索引的區別:

l 一是主索引的區別,InnoDB的數據文件本身就是索引文件。而MyISAM的索引和數據是分開的。

l 二是輔助索引的區別:InnoDB的輔助索引data域存儲相應記錄主鍵的值而不是地址。而MyISAM的輔助索引和主索引沒有多大區別。

紅黑樹 B樹 B+樹 B-樹
二叉查找樹(BST):

二叉排序樹或者是一棵空樹,或者是具有下列性質的二叉樹:

l 若左子樹不空,則左子樹上所有結點的值均小於它的根結點的值。

l 若右子樹不空,則右子樹上所有結點的值均大於它的根結點的值。

l 左、右子樹也分別爲二叉排序樹。

l 沒有鍵值相等的節點(因此,插入的時候一定是葉子節點)。

刪除算法

l 要刪除節點是葉子節點。

l 要刪除的節點只有一個孩子(左孩子或右孩子),這種情況比較簡單,只需要將該孩子連接到當前節點的父節點即可。

l 要刪除的節點有兩個孩子,這個時候的算法就比較複雜(相比較於只有一個孩子的情況)。首先我們需要找到待刪除節點的左子樹上的最大值節點,或者右子樹上的最小值節點,然後將該節點的參數值與待刪除的節點參數值進行交換,最後刪除該節點,這樣需要刪除的參數就從該二叉樹中刪除了。

紅黑樹:
紅黑樹(Red Black Tree) 是一種自平衡二叉查找樹 :

l 每個節點或者是黑色,或者是紅色。

l 根節點是黑色。

l 每個葉子節點是黑色。

l 如果一個節點是紅色的,則它的子節點必須是黑色的。

l 從一個節點到該節點的子孫節點的所有路徑上包含相同數目的黑節點。

紅黑樹的各種操作的時間複雜度是O(log2N)。

紅黑樹 vs AVL

紅黑樹的查詢性能略微遜色於AVL樹,因爲他比avl樹會稍微不平衡最多一層,也就是說紅黑樹的查詢性能只比相同內容的avl樹最多多一次比較,但是,紅黑樹在插入和刪除上完爆avl樹,avl樹每次插入刪除會進行大量的平衡度計算,而紅黑樹爲了維持紅黑性質所做的紅黑變換和旋轉的開銷,相較於avl樹爲了維持平衡的開銷要小得多

插入操作

clipboard.png

紅父

clipboard.png

 如果新節點的父結點爲紅色,這時就需要進行一系列操作以保證整棵樹紅黑性質。如下圖所示,由於父結點爲紅色,此時可以判定,祖父結點必定爲黑色。這時需要根據叔父結點的顏色來決定做什麼樣的操作。青色結點表示顏色未知。由於有可能需要根結點到新點的路徑上進行多次旋轉操作,而每次進行不平衡判斷的起始點(我們可將其視爲新點)都不一樣。所以我們在此使用一個藍色箭頭指向這個起始點,並稱之爲判定點。


l 紅叔

clipboard.png

當叔父結點爲紅色時,如下圖所示,無需進行旋轉操作,只要將父和叔結點變爲黑色,將祖父結點變爲紅色即可。但由於祖父結點的父結點有可能爲紅色,從而違反紅黑樹性質。此時必須將祖父結點作爲新的判定點繼續向上(迭代)進行平衡操作。

需要注意的是,無論“父節點”在“叔節點”的左邊還是右邊,無論“新節點”是“父節點”的左孩子還是右孩子,它們的操作都是完全一樣的(其實這種情況包括4種,只需調整顏色,不需要旋轉樹形)。

l 黑叔
當叔父結點爲黑色時,需要進行旋轉,以下圖示了所有的旋轉可能:
Case 1:

clipboard.png

Case 2:

clipboard.png

Case 3:

clipboard.png

Case 4:

clipboard.png

B樹與B-樹:
B-tree樹即B樹,B即Balanced,平衡的意思。因爲B樹的原英文名稱爲B-tree,而國內很多人喜歡把B-tree譯作B-樹,其實,這是個非常不好的直譯,很容易讓人產生誤解。如人們可能會以爲B-樹是一種樹,而B樹又是另一種樹。而事實上是,B-tree就是指的B樹。

m階B樹是一棵平衡的m路搜索樹。它是空樹,或者是滿足下列性質的樹:

l 根結點的兒子數爲[2, M];

l 除根結點以外的非葉子結點的兒子數爲[M/2, M]; (M/2向上取整)

l 每個結點存放至少M/2-1(取上整)和至多M-1個關鍵字;

l 非葉子結點的關鍵字個數=指向兒子的指針個數-1;

l 非葉子結點的關鍵字:K[1], K[2], …, K[X-1];且K[i] < K[i+1];

l 非葉子結點的指針:P[1], P[2], …, P[X];其中P[1]指向關鍵字小於K[1]的

子樹,P[X]指向關鍵字大於K[X-1]的子樹,其它P[i]指向關鍵字屬於(K[i-1], K[i])的子樹;

l 所有葉子結點位於同一層;

clipboard.png

B+樹:
B+樹是B-樹的變體,也是一種多路搜索樹:

其定義基本與B-樹同,除了:

l 非葉子結點的子樹指針與關鍵字個數相同;

l 非葉子結點的子樹指針P[i],指向關鍵字值屬於[K[i], K[i+1])的子樹

(B-樹是開區間);

l 爲所有葉子結點增加一個指針鏈;

l 所有關鍵字都在葉子結點出現;

clipboard.png

基本SQL操作
l SELECT * FROM table ORDER BY field DESC; (ASC|DESC)

SELECT DISTINCT field from table where 範圍

l INSERT INTO table_name (column1,column2,column3,...)
VALUES (value1,value2,value3,...);

l UPDATE table_name SET column1=value1,column2=value2,...
WHERE some_column=some_value;

l DELETE FROM table_name WHERE some_column=some_value;

LIKE 操作符

SELECT column_name(s) FROM table_name WHERE column_name LIKE pattern;

IN 操作符

SELECT column_name(s) FROM table_name WHERE column_name

IN (value1,value2,...);

BETWEEN 操作符

SELECT column_name(s) FROM table_name WHERE column_name BETWEEN

JOIN

左連接,右連接,內連接

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

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

inner join(等值連接): 只返回兩個表中聯結字段相等的行。(默認)

UNION 操作符

UNION 操作符用於合併兩個或多個 SELECT 語句的結果集。

SELECT country, name FROM Websites WHERE country='CN'
UNION
SELECT country, app_name FROM apps WHERE country='CN'
ORDER BY country;

創建視圖

CREATE VIEW view_name AS SELECT column_name(s) FROM table_name WHERE condition

SQL函數
Avg() Count() Max() Min() Sum()

Group By():

GROUP BY 語句用於結合聚合函數,根據一個或多個列對結果集進行分組。

SELECT column_name, aggregate_function(column_name)
FROM table_name WHERE column_name operator value
GROUP BY column_name;

HAVING 子句可以讓我們篩選分組後的各組數據。

SELECT column_name, aggregate_function(column_name)
FROM table_name WHERE column_name operator value
GROUP BY column_name

HAVING aggregate_function(column_name) operator value;

如何查詢數據庫表結構,主鍵

desc tabl_name;

建表

CREATE TABLE 表名稱

(

列名稱1 數據類型,

....

)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章