MySQL數據庫管理
查看數據庫
show databases
創建數據庫
如果沒有修改my.ini配置文件的默認字符集,在創建數據庫時,指定字符集
create database 數據庫名 character set 'utf8';
特殊字符(關鍵字)用反引號
例如:create database `create`;
顯示數據庫創建信息
show database 數據庫名
刪除數據庫
drop database 數據庫名
進入(使用)數據庫
use 數據庫名;
顯示當前打開的數據庫
select database();
表結構管理
創建數據表
create table (if not exists)表名(字段 字段類型...)(engine=數據引擎 default charset=編碼格式) ; //紅色可選(括號不用加上),表示如果表不存在則創建表,避免表存在時,再創建時報錯。
mysql\data目錄下的數據庫目錄中將生成一個對應名稱的.fm文件
刪除數據表
drop table (if exists) 表名;//紅色可選(括號不用加上),表示如果表存在則刪除表,避免表不存在,刪除時報錯。
修改數據表結構
給數據表增加一個字段:alter table 表名 add (column) 新增屬性 屬性類型;
修改表名稱:alter table 表名 rename 新表名;
修改表的存儲引擎:alter table 表名 engine= MyISAM;
刪除字段:alter table 表名 drop 字段名稱;
修改字段名稱及重新定義字段類型:alter table 表名 change 字段名 新字段名 新字段類型;
單獨修改字段的類型:alter table 表名 modify 字段名 新的字段類型;
指定位置后面添加字段:alter table 表名 add (column) 新增字段 字段類型 after 指定的字段;
在第一個位置添加字段:alter table 表名 add (column) 新增字段 字段類型 first;
查看數據表
show tables; 查看當前數據庫所有的數據表
查看字母‘abc'開頭的表
show table like 'abc%';
%是通配符
查看表創建信息
show create table 表名;(查看表創建的語句)
查看數據表結構
desc 表名;
MySQL用戶管理
登錄
MySQL是基於C/S架構,必須在客戶端通過終端窗口,連接MySQL服務器,進行操作。
mysql -h host - u usr -p / mysql -u root -p密碼
輸入密碼:xxxx
用戶管理
超級用戶root
修改賬號密碼:
例:DOS命令下修改,將root賬號密碼修改為1234
mysqladmin -u root password 1234 語句最后不要加分號,否則密碼就是1234;
例:mysql命令
set password for 'root'@'localhost' =password('1234');
創建用戶
使用create語句進行創建用戶,語句格式如下:
create user 'username'@’host' identified by 'password';
其中,username表示要創建的用戶名,host表示指定該用戶在哪個主機上可以登錄,如果是本地用戶可用localhost,如果想讓該用戶可以從任意遠程主機登錄,可以使用通配符%;password表示該用戶的登錄密碼,密碼可以為空,如果為空則該用戶可以不需要密碼登錄服務器。
例:create user 'zhangsan'@'localhost' identified by'123456';
刪除用戶
刪除用戶使用drop語句,語句格式如下:
drop user 'username'@'host';
修改配置文件my.ini
字符集
MySQL默認字符集是Latin,改變為utf8才能正確顯示中文
[mysql]下添加
prompt="mysql(\d)>"
默認數據庫
information_schema
提供了訪問數據庫元數據的方式。什么是元數據呢?元數據是關於數據的數據,如數據庫名或表名,列的數據類型,或訪問權限等。有些時候用於表述該信息的其他術語包括”數據詞典“和”系統目錄“。
performance_schema
mysql5.5版本新增了一個性能優化的引擎。
mysql
這個是MySQL的核心數據庫,主要負責存儲數據庫的用戶,權限設置,關鍵字符MySQL自己需要使用的控制和管理信息。不可以刪除,也不要輕易修改這個數據庫里面的信息。
test
安裝時候創建的一個測試用數據庫,空數據庫,沒有任何表,可以刪除(新版本MySQL已取消)。
SQL基本語法
基本規范
SQL對大小寫不敏感,一般數據庫名稱,表名稱,字段名稱全部小寫
MySQL要求在每條SQL命令的末端使用分號。
注釋
#這個注釋直到該行結束
-這個注釋直到該行結束(在dos好像沒效果了)
/*這是一個在行中間的注釋*/
/*
這個是一個
多行注釋格式
*/
MySQL基本數據類型
字段類型
數據類型是指列,存儲過程,表達式和局部變量的數據特征,它決定了數據的存儲方式,代表了不同的信息類型,不同的數據庫,數據類型有所不同,MySQL數據庫有以下幾種數據類型:
字符串型
注意:char和varchar需要指定長度,例如:char(10)
整數型
很多人喜歡定義數據時,這樣寫:
create table tbl_name( age int(10) );
int 后面()中的數字,不代表占用空間容量,而代表最小顯示位數。這個東西基本沒有意義,除非你對字段指定zerofill,MySQL會自動分配長度;int(11),tinyint(4),smallint(6),mediumint(9),big(20)。所以,建議在使用時,就用這些默認的顯示長度就可以了,不用再去自己填長度。(比如:int(10), tinyint(1)之類的基本沒用).
浮點型
M(精度),代表總長度(整數位和小數位)限制
D(標度),代表小數位的長度限制。
M必須大於等於D
日期型
列舉與枚舉
create table students( id tinyint, #微小整型 name varchar(10), #變長字符
age int, #整型 sex enum('m',w'), #單選 birthday date, #日期型 tel char(11), #定長字符 city char(1), #城市 hobby set('1','2','3','4'), #多選 introduce text #個人介紹 );
字段屬性
數據的增、刪、改
增刪改查(簡稱:CURD)
增
#方法1:指定字段 insert into students(name,age) values('張三',20); #方法2:省略字段名,字段位置一一對應,不能跳過(auto_increment 字段,可以使用null 或 default ) insert into students values(1,'張三','m',null,'110','2','3','haha',23); #方法3:批量增加數據 insert into students(name,age) values('張三',20),('李四“,21),('王五',32),......
刪
#用delete刪除積累,一定要加where條件,否則表數據全部刪除!!
delete from 表名 where xxx=xxx;
#用truncate刪除記錄,不能加where條件,直接刪除全部記錄,id索引重新從1開始
truncate table 表名; //注意truncate 一旦執行,數據不可恢復。
改
#單條修改
update 表名 set xx=xx,xxx=xx where xxx=xx and xxx=xxx;
#多條修改 update students set name = case id #id字段 when 1 then 'zhangsan' when 2 then 'lisi' when 3 then 'wangwu' when 4 then 'zhaoliu' end, city = case id when 1 then '2' when 2 then '4' when 3 then '1' when 4 then '2' end where id in (1,2,3,4);
數據的查
查詢表達式
#當前使用的數據庫 select database(); #查看當前MySQL版本 select version(); #查看當前用戶 select user(); #查看運算結果 select 1+2;
條件表達式
from 子句
#字段用逗號隔開,至少有一個字段,最終結果集按照這個順序顯示 select 字段1,字段2.. from 表名; # *代表所有字段 select * from 表名;
distinct(去重)
#去重后的結果,distinct 必須緊挨着select 后面 select distinct 字段 from 表名; #統計不重復的個數 select count(distinct 字段) from 表名;
where 子句
where子句適用於對記錄的刪,改,查等操作
對記錄進行過濾,如果沒有指定where子句,則顯示所有記錄
在where表達式中,可以使用函數或運算符,運算符包括:
#搜索id<20的所有數據 select * from students where id < 20; #搜索id編號為偶數的數據 select * from students where id % 2 = 0;
where條件關鍵字
in: 查詢一個集合的數據
#搜索id 在(1,3,7)之中的數據 select * from students where id = 1 || id =3 || id =7; select * from students where id in (1,3,7); #一次刪除多條記錄 delete from students where id = 3 || id =15 || id =23; delete from students where id in (3,15,23);
between..and..:查詢一個區間的數據
#搜索id在20-40之間的數據 select * from students where id > 20 && id < 40; select * from students where id between 20 and 40; #刪除id在20-40之間的數據 delete from students where id between 20 and 40;
not :排除
#搜索id除了20-40之間的數據 select * from students where id not between 20 and 40;
like子句
用於模糊查詢 %:任意字符長度
_ : 一個字符長度
#搜索name名字以5結尾的數據 select * from students where name like '%5’; #搜索name名字包含字母s的數據 select * from students like '%s%'; #搜索id以5結尾的兩位數 數據 select * from students where id like '_5';
limit子句
控制查詢記錄條數,數據表中的記錄,索引從0開始
select * from students limit 2 #返回兩條記錄 select * from students limit 3,4 #從索引為3的記錄開始,返回4條記錄 #php中的分頁功能,偏移值的計算:(當前頁-1) * 每頁記錄數 select name from students limit 3 offset 4; #還可以使用offset(偏移):從索引為3的記錄開始,返回4條
group by(結果分組)
根據給定數據列的每個成員對查詢結果進行分組統計,最終得到一個分組匯總表利用group by分組信息進行統計,常見的是配合max等聚合函數篩選數據后分析。
select指定的字段要么作為分組的依據(Group By語句的后面),要么就要被包含在聚合函數中。
#簡單分組,根據性別分成兩組 select sex from students group by sex; #聚合函數分組,根據cityf分組,計算每個城市的學生有幾個 select count(*),city from students group by city;
order by(結果排序)
按照給定的字段進行排序,asc:升序(默認),desc:降序
如果同時選擇多個字段,先按第一個字段排序,如果第一個字段值相等,再嘗試第二個字段,以此類推
#默認升序 select * from students order by birthday; #降序 select * from students order by birthday desc;
查詢語句的書寫順序
select -—> 字段-—> from -—> 表名 -—> where -—> group by -—> order by -—> limit
別名
給表起別名,使用as關鍵字,但是可省略as.
比如 select a.name Aname from students a; 這里給a.name起了別名Aname,也給students起了別名a.
多表查詢
score表和course表的創建語句,數據就自己插入吧。

#score表創建 create table score( user_id int, course_id int, score int ); #course表創建 create table course( id int, name varchar(4) );
分別查詢張三同學對應科目的成績。
這里先查詢張三同學的語文成績:
a 表 人名 select a.name from student as a where a.id=6; b表 分數 select b.score from score as b where b.user_id=6 and b.course_id=4; c表 科目 select c.name from course as c where c.id=4;
上面3條語句 合並語句 並添加 字段別名
select a.name,c.name as course,b.score from students as a, score as b, course as c where a.id=6 and b.user_id=6 and b.course_id=4 and c.id=4;
最終結果
#上面的語句中的where 語句還可以修改 select a.name,c.name,b.score from students a, score b ,course c where b.user_id=a.id and b.course_id=c.id;
表連接
內連接
join : 如果表中有至少一個匹配,則返回行
select 需要查詢的信息 from 表1 表1別名 join 表2 表2別名 on 表1和表2的連接條件
select sc.id,s.name from score sc join students s on sc.user_id = s.id;
內連接和上面的=連接區別在於,例子:
=連接:select sc.id,s.name from score sc,students s where sc.user_id=s.id;
對比上面的內連接明顯發現,=連接是多個表在一起,用逗號隔開,內連接是使用join分開每個表,然后使用on代替where使用,而且添加on之后,還可以加where,但是=連接使用了where,后面就不能再出現where了。
外連接
左外連接 left join:即使右表中沒有匹配,也從左表返回所有的行.(左表指的是left join 語句左邊的表)
select 需要查詢的信息 from 表1 表1別名 left join 表2 表2別名 on 表1和表2的連接條件
select sc.user_id,s.name from score sc left join students s on sc.user_id=s.id #這里的語句意思是:無論students的信息是否匹配score表,都會返回score表中所有數據
右外連接 right join :即使左表中沒有匹配,也從右表返回所有的行. (右表指的是right join 語句右邊的表)
select 需要查詢的信息 from 表1 表1別名 right join 表2 表2別名 on 表1和表2的連接條件
select sc.user_id,s.name from students s right join score sc on sc.user_id=s.id; #這和上面的左連接已經換了students表和score表的位置了,這里的語句意思是:無論students的信息是否匹配score表,都會返回score表中所有數據
全連接(比較少使用)
full join : 只要其中一個表中存在匹配,就返回行(MySQL不支持),但是可以通過另類的方式實現全連接。
mysql不支持全連接,但可以通過左外連接+ union+右外連接實現。
額外:自連接
自連接不屬於一類,應該是屬性內連接的一種,自連接是把一張表當成兩張表使用。
應用場景:找出當前表中高於平均值的所有數據,就要先把當前表的平均值計算出來,把結果當作一張表,然后再對這張結果表比較原來的表,就可以找出高於平均值的數據了。
子查詢
子查詢是指出現在其他SQL語句內的select子句(嵌套在查詢內部,且必須始終出現在圓括號內)
#城市表創建語句 create table city(id int , name varchar(10)); #查詢城市名稱是北京的 #普通方式查詢 select * from students where city=2;#2是北京 #子查詢方式 select * from students where city=(select id from city where name = '北京');
注意:on關鍵字和where關鍵字作用不相同,on只是作用於連接,where是條件過濾,如果使用on作為條件過濾會出現“笛卡兒積”。笛卡兒積:兩表數據記錄條數相乘,比如a表有3條記錄,b表有2條記錄,那么笛卡兒積就是6條記錄。
子查詢可以包含多個關鍵字或條件,如:distinct,group by ,order by ,limit,函數等
子查詢的外層可以是:select,insert,update
視圖與事務
視圖
1. 視圖是從一個或幾個基本表(或視圖)中導出的虛擬的表。在系統的數據字典中僅存放了視圖的定義,不存放視圖對應的數據。視圖是原始數據庫數據的一種變換,是查看表中數據的另外一種方式。可以將視圖看成是一個移動的窗口,通過它可以看到感興趣的數據。視圖時從一個或多個實際表中獲得的,這些表的數據存放在數據庫中。那些用於產生視圖的表叫做該視圖的基表。一個是視圖也可以從另一個視圖中產生。
2. 數據庫中視圖是一個重要的概念,其優勢在於:
安全:有的數據是需要保密的,如果直接把表給出來進行操作會造成泄密,那么可以通過創建視圖把相應視圖的權限給出來即可保證數據的安全,比如創建視圖是給原表的字段起別名。
高效:復雜的連接查詢,每次執行時效率比較低,建立視圖,每次從視圖中獲取,將會提高效率。
定制數據:將常用的字段放置在視圖中。
3. 對視圖進行增刪改查,會影響到原表數據。(通過視圖影響原表數據的,不是直接操作的原表)
接下來用例子演示操作視圖會對原表數據產生影響,如下圖:
從上圖可以發現對視圖進行修改操作,結果原表的數據也發生了改變,所以對視圖進行增刪改查,會影響到原表數據。
注意:在以下幾種條件下不能進行對視圖的插入/更新/刪除操作。
-
視圖的列中含有統計函數的情況下;
-
視圖定義時使用了GROUP BY/HAVING語句,DISTINCT語句、UNION語句的情況下;
-
視圖定義時使用了子查詢的情況下;
-
進行跨越多個表進行數據的變更操作(多表連接);
創建視圖
create view 視圖名 as select 字段名 from 表名 where 條件;
修改視圖
#alter語句: alter view 視圖名 as select 字段名 from 表名 where 條件;
刪除視圖
drop view 視圖名;
查詢視圖
show tables;
show tables status;
這兩個命令不僅可以顯示表名及表信息,而且會顯示出所有視圖名稱及視圖信息。
除此之外,使用show create view 命令可以查看某個視圖的定義,格式如下:
show create view 視圖名;
關系數據庫表時用於存儲和組織信息的數據結構,數據結構的不同,直接影響操作數據的效率和功能,對於MySQL來說,它提供了很多類型的存儲引擎,可以根據對數據處理的需求,選擇不同的存儲引擎,從而最大限定的利用MySQL強大的功能。
事務
3.1、一個事務是一個完整的業務邏輯單元,不可再分。
比如銀行賬號轉賬,從A賬戶向B賬戶轉賬10000 , 需要執行兩條update語句。
update t_act set balance = balance - 10000 where actno = 'act-001';
update t_act set balance = balance + 10000 where actno= 'act-002';
和事務相關的語句只有:DML語句。(insert delete update)
為什么?因為它們這三個語句都是和數據庫表中的“數據” 相關的。
事務的存在是為了保證數據的完整性,安全性。
3.2、事務的原理?
事務(TCL) :只有兩條語句,提交事務(commit) ;回滾事務(rollback)。
提交事務就是把操作記錄到硬盤中,回滾事務就是清空歷史操作,不保存操作記錄到硬盤中。
3.3、事務的特性?
事務包括四大特性:ACID
A : 原子性:事務是最小的工作單元,不可再分。
C : 一致性:事務必須保證多條DML語句同時成功或者同時失敗。
I : 隔離性:事務A和事務B之間具有隔離。
D : 持久性:持久性說的是最終數據必須持久化到硬盤文件中,事務才算成功的結束。
3.4、關於事務之間的隔離性
事務隔離性存在隔離級別,理論上隔離級別包括4個:
第一級別:讀未提交(read uncommitted)
對方事務還沒有提交,我們當前事務可以讀取到對方未提交的數據。
讀未提交存在臟讀(Dirty Read)現象:表示讀到了臟的數據。
第二級別:讀已提交(read committed)
對方事務提交之后的數據我方可以讀取到。
這種隔離級別解決了:臟讀現象沒有了。
讀已提交存在的問題是:不可重復讀。(共享數據被對方更改,不能讀取與原來相同的數據)
第三級別:可重復讀(repeatable read)
這種隔離級別解決了:不可重復讀問題。
這種隔離級別存在的問題是:讀取到的數據是幻象。
第四級別:序列化讀/串行化讀
解決了所有問題。
效率低。需要事務排隊。
Oracle數據庫默認的隔離級別是:讀已提交。
MySQL數據庫默認的隔離級別是:可重復讀。
3.5、使用兩個事務演示以上的隔離級別
第一:演示 讀未提交(read uncommitted):
設置事務的隔離級別:set global transaction isolation level read uncommitted;
通過 select @@global.tx_isolation; 這個是msyql5版本的命令 / select @@global.transaction_isolation; 這個是mysql8版本的命令,查看全局的事務隔離級別。
可以看到事務隔離級別已經設置為 read uncommitted,注意設置好隔離級別后,要重新打開cmd命令提示符,不然不生效。
第二:演示 讀已提交(read committed):
設置事務的隔離級別:set global transaction isolation level read committed;
然后退出MySQL,重新登錄。
可以發現 讀已提交(read committed)是共享數據被對方更改,不能讀取與原來相同的數據。
比如:你和同事共享一個數據,你已經做好邏輯處理,但是同事修改了一下你邏輯中的數據,導致結果和你預想的不一致。
第三:演示 可重復讀(repeatable read):
設置事務的隔離級別:set global transaction isolation level repeatable read;
然后退出MySQL,重新登錄。
可重復讀(repeatable read)也稱幻讀,讀取的數據是備份數據,當命令窗1結束當前事務時,命令窗2的事務才能影響到命令窗1的數據,如下圖:
第四:演示串行化讀
設置事務的隔離級別:set global transaction isolation level serializable;
然后退出MySQL,重新登錄。
然后命令窗1提交事務,命令窗2的查詢語句才能出結果,否則一直等待下去,如下圖:
如果命令窗2在命令窗1沒有提交事務前執行查詢語句,會處於等待狀態,等待有時間限制,超過等待時間,會報錯,如上圖命令窗2 的timeout exceeded.
3.6、演示事務
* MySQL事務默認情況下是自動提交的。
(什么是自動提交?只要執行任意一條DML語句則提交一次。)怎么關閉自動提交?start transaction;
* 准備表:
drop table if exists t_user;
create table t_user(
id int primary key auto_increment,
username varchar(255)
);
* 演示:MySQL中的事務是支持自動提交的,只要執行一條DML,則提交一次。
可以發現上圖rollback沒有用,因為mysql默認事務是自動提交的,也就是自動(commit).
*演示:使用 start transaction; 關閉自動提交機制。
-------------------------------------------------------------------------------------------------------------------------------------------------
MyISAM引擎
MyISAM表是獨立於操作系統的,這說明可以輕松地將其從Windows服務器移植到Linux服務器,建立一個MyISAM引擎的tb_Demo表,就會生成以下三個文件:
- mytable.frm存儲表結構的定義
- mytable.MYD存儲表行內容,即數據
- mytable.MYI存儲索引。
MyISAM無法處理事務,特別適合以下幾種情況使用:
1. 選擇密集型的表。MyISAM存儲引擎在篩選大量數據時非常迅速,這是它最突出的優點。
2. 插入密集型的表。MyISAM的並發插入特性允許同時選擇和插入數據。例如:MyISAM存儲引擎很適合管理郵件或Web服務器日志數據。
InnoDB引擎
InnoDB是一個健壯的事務型存儲引擎,InnoDB還引入了外鍵約束,在以下場合下,
使用InnoDB是最理想的選擇:
1. 更新密集的表。InnDB存儲引擎特別適合處理多重並發的更新請求。
2. 事務。InnoDB存儲引擎是支持事務的標准MySQL存儲引擎。
3. 外鍵約束。MySQL支持外鍵的存儲引擎只有InnoDB。
4. 自動災難恢復。與其他存儲引擎不同,InnoDB表能夠自動從災難中恢復。
事務處理
以銀行轉賬業務為例,張三——》李四轉賬100元,這是一個完整事務,需要兩步操作:
1. 張三數據表減去100元
2. 李四數據表增加100元
如果1步完成后,操作出現錯誤(斷電,操作異常等),使2步沒有完成,此時,張三減去了100元,而李四卻沒有收到100元。
為了避免這種情況的發生,就將整個操作定義為一個事務,任何操作步驟出現錯誤,都會回滾到上一次斷點位置,避免出現其他錯誤。
#開始 begin: update tb1_a set money=money-100 where name='zhangsan'; update tb1_bmoney=money+100 where name='lisi'; #提交 commit; #回滾 rollback;
索引約束分區
索引
1. 什么是索引?有什么用?
索引就相當於一本書的目錄,通過目錄可以快速的找到對應的資源。
在數據庫方面,查詢一張表的時候有兩種檢索方式:
第一種方式:全表掃描
第二種方式:根據索引檢索(效率很高)
索引為什么可以提高檢索效率呢?
其實最根本的原理是縮小了掃描的范圍。
索引雖然可以提高檢索效率,但是不能隨意的添加索引,因為索引也是數據庫當中的對象,也需要數據庫不斷的維護。是有維護成本的。
比如,表中的數據經常被修改,這樣就不適合添加索引,因為數據一旦修改,索引需要重新排序,進行維護。
添加索引是給某一個字段,或者某些字段添加索引。
select ename, sal from emp where ename = 'SMITH';
當ename字段上沒有添加索引的時候,以上sql語句會進行全表掃描,掃描ename字段中所有的值。
當ename字段上添加索引的時候,以上sql語句會根據索引掃描,快速定位。
2. 怎么創建索引對象?怎么刪除索引對象?
創建索引語法格式: create index 索引名 on 表名 (字段名);
刪除索引語法格式:drop index 索引名稱 on 表名;
3. 什么時候考慮給字段添加索引?(滿足什么條件)
* 數據量龐大。(根據客戶的需求,根據線上的環境)
* 該字段很少的DML操作。(因為字段進行修改操作,索引也需要維護)
* 該字段經常出現在where子句中。(經常根據哪個字段查詢)
4. 注意:主鍵和具有unique約束的字段自動會添加索引。
5. 查看sql語句的執行計划:
explain select ename,sal from emp where sal = 5000;
上圖的type就是掃描表的方式,ALL代表全表掃描,rows代表掃描行數,14行是這個表的總記錄數。
給薪資sal字段添加索引:
create index emp_sal_index on emp (sal);
從上圖可以發現創建索引后,查詢只掃描了1行。
6. 索引底層采用的數據結構是:B + Tree
7. 索引的實現原理?
通過B Tree 縮小掃描范圍,底層索引進行了排序,分區,索引會攜帶數據在表中的“物理地址”,
最終通過索引檢索到數據之后,獲取到關聯的物理地址,通過物理地址定位表中的數據,效率是最高的。
例如:select ename from emp where ename = 'SMITH';
通過索引轉化為:
select ename from emp where 物理地址 = 0x3;
下面圖解索引實現原理:
8. 索引的分類?
單一索引:給單個字段添加索引
復合索引:給多個字段聯合起來添加1個索引
主鍵索引:主鍵上會自動添加索引
唯一索引:有unique約束的字段上會自動添加索引
.......
9. 索引什么時候失效?
select ename from emp where ename like '%A%';
模糊查詢的時候,第一通配符使用的是%,這個時候索引是失效的。
索引是幫助MySQL高效獲取數據的數據結構
數據庫在保存數據之外,還維護着滿足特定查找算法的數據結構,這些數據結構以某種方式引用(指向)數據,這樣就可以在這些數據結構上實現高級查找算法。這種數據結構,就是索引。索引可以大大提高MySQL的檢索速度。
在MySQL中,對於一個Primary Key的列,MySQL已經自動對其建立了Unique和Index.
#創建索引 create table 表名( id int not null, username varchar(16) not null, index(username(length)) ###用username字段作為索引 ): #顯示索引 show index from 表名; #刪除索引 alter table 表名 drop index name;
約束
約束保證數據的完整性和一致性,根據約束的字段數目的多少,約束又分為表級約束和列級約束
列級約束:針對某一字段來使用
表級約束:針對兩個或兩個以上的字段使用
約束類型包括:
not null (非空約束)
primary key (主鍵約束)
unique key (唯一約束)
default(默認約束)
foreign key (外鍵約束)
唯一(unique)約束
unique 約束唯一標識數據庫表中的每條記錄。
unique 和 primary key 約束均為列提供了唯一性的保證。
primary key 被自動定義為unique 約束。
注意:每個表可以有多個unique 約束,但是每個表只能有一個primary key 約束。
#第一種方式 create table persons( id int not null, address varchar(255), city varchar(155), phone varchar(11) unique #定義字段的同時,定義約束 ); #第二種方式 create table persons( id int not null, address varchar(155), phone varchar(11), unique (phone) #單數一行命令,定義約束 ); #第三種方式 alter table persons add unique (city); #修改表
默認(default)約束
用於約束對應列中的值的默認值(除非默認為空值,否則不可插入空值)
create table persons( id tinyint primary key auto_increment, name varchar(30), sex enum('m','w') default 'm' #定義sex默認值為:'m' );
主鍵(primary key) 約束
每張數據表只能存在一個主鍵,主鍵保證記錄的唯一性,主鍵自動為not null (同時作為表的索引)。
#為沒有主鍵的表添加主鍵 alter table 表名 add primary key (字段名); #在創建表的時候,定義主鍵 create table persons( id int not null primary key, name varchar(10) ); #在創建表的最后,定義主鍵,通常是定義聯合主鍵 create table persons( id int not null, address varchar(10), primary key(id,address) );
外鍵(foreign key)約束
外鍵約束是為了保存數據一致性,完整性,實現一對一或一對多關系
子表(具有外鍵列的表)和 父表(子表所參照的表),存儲引擎只能為InnoDB。
外鍵列和參照列必須具有相似的數據類型。
- 如果是數字類型,數字的長度、是否有符合位 必須相同
- 字符類型的長度則可以不同
外鍵列和參照列必須創建索引(如果外鍵列不存在索引的話,MySQL將自動創建索引)。
外鍵的好處:可以使得兩張表關聯,保證數據的一致性和實現一些級聯操作。保持數據一致性,完整性,主要目的是控制存儲在外鍵表中的數據。 使兩張表形成關聯,外鍵只能引用外表中的列的值!可以使得兩張表關聯,保證數據的一致性和實現一些級聯操作;
#先建父表 子表才能建外鍵 父表和子表必須都是 innodb引擎 #city父表 create table city( id tinyint primary key, name varchar(10) not null )engine=INNODB; #students子表 create table students( id tinyint primary key auto_increment, #id #定義字段時同時定義 city tinyint, #外鍵字段類型要於主表相同 foreign key(city) references city(id) #city字段作為外鍵,引用city表中的id )engine=INNODB; #主表的數據可以修改,但不能刪除 #刪除city中的記錄 delete from city where id=1;
#創建外鍵以后,再刪除city記錄,就會報錯:
因為students的外鍵引用city的記錄,如果直接刪除city的記錄,students外鍵列找不到依賴的列就會報錯,所以MySQL規定不能刪除外鍵所依賴的數據,子表的外鍵列也不能插入被引用的父表中不存在的數據。
總結:設置外鍵的列,就全依賴於父表,外鍵列的數據全部依賴父表的數據,外鍵列插入的數據必須是父表被引用的列中存在的,父表的數據可以修改,但不能刪除。
補充:通常設置外鍵會自動生成外鍵名,不夠最好是自己設置外鍵名。
#給外鍵設置名字 create table students( id tinyint primary key auto_increment, #id #定義字段時同時定義 city tinyint, #外鍵字段類型要於主表相同 constraint 外鍵名 foreign key(city) references city(id) )engine=INNODB;
刪除約束
刪除primary key
alter table 表名 drop primary key;
刪除index
alter table 表名 drop index 索引名;
刪除外鍵約束
alter table drop foreign key 外鍵名;
索引於約束的關系
索引是面向數據庫本身的,用於查詢優化等操作。約束則更多的是業務上的關系。
通常,創建唯一約束就自動獲取唯一索引,是因為數據庫認為數據庫進行唯一檢查時,如果該字段上有索引會很快,所以創建唯一約束就默認創建唯一索引。同樣,常見的主鍵即是唯一性的約束,也是個索引。但對於not null 這樣的約束,數據庫是不會創建索引的。
分區
如果一張表的數據量太大,不僅查找數據的效率低下,而且難以找到一塊集中的存儲來存放。為了解決這個問題,數據庫退出了分區的功能。MySQL表分區主要有以下四種類型:
RANGE分區:
RANGE即范圍分區,根據區間來判斷於哪個分區。這些區間要連續且不能相互重疊,使用VALUES LESS THAN 操作符來進行定義。
create table test( id int default null, name char(30), datedata date ) partition by range(year(datedata))( partition part1 values less than(1990), partition part2 values less than(1995), partition part3 values less than(2000), partition part4 values less than MAXVALUE);
LIST分區
LIST分區類似於按RANGE分區,區別在於LIST分區是基於列值匹配一個離散值集合中的某個值來進行選擇。
create table test1( id int not null, name char(30), career varchar(30) ) partition by LIST(id)( partition part0 values in (1,5), partition part1 values in (11,15), partition part2 values in (6,10), partition part3 values in (16,20) );
HASH分區
HASH分區基於用戶定義的表達式返回值來選擇分區,該表達式對要插入到表的行中列值進行Hash計算。
create table employess( id int not null, firstname varchar(30), lastname varchar(30), hired date not null default '1970-01-01', separated date not null default '9999-12-31', job_code int, store_id int ) partition by HASH(store_id) partition 4;
KEY分區
KEY分區類似HASH,但是HASH允許用戶使用自定義表達式,而KEY分區不允許,它需要使用MySQL服務器提供的HASH函數,同時HASH分區只支持整數分區,而KEY分區支持除了BLOB和TEXT類型外其他列。
create table tk( col1 int not null, col2 char(5), col3 date, primary key (col1) ) partition by key(col1) paritions 3;
存儲過程/觸發器
存儲過程
存儲過程是一種在數據庫中存儲復雜程序,以便外部程序調用的一種數據庫對象。
存儲過程是為了完成特定功能的SQL語句集,經編譯創建並保存在數據庫中,用戶可通過指定存儲過程的名字並給參數(需要時)來調用執行。
存儲過程思想上很簡單,就是數據庫SQL語言層面的代碼封裝於重用。
優點
- 存儲過程可以封裝,並隱藏復雜的商業邏輯。
- 存儲過程可以回傳值,並可以接受參數。
- 存儲過程無法使用select 指令來運行,因為它是子程序,於查看表,數據表或用戶定義函數不同。
- 存儲過程可以用在數據檢驗,強制實行商業邏輯等。
缺點
- 存儲過程,往往定制化於特定的數據庫上,因為支持的編程語言不同。當切換到其他廠商的數據庫系統時,需要重寫原有的存儲過程。
- 存儲過程的性能調校與撰寫,受限於各種數據庫系統。
存儲過程的創建和調用
存儲過程就是具有名字的一段代碼,用來完成一個特定的功能。
創建的存儲過程保存在數據庫的數據字典中。
create produce 存儲過程名(in | out | inout 參數名稱 參數類型,.....)
begin
過程體;
end
實例
create procedure getStudentCount() begin select count(*) as num from student where classid=8; end
查詢/修改/刪除存儲過程
查詢
查看所有存儲過程狀態:
show procedure status;
查看對應數據庫下所有存儲過程狀態:
show procedure status where db=‘數據庫名';
查看名稱包含Student的存儲過程狀態:
show procedure status where name like '%student%';
查詢存儲過程詳細代碼:
show create procedure 過程名;
修改
alter procedure 過程名([過程參數[,...]])過程體;
刪除
drop procedure 過程名;
注意:不能在一個存儲過程中刪除另一個存儲過程,只能調用另一個存儲過程。
調用存儲過程
MySQL存儲過程用call和過程名以及一個括號,括號里面根據需要,加入參數,參數包括輸入參數,輸出參數,輸入輸出參數調用,格式如下:
call 存儲過程名([過程參數[,....]])
觸發器
觸發器(trigger ),也叫觸發程序,是與表有關的命名數據庫對象,是MySQL中提供給程序員來保證數據完整性的一種方法,它是與表事件insert,update , delete 相關的一種特殊的存儲過程,它的執行是由事件來觸發,比如當對一個表進行insert ,update , delete 事件時就會激活它執行。因此,刪除,新增或修改操作可能都會激活觸發器,所以不要編寫過於復雜的觸發器,也不要增加過多的觸發器,這樣會對數據的插入,修改或刪除帶來比較嚴重的影響,同時也會帶來可移植性差的后果,所以在設計觸發器的時候一定要有所考慮。
創建觸發器
create trigger trigger_name trigger_time trigger_event on tb_name for each row trigger_stmt
其創建觸發器的參數說明如下表:
觸發事件類型介紹如下表所示:
我們想要使班級表中的班內學生數隨着學生的添加自動更新,則采用觸發器來實現最為合適,創建觸發器如下:
create trigger tri_stuInsert aflter insert on student for each row begin declare c int; set c = (select stuCount from class where classID=new.classID); update class set stuCount = c + 1 where classID = new.classID; end
從需求我們可以得知,班內學生數的變化是在插入學生記錄之后發生的,所以創建的觸發器類型為after insert 類型。
查看觸發器
show triggers;
刪除觸發器
drop trigger [if exists] trigger_name
觸發器執行順序
日常開發中創建的數據庫通常都是InnoDB數據庫,在數據庫上建立的表大都是事務性表,也就是事務安全的,這時觸發器的執行順序主要是:
1. 如果 before 類型的觸發器執行失敗,SQL無法正確執行。
2. 如果SQL執行失敗時,after 類型的觸發器不會觸發。
3. 如果after 類型的觸發器執行失敗,數據會回滾。
如果是對數據庫的非事務表進行操作,當觸發器執行順序中的任何一步執行出錯,那么就無法回滾了,數據可能會出錯。
MySQL函數
運算函數
abs(x):返回x的絕對值
floor(x):返回小於x的最大整數值
round(x,y):返回參數x的四舍五入的有y位小數的值
mod(x,y):返回x/y的模(余數)
greatest(x1,x2,....,xn):返回集合中最大的值
least(x1,x2,...,xn):返回集合中最小的值
字符串函數
trim(str):去除字符串首尾兩端的空格
upper(str):字符串轉大寫
concat(s1,s2...,sn):將s1,s2....,sn連接成字符串
#concat insert into tb1_name values(concat('abc','def'));
日期函數
year(date):返回日期date的年份(1000~9999)
month(date):返回date的月份值(1~12)
day(date):返回date的日(1~31)
curdate():返回當前的日期
week(date):返回日期date為一年中第幾周(0~53)
now():返回當前的日期和時間
curtime():返回當前的時間
hour(time):返回time的小時值(0~23)
minute(time):返回time的分鍾值(0~59)
聚合函數
count(col):統計記錄的條數
sum(col):求和
avg(col):求平均值
max(col):求最大值
min(col):求最小值
#count統計總記錄數 select count(*) from tb1_name; #sum年齡總和 select sum(age) from tb1_name; #avg平均年齡 select avg(age) from tb1_name; #最大年齡 select min(birthday) from tb1_name; #日期最小的 #最小年齡 select max(birthday) from tb1_name; #日期最大的
found_rows()
#found_rows函數配合SQL_CLAC_FOUND_ROWS 用於獲取總記錄數(忽略limit ) select sql_calc_found_rows * from qa_list limi 3; select found_rows();
第一個sql里面的SQL_CALC_FOUND_ROWS不可省略,它表示需要取得結果數,也是后面使用FOUND_ROWS()函數的鋪墊。
FOUND_ROWS()返回的結果是臨時的。如果程序往后會用到這個數字,必須提取把它保存在一個變量中待用。
FOUND_ROWS()與count()的區別:
1. 當SQL限制條件太多時,count()的執行效率不是很高,最好使用FOUND_ROWS()
2. 當SQL查詢語句沒有where等條件限制時,使用count()函數的執行效率較高。
數據庫備份
使用Navicat 可視化工具導入 導出數據,備份 恢復數據
備份數據/導出整個數據庫
命令窗:myqldump -u[用戶名] -p[密碼] [數據庫名] > [path]/[名稱].sql; //前面的紅色部分可以放在命令的最后也行:myqldump [數據庫名] > [path]/[名稱].sql -u[用戶名] -p[密碼];
例:mysqldump -uroot -pxxx110 test > d:/abc/test.sql
導出指定庫下的指定表
命令窗:mysqldump [數據庫名] [表名] > [path]/[數據庫名稱].sql -u[用戶名] -p[密碼] //紅色部分也可以放在mysqldump后面也行
例:mysqldump -uroot -pxxx110 test emp_bak > d:/abc/emp.sql
上面的命令窗注意是doc,而且沒有登錄mysql的前提才能執行上面的導出語句。
Navicat備份數據:
恢復數據/導入數據
DOS命令窗:source 路徑\數據庫文件 //注意導入數據庫/數據表 之前要創建對應的數據庫
例:source c:\system.sql //比如這里數據庫文件的名字是system,所以要先創建create database system 然后use system ,才能執行source導入語句。
Navicat恢復數據/導入數據
選擇導入的數據/恢復的數據文件。
數據庫設計三范式
1. 第一范式:任何一張表都應該有主鍵,並且每一字段原子性不可再分。
2. 第二范式:建立在第一范式的基礎之上,所有非主鍵字段完全依賴主鍵,不能產生部分依賴(復合主鍵)。
多對多?三張表,關系表兩個外鍵。
3. 第三范式:建立在第二范式的基礎之上,所有非主鍵字段直接依賴主鍵,不能產生傳遞依賴。
一對多?兩張表,多的表加外鍵。
如:班級t_class
cno(pk) cname
----------------------------
1 班級1
2 班級2
學生t_student
sno(pk) sname classno(fk)
---------------------------------------------------------
101 z1 1
102 z2 1
103 z3 2
104 z4 2
學生是多,班級一,一對多,多的表加外鍵,也就是學生表加外鍵。
注意:實際業務中,需求經常改動,所以不再推薦使用外鍵,難維護(不過數據庫設計還是按照上面三規范,只是不添加外鍵,還是可以進行表連接)。
提醒:在實際的開發中,以滿足客戶的需求為主,有的時候會那冗余換執行速度。
補充:一對一怎么設計?
比如一個用戶信息,字段太多怎么處理?
一對一設計有兩種方案:
第一:主鍵共享
t_user_login 用戶登錄表
id(pk) username password
---------------------------------------------
1 zs 123
2 ls 656
t_user_detail 用戶詳細信息表
id(pk) realname tel
--------------------------------------
1 張三 323232323
2 李四 323232314
總結:主鍵共享就是個人信息用兩張表存儲,第一張表字段查詢比較多,所以對立一張表,第二張表字段查詢較少,獨立一張表,然后使用相同的主鍵數字,就可以進行表連接。
第二:外鍵唯一
t_user_login 用戶登錄表
id(pk) username password
---------------------------------------------
1 zs 123
2 ls 656
t_user_detail 用戶詳細信息表
id(pk) realname tel userid(fk+unique)
----------------------------------------------------------------------------------
1 張三 323232323 1
2 李四 323232314 2
總結:第二張表userid外鍵引用第一張表的id主鍵,但是可能會出現重復,所以使用了唯一約束,這樣第二張表的userid和第一張表的id只能一一對應。