數據庫索引
索引是對數據庫表一列或者多列進行排序的一種結構,底層結構一般是 B+ 樹,索引的主要目的是爲了加快數據檢索速度,當然不同的索引類型有不同的特性
索引類型
-
普通索引:由 key/index 定義,主要是爲了加快檢索速度,沒有限制
-
唯一索引:值必須是唯一的,可以保證數據記錄中每一行數據的唯一性
-
主鍵索引:是一種特殊的唯一索引,由
PRIMARY KEY
創建,一個表只能有一個主鍵,且不爲空 -
組合索引:可以覆蓋多個列,例如 INDEX(columnA, columnB)索引
如何建立索引
#例:爲學生課程庫中的 student 表建立索引
create unique index stusno on student(sno);
索引使用場景
- 大數據量的表建立索引比較有意義
- 一般頻繁作爲查詢條件的字段會創建索引;
- 在外鍵建立索引,可以加快表的連接速度
- 在經常需要排序的列,建立索引,因爲索引可以自動排序
- 經常使用在 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 實現的,樂觀鎖顧名思義就是很樂觀,每次讀寫事務的時候不會上鎖,因爲它認爲別人不會修改,但是在提交的時候會看一看數據的版本,如果版本和之前一致,就說明在這期間確實沒有上鎖,那就可以放心提交了
而悲觀鎖就是每次讀寫事務的時候都會上鎖,在數據處理的過程中,處於鎖定的狀態,這樣一來就會有很大的開銷,但是也不能說樂觀鎖比悲觀鎖強,主要還是看具體使用場景
像樂觀鎖這種適用於讀事務多的情況,這樣可以省去鎖的開銷,加大系統的吞吐量,對於經常更新寫的事務,加鎖還是比較划算一點
以下是數據庫 MySQL 的基本操作
-
數據定義:基本表、索引。
-
數據查詢:簡單查詢、連接查詢、嵌套查詢。
-
數據更新(增、刪、改)。
-
視圖:定義、查詢、更新
基本表的定義:
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 <視圖名>
更新視圖和表基本類似
總結一些視圖的作用
- 簡化了用戶的操作
- 是用戶以多種角度去看待同一數據
- 視圖對重構數據庫提供了一定程度的邏輯獨立性
- 視圖對機密數據提供安全保護
- 適當利用視圖可以更清晰的表達查詢
數據庫的安全性
授權與收回
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),
);
用戶定義的完整性:屬性上的約束條件,元組上的約束條件
- 列值非空 not null
- 列值唯一 unique
- 檢查列值是否滿足一個條件表達式 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.%')
);