MySQL 事務和索引
事務
什麼是事務
-
事務就是將一組SQL語句放在同一批次內去執行
-
如果一個SQL語句出錯,則該批次內的所有SQL都將被取消執行
-
MySQL事務處理只支援InnoDB和BDB資料表型別
事務的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條資料
*/
SET autocommit = 0 -- 關閉自動提交
-- 事務開啟
START TRANSACTION -- 標記一個事務的開啟,從這個之後的sql都在同一個事務內
-- 轉賬
CREATE DATABASE shop CHARACTER SET utf8 COLLATE utf8_general_ci
USE shopCREATE TABLE `account`(
`id` INT(3) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(30) NOT NULL,
`money` DECIMAL(9,2) NOT NULL,
PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8INSERT
INTO account(`name`,`money`)VALUES ('A',2000.00),('B',10000.00)-- 模擬轉賬
SET autocommit = 0; -- 關閉自動提交
START TRANSACTION -- 開啟一個事務
UPDATE account SET money=money-500 WHERE `name` = 'A' -- A減500
UPDATE account SET money=money+500 WHERE `name` = 'B' -- B加500
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 UPDATE CURRENT_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), '[email protected]', 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 等索引;