為什么學習數據庫
1、崗位技能需求
3、存儲數據的方法
4、程序,網站中,大量數據如何長久保存?
5、數據庫是幾乎軟件體系中最核心的一個存在。
什么是數據庫
數據庫 ( DataBase , 簡稱DB )
概念 : 長期存放在計算機內,有組織,可共享的大量數據的集合,是一個數據 "倉庫"
作用 : 保存,並能安全管理數據(如:增刪改查等),減少冗余...
數據庫總覽 :
-
關系型數據庫 ( SQL )
-
-
MySQL , Oracle , SQL Server , SQLite , DB2 , ...
-
關系型數據庫通過外鍵關聯來建立表與表之間的關系
-
-
非關系型數據庫 ( NOSQL )
-
-
Redis , MongoDB , ...
-
非關系型數據庫通常指數據以對象的形式存儲在數據庫中,而對象之間的關系通過每個對象自身的屬性來決定
-
什么是DBMS
數據庫管理系統 ( DataBase Management System )
數據庫管理軟件 , 科學組織和存儲數據 , 高效地獲取和維護數據
為什么要說這個呢?
因為我們要學習的MySQL應該算是一個數據庫管理系統.
MySQL簡介
概念 : 是現在流行的開源的,免費的 關系型數據庫
歷史 : 由瑞典MySQL AB 公司開發,目前屬於 Oracle 旗下產品。
特點 :
-
免費 , 開源數據庫
-
小巧 , 功能齊全
-
使用便捷
-
可運行於Windows或Linux操作系統
-
可適用於中小型甚至大型網站應用
安裝MySQL
這里建議大家使用壓縮版,安裝快,方便.不復雜.
軟件下載
mysql5.7 64位下載地址:
https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.19-winx64.zip
電腦是64位的就下載使用64位版本的!
安裝步驟
1、下載后得到zip壓縮包.
2、解壓到自己想要安裝到的目錄,本人解壓到的是D:\Environment\mysql-5.7.19
3、添加環境變量:我的電腦->屬性->高級->環境變量
選擇PATH,在其后面添加: 你的mysql 安裝文件下面的bin文件夾
4、編輯 my.ini 文件 ,注意替換路徑位置
[mysqld]
basedir=D:\Program Files\mysql-5.7\
datadir=D:\Program Files\mysql-5.7\data\
port=3306
skip-grant-tables
5、啟動管理員模式下的CMD,並將路徑切換至mysql下的bin目錄,然后輸入mysqld –install (安裝mysql)
6、再輸入 mysqld --initialize-insecure --user=mysql 初始化數據文件
7、然后再次啟動mysql 然后用命令 mysql –u root –p 進入mysql管理界面(密碼可為空)
8、進入界面后更改root密碼
update mysql.user set authentication_string=password('123456') where user='root'and Host = 'localhost';
9、刷新權限
flush privileges;
10、修改 my.ini文件刪除最后一句skip-grant-tables
11、重啟mysql即可正常使用
net stop mysql
net start mysql
12、連接上測試出現以下結果就安裝好了
一步步去做 , 理論上是沒有任何問題的 .
如果您以前裝過,現在需要重裝,一定要將環境清理干凈 .
好了,到這里大家都裝好了,因為剛接觸,所以我們先不學習命令.
這里給大家推薦一個工具 : SQLyog .
即便有了可視化工具,可是基本的DOS命名大家還是要記住!
SQLyog
可手動操作,管理MySQL數據庫的軟件工具
特點 : 簡潔 , 易用 , 圖形化
使用SQLyog管理工具自己完成以下操作 :
-
連接本地MySQL數據庫
-
新建MySchool數據庫
-
-
字段
-
GradeID : int(11) , Primary Key (pk)
-
GradeName : varchar(50)
-
數據庫名稱MySchool
-
新建數據庫表(grade)
-
在歷史記錄中可以看到相對應的數據庫操作的語句 .
連接數據庫
打開MySQL命令窗口
-
在DOS命令行窗口進入 安裝目錄\mysql\bin
-
可設置環境變量,設置了環境變量,可以在任意目錄打開!
連接數據庫語句 : mysql -h 服務器主機地址 -u 用戶名 -p 用戶密碼
注意 : -p后面不能加空格,否則會被當做密碼的內容,導致登錄失敗 !
幾個基本的數據庫操作命令 :
update user set password=password('123456')where user='root'; 修改密碼
flush privileges; 刷新數據庫
show databases; 顯示所有數據庫
use dbname;打開某個數據庫
show tables; 顯示數據庫mysql中所有的表
describe user; 顯示表mysql數據庫中user表的列信息
create database name; 創建數據庫
use databasename; 選擇數據庫
exit; 退出Mysql
? 命令關鍵詞 : 尋求幫助
-- 表示注釋
結構化查詢語句分類
數據庫操作
命令行操作數據庫
創建數據庫 : create database [if not exists] 數據庫名;
刪除數據庫 : drop database [if exists] 數據庫名;
查看數據庫 : show databases;
使用數據庫 : use 數據庫名;
對比工具操作數據庫
學習方法:
-
對照SQLyog工具自動生成的語句學習
-
固定語法中的單詞需要記憶
-
創建數據表
屬於DDL的一種,語法 :
create table [if not exists] `表名`(
'字段名1' 列類型 [屬性][索引][注釋],
'字段名2' 列類型 [屬性][索引][注釋],
#...
'字段名n' 列類型 [屬性][索引][注釋]
)[表類型][表字符集][注釋];
說明 : 反引號用於區別MySQL保留字與普通字符而引入的 (鍵盤esc下面的鍵).
數據值和列類型
列類型 : 規定數據庫中該列存放的數據類型
數值類型
字符串類型
日期和時間型數值類型
NULL值
-
理解為 "沒有值" 或 "未知值"
-
不要用NULL進行算術運算 , 結果仍為NULL
數據字段屬性
UnSigned
-
無符號的
-
聲明該數據列不允許負數 .
ZEROFILL
-
0填充的
-
不足位數的用0來填充 , 如int(3),5則為005
Auto_InCrement
-
自動增長的 , 每添加一條數據 , 自動在上一個記錄數上加 1(默認)
-
通常用於設置主鍵 , 且為整數類型
-
可定義起始值和步長
-
-
當前表設置步長(AUTO_INCREMENT=100) : 只影響當前表
-
SET @@auto_increment_increment=5 ; 影響所有使用自增的表(全局)
-
NULL 和 NOT NULL
-
默認為NULL , 即沒有插入該列的數值
-
如果設置為NOT NULL , 則該列必須有值
DEFAULT
-
默認的
-
用於設置默認值
-
例如,性別字段,默認為"男" , 否則為 "女" ; 若無指定該列的值 , 則默認值為"男"的值
-- 目標 : 創建一個school數據庫
-- 創建學生表(列,字段)
-- 學號int 登錄密碼varchar(20) 姓名,性別varchar(2),出生日期(datatime),家庭住址,email
-- 創建表之前 , 一定要先選擇數據庫
CREATE TABLE IF NOT EXISTS `student` (
`id` int(4) NOT NULL AUTO_INCREMENT COMMENT '學號',
`name` varchar(30) NOT NULL DEFAULT '匿名' COMMENT '姓名',
`pwd` varchar(20) NOT NULL DEFAULT '123456' COMMENT '密碼',
`sex` varchar(2) NOT NULL DEFAULT '男' COMMENT '性別',
`birthday` datetime DEFAULT NULL COMMENT '生日',
`address` varchar(100) DEFAULT NULL COMMENT '地址',
`email` varchar(50) DEFAULT NULL COMMENT '郵箱',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
-- 查看數據庫的定義
SHOW CREATE DATABASE school;
-- 查看數據表的定義
SHOW CREATE TABLE student;
-- 顯示表結構
DESC student; -- 設置嚴格檢查模式(不能容錯了)SET sql_mode='STRICT_TRANS_TABLES';
數據表的類型
設置數據表的類型
CREATE TABLE 表名( -- 省略一些代碼 -- Mysql注釋 -- 1. # 單行注釋 -- 2. /*...*/ 多行注釋 )ENGINE = MyISAM (or InnoDB) -- 查看mysql所支持的引擎類型 (表類型) SHOW ENGINES;
MySQL的數據表的類型 : MyISAM , InnoDB , HEAP , BOB , CSV等...
常見的 MyISAM 與 InnoDB 類型:
經驗 ( 適用場合 ) :
-
適用 MyISAM : 節約空間及相應速度
-
適用 InnoDB : 安全性 , 事務處理及多用戶操作數據表
數據表的存儲位置
-
MySQL數據表以文件方式存放在磁盤中
-
-
包括表文件 , 數據文件 , 以及數據庫的選項文件
-
位置 : Mysql安裝目錄\data\下存放數據表 . 目錄名對應數據庫名 , 該目錄下文件名對應數據表 .
-
-
注意 :
-
-
* . frm -- 表結構定義文件
-
* . MYD -- 數據文件 ( data )
-
* . MYI -- 索引文件 ( index )
-
InnoDB類型數據表只有一個 *.frm文件 , 以及上一級目錄的ibdata1文件
-
MyISAM類型數據表對應三個文件 :
-
設置數據表字符集
我們可為數據庫,數據表,數據列設定不同的字符集,設定方法 :
-
創建時通過命令來設置 , 如 : CREATE TABLE 表名()CHARSET = utf8;
-
如無設定 , 則根據MySQL數據庫配置文件 my.ini 中的參數設定
修改數據庫
修改表 ( ALTER TABLE )
修改表名 :ALTER TABLE 舊表名 RENAME AS 新表名
添加字段 : ALTER TABLE 表名 ADD字段名 列屬性[屬性]
修改字段 :
-
ALTER TABLE 表名 MODIFY 字段名 列類型[屬性]
-
ALTER TABLE 表名 CHANGE 舊字段名 新字段名 列屬性[屬性]
刪除字段 : ALTER TABLE 表名 DROP 字段名
刪除數據表
語法:DROP TABLE [IF EXISTS] 表名
-
IF EXISTS為可選 , 判斷是否存在該數據表
-
如刪除不存在的數據表會拋出錯誤
其他
1. 可用反引號(`)為標識符(庫名、表名、字段名、索引、別名)包裹,以避免與關鍵字重名!中文也可以作為標識符! 2. 每個庫目錄存在一個保存當前數據庫的選項文件db.opt。 3. 注釋: 單行注釋 # 注釋內容 多行注釋 /* 注釋內容 */ 單行注釋 -- 注釋內容 (標准SQL注釋風格,要求雙破折號后加一空格符(空格、TAB、換行等)) 4. 模式通配符: _ 任意單個字符 % 任意多個字符,甚至包括零字符 單引號需要進行轉義 \' 5. CMD命令行內的語句結束符可以為 ";", "\G", "\g",僅影響顯示結果。其他地方還是用分號結束。delimiter 可修改當前對話的語句結束符。 6. SQL對大小寫不敏感 (關鍵字) 7. 清除已有語句:\c
外鍵
外鍵概念
如果公共關鍵字在一個關系中是主關鍵字,那么這個公共關鍵字被稱為另一個關系的外鍵。由此可見,外鍵表示了兩個關系之間的相關聯系。以另一個關系的外鍵作主關鍵字的表被稱為主表,具有此外鍵的表被稱為主表的從表。
在實際操作中,將一個表的值放入第二個表來表示關聯,所使用的值是第一個表的主鍵值(在必要時可包括復合主鍵值)。此時,第二個表中保存這些值的屬性稱為外鍵(foreign key)。
外鍵作用
保持數據一致性,完整性,主要目的是控制存儲在外鍵表中的數據,約束。使兩張表形成關聯,外鍵只能引用外表中的列的值或使用空值。
創建外鍵
建表時指定外鍵約束
-- 創建外鍵的方式一 : 創建子表同時創建外鍵 -- 年級表 (id\年級名稱) CREATE TABLE `grade` ( `gradeid` INT(10) NOT NULL AUTO_INCREMENT COMMENT '年級ID', `gradename` VARCHAR(50) NOT NULL COMMENT '年級名稱', PRIMARY KEY (`gradeid`) ) ENGINE=INNODB DEFAULT CHARSET=utf8 -- 學生信息表 (學號,姓名,性別,年級,手機,地址,出生日期,郵箱,身份證號) CREATE TABLE `student` ( `studentno` INT(4) NOT NULL COMMENT '學號', `studentname` VARCHAR(20) NOT NULL DEFAULT '匿名' COMMENT '姓名', `sex` TINYINT(1) DEFAULT '1' COMMENT '性別', `gradeid` INT(10) DEFAULT NULL COMMENT '年級', `phoneNum` VARCHAR(50) NOT NULL COMMENT '手機', `address` VARCHAR(255) DEFAULT NULL COMMENT '地址', `borndate` DATETIME DEFAULT NULL COMMENT '生日', `email` VARCHAR(50) DEFAULT NULL COMMENT '郵箱', `idCard` VARCHAR(18) DEFAULT NULL COMMENT '身份證號', PRIMARY KEY (`studentno`), KEY `FK_gradeid` (`gradeid`), CONSTRAINT `FK_gradeid` FOREIGN KEY (`gradeid`) REFERENCES `grade` (`gradeid`) ) ENGINE=INNODB DEFAULT CHARSET=utf8
建表后修改
-- 創建外鍵方式二 : 創建子表完畢后,修改子表添加外鍵 ALTER TABLE `student` ADD CONSTRAINT `FK_gradeid` FOREIGN KEY (`gradeid`) REFERENCES `grade` (`gradeid`);
刪除外鍵
操作:刪除 grade 表,發現報錯
注意 : 刪除具有主外鍵關系的表時 , 要先刪子表 , 后刪主表
-- 刪除外鍵 ALTER TABLE student DROP FOREIGN KEY FK_gradeid; -- 發現執行完上面的,索引還在,所以還要刪除索引 -- 注:這個索引是建立外鍵的時候默認生成的 ALTER TABLE student DROP INDEX FK_gradeid;
DML語言
數據庫意義 : 數據存儲、數據管理
管理數據庫數據方法:
-
通過SQLyog等管理工具管理數據庫數據
-
通過DML語句管理數據庫數據
DML語言 :數據操作語言
-
用於操作數據庫對象中所包含的數據
-
包括 :
-
-
INSERT (添加數據語句)
-
UPDATE (更新數據語句)
-
DELETE (刪除數據語句)
-
添加數據
INSERT命令
語法:
INSERT INTO 表名[(字段1,字段2,字段3,...)] VALUES('值1','值2','值3')
注意 :
-
字段或值之間用英文逗號隔開 .
-
' 字段1,字段2...' 該部分可省略 , 但添加的值務必與表結構,數據列,順序相對應,且數量一致 .
-
可同時插入多條數據 , values 后用英文逗號隔開 .
-- 使用語句如何增加語句? -- 語法 : INSERT INTO 表名[(字段1,字段2,字段3,...)] VALUES('值1','值2','值3') INSERT INTO grade(gradename) VALUES ('大一'); -- 主鍵自增,那能否省略呢? INSERT INTO grade VALUES ('大二'); -- 查詢:INSERT INTO grade VALUE ('大二')錯誤代碼:1136 Column count doesn`t match value count at row 1 -- 結論:'字段1,字段2...'該部分可省略 , 但添加的值務必與表結構,數據列,順序相對應,且數量一致. -- 一次插入多條數據 INSERT INTO grade(gradename) VALUES ('大三'),('大四');
練習題目
自己使用INSERT語句為課程表subject添加數據 . 使用到外鍵.
修改數據
update命令
語法:
UPDATE 表名 SET column_name=value [,column_name2=value2,...] [WHEREcondition];
注意 :
-
column_name 為要更改的數據列
-
value 為修改后的數據 , 可以為變量 , 具體指 , 表達式或者嵌套的SELECT結果
-
condition 為篩選條件 , 如不指定則修改該表的所有列數據
where條件子句
可以簡單的理解為 : 有條件地從表中篩選數據
測試:
-- 修改年級信息 UPDATE grade SET gradename = '高中' WHERE gradeid = 1;
刪除數據
DELETE命令
語法:
DELETE FROM 表名 [WHERE condition];
注意:condition為篩選條件 , 如不指定則刪除該表的所有列數據
-- 刪除最后一個數據 DELETE FROM grade WHERE gradeid = 5
TRUNCATE命令
作用:用於完全清空表數據 , 但表結構 , 索引 , 約束等不變 ;
語法:
TRUNCATE [TABLE] table_name; -- 清空年級表 TRUNCATE grade
注意:區別於DELETE命令
-
相同 : 都能刪除數據 , 不刪除表結構 , 但TRUNCATE速度更快
-
不同 :
-
-
使用TRUNCATE TABLE 重新設置AUTO_INCREMENT計數器
-
使用TRUNCATE TABLE不會對事務有影響 (事務后面會說)
-
測試:
-- 創建一個測試表 CREATE TABLE `test` ( `id` INT(4) NOT NULL AUTO_INCREMENT, `coll` VARCHAR(20) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=INNODB DEFAULT CHARSET=utf8 -- 插入幾個測試數據 INSERT INTO test(coll) VALUES('row1'),('row2'),('row3'); -- 刪除表數據(不帶where條件的delete) DELETE FROM test; -- 結論:如不指定Where則刪除該表的所有列數據,自增當前值依然從原來基礎上進行,會記錄日志. -- 刪除表數據(truncate) TRUNCATE TABLE test; -- 結論:truncate刪除數據,自增當前值會恢復到初始值重新開始;不會記錄日志. -- 同樣使用DELETE清空不同引擎的數據庫表數據.重啟數據庫服務后 -- InnoDB : 自增列從初始值重新開始 (因為是存儲在內存中,斷電即失) -- MyISAM : 自增列依然從上一個自增數據基礎上開始 (存在文件中,不會丟失)
DQL語言
DQL( Data Query Language 數據查詢語言 )
-
查詢數據庫數據 , 如SELECT語句
-
簡單的單表查詢或多表的復雜查詢和嵌套查詢
-
是數據庫語言中最核心,最重要的語句
-
使用頻率最高的語句
SELECT語法
SELECT [ALL | DISTINCT] {* | table.* | [table.field1[as alias1][,table.field2[as alias2]][,...]]} FROM table_name [as table_alias] [left | right | inner join table_name2] -- 聯合查詢 [WHERE ...] -- 指定結果需滿足的條件 [GROUP BY ...] -- 指定結果按照哪幾個字段來分組 [HAVING] -- 過濾分組的記錄必須滿足的次要條件 [ORDER BY ...] -- 指定查詢記錄按一個或多個條件排序 [LIMIT {[offset,]row_count | row_countOFFSET offset}]; -- 指定查詢的記錄從哪條至哪條
注意 : [ ] 括號代表可選的 , { }括號代表必選得
指定查詢字段
-- 查詢表中所有的數據列結果 , 采用 **" \* "** 符號; 但是效率低,不推薦 . -- 查詢所有學生信息 SELECT * FROM student; -- 查詢指定列(學號 , 姓名) SELECT studentno,studentname FROM student;
AS 子句作為別名
作用:
-
可給數據列取一個新別名
-
可給表取一個新別名
-
可把經計算或總結的結果用另一個新名稱來代替
-- 這里是為列取別名(當然as關鍵詞可以省略) SELECT studentno AS 學號,studentname AS 姓名 FROM student; -- 使用as也可以為表取別名 SELECT studentno AS 學號,studentname AS 姓名 FROM student AS s; -- 使用as,為查詢結果取一個新名字 -- CONCAT()函數拼接字符串 SELECT CONCAT('姓名:',studentname) AS 新姓名 FROM student;
DISTINCT關鍵字的使用
作用 : 去掉SELECT查詢返回的記錄結果中重復的記錄 ( 返回所有列的值都相同 ) , 只返回一條
-- # 查看哪些同學參加了考試(學號) 去除重復項 SELECT * FROM result; -- 查看考試成績 SELECT studentno FROM result; -- 查看哪些同學參加了考試 SELECT DISTINCT studentno FROM result; -- 了解:DISTINCT 去除重復項 , (默認是ALL)
使用表達式的列
數據庫中的表達式 : 一般由文本值 , 列值 , NULL , 函數和操作符等組成
應用場景 :
-
SELECT語句返回結果列中使用
-
SELECT語句中的ORDER BY , HAVING等子句中使用
-
DML語句中的 where 條件語句中使用表達式
-- selcet查詢中可以使用表達式 SELECT @@auto_increment_increment; -- 查詢自增步長 SELECT VERSION(); -- 查詢版本號 SELECT 100*3-1 AS 計算結果; -- 表達式 -- 學員考試成績集體提分一分查看 SELECT studentno,StudentResult+1 AS '提分后' FROM result;
-
避免SQL返回結果中包含 ' . ' , ' * ' 和括號等干擾開發語言程序.
where條件語句
作用:用於檢索數據表中 符合條件 的記錄
搜索條件可由一個或多個邏輯表達式組成 , 結果一般為真或假.
邏輯操作符
測試
-- 滿足條件的查詢(where) SELECT Studentno,StudentResult FROM result; -- 查詢考試成績在95-100之間的 SELECT Studentno,StudentResult FROM result WHERE StudentResult>=95 AND StudentResult<=100; -- AND也可以寫成 && SELECT Studentno,StudentResult FROM result WHERE StudentResult>=95 && StudentResult<=100; -- 模糊查詢(對應的詞:精確查詢) SELECT Studentno,StudentResult FROM result WHERE StudentResult BETWEEN 95 AND 100; -- 除了1000號同學,要其他同學的成績 SELECT studentno,studentresult FROM result WHERE studentno!=1000; -- 使用NOT SELECT studentno,studentresult FROM result WHERE NOT studentno=1000;
模糊查詢 :比較操作符
注意:
-
數值數據類型的記錄之間才能進行算術運算 ;
-
相同數據類型的數據之間才能進行比較 ;
測試:
-- 模糊查詢 between and \ like \ in \ null -- ============================================= -- LIKE -- ============================================= -- 查詢姓劉的同學的學號及姓名 -- like結合使用的通配符 : % (代表0到任意個字符) _ (一個字符) SELECT studentno,studentname FROM student WHERE studentname LIKE '劉%'; -- 查詢姓劉的同學,后面只有一個字的 SELECT studentno,studentname FROM student WHERE studentname LIKE '劉_'; -- 查詢姓劉的同學,后面只有兩個字的 SELECT studentno,studentname FROM student WHERE studentname LIKE '劉__'; -- 查詢姓名中含有 嘉 字的 SELECT studentno,studentname FROM student WHERE studentname LIKE '%嘉%'; -- 查詢姓名中含有特殊字符的需要使用轉義符號 '\' -- 自定義轉義符關鍵字: ESCAPE ':' -- ============================================= -- IN -- ============================================= -- 查詢學號為1000,1001,1002的學生姓名 SELECT studentno,studentname FROM student WHERE studentno IN (1000,1001,1002); -- 查詢地址在北京,南京,河南洛陽的學生 SELECT studentno,studentname,address FROM student WHERE address IN ('北京','南京','河南洛陽'); -- ============================================= -- NULL 空 -- ============================================= -- 查詢出生日期沒有填寫的同學 -- 不能直接寫=NULL , 這是代表錯誤的 , 用 is null SELECT studentname FROM student WHERE BornDate IS NULL; -- 查詢出生日期填寫的同學 SELECT studentname FROM student WHERE BornDate IS NOT NULL; -- 查詢沒有寫家庭住址的同學(空字符串不等於null) SELECT studentname FROM student WHERE Address='' OR Address IS NULL;
連接查詢
JOIN 對比
七種Join:
測試
/* 連接查詢 如需要多張數據表的數據進行查詢,則可通過連接運算符實現多個查詢 內連接 inner join 查詢兩個表中的結果集中的交集 外連接 outer join 左外連接 left join (以左表作為基准,右邊表來一一匹配,匹配不上的,返回左表的記錄,右表以NULL填充) 右外連接 right join (以右表作為基准,左邊表來一一匹配,匹配不上的,返回右表的記錄,左表以NULL填充) 等值連接和非等值連接 自連接 */ -- 查詢參加了考試的同學信息(學號,學生姓名,科目編號,分數) SELECT * FROM student; SELECT * FROM result; /*思路: (1):分析需求,確定查詢的列來源於兩個類,student result,連接查詢 (2):確定使用哪種連接查詢?(內連接) */ SELECT s.studentno,studentname,subjectno,StudentResult FROM student s INNER JOIN result r ON r.studentno = s.studentno -- 右連接(也可實現) SELECT s.studentno,studentname,subjectno,StudentResult FROM student s RIGHT JOIN result r ON r.studentno = s.studentno -- 等值連接 SELECT s.studentno,studentname,subjectno,StudentResult FROM student s , result r WHERE r.studentno = s.studentno -- 左連接 (查詢了所有同學,不考試的也會查出來) SELECT s.studentno,studentname,subjectno,StudentResult FROM student s LEFT JOIN result r ON r.studentno = s.studentno -- 查一下缺考的同學(左連接應用場景) SELECT s.studentno,studentname,subjectno,StudentResult FROM student s LEFT JOIN result r ON r.studentno = s.studentno WHERE StudentResult IS NULL -- 思考題:查詢參加了考試的同學信息(學號,學生姓名,科目名,分數) SELECT s.studentno,studentname,subjectname,StudentResult FROM student s INNER JOIN result r ON r.studentno = s.studentno INNER JOIN `subject` sub ON sub.subjectno = r.subjectno
自連接
/* 自連接 數據表與自身進行連接 需求:從一個包含欄目ID , 欄目名稱和父欄目ID的表中 查詢父欄目名稱和其他子欄目名稱 */ -- 創建一個表 CREATE TABLE `category` ( `categoryid` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主題id', `pid` INT(10) NOT NULL COMMENT '父id', `categoryName` VARCHAR(50) NOT NULL COMMENT '主題名字', PRIMARY KEY (`categoryid`) ) ENGINE=INNODB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8 -- 插入數據 INSERT INTO `category` (`categoryid`, `pid`, `categoryName`) VALUES('2','1','信息技術'), ('3','1','軟件開發'), ('4','3','數據庫'), ('5','1','美術設計'), ('6','3','web開發'), ('7','5','ps技術'), ('8','2','辦公信息'); -- 編寫SQL語句,將欄目的父子關系呈現出來 (父欄目名稱,子欄目名稱) -- 核心思想:把一張表看成兩張一模一樣的表,然后將這兩張表連接查詢(自連接) SELECT a.categoryName AS '父欄目',b.categoryName AS '子欄目' FROM category AS a,category AS b WHERE a.`categoryid`=b.`pid` -- 思考題:查詢參加了考試的同學信息(學號,學生姓名,科目名,分數) SELECT s.studentno,studentname,subjectname,StudentResult FROM student s INNER JOIN result r ON r.studentno = s.studentno INNER JOIN `subject` sub ON sub.subjectno = r.subjectno -- 查詢學員及所屬的年級(學號,學生姓名,年級名) SELECT studentno AS 學號,studentname AS 學生姓名,gradename AS 年級名稱 FROM student s INNER JOIN grade g ON s.`GradeId` = g.`GradeID` -- 查詢科目及所屬的年級(科目名稱,年級名稱) SELECT subjectname AS 科目名稱,gradename AS 年級名稱 FROM SUBJECT sub INNER JOIN grade g ON sub.gradeid = g.gradeid -- 查詢 數據庫結構-1 的所有考試結果(學號 學生姓名 科目名稱 成績) SELECT s.studentno,studentname,subjectname,StudentResult FROM student s INNER JOIN result r ON r.studentno = s.studentno INNER JOIN `subject` sub ON r.subjectno = sub.subjectno WHERE subjectname='數據庫結構-1'
排序和分頁
測試
/*============== 排序 ================ 語法 : ORDER BY ORDER BY 語句用於根據指定的列對結果集進行排序。 ORDER BY 語句默認按照ASC升序對記錄進行排序。 如果您希望按照降序對記錄進行排序,可以使用 DESC 關鍵字。 */ -- 查詢 數據庫結構-1 的所有考試結果(學號 學生姓名 科目名稱 成績) -- 按成績降序排序 SELECT s.studentno,studentname,subjectname,StudentResult FROM student s INNER JOIN result r ON r.studentno = s.studentno INNER JOIN `subject` sub ON r.subjectno = sub.subjectno WHERE subjectname='數據庫結構-1' ORDER BY StudentResult DESC /*============== 分頁 ================ 語法 : SELECT * FROM table LIMIT [offset,] rows | rows OFFSET offset 好處 : (用戶體驗,網絡傳輸,查詢壓力) 推導: 第一頁 : limit 0,5 第二頁 : limit 5,5 第三頁 : limit 10,5 ...... 第N頁 : limit (pageNo-1)*pageSzie,pageSzie [pageNo:頁碼,pageSize:單頁面顯示條數] */ -- 每頁顯示5條數據 SELECT s.studentno,studentname,subjectname,StudentResult FROM student s INNER JOIN result r ON r.studentno = s.studentno INNER JOIN `subject` sub ON r.subjectno = sub.subjectno WHERE subjectname='數據庫結構-1' ORDER BY StudentResult DESC , studentno LIMIT 0,5 -- 查詢 JAVA第一學年 課程成績前10名並且分數大於80的學生信息(學號,姓名,課程名,分數) SELECT s.studentno,studentname,subjectname,StudentResult FROM student s INNER JOIN result r ON r.studentno = s.studentno INNER JOIN `subject` sub ON r.subjectno = sub.subjectno WHERE subjectname='JAVA第一學年' ORDER BY StudentResult DESC LIMIT 0,10
子查詢
/*============== 子查詢 ================ 什么是子查詢? 在查詢語句中的WHERE條件子句中,又嵌套了另一個查詢語句 嵌套查詢可由多個子查詢組成,求解的方式是由里及外; 子查詢返回的結果一般都是集合,故而建議使用IN關鍵字; */ -- 查詢 數據庫結構-1 的所有考試結果(學號,科目編號,成績),並且成績降序排列 -- 方法一:使用連接查詢 SELECT studentno,r.subjectno,StudentResult FROM result r INNER JOIN `subject` sub ON r.`SubjectNo`=sub.`SubjectNo` WHERE subjectname = '數據庫結構-1' ORDER BY studentresult DESC; -- 方法二:使用子查詢(執行順序:由里及外) SELECT studentno,subjectno,StudentResult FROM result WHERE subjectno=( SELECT subjectno FROM `subject` WHERE subjectname = '數據庫結構-1' ) ORDER BY studentresult DESC; -- 查詢課程為 高等數學-2 且分數不小於80分的學生的學號和姓名 -- 方法一:使用連接查詢 SELECT s.studentno,studentname FROM student s INNER JOIN result r ON s.`StudentNo` = r.`StudentNo` INNER JOIN `subject` sub ON sub.`SubjectNo` = r.`SubjectNo` WHERE subjectname = '高等數學-2' AND StudentResult>=80 -- 方法二:使用連接查詢+子查詢 -- 分數不小於80分的學生的學號和姓名 SELECT r.studentno,studentname FROM student s INNER JOIN result r ON s.`StudentNo`=r.`StudentNo` WHERE StudentResult>=80 -- 在上面SQL基礎上,添加需求:課程為 高等數學-2 SELECT r.studentno,studentname FROM student s INNER JOIN result r ON s.`StudentNo`=r.`StudentNo` WHERE StudentResult>=80 AND subjectno=( SELECT subjectno FROM `subject` WHERE subjectname = '高等數學-2' ) -- 方法三:使用子查詢 -- 分步寫簡單sql語句,然后將其嵌套起來 SELECT studentno,studentname FROM student WHERE studentno IN( SELECT studentno FROM result WHERE StudentResult>=80 AND subjectno=( SELECT subjectno FROM `subject` WHERE subjectname = '高等數學-2' ) ) /* 練習題目: 查 C語言-1 的前5名學生的成績信息(學號,姓名,分數) 使用子查詢,查詢郭靖同學所在的年級名稱 */
常用函數
數據函數
SELECT ABS(-8); /*絕對值*/ SELECT CEILING(9.4); /*向上取整*/ SELECT FLOOR(9.4); /*向下取整*/ SELECT RAND(); /*隨機數,返回一個0-1之間的隨機數*/ SELECT SIGN(0); /*符號函數: 負數返回-1,正數返回1,0返回0*/
字符串函數
SELECT CHAR_LENGTH('狂神說堅持就能成功'); /*返回字符串包含的字符數*/ SELECT CONCAT('我','愛','程序'); /*合並字符串,參數可以有多個*/ SELECT INSERT('我愛編程helloworld',1,2,'超級熱愛'); /*替換字符串,從某個位置開始替換某個長度*/ SELECT LOWER('KuangShen'); /*小寫*/ SELECT UPPER('KuangShen'); /*大寫*/ SELECT LEFT('hello,world',5); /*從左邊截取*/ SELECT RIGHT('hello,world',5); /*從右邊截取*/ SELECT REPLACE('狂神說堅持就能成功','堅持','努力'); /*替換字符串*/ SELECT SUBSTR('狂神說堅持就能成功',4,6); /*截取字符串,開始和長度*/ SELECT REVERSE('狂神說堅持就能成功'); /*反轉 -- 查詢姓周的同學,改成鄒 SELECT REPLACE(studentname,'周','鄒') AS 新名字 FROM student WHERE studentname LIKE '周%';
日期和時間函數
SELECT CURRENT_DATE(); /*獲取當前日期*/ SELECT CURDATE(); /*獲取當前日期*/ SELECT NOW(); /*獲取當前日期和時間*/ SELECT LOCALTIME(); /*獲取當前日期和時間*/ SELECT SYSDATE(); /*獲取當前日期和時間*/ -- 獲取年月日,時分秒 SELECT YEAR(NOW()); SELECT MONTH(NOW()); SELECT DAY(NOW()); SELECT HOUR(NOW()); SELECT MINUTE(NOW()); SELECT SECOND(NOW());
系統信息函數
SELECT VERSION(); /*版本*/ SELECT USER(); /*用戶*/
聚合函數
函數名稱 | 描述 |
---|---|
COUNT() | 返回滿足Select條件的記錄總和數,如 select count(*) 【不建議使用 *,效率低】 |
SUM() | 返回數字字段或表達式列作統計,返回一列的總和。 |
AVG() | 通常為數值字段或表達列作統計,返回一列的平均值 |
MAX() | 可以為數值字段,字符字段或表達式列作統計,返回最大的值。 |
MIN() | 可以為數值字段,字符字段或表達式列作統計,返回最小的值。 |
-- 聚合函數 /*COUNT:非空的*/ SELECT COUNT(studentname) FROM student; SELECT COUNT(*) FROM student; SELECT COUNT(1) FROM student; /*推薦*/ -- 從含義上講,count(1) 與 count(*) 都表示對全部數據行的查詢。 -- count(字段) 會統計該字段在表中出現的次數,忽略字段為null 的情況。即不統計字段為null 的記錄。 -- count(*) 包括了所有的列,相當於行數,在統計結果的時候,包含字段為null 的記錄; -- count(1) 用1代表代碼行,在統計結果的時候,包含字段為null 的記錄 。 /* 很多人認為count(1)執行的效率會比count(*)高,原因是count(*)會存在全表掃描,而count(1)可以針對一個字段進行查詢。其實不然,count(1)和count(*)都會對全表進行掃描,統計所有記錄的條數,包括那些為null的記錄,因此,它們的效率可以說是相差無幾。而count(字段)則與前兩者不同,它會統計該字段不為null的記錄條數。 下面它們之間的一些對比: 1)在表沒有主鍵時,count(1)比count(*)快 2)有主鍵時,主鍵作為計算條件,count(主鍵)效率最高; 3)若表格只有一個字段,則count(*)效率較高。 */ SELECT SUM(StudentResult) AS 總和 FROM result; SELECT AVG(StudentResult) AS 平均分 FROM result; SELECT MAX(StudentResult) AS 最高分 FROM result; SELECT MIN(StudentResult) AS 最低分 FROM result;
題目:
-- 查詢不同課程的平均分,最高分,最低分 -- 前提:根據不同的課程進行分組 SELECT subjectname,AVG(studentresult) AS 平均分,MAX(StudentResult) AS 最高分,MIN(StudentResult) AS 最低分 FROM result AS r INNER JOIN `subject` AS s ON r.subjectno = s.subjectno GROUP BY r.subjectno HAVING 平均分>80; /* where寫在group by前面. 要是放在分組后面的篩選 要使用HAVING.. 因為having是從前面篩選的字段再篩選,而where是從數據表中的>字段直接進行的篩選的 */
MD5 加密
一、MD5簡介
MD5即Message-Digest Algorithm 5(信息-摘要算法5),用於確保信息傳輸完整一致。是計算機廣泛使用的雜湊算法之一(又譯摘要算法、哈希算法),主流編程語言普遍已有MD5實現。將數據(如漢字)運算為另一固定長度值,是雜湊算法的基礎原理,MD5的前身有MD2、MD3和MD4。
二、實現數據加密
新建一個表 testmd5
CREATE TABLE `testmd5` ( `id` INT(4) NOT NULL, `name` VARCHAR(20) NOT NULL, `pwd` VARCHAR(50) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=INNODB DEFAULT CHARSET=utf8
插入一些數據
INSERT INTO testmd5 VALUES(1,'kuangshen','123456'),(2,'qinjiang','456789')
如果我們要對pwd這一列數據進行加密,語法是:
update testmd5 set pwd = md5(pwd);
如果單獨對某個用戶(如kuangshen)的密碼加密:
INSERT INTO testmd5 VALUES(3,'kuangshen2','123456') update testmd5 set pwd = md5(pwd) where name = 'kuangshen2';
插入新的數據自動加密
INSERT INTO testmd5 VALUES(4,'kuangshen3',md5('123456'));
查詢登錄用戶信息(md5對比使用,查看用戶輸入加密后的密碼進行比對)
SELECT * FROM testmd5 WHERE `name`='kuangshen' AND pwd=MD5('123456');
小結
-- ================ 內置函數 ================ -- 數值函數 abs(x) -- 絕對值 abs(-10.9) = 10 format(x, d) -- 格式化千分位數值 format(1234567.456, 2) = 1,234,567.46 ceil(x) -- 向上取整 ceil(10.1) = 11 floor(x) -- 向下取整 floor (10.1) = 10 round(x) -- 四舍五入去整 mod(m, n) -- m%n m mod n 求余 10%3=1 pi() -- 獲得圓周率 pow(m, n) -- m^n sqrt(x) -- 算術平方根 rand() -- 隨機數 truncate(x, d) -- 截取d位小數 -- 時間日期函數 now(), current_timestamp(); -- 當前日期時間 current_date(); -- 當前日期 current_time(); -- 當前時間 date('yyyy-mm-dd hh:ii:ss'); -- 獲取日期部分 time('yyyy-mm-dd hh:ii:ss'); -- 獲取時間部分 date_format('yyyy-mm-dd hh:ii:ss', '%d %y %a %d %m %b %j'); -- 格式化時間 unix_timestamp(); -- 獲得unix時間戳 from_unixtime(); -- 從時間戳獲得時間 -- 字符串函數 length(string) -- string長度,字節 char_length(string) -- string的字符個數 substring(str, position [,length]) -- 從str的position開始,取length個字符 replace(str ,search_str ,replace_str) -- 在str中用replace_str替換search_str instr(string ,substring) -- 返回substring首次在string中出現的位置 concat(string [,...]) -- 連接字串 charset(str) -- 返回字串字符集 lcase(string) -- 轉換成小寫 left(string, length) -- 從string2中的左邊起取length個字符 load_file(file_name) -- 從文件讀取內容 locate(substring, string [,start_position]) -- 同instr,但可指定開始位置 lpad(string, length, pad) -- 重復用pad加在string開頭,直到字串長度為length ltrim(string) -- 去除前端空格 repeat(string, count) -- 重復count次 rpad(string, length, pad) --在str后用pad補充,直到長度為length rtrim(string) -- 去除后端空格 strcmp(string1 ,string2) -- 逐字符比較兩字串大小 -- 聚合函數 count() sum(); max(); min(); avg(); group_concat() -- 其他常用函數 md5(); default();
事務
什么是事務
-
事務就是將一組SQL語句放在同一批次內去執行
-
如果一個SQL語句出錯,則該批次內的所有SQL都將被取消執行
-
MySQL事務處理只支持InnoDB和BDB數據表類型
事務的ACID原則 百度 ACID
原子性(Atomic)
-
整個事務中的所有操作,要么全部完成,要么全部不完成,不可能停滯在中間某個環節。事務在執行過程中發生錯誤,會被回滾(ROLLBACK)到事務開始前的狀態,就像這個事務從來沒有執行過一樣。
一致性(Consist)
-
一個事務可以封裝狀態改變(除非它是一個只讀的)。事務必須始終保持系統處於一致的狀態,不管在任何給定的時間並發事務有多少。也就是說:如果事務是並發多個,系統也必須如同串行事務一樣操作。其主要特征是保護性和不變性(Preserving an Invariant),以轉賬案例為例,假設有五個賬戶,每個賬戶余額是100元,那么五個賬戶總額是500元,如果在這個5個賬戶之間同時發生多個轉賬,無論並發多少個,比如在A與B賬戶之間轉賬5元,在C與D賬戶之間轉賬10元,在B與E之間轉賬15元,五個賬戶總額也應該還是500元,這就是保護性和不變性。
隔離性(Isolated)
-
隔離狀態執行事務,使它們好像是系統在給定時間內執行的唯一操作。如果有兩個事務,運行在相同的時間內,執行相同的功能,事務的隔離性將確保每一事務在系統中認為只有該事務在使用系統。這種屬性有時稱為串行化,為了防止事務操作間的混淆,必須串行化或序列化請求,使得在同一時間僅有一個請求用於同一數據。
持久性(Durable)
-
在事務完成以后,該事務對數據庫所作的更改便持久的保存在數據庫之中,並不會被回滾。
基本語法
-- 使用set語句來改變自動提交模式 SET autocommit = 0; /*關閉*/ SET autocommit = 1; /*開啟*/ -- 注意: --- 1.MySQL中默認是自動提交 --- 2.使用事務時應先關閉自動提交 -- 開始一個事務,標記事務的起始點 START TRANSACTION -- 提交一個事務給數據庫 COMMIT -- 將事務回滾,數據回到本次事務的初始狀態 ROLLBACK -- 還原MySQL數據庫的自動提交 SET autocommit =1; -- 保存點 SAVEPOINT 保存點名稱 -- 設置一個事務保存點 ROLLBACK TO SAVEPOINT 保存點名稱 -- 回滾到保存點 RELEASE SAVEPOINT 保存點名稱 -- 刪除保存點
測試
/* 課堂測試題目 A在線買一款價格為500元商品,網上銀行轉賬. A的銀行卡余額為2000,然后給商家B支付500. 商家B一開始的銀行卡余額為10000 創建數據庫shop和創建表account並插入2條數據 */ CREATE DATABASE `shop`CHARACTER SET utf8 COLLATE utf8_general_ci; USE `shop`; CREATE TABLE `account` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `name` VARCHAR(32) NOT NULL, `cash` DECIMAL(9,2) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=INNODB DEFAULT CHARSET=utf8 INSERT INTO account (`name`,`cash`) VALUES('A',2000.00),('B',10000.00) -- 轉賬實現 SET autocommit = 0; -- 關閉自動提交 START TRANSACTION; -- 開始一個事務,標記事務的起始點 UPDATE account SET cash=cash-500 WHERE `name`='A'; UPDATE account SET cash=cash+500 WHERE `name`='B'; COMMIT; -- 提交事務 # rollback; SET autocommit = 1; -- 恢復自動提交
索引
索引的作用
-
提高查詢速度
-
確保數據的唯一性
-
可以加速表和表之間的連接 , 實現表與表之間的參照完整性
-
使用分組和排序子句進行數據檢索時 , 可以顯著減少分組和排序的時間
-
全文檢索字段進行搜索優化.
分類
-
主鍵索引 (Primary Key)
-
唯一索引 (Unique)
-
常規索引 (Index)
-
全文索引 (FullText)
主鍵索引
主鍵 : 某一個屬性組能唯一標識一條記錄
特點 :
-
最常見的索引類型
-
確保數據記錄的唯一性
-
確定特定數據記錄在數據庫中的位置
唯一索引
作用 : 避免同一個表中某數據列中的值重復
與主鍵索引的區別
-
主鍵索引只能有一個
-
唯一索引可能有多個
CREATE TABLE `Grade`( `GradeID` INT(11) AUTO_INCREMENT PRIMARYKEY, `GradeName` VARCHAR(32) NOT NULL UNIQUE -- 或 UNIQUE KEY `GradeID` (`GradeID`) )
常規索引
作用 : 快速定位特定數據
注意 :
-
index 和 key 關鍵字都可以設置常規索引
-
應加在查詢找條件的字段
-
不宜添加太多常規索引,影響數據的插入,刪除和修改操作
CREATE TABLE `result`( -- 省略一些代碼 INDEX/KEY `ind` (`studentNo`,`subjectNo`) -- 創建表時添加 ) -- 創建后添加 ALTER TABLE `result` ADD INDEX `ind`(`studentNo`,`subjectNo`);
全文索引
百度搜索:全文索引
作用 : 快速定位特定數據
注意 :
-
只能用於MyISAM類型的數據表
-
只能用於CHAR , VARCHAR , TEXT數據列類型
-
適合大型數據集
/* #方法一:創建表時 CREATE TABLE 表名 ( 字段名1 數據類型 [完整性約束條件…], 字段名2 數據類型 [完整性約束條件…], [UNIQUE | FULLTEXT | SPATIAL ] INDEX | KEY [索引名] (字段名[(長度)] [ASC |DESC]) ); #方法二:CREATE在已存在的表上創建索引 CREATE [UNIQUE | FULLTEXT | SPATIAL ] INDEX 索引名 ON 表名 (字段名[(長度)] [ASC |DESC]) ; #方法三:ALTER TABLE在已存在的表上創建索引 ALTER TABLE 表名 ADD [UNIQUE | FULLTEXT | SPATIAL ] INDEX 索引名 (字段名[(長度)] [ASC |DESC]) ; #刪除索引:DROP INDEX 索引名 ON 表名字; #刪除主鍵索引: ALTER TABLE 表名 DROP PRIMARY KEY; #顯示索引信息: SHOW INDEX FROM student; */ /*增加全文索引*/ ALTER TABLE `school`.`student` ADD FULLTEXT INDEX `studentname` (`StudentName`); /*EXPLAIN : 分析SQL語句執行性能*/ EXPLAIN SELECT * FROM student WHERE studentno='1000'; /*使用全文索引*/ -- 全文搜索通過 MATCH() 函數完成。 -- 搜索字符串作為 against() 的參數被給定。搜索以忽略字母大小寫的方式執行。對於表中的每個記錄行,MATCH() 返回一個相關性值。即,在搜索字符串與記錄行在 MATCH() 列表中指定的列的文本之間的相似性尺度。 EXPLAIN SELECT *FROM student WHERE MATCH(studentname) AGAINST('love'); /* 開始之前,先說一下全文索引的版本、存儲引擎、數據類型的支持情況 MySQL 5.6 以前的版本,只有 MyISAM 存儲引擎支持全文索引; MySQL 5.6 及以后的版本,MyISAM 和 InnoDB 存儲引擎均支持全文索引; 只有字段的數據類型為 char、varchar、text 及其系列才可以建全文索引。 測試或使用全文索引時,要先看一下自己的 MySQL 版本、存儲引擎和數據類型是否支持全文索引。 */
拓展:測試索引
建表app_user:
CREATE TABLE `app_user` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(50) DEFAULT '' COMMENT '用戶昵稱', `email` varchar(50) NOT NULL COMMENT '用戶郵箱', `phone` varchar(20) DEFAULT '' COMMENT '手機號', `gender` tinyint(4) unsigned DEFAULT '0' COMMENT '性別(0:男;1:女)', `password` varchar(100) NOT NULL COMMENT '密碼', `age` tinyint(4) DEFAULT '0' COMMENT '年齡', `create_time` datetime DEFAULT CURRENT_TIMESTAMP, `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATECURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='app用戶表'
批量插入數據:100w
DROP FUNCTION IF EXISTS mock_data; DELIMITER $$ CREATE FUNCTION mock_data() RETURNS INT BEGIN DECLARE num INT DEFAULT 1000000; DECLARE i INT DEFAULT 0; WHILE i < num DO INSERT INTO app_user(`name`, `email`, `phone`, `gender`, `password`, `age`) VALUES(CONCAT('用戶', i), '24736743@qq.com', CONCAT('18', FLOOR(RAND()*(999999999-100000000)+100000000)),FLOOR(RAND()*2),UUID(), FLOOR(RAND()*100)); SET i = i + 1; END WHILE; RETURN i; END; SELECT mock_data();
索引效率測試
無索引
SELECT * FROM app_user WHERE name = '用戶9999'; -- 查看耗時 SELECT * FROM app_user WHERE name = '用戶9999'; SELECT * FROM app_user WHERE name = '用戶9999'; mysql> EXPLAIN SELECT * FROM app_user WHERE name = '用戶9999'\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: app_user partitions: NULL type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 992759 filtered: 10.00 Extra: Using where 1 row in set, 1 warning (0.00 sec)
創建索引
CREATE INDEX idx_app_user_name ON app_user(name);
測試普通索引
mysql> EXPLAIN SELECT * FROM app_user WHERE name = '用戶9999'\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: app_user partitions: NULL type: ref possible_keys: idx_app_user_name key: idx_app_user_name key_len: 203 ref: const rows: 1 filtered: 100.00 Extra: NULL 1 row in set, 1 warning (0.00 sec) mysql> SELECT * FROM app_user WHERE name = '用戶9999'; 1 row in set (0.00 sec) mysql> SELECT * FROM app_user WHERE name = '用戶9999'; 1 row in set (0.00 sec) mysql> SELECT * FROM app_user WHERE name = '用戶9999'; 1 row in set (0.00 sec)
索引准則
-
索引不是越多越好
-
不要對經常變動的數據加索引
-
小數據量的表建議不要加索引
-
索引一般應加在查找條件的字段
索引的數據結構
-- 我們可以在創建上述索引的時候,為其指定索引類型,分兩類 hash類型的索引:查詢單條快,范圍查詢慢 btree類型的索引:b+樹,層數越多,數據量指數級增長(我們就用它,因為innodb默認支持它) -- 不同的存儲引擎支持的索引類型也不一樣 InnoDB 支持事務,支持行級別鎖定,支持 B-tree、Full-text 等索引,不支持 Hash 索引; MyISAM 不支持事務,支持表級別鎖定,支持 B-tree、Full-text 等索引,不支持 Hash 索引; Memory 不支持事務,支持表級別鎖定,支持 B-tree、Hash 等索引,不支持 Full-text 索引; NDB 支持事務,支持行級別鎖定,支持 Hash 索引,不支持 B-tree、Full-text 等索引; Archive 不支持事務,支持表級別鎖定,不支持 B-tree、Hash、Full-text 等索引;
用戶管理
使用SQLyog 創建用戶,並授予權限演示
基本命令
/* 用戶和權限管理 */ ------------------ 用戶信息表:mysql.user -- 刷新權限 FLUSH PRIVILEGES -- 增加用戶 CREATE USER kuangshen IDENTIFIED BY '123456' CREATE USER 用戶名 IDENTIFIED BY [PASSWORD] 密碼(字符串) - 必須擁有mysql數據庫的全局CREATE USER權限,或擁有INSERT權限。 - 只能創建用戶,不能賦予權限。 - 用戶名,注意引號:如 'user_name'@'192.168.1.1' - 密碼也需引號,純數字密碼也要加引號 - 要在純文本中指定密碼,需忽略PASSWORD關鍵詞。要把密碼指定為由PASSWORD()函數返回的混編值,需包含關鍵字PASSWORD -- 重命名用戶 RENAME USER kuangshen TO kuangshen2 RENAME USER old_user TO new_user -- 設置密碼 SET PASSWORD = PASSWORD('密碼') -- 為當前用戶設置密碼 SET PASSWORD FOR 用戶名 = PASSWORD('密碼') -- 為指定用戶設置密碼 -- 刪除用戶 DROP USER kuangshen2 DROP USER 用戶名 -- 分配權限/添加用戶 GRANT 權限列表 ON 表名 TO 用戶名 [IDENTIFIED BY [PASSWORD] 'password'] - all privileges 表示所有權限 - *.* 表示所有庫的所有表 - 庫名.表名 表示某庫下面的某表 -- 查看權限 SHOW GRANTS FOR root@localhost; SHOW GRANTS FOR 用戶名 -- 查看當前用戶權限 SHOW GRANTS; 或 SHOW GRANTS FOR CURRENT_USER; 或 SHOW GRANTS FOR CURRENT_USER(); -- 撤消權限 REVOKE 權限列表 ON 表名 FROM 用戶名 REVOKE ALL PRIVILEGES, GRANT OPTION FROM 用戶名 -- 撤銷所有權限
權限解釋
-- 權限列表 ALL [PRIVILEGES] -- 設置除GRANT OPTION之外的所有簡單權限 ALTER -- 允許使用ALTER TABLE ALTER ROUTINE -- 更改或取消已存儲的子程序 CREATE -- 允許使用CREATE TABLE CREATE ROUTINE -- 創建已存儲的子程序 CREATE TEMPORARY TABLES -- 允許使用CREATE TEMPORARY TABLE CREATE USER -- 允許使用CREATE USER, DROP USER, RENAME USER和REVOKE ALL PRIVILEGES。 CREATE VIEW -- 允許使用CREATE VIEW DELETE -- 允許使用DELETE DROP -- 允許使用DROP TABLE EXECUTE -- 允許用戶運行已存儲的子程序 FILE -- 允許使用SELECT...INTO OUTFILE和LOAD DATA INFILE INDEX -- 允許使用CREATE INDEX和DROP INDEX INSERT -- 允許使用INSERT LOCK TABLES -- 允許對您擁有SELECT權限的表使用LOCK TABLES PROCESS -- 允許使用SHOW FULL PROCESSLIST REFERENCES -- 未被實施 RELOAD -- 允許使用FLUSH REPLICATION CLIENT -- 允許用戶詢問從屬服務器或主服務器的地址 REPLICATION SLAVE -- 用於復制型從屬服務器(從主服務器中讀取二進制日志事件) SELECT -- 允許使用SELECT SHOW DATABASES -- 顯示所有數據庫 SHOW VIEW -- 允許使用SHOW CREATE VIEW SHUTDOWN -- 允許使用mysqladmin shutdown SUPER -- 允許使用CHANGE MASTER, KILL, PURGE MASTER LOGS和SET GLOBAL語句,mysqladmin debug命令;允許您連接(一次),即使已達到max_connections。 UPDATE -- 允許使用UPDATE USAGE -- “無權限”的同義詞 GRANT OPTION -- 允許授予權限 /* 表維護 */ -- 分析和存儲表的關鍵字分布 ANALYZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE 表名 ... -- 檢查一個或多個表是否有錯誤 CHECK TABLE tbl_name [, tbl_name] ... [option] ... option = {QUICK | FAST | MEDIUM | EXTENDED | CHANGED} -- 整理數據文件的碎片 OPTIMIZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ...
MySQL備份
數據庫備份必要性
-
保證重要數據不丟失
-
數據轉移
MySQL數據庫備份方法
-
mysqldump備份工具
-
數據庫管理工具,如SQLyog
-
直接拷貝數據庫文件和相關配置文件
mysqldump客戶端
作用 :
-
轉儲數據庫
-
搜集數據庫進行備份
-
將數據轉移到另一個SQL服務器,不一定是MySQL服務器
-- 導出 1. 導出一張表 -- mysqldump -uroot -p123456 school student >D:/a.sql mysqldump -u用戶名 -p密碼 庫名 表名 > 文件名(D:/a.sql) 2. 導出多張表 -- mysqldump -uroot -p123456 school student result >D:/a.sql mysqldump -u用戶名 -p密碼 庫名 表1 表2 表3 > 文件名(D:/a.sql) 3. 導出所有表 -- mysqldump -uroot -p123456 school >D:/a.sql mysqldump -u用戶名 -p密碼 庫名 > 文件名(D:/a.sql) 4. 導出一個庫 -- mysqldump -uroot -p123456 -B school >D:/a.sql mysqldump -u用戶名 -p密碼 -B 庫名 > 文件名(D:/a.sql) 可以-w攜帶備份條件 -- 導入 1. 在登錄mysql的情況下:-- source D:/a.sql source 備份文件 2. 在不登錄的情況下 mysql -u用戶名 -p密碼 庫名 < 備份文件
規范化數據庫設計
為什么需要數據庫設計
當數據庫比較復雜時我們需要設計數據庫
糟糕的數據庫設計 :
-
數據冗余,存儲空間浪費
-
數據更新和插入的異常
-
程序性能差
良好的數據庫設計 :
-
節省數據的存儲空間
-
能夠保證數據的完整性
-
方便進行數據庫應用系統的開發
軟件項目開發周期中數據庫設計 :
-
需求分析階段: 分析客戶的業務和數據處理需求
-
概要設計階段:設計數據庫的E-R模型圖 , 確認需求信息的正確和完整.
設計數據庫步驟
-
收集信息
-
-
與該系統有關人員進行交流 , 座談 , 充分了解用戶需求 , 理解數據庫需要完成的任務.
-
-
標識實體[Entity]
-
-
-
標識數據庫要管理的關鍵對象或實體,實體一般是名詞
-
-
標識每個實體需要存儲的詳細信息[Attribute]
-
標識實體之間的關系[Relationship]
三大范式
問題 : 為什么需要數據規范化?
不合規范的表設計會導致的問題:
-
信息重復
-
更新異常
-
插入異常
-
-
無法正確表示信息
-
-
刪除異常
-
-
丟失有效信息
-
三大范式
第一范式 (1st NF)
第一范式的目標是確保每列的原子性,如果每列都是不可再分的最小數據單元,則滿足第一范式
第二范式(2nd NF)
第二范式(2NF)是在第一范式(1NF)的基礎上建立起來的,即滿足第二范式(2NF)必須先滿足第一范式(1NF)。
第二范式要求每個表只描述一件事情
第三范式(3rd NF)
如果一個關系滿足第二范式,並且除了主鍵以外的其他列都不傳遞依賴於主鍵列,則滿足第三范式.
第三范式需要確保數據表中的每一列數據都和主鍵直接相關,而不能間接相關。
規范化和性能的關系
為滿足某種商業目標 , 數據庫性能比規范化數據庫更重要
在數據規范化的同時 , 要綜合考慮數據庫的性能
通過在給定的表中添加額外的字段,以大量減少需要從中搜索信息所需的時間