1. 程式人生 > >2- 面試篇-數據庫

2- 面試篇-數據庫

全外連接 insert 約束 生效 cond base 提取 順序 不同

mysql內置

1、視圖、使用場景

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

視圖的優缺點
優點:
1)對數據庫的訪問,因為視圖可以有選擇性的選取數據庫裏的一部分。
2 )用戶通過簡單的查詢可以從復雜查詢中得到結果。
3 )維護數據的獨立性,試圖可從多個表檢索數據。
4 )對於相同的數據可產生不同的視圖。

缺點:
1)性能:查詢視圖時,必須把視圖的查詢轉化成對基本表的查詢,
如果這個視圖是由一個復雜的多表查詢所定義,那麽,那麽就無法更改數據
2)強耦合 :我們程序中使用的sql過分依賴數據庫中的視圖

如下兩種場景一般會使用到視圖:
(1)不希望訪問者獲取整個表的信息,只暴露部分字段給訪問者,所以就建一個虛表,就是視圖。
(2)查詢的數據來源於不同的表,而查詢者希望以統一的方式查詢,這樣也可以建立一個視圖,把多個表查詢結果聯合起來,查詢者只需要直接從視圖中獲取數據,不必考慮數據來源於不同表所帶來的差異。
註:這個視圖是在數據庫中創建的 而不是用代碼創建的。

SQL語句

#語法: CREATE VIEW 視圖名稱 AS  SQL語句
create view course_view as select * from course;  #創建表course的視圖

2、遊標

遊標實際上是一種能從包括多條數據記錄的結果集中每次提取一條記錄進行處理的機制。

遊標是對查詢出來的結果集作為一個單元來有效的處理。
遊標可以定在該單元中的特定行,從結果集的當前行檢索一行或多行。
可以對結果集當前行做修改。
一般不使用遊標,但是需要逐條處理數據的時候,遊標顯得十分重要。

3、什麽是存儲過程?有哪些優缺點?

存儲過程包含了一系列預編譯可執行的sql語句,
存儲過程存放於MySQL中,通過調用它的名字可以執行其內部的一堆sql
更加直白的理解:
存儲過程可以說是一個記錄集,它是由一些T-SQL語句組成的代碼塊,
這些T-SQL語句代碼像一個方法一樣實現一些功能(對單表或多表的增刪改查),
然後再給這個代碼塊取一個名字,在用到這個功能的時候調用他就行了。

使用存儲過程的優點:

  1. 一個存儲過程替代大量T_SQL語句 ,實現程序與sql解耦
  2. 存儲過程是預編譯過的一個代碼塊,執行效率高。
  3. 基於網絡傳輸,傳別名的數據量小,而直接傳sql數據量大
  4. 一定程度上確保數據安全,執行存儲過程需要有一定權限的用戶。

缺點

  1. 程序員擴展功能不方便
  2. 移植性差

程序與數據庫結合使用的三種方式

#方式一:
    MySQL:存儲過程
    程序:調用存儲過程

#方式二:
    MySQL:
    程序:純SQL語句

#方式三:
    MySQL:
    程序:類和對象,即ORM(本質還是純SQL語句)

使用存儲過程

# 創建存儲過程
delimiter //
create procedure p3(
    in n1 int,
    out res int
)
BEGIN
    select * from blog where id > n1;
    set res = 1;
END //
delimiter ;

#在mysql中調用
set @res=0; #0代表假(執行失敗),1代表真(執行成功)
call p3(3,@res);
select @res;

#在python中基於pymysql調用
cursor.callproc('p3',(3,0)) #0相當於set @res=0
print(cursor.fetchall())    #查詢select的查詢結果

cursor.execute('select @_p3_0,@_p3_1;') #@p3_0代表第一個參數,@p3_1代表第二個參數,即返回值
print(cursor.fetchall())

4、什麽是觸發器?

觸發器是一中特殊的存儲過程,主要是通過事件來觸發而被執行的。
它可以強化約束,來維護數據的完整性和一致性,可以跟蹤數據庫內的操作從而不允許未經許可的更新和變化。
可以聯級運算。如,某表上的觸發器上包含對另一個表的數據操作,而該操作又會導致該表觸發器被觸發。

使用觸發器可以定制用戶對表進行【增、刪、改】操作時前後的行為,註意:沒有查詢
觸發器無法由用戶直接調用,而知由於對表的【增/刪/改】操作被動引發的。

#創建觸發器
delimiter //
CREATE TRIGGER tri_after_insert_cmd AFTER INSERT ON cmd FOR EACH ROW
BEGIN
    IF NEW.success = 'no' THEN #等值判斷只有一個等號
            INSERT INTO errlog(err_cmd, err_time) VALUES(NEW.cmd, NEW.sub_time) ; #必須加分號
      END IF ; #必須加分號
END//
delimiter ;

觸發器的作用?
觸發器是一中特殊的存儲過程,主要是通過事件來觸發而被執行的。
它可以強化約束,來維護數據的完整性和一致性,可以跟蹤數據庫內的操作從而不允許未經許可的更新和變化。可以聯級運算。
如,某表上的觸發器上包含對另一個表的數據操作,而該操作又會導致該表觸發器被觸發。

5、事務:存儲過程實現

事務(Transaction)是並發控制的基本單位。
所謂的事務,將某些操作的多個SQL作為原子性操作,這些操作要麽都執行,要麽都不執行,它是一個不可分割的工作單位。一旦有某一個出現錯誤,即可回滾到原來的狀態,從而保證數據庫數據完整性。
比如銀行轉賬就是事務的典型場景。

四大特性

  1. 原子性是指事務包含的所有操作要麽全部成功,要麽全部失敗回滾,
  2. 一致性是指一個事務執行之前和執行之後都必須處於一致性狀態。 事務前後,數據總額一致
  3. 隔離性是當多個用戶並發訪問數據庫時,比如操作同一張表時,數據庫為每一個用戶開啟的事務,不能被其他事務的操作所幹擾,多個並發事務之間要相互隔離。
  4. 持久性是指一個事務一旦被提交了,那麽對數據庫中的數據的改變就是永久性的,即便是在數據庫系統遇到故障的情況下也不會丟失提交事務的操作。

據庫事務的三個常用命令
Begin Transaction、Commit Transaction、RollBack Transaction。

6、鎖:

在DBMS中,鎖是實現事務的關鍵,鎖可以保證事務的完整性和並發性。與現實生活中鎖一樣,它可以使某些數據的擁有者,在某段時間內不能使用某些數據或數據結構。當然鎖還分級別的。

樂觀鎖,自己實現,通過版本號
悲觀鎖:共享鎖,多個事務,只能讀不能寫,加 lock in share mode
排它鎖,一個事務,只能寫,for update
行鎖

數據庫的樂觀鎖和悲觀鎖是什麽?

數據庫管理系統(DBMS)中的並發控制的任務是確保在多個事務同時存取數據庫中同一數據時不破壞事務的隔離性和統一性以及數據庫的統一性。

樂觀並發控制(樂觀鎖)和悲觀並發控制(悲觀鎖)是並發控制主要采用的技術手段。

  • 悲觀鎖:假定會發生並發沖突,屏蔽一切可能違反數據完整性的操作
  • 樂觀鎖:假設不會發生並發沖突,只在提交操作時檢查是否違反數據完整性。

7、索引

索引是什麽??
數據庫索引,是數據庫管理系統中一個排序的數據結構,以協助快速查詢、更新數據庫表中數據。
索引相當於字典的音序表,如果要查某個字,如果不使用音序表,則需要從幾百頁中逐頁去查。
在數據之外,數據庫系統還維護著滿足特定查找算法的數據結構,這些數據結構以某種方式引用(指向)數據,這樣就可以在這些數據結構上實現高級查找算法。這種數據結構,就是索引。

索引有B+索引和hash索引,各自的區別
hash索引,等值查詢效率高,
不能排序
不能進行範圍查詢

B+索引
數據有序
範圍查詢

索引的實現通常使用B樹及其變種B+樹。

B+樹是通過二叉查找樹,再由平衡二叉樹,B樹演化而來。
技術分享圖片
技術分享圖片

為表設置索引要付出代價的
一是增加了數據庫的存儲空間,
二是在插入和修改數據時要花費較多的時間(因為索引也要隨之變動)。

創建索引可以大大提高系統的性能(優點):

  • 通過創建唯一性索引,可以保證數據庫表中每一行數據的唯一性。
  • 可以大大加快數據的檢索速度,這也是創建索引的最主要的原因。
  • 可以加速表和表之間的連接,特別是在實現數據的參考完整性方面特別有意義。
  • 在使用分組和排序子句進行數據檢索時,同樣可以顯著減少查詢中分組和排序的時間。
  • 通過使用索引,可以在查詢的過程中,使用優化隱藏器,提高系統的性能。

增加索引也有許多不利的方面:

  • 創建索引和維護索引要耗費時間,這種時間隨著數據量的增加而增加。
  • 索引需要占物理空間,除了數據表占數據空間之外,每一個索引還要占一定的物理空間,如果要建立聚簇索引,那麽需要的空間就會更大。
  • 當對表中的數據進行增加、刪除和修改的時候,索引也要動態的維護,這樣就降低了數據的維護速度。

什麽時候【要】創建索引
-(1)表經常進行 SELECT 操作

  • (2)表很大(記錄超多),記錄內容分布範圍很廣
  • (3)列名經常在 WHERE 子句或連接條件中出現

什麽時候【不要】創建索引

  • (1)表經常進行 INSERT/UPDATE/DELETE 操作
  • (2)表很小(記錄超少)
  • (3)列名不經常作為連接條件或出現在 WHERE 子句中

一般來說,應該在這些列上創建索引:
(1)在經常需要搜索的列上,可以加快搜索的速度;
(2)在作為主鍵的列上,強制該列的唯一性和組織表中數據的排列結構;
(3)在經常用在連接的列上,這些列主要是一些外鍵,可以加快連接的速度;
(4)在經常需要根據範圍進行搜索的列上創建索引,因為索引已經排序,其指定的範圍是連續的;
(5)在經常需要排序的列上創建索引,因為索引已經排序,這樣查詢可以利用索引的排序,加快排序查詢時間;
(6)在經常使用在WHERE子句中的列上面創建索引,加快條件的判斷速度。

有些列不應該創建索引:

  1. 對於那些在查詢中很少使用或者參考的列不應該創建索引。
  2. 對於那些只有很少數據值的列也不應該增加索引。
  3. 對於那些定義為text, image和bit數據類型的列不應該增加索引
  4. 當修改性能遠遠大於檢索性能時,不應該創建索引。

使用索引查詢一定能提高查詢的性能嗎?為什麽
通常,通過索引查詢數據比全表掃描要快.但是我們也必須註意到它的代價.
索引需要空間來存儲,也需要定期維護, 每當有記錄在表中增減或索引列被修改時,索引本身也會被修改.
這意味著每條記錄的INSERT,DELETE,UPDATE將為此多付出4,5 次的磁盤I/O.
因為索引需要額外的存儲空間和處理,那些不必要的索引反而會使查詢反應時間變慢.
使用索引查詢不一定能提高查詢性能,

索引範圍查詢(INDEX RANGE SCAN)適用於兩種情況:

  • 基於一個範圍的檢索,一般查詢返回結果集小於表中記錄數的30%
  • 基於非唯一性索引的檢索
#方式一
create table t1(
    id int,
    name char,
    age int,
    sex enum('male','female'),
    unique key uni_id(id),
    index ix_name(name) #index沒有key
);

#方式二
create index ix_age on t1(age);

#方式三
alter table t1 add index ix_sex(sex);

sql語句

1、說一說三個範式。

第一範式(1NF):數據庫表中的字段都是單一屬性的,不可再分。
學生信息表,有姓名、年齡、性別、學號等信息組成
第二範式(2NF):滿足第一範式,表中的字段必須完全依賴於全部主鍵而非部分主鍵。
要有主鍵,要求其他字段都依賴於主鍵。
第三範式(3NF):滿足第二範式,非主鍵外的所有字段必須互不依賴
就是數據只在一個地方存儲,不重復出現在多張表中,可以認為就是消除傳遞依賴
消除傳遞依賴,方便理解,可以看做是“消除冗余”。
所謂傳遞函數依賴,指的是如 果存在"A → B → C"的決定關系,則C傳遞函數依賴於A。

2、drop、deletetruncate

簡單說一說區別
SQL中的drop、delete、truncate都表示刪除,但是三者有一些差別

  1. delete和truncate只刪除表的數據不刪除表的結構
  2. 速度,一般來說: drop> truncate >delete
  3. delete語句是dml,這個操作會放到rollback segement中,事務提交之後才生效;如果有相應的trigger,執行的時候將被觸發.
  4. truncate,drop是ddl, 操作立即生效,原數據不放到rollback segment中,不能回滾. 操作不觸發trigger.
  5. 安全性:小心使用drop 和truncate,尤其沒有備份的時候 ,不可回滾

分別在什麽場景之下使用?

  • 不再需要一張表的時候,用drop
  • 想刪除部分數據行時候,用delete,並且帶上where子句
  • 保留表而刪除所有數據的時候用truncate

3、列舉幾種表連接方式,有什麽區別?

  • 內聯接(Inner Join):匹配2張表中相關聯的記錄。
  • 左外聯接(Left Outer Join):除了匹配2張表中相關聯的記錄外,還會匹配左表中剩余的記錄,右表中未匹配到的字段用NULL表示。
  • 右外聯接(Right Outer Join):除了匹配2張表中相關聯的記錄外,還會匹配右表中剩余的記錄,左表中未匹配到的字段用NULL表示。
  • 全外連接:連接的表中不匹配的數據全部會顯示出來。
  • 交叉連接: 笛卡爾效應,顯示的結果是鏈接表數的乘積。

4. 什麽是數據庫約束,常見的約束有哪幾種?

數據庫約束用於保證數據庫表數據的完整性(正確性和一致性)。可以通過定義約束\索引\觸發器來保證數據的完整性。

主鍵約束:primary key;
外鍵約束:foreign key;
唯一約束:unique;
檢查約束:check;
空值約束:not null;
默認值約束:default;

5、如何描述多對多的關系?

在關系型數據庫中描述多對多的關系,需要建立第三張數據表。
比如學生選課,需要在學生信息表和課程信息表的基礎上,再建立選課信息表,該表中存放學生Id和課程Id。

6、 列舉幾種常用的聚合函數?

Sum:求和?Avg:求平均數?Max:求最大值?Min:求最小值?Count:求記錄數

7、 超鍵、候選鍵、主鍵、外鍵分別是什麽?

超鍵:在關系中能唯一標識元組的屬性集稱為關系模式的超鍵。
一個屬性可以為作為一個超鍵,多個屬性組合在一起也可以作為一個超鍵。
超鍵包含候選鍵和主鍵。
候選鍵:是最小超鍵,即沒有冗余元素的超鍵。
主鍵:數據庫表中對儲存數據對象予以唯一和完整標識的數據列或屬性的組合。
一個數據列只能有一個主鍵,且主鍵的取值不能缺失,即不能為空值(Null)。
外鍵:在一個表中存在的另一個表的主鍵稱此表的外鍵。

8、 SELECT語句關鍵字順序

定義順序

SELECT DISTINCT <select_list>
FROM <left_table>
<join_type> JOIN <right_table>
ON <join_condition>
WHERE <where_condition>
GROUP BY <group_by_list>
HAVING <having_condition>
ORDER BY <order_by_condition>
LIMIT <limit_number>

執行順序

(7)     SELECT 
(8)     DISTINCT <select_list>
(1)     FROM <left_table>
(3)     <join_type> JOIN <right_table>
(2)     ON <join_condition>
(4)     WHERE <where_condition>
(5)     GROUP BY <group_by_list>
(6)     HAVING <having_condition>
(9)     ORDER BY <order_by_condition>
(10)    LIMIT <limit_number>

查詢來自杭州,並且訂單數少於2的客戶。


select a.customer_id, count(b.order_id) as total_orders
from table1 as a left join table2 as b
on a.customer_id = b.customer_id
where a.city = 'hangzhou'
group by a.customer_id
having count(b.order_id) < 2
order by total_orders desc
limit 1;

技術分享圖片

數據庫優化的思路

1、在數據庫中查詢語句速度很慢,如何優化?

1.建索引
2.減少表之間的關聯
3.優化sql,盡量讓sql很快定位數據,不要讓sql做全表查詢,應該走索引,把數據 量大的表排在前面
4.簡化查詢字段,沒用的字段不要,盡量返回少量數據
5.盡量用PreparedStatement來查詢,不要用Statement

2、數據庫優化的思路

1.SQL語句優化
1)應盡量避免在 where 子句中使用!=或<>操作符,否則將引擎放棄使用索引而進行全表掃描。
2)應盡量避免在 where 子句中對字段進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描, 如:select id from t where num is null
可以在num上設置默認值0,確保表中num列沒有null值,然後這樣查詢:
select id from t where num=0
3)很多時候用 exists 代替 in 是一個好的選擇
4)用Where子句替換HAVING 子句 因為HAVING 只會在檢索出所有記錄之後才對結果集進行過濾

2.索引優化
看上文索引

3.數據庫結構優化
? 1)範式優化: 比如消除冗余(節省空間。。)

? 2)反範式優化:比如適當加冗余等(減少join)

? 3)拆分表: 分區將數據在物理上分隔開,不同分區的數據可以制定保存在處於不同磁盤上的數據文件裏。這樣,當對這個表進行查詢時,只需要在表分區中進行掃描,而不必進行全表掃描,明顯縮短了查詢時間,另外處於不同磁盤的分區也將對這個表的數據傳輸分散在不同的磁盤I/O,一個精心設置的分區可以將數據傳輸對磁盤I/O競爭均勻地分散開。對數據量大的時時表可采取此方法。可按月自動建表分區。
4)拆分其實又分垂直拆分和水平拆分:

4.服務器硬件優化

3、面試回答數據庫優化問題從以下幾個層面入手

(1)、根據服務層面:配置mysql性能優化參數;
(2)、從系統層面增強mysql的性能:優化數據表結構、字段類型、字段索引、分表,分庫、讀寫分離等等。
(3)、從數據庫層面增強性能:優化SQL語句,合理使用字段索引。
(4)、從代碼層面增強性能:使用緩存和NoSQL數據庫方式存儲,如MongoDB/Memcached/Redis來緩解高並發下數據庫查詢的壓力。
(5)、減少數據庫操作次數,盡量使用數據庫訪問驅動的批處理方法。
(6)、不常使用的數據遷移備份,避免每次都在海量數據中去檢索。
(7)、提升數據庫服務器硬件配置,或者搭建數據庫集群。
(8)、編程手段防止SQL註入:使用JDBC PreparedStatement按位插入或查詢;正則表達式過濾(非法字符串過濾);

### 4、SQL常用命令:

CREATE TABLE Student( 
ID NUMBER PRIMARY KEY, 
NAME VARCHAR2(50) NOT NULL);    //建表 

CREATE VIEW view_name AS Select * FROM Table_name;  //建視圖 

Create UNIQUE INDEX index_name ON TableName(col_name);  //建索引 

INSERT INTO tablename {column1,column2,…} values(exp1,exp2,…);  //插入 

INSERT INTO Viewname {column1,column2,…} values(exp1,exp2,…);   //插入視圖實際影響表 

UPDATE tablename SET name='zang 3' condition;   //更新數據 

DELETE FROM Tablename WHERE condition;  //刪除 

GRANT (Select,delete,…) ON (對象) TO USER_NAME [WITH GRANT OPTION];   //授權 
REVOKE (權限表) ON(對象) FROM USER_NAME [WITH REVOKE OPTION]     //撤權

5、關系型非關系型

? 比如 有一個學生的數據:
? 姓名:張三,性別:男,學號:12345,班級:二年級一班
? 還有一個班級的數據:
? 班級:二年級一班,班主任:李四

數據庫 類型 特性 優點 缺點
關系型數據庫 SQLite、Oracle、mysql 1、關系型數據庫,是指采用了關系模型來組織 數據的數據庫; 2、關系型數據庫的最大特點就是事務的一致性; 3、簡單來說,關系模型指的就是二維表格模型, 而一個關系型數據庫就是由二維表及其之間的聯系所組成的一個數據組織。 1、容易理解:二維表結構是非常貼近邏輯世界一個概念,關系模型相對網狀、層次等其他模型來說更容易理解; 2、使用方便:通用的SQL語言使得操作關系型數據庫非常方便; 3、易於維護:豐富的完整性(實體完整性、參照完整性和用戶定義的完整性)大大減低了數據冗余和數據不一致的概率; 4、支持SQL,可用於復雜的查詢。 1、為了維護一致性所付出的巨大代價就是其讀寫性能比較差; 2、固定的表結構; 3、高並發讀寫需求; 4、海量數據的高效率讀寫;
非關系型數據庫 MongoDb、redis、HBase 1、使用鍵值對存儲數據; 2、分布式; 3、一般不支持ACID特性; 4、非關系型數據庫嚴格上不是一種數據庫,應該是一種數據結構化存儲方法的集合。 1、無需經過sql層的解析,讀寫性能很高; 2、基於鍵值對,數據沒有耦合性,容易擴展; 3、存儲數據的格式:nosql的存儲格式是key,value形式、文檔形式、圖片形式等等,文檔形式、圖片形式等等,而關系型數據庫則只支持基礎類型。 1、不提供sql支持,學習和使用成本較高; 2、無事務處理,附加功能bi和報表等支持也不好;

技術分享圖片

6、MYSQL的兩種存儲引擎區別(事務、鎖級別等等),各自的適用場景

MYISAM 不支持事務,不支持外鍵,表鎖,插入數據時,鎖定整個表,查表總行數時,不需要全表掃描
INNODB 支持事務,支持外鍵,行鎖,查表總行數時,全表掃描

2- 面試篇-數據庫