前言
-
最近系統地學習了一邊MySQL數據庫的基礎知識,鞏固了一下以前學習的數據庫查詢基礎,又新學習了關於索引、事務等的新內容,做了一些學習筆記。因為MySQL的學習,實操性比較強,所以筆記內容也比較簡單,主要是關於常用語句的操作的整理和練習。
-
本文包括一些學習資源和教程,可以根據個人情況來按照教程學習,學習過程中也可以參考本筆記,如有錯誤,歡迎指正。
學習資源
-
視頻資料:韓順平講MySQL
-
MySQL安裝(Windows):MySQL安裝+初始化操作
-
MySQL本地服務配置(Windows):制作MySQL的Windows服務+創建用戶及授權
數據庫
備份數據庫
mysqldump -u root -p -B 數據庫名 > d:\\文件名.sql
恢復數據庫
SOURCE d:\\bak.sql
備份數據庫表
mysqldump -u root -p 數據庫名 表1 表2 > d:\\文件名.sql
數據表
創建
#創建
CREATE TABLE `user`(
id INT,
`name` VARCHAR(255),
`password` VARCHAR(255),
`birthday` DATE)
CHARACTER SET utf8 COLLATE utf8_bin ENGINE INNODB;
刪除
drop table `actor`;
修改
--在password后面添加salary列
ALTER TABLE `user`
ADD salary VARCHAR(32) NOT NULL DEFAULT ''
AFTER PASSWORD;
--修改列birthday字段的結構
ALTER TABLE `user`
MODIFY birthday VARCHAR(60) NOT NULL DEFAULT '';
--刪除name字段
ALTER TABLE `user`
DROP NAME;
--重命名表
RENAME TABLE `user` TO `student`;
--修改表的字符集為utf8
ALTER TABLE student CHARACTER SET utf8;
--修改列名salary為user_name
ALTER TABLE student
CHANGE salary user_name VARCHAR(32) NOT NULL DEFAULT '';
DESC `user`;--顯示表結構,查看所有的列
CRUD(增刪改查)
insert
INSERT INTO `goods`(id,good_name,price)
VALUES (1,'華為手機',2000);
INSERT INTO `goods`(id,good_name,price)
VALUES (2,'蘋果手機',3000);
update
UPDATE `goods`SET price = 1000;
UPDATE `goods`SET price = 2000 WHERE good_name='華為手機';
UPDATE `goods`SET price=price+5000 WHERE good_name='蘋果手機';
#如果需要修改多個字段,可以通過 set 字段1=值1,字段2=值2...
delete
DELETE FROM `goods` WHERE price=2000;
select
#查找表內所有內容
SELECT * FROM student;
#按列查找表內容
SELECT id FROM student;
SELECT `id`,english FROM student;
#去除重復數據(只有這一行每一列的數據相同的時候才會去重)
SELECT DISTINCT english FROM student;
#使用表達式對查詢的列進行運算
#在select語句中可使用as語句
SELECT `name`AS`名字`,(chinese+english+math) AS `COUNT` FROM student;
#條件查詢
SELECT * FROM student
WHERE `name` = '趙雲';
SELECT * FROM student
WHERE `english` > 90;
SELECT * FROM student
WHERE (chinese + english + math) > 200;
#order by
#升序
SELECT `name`,(chinese + english + math)AS`count` FROM student
WHERE (chinese+english+math)>200
ORDER BY math ASC;
#降序
SELECT `name`,(chinese + english + math)AS`count` FROM student
WHERE (chinese+english+math)>200
ORDER BY math DESC;
#多條件升降序查詢
SELECT `name`,(chinese+english+math)AS`count` FROM student
WHERE `name` LIKE '張%'
ORDER BY `count` DESC;
where語句中常用到的運算符
MySQL函數
合計/統計函數
#count(返回查詢結果的行數)
#統計滿足條件的某列有多少個,但是會排除為null的情況
SELECT COUNT(*) FROM student;
SELECT COUNT(*) FROM student
WHERE (math+chinese+english)>200;
SELECT COUNT(chinese) FROM student
WHERE chinese>90;
#SUM函數
#僅對數值起作用,否則會報錯
SELECT SUM(math) FROM student;
SELECT SUM(math),SUM(chinese),SUM(english) FROM student;
SELECT SUM(chinese+english+math) FROM student;
SELECT SUM(chinese)/COUNT(*) FROM student;
#AVG函數
SELECT AVG(math) FROM student;
SELECT AVG(math+english+chinese) FROM student;
#MAX函數
SELECT MAX(math) FROM student;
#MIN函數
SELECT MIN(math) FROM student;
分組統計
--按照部門查詢工資平均值和最大值
SELECT AVG(sal),MAX(sal),deptno FROM emp GROUP BY deptno;
--多條件分組
SELECT AVG(sal),MAX(sal),deptno , job FROM emp GROUP BY deptno , job;
--查找平均工資低於2000的部門
SELECT AVG(sal) , deptno FROM emp GROUP BY deptno HAVING AVG(sal) < 2000;
字符串函數
加密和系統函數
--演示加密函數和系統函數
查詢增強
WHERE
-- 查詢增強
-- 使用where子句
-- 在MySQL中,日期類型可以直接比較
SELECT * FROM emp WHERE hiredate <= '1991-12-11'; -- 需要注意格式
-- 模糊查詢like
-- %表示0~多個任意字符
-- _表示單個任意字符
SELECT ename,sal FROM emp WHERE ename LIKE 'S%' ;
SELECT ename,sal FROM emp WHERE ename LIKE '__o%';
-- 顯示沒有上級的員工信息
SELECT * FROM emp WHERE mgr IS NULL;
-- 查詢表結構
DESC emp;
ORDER BY
-- 使用ORDER BY
-- 按照工資從低到高顯示信息
SELECT * FROM emp ORDER BY sal; -- 默認降序
SELECT * FROM emp ORDER BY deptno ASC; -- 升序
SELECT * FROM emp ORDER BY deptno ASC , sal DESC;
分頁查詢
-- 分頁查詢
SELECT * FROM emp ORDER BY empno LIMIT 0,3;-- 第一頁
SELECT * FROM emp ORDER BY empno LIMIT 3,3;-- 第二頁
分組增強
-- 增強 GROUP BY 的使用
SELECT COUNT(*) FROM emp GROUP BY job;-- 各個崗位的人數
SELECT COUNT(*),COUNT(comm) FROM emp;-- 雇員總數、獲得補助的雇員數
多子句查詢
--統計各部門平均工資,並且大於1000的按照平均工資降序排序,取出前兩行數據
SELECT deptno,AVG(sal) AS avg_sal
FROM emp
GROUP BY deptno
HAVING avg_sal > 1000
ORDER BY avg_sal DESC
LIMIT 0,2;
多表查詢
多表笛卡爾集
-- 多表查詢
SELECT * FROM emp,dept;
SELECT * FROM emp;
SELECT * FROM dept;
-- 顯示雇員名稱和雇員所在部門的名稱
-- 從第一張表取出一行,與第二張表中的每一行進行組合,返回結果包含兩張表的所有列
SELECT ename,sal,dname,emp.deptno FROM emp,dept WHERE emp.deptno = dept.deptno;
-- 顯示部門10的部門名、員工名、工資
SELECT ename,sal,dname,emp.deptno FROM emp,dept WHERE emp.deptno = dept.deptno AND emp.deptno = 10;
-- 顯示各個員工的姓名、工資和工資級別
SELECT ename,sal,grade FROM emp,salgrade WHERE sal BETWEEN losal AND hisal;
自連接
自連接是指在同一張表的連接查詢,即將同一張表看成兩張表
-- 自連接
SELECT worker.ename AS '職員名',boss.ename AS '上級名'
FROM emp worker,emp boss
WHERE worker.mgr = boss.empno;
子查詢
單/多行子查詢
子查詢是指嵌入在其他SQL語句中的select語句,也叫嵌套查詢
-
單行子查詢
單行子查詢是指只返回同一行數據的子查詢語句
例:如何顯示與SMITH同一部門的所有員工
-
多行子查詢
多行子查詢指返回多行數據的子查詢,使用關鍵字in
-- 子查詢
-- 單行子查詢
SELECT deptno FROM emp WHERE ename = 'SMITH'; -- 子查詢語句
SELECT * FROM emp
WHERE deptno = (
SELECT deptno FROM emp WHERE ename = 'SMITH'
);
-- 多行子查詢
SELECT DISTINCT job FROM emp WHERE deptno = 10; -- 子查詢語句
SELECT ename,job,sal,deptno FROM emp
WHERE job IN (
SELECT DISTINCT job FROM emp WHERE deptno = 10
) AND deptno != 10;
子查詢臨時表
可以將子查詢結果當做一張臨時表使用
all any
-- all 和 any
-- 顯示工資比部門30所有員工的工資都高的員工的姓名、工資和部門號
SELECT ename,sal,deptno FROM emp
WHERE sal > ALL(
SELECT sal FROM emp WHERE deptno = 30
);
SELECT ename,sal,deptno FROM emp
WHERE sal > (
SELECT MAX(sal) FROM emp WHERE deptno = 30
);
-- 顯示工資比30號部門的其中一個員工工資高的員工的姓名、工資和部門號
SELECT ename,sal,deptno FROM emp
WHERE sal > ANY(
SELECT sal FROM emp WHERE deptno = 30
);
SELECT ename,sal,deptno FROM emp
WHERE sal > (
SELECT MIN(sal) FROM emp WHERE deptno = 30
);ss
多列子查詢
多列子查詢是指查詢返回多個列數據的子查詢語句
-- 多列子查詢
-- 查詢與 SMITH 的部門和和崗位完全相同的所有雇員(不包含SMITH本人)
SELECT deptno,job FROM emp
WHERE ename = 'SMITH'; -- 子查詢語句
-- 把上面的子查詢語句與下面的多列子查詢語句進行匹配
SELECT ename FROM emp
WHERE (deptno,job) = (
SELECT deptno,job FROM emp
WHERE ename = 'SMITH'
) AND ename != 'SMITH';
表復制和去重
-
自我復制數據(蠕蟲復制)
為了對某個SQL語句進行效率測試,我們需要海量數據時,可以使用此方法為表創建海量數據
-- 表復制
CREATE TABLE my_tab01
(
id INT,
`name` VARCHAR(32),
sal DOUBLE,
job VARCHAR(32),
deptno INT
);
DESC my_tab01;
-- 演示如何自我復制
-- 先把emp表的記錄復制進 my_tab01
INSERT INTO my_tab01
(id,`name`,sal,job,deptno)
SELECT empno,ename,sal,job,deptno FROM emp; -- 相當於數據遷移
-- 自我復制
INSERT INTO my_tab01
SELECT * FROM my_tab01;
-- 去重
DELETE FROM my_tab01;
合並查詢
-- 合並查詢
SELECT ename,sal,job FROM emp WHERE sal > 2500;
SELECT ename,sal,job FROM emp WHERE job = 'MANAGER';
-- UNION不會去重
SELECT ename,sal,job FROM emp WHERE sal > 2500
UNION ALL
SELECT ename,sal,job FROM emp WHERE job = 'MANAGER';
外連接
-- 左外連接
-- 右外連接
主鍵
MySQL約束
約束用於確保數據庫滿足特定的商業規則,在MySQL中,約束包括:
NOT NULL, UNIQUE, PRIMARY KEY, FOREIGN KEY, CHECK
主鍵的指定
-- 主鍵的使用
CREATE TABLE t17 (
id INT PRIMARY KEY,
`name` VARCHAR(32),
email VARCHAR(32)
);
INSERT INTO t17
VALUE(1,'jack','shuaiwang2019@126.com');
INSERT INTO t17
VALUE(2,'wangshuai','jack2019@126.com');
INSERT INTO t17
VALUE(3,'jack','shuaiwang2019@126.com');
-- 主鍵使用的細節
-- PRIMARY KEY 不能重復,而且不能為 NULL
-- 一張表中只能有一個主鍵,但可以是復合主鍵
CREATE TABLE t18 (
id INT,
`name` VARCHAR(32),
email VARCHAR(32),
PRIMARY KEY (id,`name`) -- 復合主鍵
);
-- 主鍵指定方式有兩種:
-- 在字段名后指定
-- 在SQL語句后面指定
DESC t18;
UNIQUE
-- unique的使用
CREATE TABLE t21 (
id INT UNIQUE, -- 表示id列是唯一的
`name` VARCHAR(32),
email VARCHAR(32)
);
-- unique的使用細節
-- 如果沒有指定not null,則unique字段可以有多個null
-- 一張表可以有多個unique字段
FOREIGN KEY(外鍵)
用於定義主表和從表之間的關系:外鍵約束要定義在從表上,主表則必須有主鍵約束或是unique約束,當定義外鍵約束之后,要求外鍵列數據必須在主表的主鍵列存在或是為null
-- 外鍵的使用
-- 創建班級表
CREATE TABLE class(
id INT PRIMARY KEY,
`name` VARCHAR(32) NOT NULL DEFAULT ''
)
-- 創建學生表
CREATE TABLE stu(
id INT PRIMARY KEY,
`name` VARCHAR(32) NOT NULL DEFAULT '',
class_id INT,
-- 下面指定外鍵關系
FOREIGN KEY (class_id) REFERENCES class (id)
);
DESC stu;
-- 測試數據
INSERT INTO class
VALUES (100,'java'),(200,'web');
INSERT INTO stu
VALUES (1,'張三',100),(2,'張三',200);
-- 外鍵細節
-- 外鍵指向的表的字段,要求是primary key或者是unique
-- 表的類型是innodb,這樣的表才支持外鍵
-- 外鍵字段類型主要和主鍵字段類型一致(長度可以不同)
-- 外鍵字段的值,必須在之間字段中出現過,或者為null(前提是外鍵字段允許null)
-- 一旦建立主外鍵的關系,數據就不能隨意刪除了
CHECK
用於強制型數據必須滿足的條件,假如在sal列上定義了check約束,並要求sal列值在100~200之間,不在的話就會報錯
-- CHECK的使用
CREATE TABLE t23 (
id INT PRIMARY KEY,
`name` VARCHAR(32),
sex VARCHAR(6) CHECK(sex IN ('man','woman')),
sal DOUBLE CHECK(sal>1000 AND sal<2000)
);
INSERT INTO t23 VALUES
(1,'jack','man',1500);
練習
-- 商店表設計
CREATE TABLE goods(
goods_id INT PRIMARY KEY,
goods_name VARCHAR(32) NOT NULL DEFAULT '',
unitprice DOUBLE CHECK(unitprice>1.0 AND unitprice<9999.99)
);
CREATE TABLE customer(
customer_id INT PRIMARY KEY,
`name` VARCHAR(32) NOT NULL DEFAULT '',
address VARCHAR(32),
email VARCHAR(32) UNIQUE,
sex VARCHAR(6) CHECK(sex IN ('man','woman')),
card_id INT
);
CREATE TABLE purchase(
order_id INT PRIMARY KEY,
customer_id INT NOT NULL,
goods_id INT NOT NULL,
nums INT NOT NULL DEFAULT 0,
FOREIGN KEY (customer_id) REFERENCES customer (customer_id),
FOREIGN KEY (goods_id) REFERENCES goods(goods_id)
);
自增
-- 自增使用
CREATE TABLE t24(
id INT PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(32) NOT NULL DEFAULT''
);
INSERT INTO t24 VALUES (NULL,'jack');
MySQL索引
索引優化速度
說起提高數據庫性能,索引最為物美價廉,不需要加內存,不需要改程序,不需要調SQL,查詢速度就可能提高百倍千倍
索引機制
索引原理
- 當表中沒有索引的時候,SQL語句查詢過程是按照 WHERE 條件進行全表掃描,與每一條數據進行對比,效率非常低下;
- 在某一個字段的列創建索引之后,會創建二叉樹,提高查找數據的效率;
- 生成的索引會占用磁盤;
- 對表進行dml操作(修改,刪除,添加),會對索引進行維護,對速度有影響。
創建索引
主鍵索引
主鍵就是一種索引 PRIMARY KEY,即主鍵索引。
唯一索引
UNIQUE 的字段的索引被稱為唯一索引。
普通索引
全文索引
適用於 MyISAM 存儲引擎,開發中考慮使用:全文索引 Solr 和 ElasticSearch(ES)
-- 索引的使用
-- 主鍵索引
CREATE TABLE t25(
id INT,
`name` VARCHAR(32)
);
-- 查詢表是否有索引
SHOW INDEXES FROM t25;
-- 添加索引
-- 添加唯一索引
CREATE UNIQUE INDEX id_index ON t25 (id);
-- 添加普通索引
CREATE INDEX id_index ON t25 (id);
ALTER TABLE t25 ADD INDEX id_index (id);
-- 添加主鍵索引
ALTER TABLE t25 ADD PRIMARY KEY id_index (id);
-- 刪除索引
DROP INDEX id_index ON t25;
-- 刪除主鍵索引
ALTER TABLE t25 DROP PRIMARY KEY;
-- 修改索引(先刪除,再添加新的索引)
-- 查詢索引
SHOW INDEX FROM t25;
SHOW INDEXES FROM t25;
SHOW KEYS FROM t25;
#不推薦
DESC t25;
創建索引規則
在哪些列上適合使用索引?
- 較頻繁的作為查詢條件字段應該創建索引;
- 唯一性太差的字段不適合單獨創建索引,即使頻繁作為查詢條件;
- 更新非常頻繁的字段不適合創建索引;
- 不會出現在WHERE子句中的字段不該創建索引。
事務
事務概念
事務用於保證數據的一致性,它由一組相關的dml語句組成,該組的dml語句要么全部成功,要么全部失敗。如:轉賬就要用事務來處理,用以保證數據的一致性。
事務和鎖
當執行事務操作時(dml語句),MySQL會在表上加鎖,防止其他用戶修改表的數據,這對用戶來講是非常重要的。
MySQL數據庫控制台事務的幾個重要操作
-- 創建測試表
CREATE TABLE t27(
id INT,
`name` VARCHAR(32)
);
-- 開啟事務
START TRANSACTION;
-- 設置保存點
SAVEPOINT a;
-- 執行dml操作
INSERT INTO t27 VALUES (100,'jack');
SELECT * FROM t27;
-- 設置保存點
SAVEPOINT b;
INSERT INTO t27 VALUES(200,'ben');
-- 數據回滾
ROLLBACK TO b;
ROLLBACK TO a;
-- 回退全部事務
ROLLBACK;
-- 提交事務,所有的操作生效,不能回退
COMMIT
事務注意事項
-- 事務注意事項
-- 如果不開啟事務,默認情況下,dml操作是自動提交的,不能回滾;
-- 如果開啟一個事務,沒有創建保存點,可以執行rollback,默認就是回退到事務開始的狀態;
-- 可以在事務沒有提交的時候,創建多個保存點;
-- 可以在事務沒有提交之前,選擇回退到哪個保存點;
-- MySQL的事務機制需要innodb的存儲引擎才能使用;
-- 開始一個事務
START TRANSACTION ,
SET autocommit = off;
隔離級別
4種隔離級別
- 多個連接開啟各自事務操作數據庫中數據時,數據庫系統要負責隔離操作,以保證各個連接在獲取數據時的准確性
- 如果不考慮隔離性,可能會引發如下問題
- 臟讀
- 不可重復讀
- 幻讀
-- 臟讀:當一個事務讀取另一個事務尚未提交的修改時,會產生臟讀
-- 不可重復讀:同一查詢在同一事務中多次進行,由於其他提交事務所做的修改或刪除,每次返回不同的結果集,此時發生不可重復讀
-- 幻讀:同一查詢在同一事務中多次進行,由於其他提交事務所做的插入操作,每次返回不同的結果集,此時發生幻讀
-- 演示MySQL的事務隔離級別
-- 開啟兩個MySQL控制台
-- 查看當前MySQL的隔離級別
SELECT @@tx_isolation;
SELECT @@transaction_isolation;
-- mysql> select @@transaction_isolation;
-- +-------------------------+
-- | @@transaction_isolation |
-- +-------------------------+
-- | REPEATABLE-READ |
-- +-------------------------+
-- 1 row in set (0.00 sec)
-- 把其中一個控制台的隔離級別設置 Read uncommitted
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
-- 創建表
CREATE TABLE ACCOUNT(
id INT,
`name` VARCHAR(32),
money INT
);
-- 把其中一個控制台的隔離級別設置 Read committed
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- mysql> SELECT @@transaction_isolation;
-- +-------------------------+
-- | @@transaction_isolation |
-- +-------------------------+
-- | READ-COMMITTED |
-- +-------------------------+
-- 1 row in set (0.00 sec)
-- 把其中一個控制台的隔離級別設置 Repeatable read
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-- 把其中一個控制台的隔離級別設置 Serializable
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
設置隔離
-- 設置隔離
-- 查看當前會話隔離級別
SELECT @@transaction_isolation;
-- 查看系統當前隔離級別
SELECT @@global.transaction_isolation;
-- 設置當前會話隔離級別
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
-- 設置系統當前隔離級別
SET GLOBAL TRANSACTION ISOLATION LEVEL [級別];
-- MySQL的默認級別
REPEATABLE READ;
-- 事務的acid特性
-- 原子性:原子性是指事務是一個不可分割的工作單位,事務中的操作要么都發生,要么都不發生
-- 一致性:事務必須使數據庫從一個一致性狀態變換到另外一個一致性狀態
-- 隔離性:事務的隔離性是多個用戶並發訪問數據庫時,數據庫為每一個用戶開啟的一個事務,不能被其他事務的操作數據所干 擾,多個並發事務之間要相互隔離
-- 持久性:持久性是指一個事務一旦被提交,它對數據庫中數據的改變就是永久性的,接下來即使數據庫發生故障也不應該對其 有任何影響
MySQL表類型和存儲引擎
- MySQL的表類型由存儲引擎(Storage Engines)決定,主要包括MyISAM、innoDB、Memory等
- MySQL數據表主要支持6種類型,分別是:CSV、Memory、ARCHIVE、MRG_MYISAM、MYISAM、InnoBDB。
- 這六種類型分為兩類,一類是“事務安全型”(transaction-safe):InnoDB;其余都屬於第二類,稱為“非事務安全型”(non-transaction-safe)