mysql面試

基礎篇

通用語法及分類

  • DDL: 數據定義語言,用來定義數據庫對象(數據庫、表、字段)
  • DML: 數據操作語言,用來對數據庫表中的數據進行增刪改
  • DQL: 數據查詢語言,用來查詢數據庫中表的記錄
  • DCL: 數據控制語言,用來創建數據庫用戶、控制數據庫的控制權限

DDL(數據定義語言)

數據定義語言

數據庫操作

查詢所有數據庫:
SHOW DATABASES;
查詢當前數據庫:
SELECT DATABASE();
創建數據庫:
CREATE DATABASE [ IF NOT EXISTS ] 數據庫名 [ DEFAULT CHARSET 字符集] [COLLATE 排序規則 ];
刪除數據庫:
DROP DATABASE [ IF EXISTS ] 數據庫名;
使用數據庫:
USE 數據庫名;

注意事項
  • UTF8字符集長度為3字節,有些符號占4字節,所以推薦用utf8mb4字符集

表操作

查詢當前數據庫所有表:
SHOW TABLES;
查詢表結構:
DESC 表名;
查詢指定表的建表語句:
SHOW CREATE TABLE 表名;

創建表:

CREATE TABLE 表名(字段1 字段1類型 [COMMENT 字段1注釋],字段2 字段2類型 [COMMENT 字段2注釋],字段3 字段3類型 [COMMENT 字段3注釋],...字段n 字段n類型 [COMMENT 字段n注釋]
)[ COMMENT 表注釋 ];

所有的要用英文的格式
最后一個字段后面沒有逗號

添加字段:
ALTER TABLE 表名 ADD 字段名 類型(長度) [COMMENT 注釋] [約束];
例:ALTER TABLE emp ADD nickname varchar(20) COMMENT '昵稱';

修改數據類型:
ALTER TABLE 表名 MODIFY 字段名 新數據類型(長度);

修改字段名和字段類型:
ALTER TABLE 表名 CHANGE 舊字段名 新字段名 類型(長度) [COMMENT 注釋] [約束];

例:將emp表的nickname字段修改為username,類型為varchar(30)
ALTER TABLE emp CHANGE nickname username varchar(30) COMMENT '昵稱';

刪除字段:
ALTER TABLE 表名 DROP 字段名;

修改表名:
ALTER TABLE 表名 RENAME TO 新表名

刪除表:
DROP TABLE [IF EXISTS] 表名;

刪除表,并重新創建該表:
TRUNCATE TABLE 表名;

DML(數據操作語言)

添加數據

指定字段:
INSERT INTO 表名 (字段名1, 字段名2, ...) VALUES (值1, 值2, ...);
全部字段:
INSERT INTO 表名 VALUES (值1, 值2, ...);

批量添加數據:
INSERT INTO 表名 (字段名1, 字段名2, ...) VALUES (值1, 值2, ...), (值1, 值2, ...), (值1, 值2, ...);
INSERT INTO 表名 VALUES (值1, 值2, ...), (值1, 值2, ...), (值1, 值2, ...);

注意事項
  • 字符串和日期類型數據應該包含在引號中
  • 插入的數據大小應該在字段的規定范圍內

更新和刪除數據

修改數據:
UPDATE 表名 SET 字段名1 = 值1, 字段名2 = 值2, ... [ WHERE 條件 ];
例:
UPDATE emp SET name = 'Jack' WHERE id = 1;

刪除數據:
DELETE FROM 表名 [ WHERE 條件 ];

DQL(數據查詢語言)

語法:

SELECT字段列表
FROM表名字段
WHERE條件列表
GROUP BY分組字段列表
HAVING分組后的條件列表
ORDER BY排序字段列表
LIMIT分頁參數

基礎查詢

查詢多個字段:
SELECT 字段1, 字段2, 字段3, ... FROM 表名;
SELECT * FROM 表名;

設置別名:
SELECT 字段1 [ AS 別名1 ], 字段2 [ AS 別名2 ], 字段3 [ AS 別名3 ], ... FROM 表名;
SELECT 字段1 [ 別名1 ], 字段2 [ 別名2 ], 字段3 [ 別名3 ], ... FROM 表名;

去除重復記錄:
SELECT DISTINCT 字段列表 FROM 表名;

轉義:
SELECT * FROM 表名 WHERE name LIKE '/_張三' ESCAPE '/'
/ 之后的_不作為通配符

條件查詢

語法:
SELECT 字段列表 FROM 表名 WHERE 條件列表;

條件:

比較運算符功能
>大于
>=大于等于
<小于
<=小于等于
=等于
<> 或 !=不等于
BETWEEN … AND …在某個范圍內(含最小、最大值)
IN(…)在in之后的列表中的值,多選一
LIKE 占位符模糊匹配(_匹配單個字符,%匹配任意個字符)
IS NULL是NULL
邏輯運算符功能
AND 或 &&并且(多個條件同時成立)
OR 或 ||或者(多個條件任意一個成立)
NOT 或 !非,不是

例子:

-- 年齡等于30
select * from employee where age = 30;
-- 年齡小于30
select * from employee where age < 30;
-- 小于等于
select * from employee where age <= 30;
-- 沒有身份證
select * from employee where idcard is null or idcard = '';
-- 有身份證
select * from employee where idcard;
select * from employee where idcard is not null;
-- 不等于
select * from employee where age != 30;
-- 年齡在20到30之間
select * from employee where age between 20 and 30;
select * from employee where age >= 20 and age <= 30;
-- 下面語句不報錯,但查不到任何信息
select * from employee where age between 30 and 20;
-- 性別為女且年齡小于30
select * from employee where age < 30 and gender = '女';
-- 年齡等于25或30或35
select * from employee where age = 25 or age = 30 or age = 35;
select * from employee where age in (25, 30, 35);
-- 姓名為兩個字
select * from employee where name like '__';
-- 身份證最后為X
select * from employee where idcard like '%X';

聚合查詢(聚合函數)

常見聚合函數:

函數功能
count統計數量
max最大值
min最小值
avg平均值
sum求和

語法:
SELECT 聚合函數(字段列表) FROM 表名;
例:
SELECT count(id) from employee where workaddress = "廣東省";

分組查詢

語法:
SELECT 字段列表 FROM 表名 [ WHERE 條件 ] GROUP BY 分組字段名 [ HAVING 分組后的過濾條件 ];

where 和 having 的區別:

  • 執行時機不同:where是分組之前進行過濾,不滿足where條件不參與分組;having是分組后對結果進行過濾。
  • 判斷條件不同:where不能對聚合函數進行判斷,而having可以。

例子:

-- 根據性別分組,統計男性和女性數量(只顯示分組數量,不顯示哪個是男哪個是女)
select count(*) from employee group by gender;
-- 根據性別分組,統計男性和女性數量
select gender, count(*) from employee group by gender;
-- 根據性別分組,統計男性和女性的平均年齡
select gender, avg(age) from employee group by gender;
-- 年齡小于45,并根據工作地址分組
select workaddress, count(*) from employee where age < 45 group by workaddress;
-- 年齡小于45,并根據工作地址分組,獲取員工數量大于等于3的工作地址
select workaddress, count(*) address_count from employee where age < 45 group by workaddress having address_count >= 3;
注意事項
  • 執行順序:where > 聚合函數 > having
  • 分組之后,查詢的字段一般為聚合函數和分組字段,查詢其他字段無任何意義

排序查詢

語法:
SELECT 字段列表 FROM 表名 ORDER BY 字段1 排序方式1, 字段2 排序方式2;

排序方式:

  • ASC: 升序(默認)
  • DESC: 降序

例子:

-- 根據年齡升序排序
SELECT * FROM employee ORDER BY age ASC;
SELECT * FROM employee ORDER BY age;
-- 兩字段排序,根據年齡升序排序,入職時間降序排序(如果年齡相同那么就按這個)
SELECT * FROM employee ORDER BY age ASC, entrydate DESC;
注意事項

如果是多字段排序,當第一個字段值相同時,才會根據第二個字段進行排序

分頁查詢

語法:
SELECT 字段列表 FROM 表名 LIMIT 起始索引, 查詢記錄數;

例子:

-- 查詢第一頁數據,展示10條
SELECT * FROM employee LIMIT 0, 10;
-- 查詢第二頁
SELECT * FROM employee LIMIT 10, 10;
注意事項
  • 起始索引從0開始,起始索引 = (查詢頁碼 - 1) * 每頁顯示記錄數
  • 分頁查詢是數據庫的方言,不同數據庫有不同實現,MySQL是LIMIT
  • 如果查詢的是第一頁數據,起始索引可以省略,直接簡寫 LIMIT 10

DQL執行順序

FROM -> WHERE -> GROUP BY -> SELECT -> ORDER BY -> LIMIT

DCL

管理用戶

查詢用戶:

USER mysql;
SELECT * FROM user;

創建用戶:
CREATE USER '用戶名'@'主機名' IDENTIFIED BY '密碼';

修改用戶密碼:
ALTER USER '用戶名'@'主機名' IDENTIFIED WITH mysql_native_password BY '新密碼';

刪除用戶:
DROP USER '用戶名'@'主機名';

例子:

-- 創建用戶test,只能在當前主機localhost訪問
create user 'test'@'localhost' identified by '123456';
-- 創建用戶test,能在任意主機訪問
create user 'test'@'%' identified by '123456';
create user 'test' identified by '123456';
-- 修改密碼
alter user 'test'@'localhost' identified with mysql_native_password by '1234';
-- 刪除用戶
drop user 'test'@'localhost';
注意事項
  • 主機名可以使用 % 通配

權限控制

常用權限:

權限說明
ALL, ALL PRIVILEGES所有權限
SELECT查詢數據
INSERT插入數據
UPDATE修改數據
DELETE刪除數據
ALTER修改表
DROP刪除數據庫/表/視圖
CREATE創建數據庫/表

更多權限請看權限一覽表

查詢權限:
SHOW GRANTS FOR '用戶名'@'主機名';

授予權限:
GRANT 權限列表 ON 數據庫名.表名 TO '用戶名'@'主機名';

撤銷權限:
REVOKE 權限列表 ON 數據庫名.表名 FROM '用戶名'@'主機名';

注意事項
  • 多個權限用逗號分隔
  • 授權時,數據庫名和表名可以用 * 進行通配,代表所有

函數

函數 是指一段可以直接被另外一段程序調用的程序或代碼。

  • 字符串函數
  • 數值函數
  • 日期函數
  • 流程函數

字符串函數

常用函數:

函數功能
CONCAT(s1, s2, …, sn)字符串拼接,將s1, s2, …, sn拼接成一個字符串
LOWER(str)將字符串全部轉為小寫
UPPER(str)將字符串全部轉為大寫
LPAD(str, n, pad)左填充,用字符串pad對str的左邊進行填充,達到n個字符串長度
RPAD(str, n, pad)右填充,用字符串pad對str的右邊進行填充,達到n個字符串長度
TRIM(str)去掉字符串頭部和尾部的空格
SUBSTRING(str, start, len)返回從字符串str從start位置起的len個長度的字符串

使用示例:

-- 拼接
SELECT CONCAT('Hello', 'World');
-- 小寫
SELECT LOWER('Hello');
-- 大寫
SELECT UPPER('Hello');
-- 左填充
SELECT LPAD('01', 5, '-');
-- 右填充
SELECT RPAD('01', 5, '-');
-- 去除空格
SELECT TRIM(' Hello World ');
-- 切片(起始索引為1)
SELECT SUBSTRING('Hello World', 1, 5);

數值函數

常見函數:

函數功能
CEIL(x)向上取整
FLOOR(x)向下取整
MOD(x, y)返回x/y的模
RAND()返回0~1內的隨機數
ROUND(x, y)求參數x的四舍五入值,保留y位小數

日期函數

常用函數:

函數功能
CURDATE()返回當前日期
CURTIME()返回當前時間
NOW()返回當前日期和時間
YEAR(date)獲取指定date的年份
MONTH(date)獲取指定date的月份
DAY(date)獲取指定date的日期
DATE_ADD(date, INTERVAL expr type)返回一個日期/時間值加上一個時間間隔expr后的時間值
DATEDIFF(date1, date2)返回起始時間date1和結束時間date2之間的天數

例子:

-- DATE_ADD
SELECT DATE_ADD(NOW(), INTERVAL 70 YEAR);

流程函數

常用函數:

函數功能
IF(value, t, f)如果value為true,則返回t,否則返回f
IFNULL(value1, value2)如果value1不為空,返回value1,否則返回value2
CASE WHEN [ val1 ] THEN [ res1 ] … ELSE [ default ] END如果val1為true,返回res1,… 否則返回default默認值
CASE [ expr ] WHEN [ val1 ] THEN [ res1 ] … ELSE [ default ] END如果expr的值等于val1,返回res1,… 否則返回default默認值

例子:

selectname,(case when age > 30 then '中年' else '青年' end)
from employee;
selectname,(case workaddress when '北京市' then '一線城市' when '上海市' then '一線城市' else '二線城市' end) as '工作地址'
from employee;

約束

  1. 概念:約束是用來作用于表中字段上的規則,用于限制存儲在表中的數據。
  2. 目的:保證數據庫中的數據的正確、有效性和完整性

分類:

約束描述關鍵字
非空約束限制該字段的數據不能為nullNOT NULL
唯一約束保證該字段的所有數據都是唯一、不重復的UNIQUE
主鍵約束主鍵是一行數據的唯一標識,要求非空且唯一PRIMARY KEY
默認約束保存數據時,如果未指定該字段的值,則采用默認值DEFAULT
檢查約束(8.0.1版本后)保證字段值滿足某一個條件CHECK
外鍵約束用來讓兩張圖的數據之間建立連接,保證數據的一致性和完整性FOREIGN KEY

約束是作用于表中字段上的,可以再創建表/修改表的時候添加約束。

常用約束

約束條件關鍵字
主鍵PRIMARY KEY
自動增長AUTO_INCREMENT
不為空NOT NULL
唯一UNIQUE
邏輯條件CHECK
默認值DEFAULT

例子:

create table user(id int primary key auto_increment,name varchar(10) not null unique,age int check(age > 0 and age < 120),status char(1) default '1',gender char(1)
);

外鍵約束

外鍵用來讓兩張表的數據之間建立連接,從而保證數據的一致性和完整性。

添加外鍵:

CREATE TABLE 表名(字段名 字段類型,...[CONSTRAINT] [外鍵名稱] FOREIGN KEY(外鍵字段名) REFERENCES 主表(主表列名)
);  
ALTER TABLE 表名 ADD CONSTRAINT 外鍵名稱 FOREIGN KEY (外鍵字段名) REFERENCES 主表(主表列名);-- 例子  
alter table emp add constraint fk_emp_dept_id foreign key(dept_id) references dept(id);  

刪除外鍵:
ALTER TABLE 表名 DROP FOREIGN KEY 外鍵名;

刪除/更新行為

行為說明
NO ACTION當在父表中刪除/更新對應記錄時,首先檢查該記錄是否有對應外鍵,如果有則不允許刪除/更新(與RESTRICT一致)
RESTRICT當在父表中刪除/更新對應記錄時,首先檢查該記錄是否有對應外鍵,如果有則不允許刪除/更新(與NO ACTION一致)
CASCADE當在父表中刪除/更新對應記錄時,首先檢查該記錄是否有對應外鍵,如果有則也刪除/更新外鍵在子表中的記錄
SET NULL當在父表中刪除/更新對應記錄時,首先檢查該記錄是否有對應外鍵,如果有則設置子表中該外鍵值為null(要求該外鍵允許為null)
SET DEFAULT父表有變更時,子表將外鍵設為一個默認值(Innodb不支持)

更改刪除/更新行為:
ALTER TABLE 表名 ADD CONSTRAINT 外鍵名稱 FOREIGN KEY (外鍵字段) REFERENCES 主表名(主表字段名) ON UPDATE 行為 ON DELETE 行為;

多表查詢

多表關系

  • 一對多(多對一)
  • 多對多
  • 一對一

一對多

案例:部門與員工
關系:一個部門對應多個員工,一個員工對應一個部門
實現:在多的一方建立外鍵,指向一的一方的主鍵

多對多

案例:學生與課程
關系:一個學生可以選多門課程,一門課程也可以供多個學生選修
實現:建立第三張中間表,中間表至少包含兩個外鍵,分別關聯兩方主鍵

一對一

案例:用戶與用戶詳情
關系:一對一關系,多用于單表拆分,將一張表的基礎字段放在一張表中,其他詳情字段放在另一張表中,以提升操作效率
實現:在任意一方加入外鍵,關聯另外一方的主鍵,并且設置外鍵為唯一的(UNIQUE)

查詢

合并查詢(笛卡爾積,會展示所有組合結果):
select * from employee, dept;

笛卡爾積:兩個集合A集合和B集合的所有組合情況(在多表查詢時,需要消除無效的笛卡爾積)

消除無效笛卡爾積:
select * from employee, dept where employee.dept = dept.id;

內連接查詢

內連接查詢的是兩張表交集的部分

隱式內連接:
SELECT 字段列表 FROM 表1, 表2 WHERE 條件 ...;

顯式內連接:
SELECT 字段列表 FROM 表1 [ INNER ] JOIN 表2 ON 連接條件 ...;

顯式性能比隱式高

例子:

-- 查詢員工姓名,及關聯的部門的名稱
-- 隱式
select e.name, d.name from employee as e, dept as d where e.dept = d.id;
-- 顯式
select e.name, d.name from employee as e inner join dept as d on e.dept = d.id;

外連接查詢

左外連接:
查詢左表所有數據,以及兩張表交集部分數據
SELECT 字段列表 FROM 表1 LEFT [ OUTER ] JOIN 表2 ON 條件 ...;
相當于查詢表1的所有數據,包含表1和表2交集部分數據

右外連接:
查詢右表所有數據,以及兩張表交集部分數據
SELECT 字段列表 FROM 表1 RIGHT [ OUTER ] JOIN 表2 ON 條件 ...;

例子:

-- 左
select e.*, d.name from employee as e left outer join dept as d on e.dept = d.id;  
select d.name, e.* from dept d left outer join emp e on e.dept = d.id;  -- 這條語句與下面的語句效果一樣  
-- 右
select d.name, e.* from employee as e right outer join dept as d on e.dept = d.id;  

左連接可以查詢到沒有dept的employee,右連接可以查詢到沒有employee的dept

自連接查詢

當前表與自身的連接查詢,自連接必須使用表別名

語法:
SELECT 字段列表 FROM 表A 別名A JOIN 表A 別名B ON 條件 ...;

自連接查詢,可以是內連接查詢,也可以是外連接查詢

例子:

-- 查詢員工及其所屬領導的名字  
select a.name, b.name from employee a, employee b where a.manager = b.id;  
-- 沒有領導的也查詢出來  
select a.name, b.name from employee a left join employee b on a.manager = b.id;  

聯合查詢 union, union all

把多次查詢的結果合并,形成一個新的查詢集

語法:

SELECT 字段列表 FROM 表A ...
UNION [ALL]
SELECT 字段列表 FROM 表B ...

注意事項

  • UNION ALL 會有重復結果,UNION 不會
  • 聯合查詢比使用or效率高,不會使索引失效

子查詢

SQL語句中嵌套SELECT語句,稱謂嵌套查詢,又稱子查詢。
SELECT * FROM t1 WHERE column1 = ( SELECT column1 FROM t2);
子查詢外部的語句可以是 INSERT / UPDATE / DELETE / SELECT 的任何一個

根據子查詢結果可以分為:

  • 標量子查詢(子查詢結果為單個值)
  • 列子查詢(子查詢結果為一列)
  • 行子查詢(子查詢結果為一行)
  • 表子查詢(子查詢結果為多行多列)

根據子查詢位置可分為:

  • WHERE 之后
  • FROM 之后
  • SELECT 之后

標量子查詢

子查詢返回的結果是單個值(數字、字符串、日期等)。
常用操作符:- < > > >= < <=

例子:

-- 查詢銷售部所有員工
select id from dept where name = '銷售部';
-- 根據銷售部部門ID,查詢員工信息
select * from employee where dept = 4;
-- 合并(子查詢)  
select * from employee where dept = (select id from dept where name = '銷售部');  -- 查詢xxx入職之后的員工信息  
select * from employee where entrydate > (select entrydate from employee where name = 'xxx');  

列子查詢

返回的結果是一列(可以是多行)。

常用操作符:

操作符描述
IN在指定的集合范圍內,多選一
NOT IN不在指定的集合范圍內
ANY子查詢返回列表中,有任意一個滿足即可
SOME與ANY等同,使用SOME的地方都可以使用ANY
ALL子查詢返回列表的所有值都必須滿足

例子:

-- 查詢銷售部和市場部的所有員工信息  
select * from employee where dept in (select id from dept where name = '銷售部' or name = '市場部');
-- 查詢比財務部所有人工資都高的員工信息
select * from employee where salary > all(select salary from employee where dept = (select id from dept where name = '財務部'));
-- 查詢比研發部任意一人工資高的員工信息
select * from employee where salary > any (select salary from employee where dept = (select id from dept where name = '研發部'));

行子查詢

返回的結果是一行(可以是多列)。
常用操作符:=, <, >, IN, NOT IN

例子:

-- 查詢與xxx的薪資及直屬領導相同的員工信息  
select * from employee where (salary, manager) = (12500, 1);  
select * from employee where (salary, manager) = (select salary, manager from employee where name = 'xxx');  

表子查詢

返回的結果是多行多列
常用操作符:IN

例子:

-- 查詢與xxx1,xxx2的職位和薪資相同的員工
select * from employee where (job, salary) in (select job, salary from employee where name = 'xxx1' or name = 'xxx2');
-- 查詢入職日期是2006-01-01之后的員工,及其部門信息
select e.*, d.* from (select * from employee where entrydate > '2006-01-01') as e left join dept as d on e.dept = d.id;

事務

事務是一組操作的集合,事務會把所有操作作為一個整體一起向系統提交或撤銷操作請求,即這些操作要么同時成功,要么同時失敗。

基本操作:

-- 1. 查詢張三賬戶余額
select * from account where name = '張三';
-- 2. 將張三賬戶余額-1000
update account set money = money - 1000 where name = '張三';
-- 此語句出錯后張三錢減少但是李四錢沒有增加
模擬sql語句錯誤
-- 3. 將李四賬戶余額+1000
update account set money = money + 1000 where name = '李四';-- 查看事務提交方式
SELECT @@AUTOCOMMIT;
-- 設置事務提交方式,1為自動提交,0為手動提交,該設置只對當前會話有效
SET @@AUTOCOMMIT = 0;
-- 提交事務
COMMIT;
-- 回滾事務
ROLLBACK;-- 設置手動提交后上面代碼改為:
select * from account where name = '張三';  
update account set money = money - 1000 where name = '張三';  
update account set money = money + 1000 where name = '李四';  
commit;  

操作方式二:

開啟事務:
START TRANSACTION 或 BEGIN TRANSACTION;
提交事務:
COMMIT;
回滾事務:
ROLLBACK;

操作實例:

start transaction; 
select * from account where name = '張三';
update account set money = money - 1000 where name = '張三';
update account set money = money + 1000 where name = '李四';
commit;

開啟事務后,只有手動提交才會改變數據庫中的數據。

四大特性ACID

  • 原子性(Atomicity):事務是不可分割的最小操作但愿,要么全部成功,要么全部失敗
  • 一致性(Consistency):事務完成時,必須使所有數據都保持一致狀態
  • 隔離性(Isolation):數據庫系統提供的隔離機制,保證事務在不受外部并發操作影響的獨立環境下運行
  • 持久性(Durability):事務一旦提交或回滾,它對數據庫中的數據的改變就是永久的

并發事務

問題描述
臟讀一個事務讀到另一個事務還沒提交的數據
不可重復讀一個事務先后讀取同一條記錄,但兩次讀取的數據不同
幻讀一個事務按照條件查詢數據時,沒有對應的數據行,但是再插入數據時,又發現這行數據已經存在

這三個問題的詳細演示:https://www.bilibili.com/video/BV1Kr4y1i7ru?p=55cd

并發事務隔離級別:

隔離級別臟讀不可重復讀幻讀
Read uncommitted
Read committed×
Repeatable Read(默認)××
Serializable×××
  • √表示在當前隔離級別下該問題會出現
  • Serializable 性能最低;Read uncommitted 性能最高,數據安全性最差

查看事務隔離級別:
SELECT @@TRANSACTION_ISOLATION;
設置事務隔離級別:
SET [ SESSION | GLOBAL ] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE };
SESSION 是會話級別,表示只針對當前會話有效,GLOBAL 表示對所有會話有效

進階篇

存儲引擎

MySQL體系結構:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-auIab3zX-1692120469795)(https://dhc.pythonanywhere.com/media/editor/MySQL體系結構_20220315034329549927.png “結構圖”)]
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-lMxFlbk7-1692120469796)(https://dhc.pythonanywhere.com/media/editor/MySQL體系結構層級含義_20220315034359342837.png “層級描述”)]

存儲引擎就是存儲數據、建立索引、更新/查詢數據等技術的實現方式。存儲引擎是基于表而不是基于庫的,所以存儲引擎也可以被稱為表引擎。
默認存儲引擎是InnoDB。

相關操作:

-- 查詢建表語句
show create table account;  
-- 建表時指定存儲引擎
CREATE TABLE 表名(...
) ENGINE=INNODB;
-- 查看當前數據庫支持的存儲引擎
show engines;

InnoDB

InnoDB 是一種兼顧高可靠性和高性能的通用存儲引擎,在 MySQL 5.5 之后,InnoDB 是默認的 MySQL 引擎。

特點:

  • DML 操作遵循 ACID 模型,支持事務
  • 行級鎖,提高并發訪問性能
  • 支持外鍵約束,保證數據的完整性和正確性

文件:

  • xxx.ibd: xxx代表表名,InnoDB 引擎的每張表都會對應這樣一個表空間文件,存儲該表的表結構(frm、sdi)、數據和索引。

參數:innodb_file_per_table,決定多張表共享一個表空間還是每張表對應一個表空間

知識點:

查看 Mysql 變量:
show variables like 'innodb_file_per_table';

從idb文件提取表結構數據:
(在cmd運行)
ibd2sdi xxx.ibd

InnoDB 邏輯存儲結構:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Qd5rvjJ0-1692120469796)(https://dhc.pythonanywhere.com/media/editor/邏輯存儲結構_20220316030616590001.png “InnoDB邏輯存儲結構”)]

MyISAM

MyISAM 是 MySQL 早期的默認存儲引擎。

特點:

  • 不支持事務,不支持外鍵
  • 支持表鎖,不支持行鎖
  • 訪問速度快

文件:

  • xxx.sdi: 存儲表結構信息
  • xxx.MYD: 存儲數據
  • xxx.MYI: 存儲索引

Memory

Memory 引擎的表數據是存儲在內存中的,受硬件問題、斷電問題的影響,只能將這些表作為臨時表或緩存使用。

特點:

  • 存放在內存中,速度快
  • hash索引(默認)

文件:

  • xxx.sdi: 存儲表結構信息

存儲引擎特點

特點InnoDBMyISAMMemory
存儲限制64TB
事務安全支持--
鎖機制行鎖表鎖表鎖
B+tree索引支持支持支持
Hash索引--支持
全文索引支持(5.6版本之后)支持-
空間使用N/A
內存使用中等
批量插入速度
支持外鍵支持--

存儲引擎的選擇

在選擇存儲引擎時,應該根據應用系統的特點選擇合適的存儲引擎。對于復雜的應用系統,還可以根據實際情況選擇多種存儲引擎進行組合。

  • InnoDB: 如果應用對事物的完整性有比較高的要求,在并發條件下要求數據的一致性,數據操作除了插入和查詢之外,還包含很多的更新、刪除操作,則 InnoDB 是比較合適的選擇
  • MyISAM: 如果應用是以讀操作和插入操作為主,只有很少的更新和刪除操作,并且對事務的完整性、并發性要求不高,那這個存儲引擎是非常合適的。
  • Memory: 將所有數據保存在內存中,訪問速度快,通常用于臨時表及緩存。Memory 的缺陷是對表的大小有限制,太大的表無法緩存在內存中,而且無法保障數據的安全性

電商中的足跡和評論適合使用 MyISAM 引擎,緩存適合使用 Memory 引擎。

性能分析

查看執行頻次

查看當前數據庫的 INSERT, UPDATE, DELETE, SELECT 訪問頻次:
SHOW GLOBAL STATUS LIKE 'Com_______'; 或者 SHOW SESSION STATUS LIKE 'Com_______';
例:show global status like 'Com_______'

慢查詢日志

慢查詢日志記錄了所有執行時間超過指定參數(long_query_time,單位:秒,默認10秒)的所有SQL語句的日志。
MySQL的慢查詢日志默認沒有開啟,需要在MySQL的配置文件(/etc/my.cnf)中配置如下信息:
# 開啟慢查詢日志開關
slow_query_log=1
# 設置慢查詢日志的時間為2秒,SQL語句執行時間超過2秒,就會視為慢查詢,記錄慢查詢日志
long_query_time=2
更改后記得重啟MySQL服務,日志文件位置:/var/lib/mysql/localhost-slow.log

查看慢查詢日志開關狀態:
show variables like 'slow_query_log';

profile

show profile 能在做SQL優化時幫我們了解時間都耗費在哪里。通過 have_profiling 參數,能看到當前 MySQL 是否支持 profile 操作:
SELECT @@have_profiling;
profiling 默認關閉,可以通過set語句在session/global級別開啟 profiling:
SET profiling = 1;
查看所有語句的耗時:
show profiles;
查看指定query_id的SQL語句各個階段的耗時:
show profile for query query_id;
查看指定query_id的SQL語句CPU的使用情況
show profile cpu for query query_id;

explain

EXPLAIN 或者 DESC 命令獲取 MySQL 如何執行 SELECT 語句的信息,包括在 SELECT 語句執行過程中表如何連接和連接的順序。
語法:
# 直接在select語句之前加上關鍵字 explain / desc
EXPLAIN SELECT 字段列表 FROM 表名 HWERE 條件;

EXPLAIN 各字段含義:

  • id:select 查詢的序列號,表示查詢中執行 select 子句或者操作表的順序(id相同,執行順序從上到下;id不同,值越大越先執行)
  • select_type:表示 SELECT 的類型,常見取值有 SIMPLE(簡單表,即不適用表連接或者子查詢)、PRIMARY(主查詢,即外層的查詢)、UNION(UNION中的第二個或者后面的查詢語句)、 SUBQUERY(SELECT/WHERE之后包含了子查詢)等
  • type:表示連接類型,性能由好到差的連接類型為 NULL、system、const、eq_ref、ref、range、index、all,當不查詢任何表的時候type為NULL一般不可能,當訪問主鍵或者唯一索引時會出現const,非唯一索引會出現ref。all表示全表掃描,index表示用了索引,但是會對全部索引進行掃描,性能也不高。
  • possible_key:可能應用在這張表上的索引,一個或多個
  • Key:實際使用的索引,如果為 NULL,則沒有使用索引
  • Key_len:表示索引中使用的字節數,該值為索引字段最大可能長度,并非實際使用長度,在不損失精確性的前提下,長度越短越好
  • rows:MySQL認為必須要執行的行數,在InnoDB引擎的表中,是一個估計值,可能并不總是準確的
  • filtered:表示返回結果的行數占需讀取行數的百分比,filtered的值越大越好
  • [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-104rXATR-1692120469797)(C:\Users\14361\AppData\Roaming\Typora\typora-user-images\image-20230811022103408.png)]

索引

索引是幫助 MySQL 高效獲取數據數據結構(有序)。在數據之外,數據庫系統還維護著滿足特定查找算法的數據結構,這些數據結構以某種方式引用(指向)數據,這樣就可以在這些數據結構上實現高級查詢算法,這種數據結構就是索引。

優缺點:

優點:

  • 提高數據檢索效率,降低數據庫的IO成本
  • 通過索引列對數據進行排序,降低數據排序的成本,降低CPU的消耗

缺點:

  • 索引列也是要占用空間的
  • 索引大大提高了查詢效率,但降低了更新的速度,比如 INSERT、UPDATE、DELETE

索引結構

索引結構描述
B+Tree最常見的索引類型,大部分引擎都支持B+樹索引
Hash底層數據結構是用哈希表實現,只有精確匹配索引列的查詢才有效,不支持范圍查詢
R-Tree(空間索引)空間索引是 MyISAM 引擎的一個特殊索引類型,主要用于地理空間數據類型,通常使用較少
Full-Text(全文索引)是一種通過建立倒排索引,快速匹配文檔的方式,類似于 Lucene, Solr, ES
索引InnoDBMyISAMMemory
B+Tree索引支持支持支持
Hash索引不支持不支持支持
R-Tree索引不支持支持不支持
Full-text5.6版本后支持支持不支持

B-Tree

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-J7G4Bmh5-1692120469797)(https://dhc.pythonanywhere.com/media/editor/二叉樹_20220316153214227108.png “二叉樹”)]

二叉樹形成鏈表的缺點可以用紅黑樹來解決:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-61XPaR9i-1692120469797)(https://dhc.pythonanywhere.com/media/editor/紅黑樹_20220316163142686602.png “紅黑樹”)]
紅黑樹也存在大數據量情況下,層級較深,檢索速度慢的問題。

為了解決上述問題,可以使用 B-Tree 結構。
B-Tree (多路平衡查找樹) 以一棵最大度數(max-degree,指一個節點的子節點個數)為5(5階)的 b-tree 為例(每個節點最多存儲4個key,5個指針)

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-dSk0JoAy-1692120469798)(https://dhc.pythonanywhere.com/media/editor/B-Tree結構_20220316163813441163.png “B-Tree結構”)]

B-Tree 的數據插入過程動畫參照:https://www.bilibili.com/video/BV1Kr4y1i7ru?p=68
演示地址:https://www.cs.usfca.edu/~galles/visualization/BTree.html

B+Tree

結構圖:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-FTv5Px9T-1692120469798)(https://dhc.pythonanywhere.com/media/editor/B+Tree結構圖_20220316170700591277.png “B+Tree結構圖”)]

演示地址:https://www.cs.usfca.edu/~galles/visualization/BPlusTree.html

與 B-Tree 的區別:

  • 所有的數據都會出現在葉子節點
  • 葉子節點形成一個單向鏈表

MySQL 索引數據結構對經典的 B+Tree 進行了優化。在原 B+Tree 的基礎上,增加一個指向相鄰葉子節點的鏈表指針,就形成了帶有順序指針的 B+Tree,提高區間訪問的性能。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-hM2vmCqe-1692120469799)(https://dhc.pythonanywhere.com/media/editor/結構圖_20220316171730865611.png “MySQL B+Tree 結構圖”)]

Hash

哈希索引就是采用一定的hash算法,將鍵值換算成新的hash值,映射到對應的槽位上,然后存儲在hash表中。
如果兩個(或多個)鍵值,映射到一個相同的槽位上,他們就產生了hash沖突(也稱為hash碰撞),可以通過鏈表來解決。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-ccRHGqSc-1692120469799)(https://dhc.pythonanywhere.com/media/editor/Hash索引原理圖_20220317143226150679.png “Hash索引原理圖”)]

特點:

  • Hash索引只能用于對等比較(=、in),不支持范圍查詢(betwwn、>、<、…)
  • 無法利用索引完成排序操作
  • 查詢效率高,通常只需要一次檢索就可以了,效率通常要高于 B+Tree 索引

存儲引擎支持:

  • Memory
  • InnoDB: 具有自適應hash功能,hash索引是存儲引擎根據 B+Tree 索引在指定條件下自動構建的

面試題

  1. 為什么 InnoDB 存儲引擎選擇使用 B+Tree 索引結構?
  • 相對于二叉樹,層級更少,搜索效率高
  • 對于 B-Tree,無論是葉子節點還是非葉子節點,都會保存數據,這樣導致一頁中存儲的鍵值減少,指針也跟著減少,要同樣保存大量數據,只能增加樹的高度,導致性能降低
  • 相對于 Hash 索引,B+Tree 支持范圍匹配及排序操作

索引分類

分類含義特點關鍵字
主鍵索引針對于表中主鍵創建的索引默認自動創建,只能有一個PRIMARY
唯一索引避免同一個表中某數據列中的值重復可以有多個UNIQUE
常規索引快速定位特定數據可以有多個
全文索引全文索引查找的是文本中的關鍵詞,而不是比較索引中的值可以有多個FULLTEXT

在 InnoDB 存儲引擎中,根據索引的存儲形式,又可以分為以下兩種:

分類含義特點
聚集索引(Clustered Index)將數據存儲與索引放一塊,索引結構的葉子節點保存了行數據必須有,而且只有一個
二級索引(Secondary Index)將數據與索引分開存儲,索引結構的葉子節點關聯的是對應的主鍵可以存在多個

演示圖:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Fe9d4nKQ-1692120469800)(https://dhc.pythonanywhere.com/media/editor/原理圖_20220318194454880073.png “大致原理”)]
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-MfApI9TH-1692120469801)(https://dhc.pythonanywhere.com/media/editor/演示圖_20220319215403721066.png “演示圖”)]

聚集索引選取規則:

  • 如果存在主鍵,主鍵索引就是聚集索引
  • 如果不存在主鍵,將使用第一個唯一(UNIQUE)索引作為聚集索引
  • 如果表沒有主鍵或沒有合適的唯一索引,則 InnoDB 會自動生成一個 rowid 作為隱藏的聚集索引

思考題

1. 以下 SQL 語句,哪個執行效率高?為什么?

select * from user where id = 10;
select * from user where name = 'Arm';
-- 備注:id為主鍵,name字段創建的有索引

答:第一條語句,因為第二條需要回表查詢,相當于兩個步驟。

2. InnoDB 主鍵索引的 B+Tree 高度為多少?

答:假設一行數據大小為1k,一頁中可以存儲16行這樣的數據。InnoDB 的指針占用6個字節的空間,主鍵假設為bigint,占用字節數為8.
可得公式:n * 8 + (n + 1) * 6 = 16 * 1024,其中 8 表示 bigint 占用的字節數,n 表示當前節點存儲的key的數量,(n + 1) 表示指針數量(比key多一個)。算出n約為1170。

如果樹的高度為2,那么他能存儲的數據量大概為:1171 * 16 = 18736
如果樹的高度為3,那么他能存儲的數據量大概為:1171 * 1171 * 16 = 21939856

另外,如果有成千上萬的數據,那么就要考慮分表,涉及運維篇知識。

語法

創建索引:
CREATE [ UNIQUE | FULLTEXT ] INDEX index_name ON table_name (index_col_name, ...);
如果不加 CREATE 后面不加索引類型參數,則創建的是常規索引

查看索引:
SHOW INDEX FROM table_name;

刪除索引:
DROP INDEX index_name ON table_name;

案例:

-- name字段為姓名字段,該字段的值可能會重復,為該字段創建索引
create index idx_user_name on tb_user(name);
-- phone手機號字段的值非空,且唯一,為該字段創建唯一索引
create unique index idx_user_phone on tb_user (phone);
-- 為profession, age, status創建聯合索引
create index idx_user_pro_age_stat on tb_user(profession, age, status);
-- 為email建立合適的索引來提升查詢效率
create index idx_user_email on tb_user(email);-- 刪除索引  
drop index idx_user_email on tb_user;  

使用規則

最左前綴法則

如果索引關聯了多列(聯合索引),要遵守最左前綴法則,最左前綴法則指的是查詢從索引的最左列開始,并且不跳過索引中的列。
如果跳躍某一列,索引將部分失效(后面的字段索引失效)。跳過的話,后面的排序就無從說起了。最左前綴法則在用select的時候,和放的位置是沒有關系的,只要存在就行。

聯合索引中,出現范圍查詢(<, >),范圍查詢右側的列索引失效。可以用>=或者<=來規避索引失效問題。

索引失效情況

  1. 在索引列上進行運算操作,索引將失效。如:explain select * from tb_user where substring(phone, 10, 2) = '15'; 換成 explain select * from tb_user where phone = '17799990015';這是可以的。
  2. 字符串類型字段使用時,不加引號,索引將失效。如:explain select * from tb_user where phone = 17799990015;,此處phone的值沒有加引號
  3. 模糊查詢中,如果僅僅是尾部模糊匹配,索引不會是失效;如果是頭部模糊匹配,索引失效。如:explain select * from tb_user where profession like '%工程';,前后都有 % 也會失效。explain select * from tb_user where profession like '軟件%'; 這個是不會失效的,只有前面加了%才會失效。
  4. 用 or 分割開的條件,如果 or 其中一個條件的列沒有索引,那么涉及的索引都不會被用到。
  5. 如果 MySQL 評估使用索引比全表更慢,則不使用索引,比如根據查詢條件查詢的是大部分數據,mysql就不會走索引直接走全表掃描。

SQL 提示

是優化數據庫的一個重要手段,簡單來說,就是在SQL語句中加入一些人為的提示來達到優化操作的目的。

例如,使用索引:
explain select * from tb_user use index(idx_user_pro) where profession="軟件工程";
不使用哪個索引:
explain select * from tb_user ignore index(idx_user_pro) where profession="軟件工程";
必須使用哪個索引:
explain select * from tb_user force index(idx_user_pro) where profession="軟件工程";

use 是建議,實際使用哪個索引 MySQL 還會自己權衡運行速度去更改,force就是無論如何都強制使用該索引。

覆蓋索引&回表查詢

盡量使用覆蓋索引(查詢使用了索引,并且需要返回的列,在該索引中已經全部能找到),減少 select *。

explain 中 extra 字段含義:
using index condition:查找使用了索引,但是需要回表查詢數據
using where; using index;:查找使用了索引,但是需要的數據都在索引列中能找到,所以不需要回表查詢

覆蓋索引:
如果在生成的二級索引(輔助索引)中可以一次性獲得select所需要的字段,不需要回表查詢。

如果在聚集索引中直接能找到對應的行,則直接返回行數據,只需要一次查詢,哪怕是select *;
如果在輔助索引(二級索引)中找聚集索引,如select id, name from xxx where name='xxx';,也只需要通過輔助索引(name)查找到對應的id,返回name和name索引對應的id即可,只需要一次查詢;
如果是通過輔助索引查找其他字段,則需要回表查詢,如select id, name, gender from xxx where name='xxx';

所以盡量不要用select *,容易出現回表查詢,降低效率,除非有聯合索引包含了所有字段

面試題:一張表,有四個字段(id, username, password, status),由于數據量大,需要對以下SQL語句進行優化,該如何進行才是最優方案:
select id, username, password from tb_user where username='itcast';

解:給username和password字段建立聯合索引,則不需要回表查詢,直接覆蓋索引。
username和password字段建立聯合索引的葉子節點掛的就是 id 所以不需要三者同時建索引。

前綴索引

當字段類型為字符串(varchar, text等)時,有時候需要索引很長的字符串,這會讓索引變得很大,查詢時,浪費大量的磁盤IO,影響查詢效率,此時可以只降字符串的一部分前綴,建立索引,這樣可以大大節約索引空間,從而提高索引效率。

語法:create index idx_xxxx on table_name(columnn(n));
前綴長度:可以根據索引的選擇性來決定,而選擇性是指不重復的索引值(基數)和數據表的記錄總數的比值,索引選擇性越高則查詢效率越高,唯一索引的選擇性是1,這是最好的索引選擇性,性能也是最好的。

求選擇性公式:

select count(distinct email) / count(*) from tb_user;
select count(distinct substring(email, 1, 5)) / count(*) from tb_user;

前綴索引中是有可能碰到相同的索引的情況的(因為選擇性可能不為1),所以使用前綴索引進行查詢的時候,mysql 會有一個回表查詢的過程,確定是否為所需數據。如圖中的查詢到lvbu6之后還要進行回表,回表完再查xiaoy,看到xiaoy是不需要的數據,則停止查下一個。

![images]pre.png

show index 里面的sub_part可以看到接取的長度

單列索引&聯合索引

單列索引:即一個索引只包含單個列
聯合索引:即一個索引包含了多個列
在業務場景中,如果存在多個查詢條件,考慮針對于查詢字段建立索引時,建議建立聯合索引,而非單列索引。

單列索引情況:

explain select id, phone, name from tb_user where phone = '17799990010' and name = '韓信';
phone 和 name 都建立了索引情況下,這句只會用到phone索引字段。

聯合索引的數據組織圖:

uion.png

注意事項
  • 多條件聯合查詢時,MySQL優化器會評估哪個字段的索引效率更高,會選擇該索引完成本次查詢。

設計原則

  1. 針對于數據量較大,且查詢比較頻繁的表建立索引,一百多萬建索引,幾千條幾萬條沒必要。
  2. 針對于常作為查詢條件(where)、排序(order by)、分組(group by)操作的字段建立索引
  3. 盡量選擇區分度高的列作為索引,盡量建立唯一索引,區分度越高,使用索引的效率越高
  4. 如果是字符串類型的字段,字段長度較長,可以針對于字段的特點,建立前綴索引
  5. 盡量使用聯合索引,減少單列索引,查詢時,聯合索引很多時候可以覆蓋索引,節省存儲空間,避免回表,提高查詢效率
  6. 要控制索引的數量,索引并不是多多益善,索引越多,維護索引結構的代價就越大,會影響增刪改的效率
  7. 如果索引列不能存儲NULL值,請在創建表時使用NOT NULL約束它。當優化器知道每列是否包含NULL值時,它可以更好地確定哪個索引最有效地用于查詢

SQL 優化

插入數據

普通插入:

  1. 采用批量插入(一次插入的數據不建議超過1000條,500 - 1000 為宜)
  2. 手動提交事務
  3. 主鍵順序插入(主鍵順序插入的效率大于亂序插入)

大批量插入:
如果一次性需要插入大批量數據,使用insert語句插入性能較低,此時可以使用MySQL數據庫提供的load指令插入。

# 客戶端連接服務端時,加上參數 --local-infile(這一行在bash/cmd界面輸入)
mysql --local-infile -u root -p
# 設置全局參數local_infile為1,開啟從本地加載文件導入數據的開關
set global local_infile = 1;
select @@local_infile;
# 執行load指令將準備好的數據,加載到表結構中,先要把表建立起來。下述代碼的意思是把本地文件sql1.log插入到表tb_user中,字段以“,”分隔,每一行以\n分隔。
load data local infile '/root/sql1.log' into table 'tb_user' fields terminated by ',' lines terminated by '\n';

主鍵優化

數據組織方式:在InnoDB存儲引擎中,表數據都是根據主鍵順序組織存放的,這種存儲方式的表稱為索引組織表(Index organized table, IOT)

主鍵的順序的插入過程如下:

![images]keySort.png

但是如果主鍵是亂序插入的話,就會導致需要插入的位置為中間的位置,會有頁分裂的過程。

頁分裂:頁可以為空,也可以填充一般,也可以填充100%,每個頁包含了2-N行數據(如果一行數據過大,會行溢出),根據主鍵排列。

頁合并:當刪除一行記錄時,實際上記錄并沒有被物理刪除,只是記錄被標記(flaged)為刪除并且它的空間變得允許被其他記錄聲明使用。當頁中刪除的記錄到達 MERGE_THRESHOLD(默認為頁的50%),InnoDB會開始尋找最靠近的頁(前后)看看是否可以將這兩個頁合并以優化空間使用。

MERGE_THRESHOLD:合并頁的閾值,可以自己設置,在創建表或創建索引時指定

文字說明不夠清晰明了,具體可以看視頻里的PPT演示過程:https://www.bilibili.com/video/BV1Kr4y1i7ru?p=90

主鍵設計原則:

  • 滿足業務需求的情況下,盡量降低主鍵的長度,二級索引的葉子節點保存的就是主鍵,所以主鍵小占用的空間也就會少。
  • 插入數據時,盡量選擇順序插入,選擇使用 AUTO_INCREMENT 自增主鍵
  • 盡量不要使用 UUID 做主鍵或者是其他的自然主鍵,如身份證號,占用的空間大。
  • 業務操作時,避免對主鍵的修改

order by優化

  1. Using filesort:通過表的索引或全表掃描,讀取滿足條件的數據行,然后在排序緩沖區 sort buffer 中完成排序操作,所有不是通過索引直接返回排序結果的排序都叫 FileSort 排序
  2. Using index:通過有序索引順序掃描直接返回有序數據,這種情況即為 using index,不需要額外排序,操作效率高

如果order by字段全部使用升序排序或者降序排序,則都會走索引,但是如果一個字段升序排序,另一個字段降序排序,則不會走索引,explain的extra信息顯示的是Using index, Using filesort,如果要優化掉Using filesort,則需要另外再創建一個索引,如:create index idx_user_age_phone_ad on tb_user(age asc, phone desc);,此時使用select id, age, phone from tb_user order by age asc, phone desc;會全部走索引

總結:

  • 根據排序字段建立合適的索引,多字段排序時,也遵循最左前綴法則
  • 盡量使用覆蓋索引
  • 多字段排序,一個升序一個降序,此時需要注意聯合索引在創建時的規則(ASC/DESC)
  • 如果不可避免出現filesort,大數據量排序時,可以適當增大排序緩沖區大小 sort_buffer_size(默認256k)

group by優化

  • 在分組操作時,可以通過索引來提高效率
  • 分組操作時,索引的使用也是滿足最左前綴法則的

如索引為idx_user_pro_age_stat,則句式可以是select ... where profession order by age,這樣也符合最左前綴法則

limit優化

常見的問題如limit 2000000, 10,此時需要 MySQL 排序前2000000條記錄,但僅僅返回2000000 - 2000010的記錄,其他記錄丟棄,查詢排序的代價非常大。
優化方案:一般分頁查詢時,通過創建覆蓋索引能夠比較好地提高性能,可以通過覆蓋索引加子查詢形式進行優化

例如:

-- 此語句耗時很長
select * from tb_sku limit 9000000, 10;
-- 通過覆蓋索引加快速度,直接通過主鍵索引進行排序及查詢
select id from tb_sku order by id limit 9000000, 10;
-- 下面的語句是錯誤的,因為 MySQL 不支持 in 里面使用 limit
-- select * from tb_sku where id in (select id from tb_sku order by id limit 9000000, 10);
-- 通過連表查詢即可實現第一句的效果,并且能達到第二句的速度
select * from tb_sku as s, (select id from tb_sku order by id limit 9000000, 10) as a where s.id = a.id;

count優化

MyISAM 引擎把一個表的總行數存在了磁盤上,因此執行 count(*) 的時候會直接返回這個數,效率很高(前提是不適用where);
InnoDB 在執行 count(*) 時,需要把數據一行一行地從引擎里面讀出來,然后累計計數。
優化方案:自己計數,如創建key-value表存儲在內存或硬盤,或者是用redis

count的幾種用法:

  • 如果count函數的參數(count里面寫的那個字段)不是NULL(字段值不為NULL),累計值就加一,最后返回累計值
  • 用法:count(*)、count(主鍵)、count(字段)、count(1)
  • count(主鍵)跟count(*)一樣,因為主鍵不能為空;count(字段)只計算字段值不為NULL的行;count(1)引擎會為每行添加一個1,然后就count這個1,返回結果也跟count(*)一樣;count(null)返回0

各種用法的性能:

  • count(主鍵):InnoDB引擎會遍歷整張表,把每行的主鍵id值都取出來,返回給服務層,服務層拿到主鍵后,直接按行進行累加(主鍵不可能為空)
  • count(字段):沒有not null約束的話,InnoDB引擎會遍歷整張表把每一行的字段值都取出來,返回給服務層,服務層判斷是否為null,不為null,計數累加;有not null約束的話,InnoDB引擎會遍歷整張表把每一行的字段值都取出來,返回給服務層,直接按行進行累加
  • count(1):InnoDB 引擎遍歷整張表,但不取值。服務層對于返回的每一層,放一個數字 1 進去,直接按行進行累加
  • count(*):InnoDB 引擎并不會把全部字段取出來,而是專門做了優化,不取值,服務層直接按行進行累加

按效率排序:count(字段) < count(主鍵) < count(1) < count(*),所以盡量使用 count(*)

update優化(避免行鎖升級為表鎖)

InnoDB 的行鎖是針對索引加的鎖,不是針對記錄加的鎖,并且該索引不能失效,否則會從行鎖升級為表鎖。

如以下兩條語句:
update student set no = '123' where id = 1;,這句由于id有主鍵索引,所以只會鎖這一行;
update student set no = '123' where name = 'test';,這句由于name沒有索引,所以會把整張表都鎖住進行數據更新,解決方法是給name字段添加索引,就可以由表鎖變成行鎖。

視圖

視圖(View)是一種虛擬存在的表。視圖中的數據并不在數據庫中實際存在,行和列數據來自定義視圖的查詢中使用的表,并且是在使用視圖時動態生成的。
通俗的講,視圖只保存了查詢的SQL邏輯,不保存查詢結果。所以我們在創建視圖的時候,主要的工作就落在創建這條SQL查詢語句上。

創建視圖

CREATE [ OR REPLACE ] VIEW 視圖名稱[(列名列表)] AS SELECT 語句 [ WITH [ CASCADED | LOCAL ] CHECK OPTION ]

例子: create or replace view stu_wll as select id,name from student where id<=10;

查詢視圖

查看創建視圖語句: SHOW CREATE VIEW 視圖名稱;

查看視圖數據:SELECT*FROM 視圖名稱;
show create view stu_v_1;

修改視圖

方式一:CREATE[OR REPLACE] VIEW 視圖名稱[(列名列表))] AS SELECT 語句[ WITH[ CASCADED | LOCAL ] CHECK OPTION ]

方式二:ALTER VIEW 視圖名稱 [(列名列表)] AS SELECT語句 [WITH [CASCADED | LOCAL] CHECK OPTION]

刪除視圖

DROP VIEW [IF EXISTS] 視圖名稱 [視圖名稱]

視圖檢查選項

當使用WITH CHECK QPTION子句創建視圖時,MySQL會通過視圖檢查正在更改的每個行,例如插入,更新,刪除,以使其符合視圖的定義。MySQL允許基于另一個視圖創建視圖,它還會檢查依賴視圖中的規則以保持一致性。為了確定檢查的范圍,mysql提供了兩個選項:CASCADED 和 LOCAL ,默認值為 CASCADED。

NOTE:如果沒有開檢查選項就不會進行檢查。不同版本是不同含義的,要看版本。

CASCADED

級聯,一旦選擇了這個選項,除了會檢查創建視圖時候的條件,還會檢查所依賴視圖的條件。

比如下面的例子:創建stu_V_l 視圖,id是小于等于 20的。
create or replace view stu_V_l as select id,name from student where id <=20;
再創建 stu_v_2 視圖,20 >= id >=10。
create or replace view stu_v_2 as select id,name from stu_v_1 where id >=10 with cascaded check option;
再創建 stu_v_3 視圖。
create or replace view stu_v_3 as select id,name from stu_v_2 where id<=15;
這條數據能夠成功,stu_v_3 沒有開檢查選項所以不會 去判斷 id 是否小于等于15, 直接檢查 是否滿足 stu_v_2。
insert into stu_v_3 values(17,'Tom');

LOCAL

本地的條件也會檢查,還會向上檢查。在向上找的時候,就要看是否上面開了檢查選項,如果沒開就不檢查。和 CASCADED 的區別就是 CASCADED 不管上面開沒開檢查選項都會進行檢查。

更新及作用

要使視圖可更新,視圖中的行與基礎表中的行之間必須存在一對一的關系。如果視圖包含以下任何一項,則該視圖不可更新

  1. 聚合函數或窗口函數 ( SUM()、MIN()、MAX()、COUNT() 等 )
  2. DISTINCT
  3. GROUP BY
  4. HAVING
  5. UNION 或者UNION ALL

例子: 使用了聚合函數,插入會失敗。
create view stu_v_count as select count(*) from student;
insert into stu_v_count values(10);

作用

視圖不僅可以簡化用戶對數據的理解,也可以簡化他們的操作。那些被經常使用的查詢可以被定義為視圖,從而使得用戶不必為以后的操作每次指定全部的條件。

安全
數據庫可以授權,但不能授權到數據庫特定行和特定的列上。通過視圖用戶只能查詢和修改他們所能見到的數據
數據獨立
視圖可幫助用戶屏蔽真實表結構變化帶來的影響。

總而言之 類似于給表加上了一個外殼,通過這個外殼訪問表的時候,只能按照所設計的方式進行訪問與更新。

存儲過程

存儲過程是事先經過編譯并存儲在數據庫中的一段SQL 語句的集合,調用存儲過程可以簡化應用開發人員的很多工作,減少數據在數據庫和應用服務器之間的傳輸,對于提高數據處理的效率是有好處的。
存儲過程思想上很簡單,就是數據庫SQL 語言層面的代碼封裝與重用。

特點

  1. 封裝
  2. 復用
  3. 可以接收參數,也可以返回數據減少網絡交互,效率提升

創建

CREATE PROCEDURE 存儲過程名稱( [參數列表] ) BEGINSQL 語句 END;

NOTE: 在命令行中,執行創建存儲過程的SQL時,需要通過關鍵字delimiter 指定SQL語句的結束符。默認是 分號作為結束符。

delimiter $ ,則 $ 符作為結束符。

調用

CALL 名稱 ( [參數])

查看

查詢指定數據庫的存儲過程及狀態信息

SELECT* FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_SCHEMA = 'xxx'

存儲過程名稱;–查詢某個存儲過程的定義

SHOW CREATE PROCEDURE

刪除

DROP PROCEDURE [ IFEXISTS ] 存儲過程名稱

游標

游標(CURSOR)是用來存儲查詢結果集的數據類型,在存儲過程和函數中可以使用游標對結果集進行循環的處理。游標的使用包括游標的聲明、OPEN、FETCH和CLOSE,其語法分別如下。

聲明游標:
DECLARE 游標名稱 CURSOR FOR 查詢語句

打開游標:
OPEN 游標名稱

獲取游標記錄:
FETCH 游標名稱INTO變量[變量]

條件處理程序:
條件處理程序(Handler)可以用來定義在流程控制結構執行過程中遇到問題時相應的處理步驟。具體語法為:

DECLARE handler action HANDLER FOR condition value L condition value]…statement

handler_action CONTINUE:繼續執行當前程序

EXIT:終止執行當前程序

condition_value :

SQLSTATE sqlstate_value:狀態碼,如02000

SQLWARNING:所有以01開頭的SQLSTATE代碼的簡寫

NOT FOUND:所有以02開頭的SQLSTATE代碼的簡寫

SQLEXCEPTION:所有沒有被SQLWARNING或NOT FOUND捕獲的SQLSTATE代碼的簡寫

例子:

NOTE:要先聲明普通變量,再申請游標。

要求:
根據傳入的參數uage,來查詢用戶表tb_user中,所有的用戶年齡小于等于uage的用戶姓名(name)和專業(profession),并將用戶的姓名和專業插入到所創建的一張新表(id,name,profession)中。

create procedure p1l(in uage int)begindeclare uname varchar(100); decLare upro varchar(100);declare u_cursor cursor for select name,profession from tb_user where age <= uage; 當 條件處理程序的處理的狀態碼為02000的時候,就會退出。declare exit handler for SQLSTATE '02000'close u_cursor;drop table if exists tb_user_pro; create table if not exists tb_user_pro(id int primary key auto_increment, name varchar(100), profession varchar(100));open u_cursor; while true do fetch u_cursor into uname,Upro; insert into tb_user_pro values(null,uname,Upro); end while;close u_cursor; end;

觸發器

介紹
觸發器是與表有關的數據庫對象,指在insert/update/delete之前或之后,觸發并執行觸發器中定義的SQL語句集合。觸發器的這種特性可以協助應用在數據庫端確保數據的完整性,日志記錄,數據校驗等操作。
使用別名OLD和NEW來引用觸發器中發生變化的記錄內容,這與其他的數據庫是相似的。現在觸發器還只支持行級觸發(比如說 一條語句影響了 5 行 則會被觸發 5 次),不支持語句級觸發(比如說 一條語句影響了 5 行 則會被觸發 1 次)。

觸發器類型NEW 和 OLD
INSERTNEW 表示將要或者已經新增的數據
UPDATEOLD表示修改之前的數據,NEW表示將要或已經修改后的數據
DELETEOLD表示將要或者已經刪除的數據

鎖是計算機協調多個進程或線程并發訪問某一資源的機制。在數據庫中,除傳統的計算資源(CPU、RAM、I/O)的爭用以外,數據也是一種供許多用戶共享的資源。如何保證數據并發訪問的一致性、有效性是所有數據庫必須解決的一個問題,鎖沖突也是影響數據庫并發訪問性能的一個重要因素。從這個角度來說,鎖對數據庫而言顯得尤其重要,也更加復雜。

NOTE : 針對事物才有加鎖的意義。

分類:MySQL中的鎖,按照鎖的粒度分,分為以下三類:

  1. 全局鎖:鎖定數據庫中的所有表。
  2. 表級鎖:每次操作鎖住整張表。
  3. 行級鎖:每次操作鎖住對應的行數據。

全局鎖:

全局鎖就是對整個數據庫實例加鎖,加鎖后整個實例就處于只讀狀態,后續的DML的寫語句,DDL語句,已經更新操作的事務提交語句都將被阻塞。
其典型的使用場景是做全庫的邏輯備份,對所有的表進行鎖定,從而獲取一致性視圖,保證數據的完整性.

表鎖:

表級鎖,每次操作鎖住整張表。鎖定粒度大,發生鎖沖突的概率最高,并發度最低。應用在MyISAM、InnoDB、BDB等存儲引擎中。

對于表級鎖,主要分為以下三類:

  1. 表鎖:對于表鎖,分為兩類:1.表共享讀鎖(read lock)所有的事物都只能讀(當前加鎖的客戶端也只能讀,不能寫),不能寫 2.表獨占寫鎖(write lock),對當前加鎖的客戶端,可讀可寫,對于其他的客戶端,不可讀也不可寫。
    讀鎖不會阻塞其他客戶端的讀,但是會阻塞寫。寫鎖既會阻塞其他客戶端的讀,又會阻塞其他客戶端的寫。
  2. 元數據鎖(meta data lock,MDL),MDL加鎖過程是系統自動控制,無需顯式使用,在訪問一張表的時候會自動加上。MDL鎖主要作用是維護表元數據的數據一致性,在表上有活動事務的時候,不可以對元數據進行寫入操作。在MySQL5.5中引入了MDL,當對一張表進行增刪改查的時候,加MDL讀鎖(共享);當對表結構進行變更操作的時候,加MDL寫鎖(排他)。
  3. 意向鎖: 為了避免DML在執行時,加的行鎖與表鎖的沖突,在InnoDB中引入了意向鎖,使得表鎖不用檢查每行數據是否加鎖,使用意向鎖來減少表鎖的檢查。
    一個客戶端對某一行加上了行鎖,那么系統也會對其加上一個意向鎖,當別的客戶端來想要對其加上表鎖時,便會檢查意向鎖是否兼容,若是不兼容,便會阻塞直到意向鎖釋放。

意向鎖兼容性:

  1. 意向共享鎖(IS):與表鎖共享鎖(read)兼容,與表鎖排它鎖(write)互斥。
  2. 意向排他鎖(lX):與表鎖共享鎖(read)及排它鎖(write)都互斥。意向鎖之間不會互斥。

行鎖:

行級鎖,每次操作鎖住對應的行數據。鎖定粒度最小,發生鎖沖突的概率最低,并發度最高。應用在InnoDB存儲引擎中。
InnoDB的數據是基于索引組織的,行鎖是通過對索引上的索引項加鎖來實現的,而不是對記錄加的鎖。對于行級鎖,主要分為以下三類:

  1. 行鎖(Record Lock):鎖定單個行記錄的鎖,防止其他事務對此行進行update和delete。在RC(read commit )、RR(repeat read)隔離級別下都支持。
  2. 間隙鎖(GapLock):鎖定索引記錄間隙(不含該記錄),確保索引記錄間隙不變,防止其他事務在這個間隙進行insert,產生幻讀。在RR隔離級別下都支持。比如說 兩個臨近葉子節點為 15 23,那么間隙就是指 [15 , 23],鎖的是這個間隙。
  3. 臨鍵鎖(Next-Key Lock):行鎖和間隙鎖組合,同時鎖住數據,并鎖住數據前面的間隙Gap。在RR隔離級別下支持。

InnoDB實現了以下兩種類型的行鎖:

  1. 共享鎖(S):允許一個事務去讀一行,阻止其他事務獲得相同數據集的排它鎖。
  2. 排他鎖(X):允許獲取排他鎖的事務更新數據,阻止其他事務獲得相同數據集的共享鎖和排他鎖。
SQL行鎖類型說明
insert排他鎖自動加鎖
update排他鎖自動加鎖
delete排他鎖自動加鎖
select不加任何鎖
select lock in share mode排他鎖需要手動在SELECT之后加LOCK IN SHARE MODE
select for update排他鎖需要手動在SELECT之后加FOR UPDATE

行鎖 - 演示

默認情況下,InnoDB在REPEATABLE READ事務隔離級別運行,InnoDB使用next-key 鎖進行搜索和索引掃描,以防止幻讀。

  1. 針對唯一索引進行檢索時,對已存在的記錄進行等值匹配時,將會自動優化為行鎖。
  2. InnoDB的行鎖是針對于索引加的鎖,不通過索引條件檢索數據,那么InnoDB將對表中的所有記錄加鎖,此時就會升級為表鎖。

間隙鎖/臨鍵鎖-演示

默認情況下,InnoDB在REPEATABLE READ事務隔離級別運行,InnoDB使用next-key 鎖進行搜索和索引掃描,以防止幻讀。

  1. 索引上的等值查詢(唯一索引),給不存在的記錄加鎖時,優化為間隙鎖。
  2. 索引上的等值查詢(普通索引),向右遍歷時最后一個值不滿足查詢需求時,next-key lock 退化為間隙鎖。
  3. 索引上的范圍查詢(唯一索引)–會訪問到不滿足條件的第一個值為止。

注意:間隙鎖唯一目的是防止其他事務插入間隙。間隙鎖可以共存,一個事務采用的間隙鎖不會阻止另一個事務在同一間隙上采用間隙鎖。

InnoDB 引擎

邏輯存儲結構

表空間(ibd文件),一個mysql實例可以對應多個表空間,用于存儲記錄、索引等數據。

段,分為數據段(Leaf node segment)、索引段(Non-leaf node segment)、回滾段(Rollback segment),InnoDB是索引組織表,數據段就是B+樹的葉子節點,索引段即為B+樹的非葉子節點。段用來管理多個Extent(區)。

區,表空間的單元結構,每個區的大小為1M。默認情況下,InnoDB存儲引擎頁大小為16K,即一個區中一共有64個連續的頁。

頁,是InnoDB存儲引擎磁盤管理的最小單元,每個頁的大小默認為16KB。為了保證頁的連續性,InnoDB存儲引擎每從磁盤申請4-5個區。一頁包含若干行。

行,InnoDB存儲引擎數據是按進行存放的。

架構

![images]artic.png

Buffer Pool:緩沖池是主內存中的一個區域,里面可以緩存磁盤上經常操作的真實數據,在執行增刪改查操作時,先操作緩沖池中的數據(若緩沖池沒有數據,則從磁盤加載并緩存),然后再以一定頻率刷新到磁盤,從而減少磁盤I0,加快處理速度。

![images]artic2.png
![images]artic3.png
![images]artic4.png
![images]artic5.png

磁盤架構:
![images]artic6.png
![images]artic7.png
![images]artic8.png

InnoDB的整個體系結構為:

當業務操作的時候直接操作的是內存緩沖區,如果緩沖區當中沒有數據,則會從磁盤中加載到緩沖區,增刪改查都是在緩沖區的,后臺線程以一定的速率刷新到磁盤。

事務原理

事務是一組操作的集合,它是一個不可分割的工作單位,事務會把所有的操作作為一個整體一起向系統提交或撤銷操作請求,即這些操作要么同時成功,要么同時敗。具有ACID四大特征。

原子性,一致性,持久性這三大特性由 redo log 和 undo log 日志來保證的。
隔離性 是由鎖機制和MVCC保證的。

redo log:

重做日志,記錄的是事務提交時數據頁的物理修改,是用來實現事務的持久性。
該日志文件由兩部分組成:重做日志緩沖(redo log buffer)以及重做日志文件(redo log file),前者是在內存中,后者在磁盤中。當事務提交之后會把所有修改信息都存到該日志文件中,用于在刷新臟頁到磁盤,發生錯誤時,進行數據恢復使用。

個人理解: 事物每次提交的時候都會將數據刷到redo log中而不是直接將buffer pool中的數據直接刷到磁盤中(ibd文件中),是因為redo log 是順序寫,性能處理的夠快,直接刷到ibd中,是隨機寫,性能慢。所以臟頁是在下一次讀的時候,或者后臺線程采用一定的機制進行刷盤到ibd中。

undo log:
回滾日志,用于記錄數據被修改前的信息,作用包含兩個:提供回滾和MVCC(多版本并發控制)。
undo log和redo log記錄物理日志不一樣,它是邏輯日志。可以認為當delete一條記錄,undo log中會記錄一條對應的insert記錄,反之亦然,當update一條記錄時,它記錄一條對應相反的update記錄。當執行rollback時,就可以從undo log中的邏輯記錄讀取到相應的內容并進行回滾。

Undo log銷毀:undo log在事務執行時產生,事務提交時,并不會立即刪除undo log,因為這些日志可能還用于MVCC。
Undo log存儲:undo log采用段的方式進行管理和記錄,存放在前面介紹的rollback segment回滾段中,內部包含1024個undo log segment。

MVCC

當前讀:

讀取的是記錄的最新版本,讀取時還要保證其他并發事務不能修改當前記錄,會對讀取的記錄進行加鎖。對于我們日常的操作,如:

  • select…lock in share mode(共享鎖)。
  • select……for update、update、insert、delete(排他鎖)都是一種當前讀。

快照讀:

簡單的select(不加鎖)就是快照讀,快照讀,讀取的是記錄數據的可見版本,有可能是歷史數據,不加鎖,是非阻塞讀。

  • Read Committed:每次select,都生成一個快照讀。
  • Repeatable Read:開啟事務后第一個select語句才是快照讀的地方。
  • Serializable:快照讀會退化為當前讀。

MVCC:

全稱Multi-Version Concurrency Control,多版本并發控制。指維護一個數據的多個版本,使得讀寫操作沒有沖突,快照讀為MySQL實現MVCC提供了一個非阻塞讀功能。MVCC的具體實現,還需要依賴于數據庫記錄中的三個隱式字段、undo log日志、readView。

MVCC 實現原理:

有三個隱藏的字段:

![images]MVCC.png

undo log回滾日志,在insert、update、delete的時候產生的便于數據回滾的日志。
當insert的時候,產生的undo log日志只在回滾時需要,在事務提交后,可被立即刪除。
而update、delete的時候,產生的undo log日志不僅在回滾時需要,在快照讀時也需要,不會立即被刪除。

undo log 版本鏈:

undo log日志會記錄原來的版本的數據,因為是通過undo log 日志進行回滾的。

![images]MVCCList.png

如何確定返回哪一個版本 這是由read view決定返回 undo log 中的哪一個版本。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-d48Fi13f-1692120469805)(readview0.png]

RC隔離級別下,在事務中每一次執行快照讀時生成ReadView。
RR隔離級別下,在事務中第一次執行快照讀時生成ReadView,后續會復用。

https://www.bilibili.com/video/BV1Kr4y1i7ru?p=145&spm_id_from=pageDriver&vd_source=bbc04b831b54029788a178a7c2e9ae20

MVCC 靠 隱藏字段 , undo log 版本鏈 , read view 實現的。

  • 原子性-undo log
  • 持久性-redo log
  • 一致性-undo log + redo log
  • 隔離性-鎖 + MVCC

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-ptiHcKQ4-1692120469805)(readview.png]

數據類型

整型

類型名稱取值范圍大小
TINYINT-128?1271個字節
SMALLINT-32768?327672個宇節
MEDIUMINT-8388608?83886073個字節
INT (INTEGHR)-2147483648?21474836474個字節
BIGINT-9223372036854775808?92233720368547758078個字節

無符號在數據類型后加 unsigned 關鍵字。

浮點型

類型名稱說明存儲需求
FLOAT單精度浮點數4 個字節
DOUBLE雙精度浮點數8 個字節
DECIMAL (M, D),DEC壓縮的“嚴格”定點數M+2 個字節

日期和時間

類型名稱日期格式日期范圍存儲需求
YEARYYYY1901 ~ 21551 個字節
TIMEHH:MM:SS-838:59:59 ~ 838:59:593 個字節
DATEYYYY-MM-DD1000-01-01 ~ 9999-12-33 個字節
DATETIMEYYYY-MM-DD HH:MM:SS1000-01-01 00:00:00 ~ 9999-12-31 23:59:598 個字節
TIMESTAMPYYYY-MM-DD HH:MM:SS1980-01-01 00:00:01 UTC ~ 2040-01-19 03:14:07 UTC4 個字節

字符串

類型名稱說明存儲需求
CHAR(M)固定長度非二進制字符串M 字節,1<=M<=255
VARCHAR(M)變長非二進制字符串L+1字節,在此,L< = M和 1<=M<=255
TINYTEXT非常小的非二進制字符串L+1字節,在此,L<2^8
TEXT小的非二進制字符串L+2字節,在此,L<2^16
MEDIUMTEXT中等大小的非二進制字符串L+3字節,在此,L<2^24
LONGTEXT大的非二進制字符串L+4字節,在此,L<2^32
ENUM枚舉類型,只能有一個枚舉字符串值1或2個字節,取決于枚舉值的數目 (最大值為65535)
SET一個設置,字符串對象可以有零個或 多個SET成員1、2、3、4或8個字節,取決于集合 成員的數量(最多64個成員)

二進制類型

類型名稱說明存儲需求
BIT(M)位字段類型大約 (M+7)/8 字節
BINARY(M)固定長度二進制字符串M 字節
VARBINARY (M)可變長度二進制字符串M+1 字節
TINYBLOB (M)非常小的BLOBL+1 字節,在此,L<2^8
BLOB (M)小 BLOBL+2 字節,在此,L<2^16
MEDIUMBLOB (M)中等大小的BLOBL+3 字節,在此,L<2^24
LONGBLOB (M)非常大的BLOBL+4 字節,在此,L<2^32

權限一覽表

具體權限的作用詳見官方文檔

GRANT 和 REVOKE 允許的靜態權限

PrivilegeGrant Table ColumnContext
ALL [PRIVILEGES]Synonym for “all privileges”Server administration
ALTERAlter_privTables
ALTER ROUTINEAlter_routine_privStored routines
CREATECreate_privDatabases, tables, or indexes
CREATE ROLECreate_role_privServer administration
CREATE ROUTINECreate_routine_privStored routines
CREATE TABLESPACECreate_tablespace_privServer administration
CREATE TEMPORARY TABLESCreate_tmp_table_privTables
CREATE USERCreate_user_privServer administration
CREATE VIEWCreate_view_privViews
DELETEDelete_privTables
DROPDrop_privDatabases, tables, or views
DROP ROLEDrop_role_privServer administration
EVENTEvent_privDatabases
EXECUTEExecute_privStored routines
FILEFile_privFile access on server host
GRANT OPTIONGrant_privDatabases, tables, or stored routines
INDEXIndex_privTables
INSERTInsert_privTables or columns
LOCK TABLESLock_tables_privDatabases
PROCESSProcess_privServer administration
PROXYSee proxies_priv tableServer administration
REFERENCESReferences_privDatabases or tables
RELOADReload_privServer administration
REPLICATION CLIENTRepl_client_privServer administration
REPLICATION SLAVERepl_slave_privServer administration
SELECTSelect_privTables or columns
SHOW DATABASESShow_db_privServer administration
SHOW VIEWShow_view_privViews
SHUTDOWNShutdown_privServer administration
SUPERSuper_privServer administration
TRIGGERTrigger_privTables
UPDATEUpdate_privTables or columns
USAGESynonym for “no privileges”Server administration

GRANT 和 REVOKE 允許的動態權限

PrivilegeContext
APPLICATION_PASSWORD_ADMINDual password administration
AUDIT_ABORT_EXEMPTAllow queries blocked by audit log filter
AUDIT_ADMINAudit log administration
AUTHENTICATION_POLICY_ADMINAuthentication administration
BACKUP_ADMINBackup administration
BINLOG_ADMINBackup and Replication administration
BINLOG_ENCRYPTION_ADMINBackup and Replication administration
CLONE_ADMINClone administration
CONNECTION_ADMINServer administration
ENCRYPTION_KEY_ADMINServer administration
FIREWALL_ADMINFirewall administration
FIREWALL_EXEMPTFirewall administration
FIREWALL_USERFirewall administration
FLUSH_OPTIMIZER_COSTSServer administration
FLUSH_STATUSServer administration
FLUSH_TABLESServer administration
FLUSH_USER_RESOURCESServer administration
GROUP_REPLICATION_ADMINReplication administration
GROUP_REPLICATION_STREAMReplication administration
INNODB_REDO_LOG_ARCHIVERedo log archiving administration
NDB_STORED_USERNDB Cluster
PASSWORDLESS_USER_ADMINAuthentication administration
PERSIST_RO_VARIABLES_ADMINServer administration
REPLICATION_APPLIERPRIVILEGE_CHECKS_USER for a replication channel
REPLICATION_SLAVE_ADMINReplication administration
RESOURCE_GROUP_ADMINResource group administration
RESOURCE_GROUP_USERResource group administration
ROLE_ADMINServer administration
SESSION_VARIABLES_ADMINServer administration
SET_USER_IDServer administration
SHOW_ROUTINEServer administration
SYSTEM_USERServer administration
SYSTEM_VARIABLES_ADMINServer administration
TABLE_ENCRYPTION_ADMINServer administration
VERSION_TOKEN_ADMINServer administration
XA_RECOVER_ADMINServer administration

圖形化界面工具

  • Workbench(免費): http://dev.mysql.com/downloads/workbench/
  • navicat(收費,試用版30天): https://www.navicat.com/en/download/navicat-for-mysql
  • Sequel Pro(開源免費,僅支持Mac OS): http://www.sequelpro.com/
  • HeidiSQL(免費): http://www.heidisql.com/
  • phpMyAdmin(免費): https://www.phpmyadmin.net/
  • SQLyog: https://sqlyog.en.softonic.com/

安裝

小技巧

  1. 在SQL語句之后加上\G會將結果的表格形式轉換成行文本形式
  2. 查看Mysql數據庫占用空間:
SELECT table_schema "Database Name", SUM(data_length + index_length) / (1024 * 1024) "Database Size in MB"
FROM information_schema.TABLES
GROUP BY table_schema;

參考文獻

https://dhc.pythonanywhere.com/entry/share/?key=3ad29aad765a2b98b2b2a745d71bef715507ee9db8adbec98257bac0ad84cbe4#h1-u6743u9650u4E00u89C8u8868
這篇筆記是在別人的基礎上完善而來,感謝B站的黑馬程序員up主,也感謝路途博客。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/40188.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/40188.shtml
英文地址,請注明出處:http://en.pswp.cn/news/40188.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

php正則替換文章的圖片

要使用正則表達式替換文章中的圖片鏈接&#xff0c;可以按照以下步驟進行操作&#xff1a; 1. 獲取文章內容&#xff1a;首先&#xff0c;你需要獲取包含圖片鏈接的文章內容。你可以從文件中讀取文章&#xff0c;或者從數據庫中檢索文章內容。 2. 使用正則表達式匹配圖片鏈接…

JAVA編程學習筆記

常用代碼、特定函數、復雜概念、特定功能……在學習編程的過程中你會記錄下哪些內容&#xff1f;快來分享你的筆記&#xff0c;一起切磋進步吧&#xff01; 一、常用代碼 在java編程中常用需要儲備的就是工具類。包括封裝的時間工具類。http工具類&#xff0c;加解密工具類&am…

day17 | 110.平衡二叉樹、257. 二叉樹的所有路徑、404.左葉子之和

目錄&#xff1a; 解題及思路學習 110.平衡二叉樹 https://leetcode.cn/problems/balanced-binary-tree/ 給定一個二叉樹&#xff0c;判斷它是否是高度平衡的二叉樹。 本題中&#xff0c;一棵高度平衡二叉樹定義為&#xff1a; 一個二叉樹每個節點 的左右兩個子樹的高度差…

Linux學習之firewallD

systemctl status firewalld.service查看一下firewalld服務的狀態&#xff0c;發現狀態是inactive (dead)。 systemctl start firewalld.service啟動firewalld&#xff0c;systemctl status firewalld.service查看一下firewalld服務的狀態&#xff0c;發現狀態是active (runni…

okcc呼叫系統導入呼叫名單/客戶資料的數量上限,okcc通話聲音小有哪幾種處理辦法?

系統導入呼叫名單/客戶資料的數量上限 呼叫名單一次最多十萬 客戶資料一次最多五萬 通話聲音小有哪幾種處理辦法&#xff1f; 1、IP話機&#xff1a;通過話機上的音量調節按鈕來進行調節。 2、模擬話機&#xff1a;修改語音網關上的增益來實現。 “ 往IP增益”表示電話呼入…

stable diffusion 運行時報錯: returned non-zero exit status 1.

運行sh run.sh安裝stable diffusion時報錯&#xff1a;ImportError: cannot import name builder from google.protobuf.internal (stable-diffusion-webui/venv/lib/python3.8/site-packages/google/protobuf/internal/__init__.py) 原因&#xff1a;python版本過低&#xff0…

ubuntu16.04制作本地apt源離線安裝

一、首先在有外網的服務器安裝需要安裝的軟件&#xff0c;打包deb軟件。 cd /var/cache/apt zip -r archives.zip archives sz archives.zip 二、在無外網服務器上傳deb包&#xff0c;并配置apt源。 1、上傳deb包安裝lrzsz、unzip 用ftp軟件連接無外網服務器協議選擇sftp…

股票交易c接口包含哪些調用函數?

股票交易的C接口中可能包含多個調用函數&#xff0c;具體的調用函數取決于所使用的接口規范和交易所的要求。接下來看看下面是一些可能常見的股票交易C接口調用函數的示例&#xff1a; 1. 連接函數&#xff08;Connect&#xff09;&#xff1a;用于與交易所建立網絡連接。 2.…

CSS(JavaEE初階系列14)

目錄 前言&#xff1a; 1.CSS是什么 1.1CSS基本語法 2.引入樣式 2.1內部樣式表 2.2行內樣式表 2.3外部樣式 3.選擇器 3.1選擇器的種類 3.1.1基礎選擇器 3.1.2復合選擇器 4.常用元素屬性 4.1字體屬性 4.2文本屬性 4.3背景屬性 4.4圓角矩形 4.5元素的顯示模式 4…

?LeetCode解法匯總2682. 找出轉圈游戲輸家

目錄鏈接&#xff1a; 力扣編程題-解法匯總_分享記錄-CSDN博客 GitHub同步刷題項目&#xff1a; https://github.com/September26/java-algorithms 原題鏈接&#xff1a; 力扣&#xff08;LeetCode&#xff09;官網 - 全球極客摯愛的技術成長平臺 描述&#xff1a; n 個朋友…

【Leetcode】84.柱狀圖中最大的矩形(Hard)

一、題目 1、題目描述 給定 n n n 個非負整數,用來表示柱狀圖中各個柱子的高度。每個柱子彼此相鄰,且寬度為 1 。 求在該柱狀圖中,能夠勾勒出來的矩形的最大面積。 示例1: 輸入:heights = [2,1,5,6,2,3] 輸出:10 解釋:最大的矩形為圖中紅色區域,面積為 10示例2:…

學習Vue:Vue Router的集成與基本配置

在Vue.js中&#xff0c;路由與導航是構建單頁應用程序&#xff08;SPA&#xff09;的關鍵概念。Vue Router是Vue.js官方提供的路由管理庫&#xff0c;它允許您輕松地實現頁面之間的切換、嵌套路由和參數傳遞。在本文中&#xff0c;我們將深入了解Vue Router的集成和基本配置。 …

Stephen Wolfram:那么…ChatGPT 在做什么,為什么它有效呢?

So … What Is ChatGPT Doing, and Why Does It Work? 那么…ChatGPT在做什么&#xff0c;為什么它有效呢&#xff1f; The basic concept of ChatGPT is at some level rather simple. Start from a huge sample of human-created text from the web, books, etc. Then train…

IDA遠程調試真機app

IDA遠程調試真機app 第一步&#xff1a;啟動 android_server&#xff0c;并修改端口 # 啟動android_server ./android_server -p31928第二步&#xff1a;端口轉發、掛起程序 # 端口轉發adb forward tcp:31928 tcp:31928# 掛起程序 adb shell am start -D -n com.qianyu.antid…

Hyper-V增加橋接網絡設置(其他方式類同)

點擊連接到的服務器&#xff0c;右單擊或者右邊點擊“虛擬交換機管理器” 選擇網絡種類 配置虛擬交換機信息 外部網絡選擇物理機網卡設備

Linux中UDP服務端和客戶端

1 服務端代碼 #include <stdio.h> #include <head.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h>#define PORT 6666 //端口號&#xff1a;1024~49191 #define IP "192.168.1.110"//"192.168.122.1…

中國“諾貝爾獎”未來科學大獎公布2023年獲獎名單

未來科學大獎委員會于8月16日公布2023年獲獎名單。柴繼杰、周儉民因發現抗病小體并闡明其結構和在抗植物病蟲害中的功能做出的開創性工作獲得“生命科學獎”&#xff0c;趙忠賢、陳仙輝因對高溫超導材料的突破性發現和對轉變溫度的系統性提升所做出的開創性貢獻獲得“物質科學獎…

突破網絡編程1024限制的方法(修改配置文件)

文章目錄 概述修改linux配置相關命令步驟1. 打開終端2. 使用sudo權限編輯文件3. 添加資源限制配置4. 保存和退出5. 重啟系統或重新登錄 其他方法1. 使用事件驅動的框架2. 使用連接池3. 負載均衡4. 使用線程池和進程池5. 升級操作系統設置6. 使用專業的高性能服務器7. 分布式架構…

深入源碼分析kubernetes informer機制(三)Resync

[閱讀指南] 這是該系列第三篇 基于kubernetes 1.27 stage版本 為了方便閱讀&#xff0c;后續所有代碼均省略了錯誤處理及與關注邏輯無關的部分。 文章目錄 為什么需要resyncresync做了什么 為什么需要resync 如果看過上一篇&#xff0c;大概能了解&#xff0c;client數據主要通…

1、基于 CentOS 7 構建 LVS-DR 群集。 2、配置nginx負載均衡

一、基于CentOS7和、構建LVS-DR群集 準備四臺虛擬機 ip作用192.168.27.150客戶端192.168.27.151LVS192.168.27.152RS192.168.27.152RS 關閉防火墻 [rootlocalhost ~]# systemctl stop firewalld安裝ifconfig yum install net-tools.x86_64 -y1、DS上 1.1 配置LVS虛擬IP …