MySQL數據庫面試題合集

數據庫索引

索引是對數據庫表一列或者多列進行排序的一種結構,底層結構一般是 B+ 樹,索引的主要目的是爲了加快數據檢索速度,當然不同的索引類型有不同的特性

索引類型

  • 普通索引:由 key/index 定義,主要是爲了加快檢索速度,沒有限制

  • 唯一索引:值必須是唯一的,可以保證數據記錄中每一行數據的唯一性

  • 主鍵索引:是一種特殊的唯一索引,由PRIMARY KEY創建,一個表只能有一個主鍵,且不爲空

  • 組合索引:可以覆蓋多個列,例如 INDEX(columnA, columnB)索引

如何建立索引

#例:爲學生課程庫中的 student 表建立索引
create unique index stusno on student(sno);

參考文章:https://www.cnblogs.com/zlingh/p/3883716.html

索引使用場景

  • 大數據量的表建立索引比較有意義
  • 一般頻繁作爲查詢條件的字段會創建索引;
  • 在外鍵建立索引,可以加快表的連接速度
  • 在經常需要排序的列,建立索引,因爲索引可以自動排序
  • 經常使用在 where 子句中的字段加索引可以提高條件判斷的速度,像那些很少或從不引用的字段,比如性別,就不要建立索引了

索引的缺陷

索引佔據存儲空間,另外在插入和刪除時需要費時,因爲索引也會動態變化,這樣就降低數據維護效率

以 % 符號開頭的 like 語句,索引是失效,比如 like %123%

如果數據類型出現隱式轉化,也無法使用索引(如varchar不加單引號的話可能會自動轉換爲int型)

參考文章:https://blog.csdn.net/kennyrose/article/details/7532032

數據庫事務

對系統中數據進行訪問與更新的一系列操作 ,而這些操作所組成的一個程序執行邏輯單元,要麼成功要麼失敗,一共有四大特性

原子性:事務的操作要麼成功,要麼失敗,成功後應用到數據庫,失敗後對數據庫沒有任何影響

一致性:事務開始前和結束後,沒有破壞數據的完整性約束,比如,我給你轉1000萬,你收到 1000 萬,我肯定會減少 1000 萬,如果我沒有減少,或者你沒有收到,這個時候是不一致的

隔離性:主要針對多個用戶併發操作數據庫的時候,比如我給銀行卡轉賬的同時,不可以取錢,同一時間,只允許一個事物請求同一數據

持久性:一旦提交後,數據庫中的數據就是永久的

如果不考慮事務隔離,會造成

髒讀:一個事務讀取了另一個事務未提交的數據

不可重複讀:主要針對更新操作,在一個事務中,兩次查詢結果不一致

幻讀:主要針對插入刪除操作,在一個事務中,兩次查詢結果不一致

數據庫通過事務隔離級別來解決讀的問題

讀未提交:所有的事務可以看見其它未提交事務的執行結果,很少在實際中應用,讀取到未提交的數據稱爲髒讀.

讀已提交:讀取已經提交的數據,可避免髒讀,這也是大多數數據庫系統的默認隔離級別

可重複讀:MySQL的默認隔離級別,寫數據鎖住了滿足條件的行,避免了髒讀和不可重複讀帶來的影響,但是可能會出現幻讀的現象

可串行化:隔離的最高級別,在讀的時候鎖住了整張表,可避免幻讀的問題,但是會造成超時現象和鎖競爭

那數據庫爲什麼不默認設置爲可串行化?

數據庫隔離級別越高,越能保證數據的完整性和一致性,但是對併發性能的影響也越大

嵌套事務

嵌套是子事務套在父事務中執行,子事務是父事務的一部分,在進入子事務之前,父事務建立一個回滾點,叫 save point,然後執行子事務,這個子事務的執行也算是父事務的一部分,然後子事務執行結束,父事務繼續執行

如果子事務回滾,父事務會回滾到進入子事務前建立的 save point,然後嘗試其他的事務或者其他的業務邏輯,父事務之前的操作不會受到影響,更不會自動回滾。

如果父事務回滾,子事務也會跟着回滾,因爲父事務結束之前,子事務是不會提交的,我們說子事務是父事務的一部分

事務的提交,是什麼情況?

子事務先提交,父事務再提交,子事務是父事務的一部分,由父事務統一提交。

數據庫三大範式

MySQL 引擎

MySQL 中的數據用各種不同的技術存儲在文件(或者內存)中,不同的引擎對應不同的技術,MySQL 主要使用三種存儲引擎

  • InnoDB
  • MyISAM
  • MEMORY

首先說說 InnoDB 和 MyISAM 的區別?

InnoDB 支持事務特性,可以進行回滾,而 MyISAM 不行,MyISAM 比較適合以查詢和插入爲主,而 InnoDB 使用場景是那些頻繁修改,安全性比較高的應用,所以 InnoDB 也是 MySQL 的默認存儲引擎,但是 MyISAM 性能比較高,佔用存儲空間少,所以如何使用視情況而定

對於 MEMORY 存儲引擎,它使用存儲在內存中的內容來創建表,而且數據全部放在內存中,這樣有利於數據的快速處理,提高整個表的效率

需要注意,服務器需要有足夠的內存來維持 MEMORY 存儲引擎的表的使用。如果內存出現異常就會影響數據,比如重啓或者關機,所有數據都會消失。因此,基於 MEMORY 的表的生命週期很短,一般是一次性的

MySQL 的 MVCC 機制

是一種併發控制的方法,在數據庫管理系統中實現對數據庫的併發訪問

樂觀鎖的就是基於 MVCC 實現的,樂觀鎖顧名思義就是很樂觀,每次讀寫事務的時候不會上鎖,因爲它認爲別人不會修改,但是在提交的時候會看一看數據的版本,如果版本和之前一致,就說明在這期間確實沒有上鎖,那就可以放心提交了

而悲觀鎖就是每次讀寫事務的時候都會上鎖,在數據處理的過程中,處於鎖定的狀態,這樣一來就會有很大的開銷,但是也不能說樂觀鎖比悲觀鎖強,主要還是看具體使用場景

像樂觀鎖這種適用於讀事務多的情況,這樣可以省去鎖的開銷,加大系統的吞吐量,對於經常更新寫的事務,加鎖還是比較划算一點

參考文章:https://www.cnblogs.com/moershiwei/p/9766916.html


以下是數據庫 MySQL 的基本操作

  1. 數據定義:基本表、索引。

  2. 數據查詢:簡單查詢、連接查詢、嵌套查詢。

  3. 數據更新(增、刪、改)。

  4. 視圖:定義、查詢、更新

基本表的定義:

create table student(
	sno char(9) primary key,
	sname char(20) unique,
	sex char(2)
);

基本表的修改

# 向student 中加入’入學時間‘列,
# 數據類型是日期類型,那麼他的mysql數據怎麼寫?
alter table student add 列名 data(類型) 

# 或者想要修改某一屬性的數據類型該怎麼寫?
alter table student alter 列名 新類型 

# 刪除基本表
drop table 表名 

索引的建立與刪除,格式一般爲

create unique index <索引名> on <表名> 

#例:爲學生課程庫中的 student 表建立索引
create unique index stusno on student(sno);

# 刪除索引:drop index <索引名>
drop index stusno;

#修改索引:alter index <舊索引名> rename to <新索引名>
alter index scno rename to scc;

數據的 簡單查詢

查詢學號和名字:select sno ,sname from student;

消除取值重複的行:意思就是如果查詢出現了重複的行,那麼可以使用 distinct去重,例:select distinct sno from student

利用 where加判斷條件,例:查詢年齡在20歲以下的學生姓名和年齡

select sname,age from student 
	where age<20;

另外還有其他比如,between on ,not between on ,in ,not in 等關鍵字,例:

select *from student 
	where age between 20 and 23;
	
select *from student 
	where age not between 20 and 23;

#下面這條語句是查詢 sdept 屬性在 /不在 CS,MA的學生所有信息
select *from student 
	where sdept in('CS','MA');
	
select *from student 
	where sdept not in('CS','MA');

字符匹配,利用謂詞like 進行字符串的匹配,例:

select sname from student where sname like '馬%';
select sname from student where sname like '歐陽_';

按照升序或者降序的方式進行查詢

# 降序的方式
select sno,grade from student 
	where co='3' order by grade desc;

# 升序的方式
select sno,grade from student 
	where co='3' order by grade asc;

當然還有一些函數使用

# 查詢學生的總數
select count(*) from student;

# 查詢1號課程的平均成績
select avg(grade) from student where cno='1';

select max(grade) from student where com='1';

數據的查詢之 連接查詢
連接查詢針對的是多張表的聯合查詢

student 表

學號 sno 姓名sname 性別sex 年齡age 所在系sdept
201215121 李勇 20 cs
201215122 劉晨 18 cs
201215123 王敏 18 ma
201215125 張立 19 is

SC表

學號sno 課程號cno 成績grade
201215121 1 92
201215121 2 85
201215121 3 88
201215122 2 90
201215122 3 80

將兩張表連接,去掉重複的列屬性元素,由於sno 在兩張表都出現了,所以得加上前綴名,否則數據庫是分不清的!

select student.sno,sname,
sex,age,sdept,cno,grade 
	from student,sc 
	where student.sno=sc.sno;

連接謂詞和選擇謂詞組成的複合條件
查詢選修2號課程且成績在90分以上的所有學生的學號和姓名

select student.sno ,sname from student,sc 
	where student.sno=sc.sno 
		and sc.cno='2' and sc.grade>90;

嵌套查詢,比如在書中提到的:查詢與劉晨在同一個系的學生?

查詢的時候,我們首先得知道劉晨在哪個系,然後才能查詢該系的所有學生,所以查詢劉晨在哪個系的語句應該嵌套在查詢所有學生的裏面。

select sno,sname,sdept
from student
where sdept in(
	select sdept from student where sname='劉晨'
);

查詢選修了課程名爲信息系統的學生學號和姓名

首先分析學生學號的姓名在Student 表,課程名存放在Course(沒畫出來),但是在Course 中有課程號,而課程號在CS表中也存在,所以就得通過課程號來建立兩者表的連接,最後在找出學號和姓名

第一步:查出課程名信息系統 的課程號,比如課程號爲3
seclect cno from course where cname='信息系統'

第二步:在SC表中找出選修了3號課程的學生學號
select sno from sc

第三步:在student 中根據第二部所查出來的學號進行查詢學生姓名和學號。
select sno,sname from student

整合起來就是

# 第三步
select sno,sname from student where sno in(
	# 第二步
	select sno from sc where cno in(
		# 第一步
		select cno from course where cname='信息系統'
	)
);

當然這種嵌套看起來還是挺繁瑣的,我們也可以使用連接表來查詢

select student.sno,sname from student,sc,course
	where student.sno=sc.sno and
		sc.cno=course.cno and course.cname='信息系統'

數據的更新

修改數據:例如將學生學號爲 201212121 的年齡改爲22歲
update student set age=22 where sno='201212121';

將所有學生年齡+1
update student set age = age+1;

將計算機科的所有學生全體成績置位0
update sc set grade=0 where sno in (select sno from student where sdept='cs');

刪除數據:例如刪除學號爲 201212128 的學生記錄
delete from student where sno='201212128';

刪除所有學生的選課記錄
delete from sc;

刪除計算機科學系的所有學生的選課記錄
delete from sc where sno in(select sno from student where sdept='sc');

視圖的定義、查詢、更新

建立視圖

案列1:建立信息系學生的視圖

一般格式爲 create view <視圖名> [列名] as <子查詢> [where 語句]

create view is_student #此處省略了列名
	as select sno,sname,age from student 
		where sdept='IS'

如果要保持在進行修改和插入的操作時仍然只有信息系的學生則在where 語句後面 加:with check option

案列2:建立信息系選修了 1 號課程的學生視圖

create view IS_si(sno,sname,grade)
	as select student,sc where sdept='IS'
		and student.sno=sc.sno and sc.cno='1';

案列3:建立信息系統選修了1號課程且成績在90分以上的學生的視圖,直接在視圖1的基礎上進行建立。

create view is_s2
	as select sno,sname,grade from is_si
		where grade>=90;

案列4:將學生的學號、平均成績定義爲視圖

create view S_G(sno,Gavg)
	as select sno,avg(grade) from sc 
		group by sno;

刪除視圖
格式爲:drop view <視圖名>
更新視圖和表基本類似

總結一些視圖的作用

  1. 簡化了用戶的操作
  2. 是用戶以多種角度去看待同一數據
  3. 視圖對重構數據庫提供了一定程度的邏輯獨立性
  4. 視圖對機密數據提供安全保護
  5. 適當利用視圖可以更清晰的表達查詢

數據庫的安全性

授權與收回
SQL 中採用 grant 和 revoke 語句向用戶授予或收回對數據的操作權限。 一般格式爲:
grant <權限> on <對象類型><對象名> to <用戶>;

# 案列1:把查詢 student 表的權限授予用戶UI
grant select on table student to UI;

# 案例2:把堆student 表和 course 表的全部操作權限授予用戶U2和U3
grant all privileges 
	on table student,course to U2,U3;

# 案列3:把對錶SC的查詢權限授予所有用戶
grant select on table SC to public;

# 案列4:把查詢 student 表和修改學生學號的權限授予給用戶U4
grant update(sno),select no table student to U4;

# 案例5:把對錶 sc 的 insert 權限授予U5用戶,
# 		並允許將此權限再授予其他用戶
grant insert on table sc to U5 with grant option

收回權限是 revoke ,一般格式爲:
revoke <權限>on <對象類型><對象名> from <用戶>;

# 案例1:把用戶 U4 修改學生學號的權限收回
revoke update (sno) on table student from u4;

# 案例2:收回所有用戶對錶 SC 的查詢權限
revoke select on table sc  from public;

# 案列3:把用戶 U5 對 SC 表的 insert 權限收回
revoke insert on table sc from U5 cascade

# cascade 的意思就是:級聯收回U6,U7的insert 權限,
# 因爲 U5對sc表我的insert 權限授予過 U6和U7

數據庫角色的創建
案例1:首先創建一個角色 R1

create role R1;

# 然後使用 grant 語句使角色R1 擁有 student 表的 
# select ,update 、insert 權限
grant select,update,insert on table student to R1;

# 將這個角色授予王平、張明、趙玲,
# 使他們具有角色R1所包含的全部權限
grant R1 to 王平,張明,趙玲;

# 一次性收回王平的三個權限
revoke R1 from 王平;

案列2:角色的權限修改

# 使角色R1在原來的基礎上增加 student 表的delete 權限
grant delete on table student to R1

#使R1 減少 select 的權限
revoke select on table student 

對於視圖授予權限

例:建立計算機系學生的視圖,把對該視圖的 select 權限授予王平,把該視圖上的所有操作權限授予張明

create view CS_STUDENT as
	select* from student where
		sdept='CS';
		
grant select on CS_STUDENT to 王平;

grant all privileges on CS_STUDENT to 張明;

定義實體完整性

案例1:將student 表中的 sno 屬性定義爲碼

# 方法一
create table student(
	sno char(9) primary key,
	sname char(20)not null,
	sex char(2)
);
# 方法二
create table student(
	sno char(9),
	sname char(20) not null;
	sex char(2)
	primary key (sno)	
);

定義參照完整性

關係模型的參照完整性在 create table 中用 foreign key 短語定義哪些爲外碼,用 references 短語指明這些外碼參照哪些表的主碼.

例:關係SC 中一個元組表示一個學生選修的某門課程成績,(sno,cno)是主碼,sno,cno 分別參照引用 student 表的主碼和course 表的主碼。

create table sc(
	sno char(9)not null,
	cno char(4) unique not null,
	primary key(sno,cno),
	# 在表級定義參照完整性
	foreign key (sno) references student(sno),
	foreign key (cno) references student(cno),
);

用戶定義的完整性:屬性上的約束條件,元組上的約束條件

  1. 列值非空 not null
  2. 列值唯一 unique
  3. 檢查列值是否滿足一個條件表達式 check 短語

屬性上的約束條件前兩個上面已近涉及到了,第三個檢查列值是否滿足一個條件表達式,check 短語指定列值應該滿足的條件

案例1:student 表中的sex 只允許取 ’男‘、’女‘

create table student(
	sno char(9) primary key,
	sname char(8) not null,
	sex char(2)check (sxe in('男','女')),
	age smallint,
	sdept char(20)
);

案列2:sc 表的 grade 的值應該在 0 - 100 之間

create table sc(
	sno char(9),
	cno char(4),
	grade smallint check(grade>=0 and grade<=100),
	primary key(sno,cno),
	foreign key(sno) references student(sno)
);

元組上的約束條件定義:以check 短語定義元組上的約束條件,即元組級的限制

案列1:當學生的性別是男時,其名字不能以 Ms.打頭

create table student(
	sno char(9),
	sname char(8) not null,
	sex char(2),
	age smallint,
	sdept char(20),
	primary key (sno),
	check (sex='女' or sname not like 'Ms.%')
);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章