SQL注释:
-- 单行注释,-- 后一定有空格;#单行注释
/*
多行注释
.....
*/
使用SQL时刻注意的思想:
定义数据库对象(数据库,表,字段)
功能 | SQL |
---|---|
查看所有数据库 | show databases |
创建数据库 | create database [if not exists] mydb [charset=utf8]; |
选择数据库 | use mydb; |
删除数据库 | drop database [if exists] mydb; |
修改数据库编码 | alter table mydb character set utf8; |
功能 | SQL |
---|---|
创建表 | create table [if not exists] tableName(字段1 类型[(宽度)] [约束条件] [comment '字段说明'],字段2 类型[(宽度)] [约束条件] [comment '字段说明'])charset=utf8; 创建临时表create temporary table tableName as select … |
查看当前数据库所有表名称 | show tables; |
查看指定表的创建语句 | show create table tableName; |
查看表结构 | desc tableName; |
删除表 | drop table tableName; |
修改表结构 | alter table tableName add 列名 类型(长度) [约束]; |
alter table tableName modify 列名 新数据类型(长度) [约束]; |
|
修改列名称和类型 | alter table tableName change 旧列名 新列名 类型(长度) [约束]; |
删除表字段 | alter table tableName drop 删除列名; |
修改表名 | rename table 表名 to 新表名; |
-- 创建表
create table [if not exists] tableName(
字段1 类型[(宽度)] [约束条件] [comment '字段说明'],
字段2 类型[(宽度)] [约束条件] [comment '字段说明'],
)charset=utf8;
数据类型
1)整数类型:tinyint,smallint,mediumint,int,bigint 。默认有符号,可在数值类型后面加入unsigned指定无符号
2)浮点数:float,double,decimal(m,n)-m个有效位小数保留n位
3)日期类型:date(年月日),datetime(年月日时分秒),year,time,timestamp(自动填充当前时间)
4)字符串类型:char(m),varchar(m),text(文本数据),longtext,blob(二进制数据)
MySQL约束
约束是作用于表中字段的规则,用于限制存储在表中的数据,作用是保证数据库中数据的正确、有效性和完整性。
primary key
):一个列或者多个列的组合,值能唯一的标识表中的每一行。特点唯一+非空-- 创建表定义字段时指定主键
create table tableName (
<字段名> <数据类型> primary key,
<字段名> <数据类型>
....)charset=utf8;
-- 创建表定义字段后指定主键
create table tableName (
<字段名> <数据类型>,
<字段名> <数据类型>
....
[constraint <约束名>] primary key (字段1,字段2,...) ]
)charset=utf8;
-- 修改表结构时添加主键
alter table tableName add primary key (字段名,字段2,...);
-- 删除主键
alter table tableName drop primary key;
auto_increment
):给主键列添加自增长约束,用户不输入数据自动赋值delete
再插入数据自增长字段从断点开始;truncate
自增长字段值从1开始
-- 创建表添加自增长约束
create table tableName (
<字段名> <数据类型> primary key auto_increment,
<字段名> <数据类型>
....)charset=utf8;
-- 创建表时添加自增长约束并指定自增长开始值
create table tableName (
<字段名> <数据类型> primary key auto_increment,
<字段名> <数据类型>
....)auto_increment=100;
-- 创建表后修改自增长字段开始值
alter table tableName auto_increment=100;
not null
):指定字段值非空-- 创建表时指定
create table tableName (
<字段名> <数据类型> primary key auto_increment,
<字段名> <数据类型> not null
....)charset=utf8;
-- 修改表结构指定
alter table tableName modify 字段名 类型 not null;
-- 删除非空约束
alter table tableName drop 字段名 类型;
unique
):说明字段取值唯一性,可以为NULL(NULL和任何值包括自己不相同)-- 创建表时指定
create table tableName (
<字段名> <数据类型> primary key auto_increment,
<字段名> <数据类型> unique
....)charset=utf8;
-- 修改表结构指定
alter table tableName add constraint 约束名 unique(列名);
-- 删除唯一约束
alter table tableName drop index 唯一约束名;
default
):指定某列的默认值-- 创建表时指定
create table tableName (
<字段名> <数据类型> primary key auto_increment,
<字段名> <数据类型> default <默认值>
....)charset=utf8;
-- 修改表结构添加默认值
alter table tableName modify 列名 类型 default <默认值>;
-- 删除默认约束
alter table tableName modify 列名 类型 default NULL;
zerofill
):插入数据时数值类型字段值小于定义的长度会在值前面补上0,默认长度int(10)-- 创建表时指定
create table tableName (
<字段名> <数据类型> zerofill,
....)charset=utf8;
-- 删除零填充约束
alter table tableName modify 列名 类型;
foreign key
):建立主表与从表的关联关系(主表主键列控制从表外键列,主表主键没有的数据从表添加不了),主表数据被从表依赖时不可随便删除,从表可随便删除,保证数据一致性和完整性。-- 创建表时指定
create table tableName (
<字段名> <数据类型>,
<字段名> <数据类型>,
....
[constraint <约束名>] foreign key (字段[,字段2,...]) references <主表名> (主键列[,主键列2,...])
)charset=utf8;
-- 修改表结构添加外键约束(多对多关系要创建中间表作为从表,其他两张表都是主表)
alter table tableName add constraint <约束名> foreign key (字段[,字段2,...]) references <主表名> (主键列[,主键列2,...]);
-- 删除外键约束
alter table tableName drop foreign key 外键约束名;
父表删除/更新行为:
行为 | 说明 |
---|---|
NO ACTION | 当在父表中删除/更新对应记录时,首先检查该记录是否有对应外键,如果有则不允许删除/更新。 (与 RESTRICT 一致) 默认行为 |
RESTRICT | 当在父表中删除/更新对应记录时,首先检查该记录是否有对应外键,如果有则不允许删除/更新。 (与 NO ACTION 一致) 默认行为 |
CASCADE | 当在父表中删除/更新对应记录时,首先检查该记录是否有对应外键,如果有,则也删除/更新外键在子表中的记录。 |
SET NULL | 当在父表中删除对应记录时,首先检查该记录是否有对应外键,如果有则设置子表中该外键值为null(这就要求该外键允许取null)。 |
SET DEFAULT | 父表有变更时,子表将外键列设置成一个默认的值 (Innodb不支持) |
-- 语法(更新和删除添加cascade行为)
ALTER TABLE 表名 ADD CONSTRAINT 外键名称 FOREIGN KEY (外键字段) REFERENCES 主表名 (主表字段名) ON UPDATE CASCADE ON DELETE CASCADE;
check
):保证字段值输入按照表建立者设定的规则。mysql 8.0.16版本及以上create table tableName (
<字段名> <数据类型> check(字段名 >0 && 字段名 < 100),
<字段名> <数据类型>,
....
)charset=utf8;
insert into tableName (列1,列2,...) values (值1,值2,...);
insert into tableName values (值1,值2,...),(值3,值4,...),(值5,值6,...);
update tableName set 字段名1=值1,字段名2=值2,...where 条件;
--删除表数据(所有数据),只删除内容,保留表结构再插入数据自增长字段从断点开始
delete from tableName [where 条件];
--清空表数据,保留表结构,自增长字段从1开始
truncate table tableName; | truncate tableName;
-- 删除数据和表结构
drop table tableName;
-- 基本语法
select [distinct] --distinct *去除重复行;distinct 字段名 去除重复列
字段名1 [as 别名1],
字段名2 别名2,...
from <表名或视图名> [别名],<表名或视图名> [别名]...
[where where_contition] -- 分组前过滤,不能对聚合函数进行判断
[group by <分组字段>]-- 分组字段列表,可以对聚合函数进行判断
[having where_contiton] -- 分组后过滤条件
[order by <排序字段1>[desc],<排序字段2>,... [desc]] -- 排序字段列表,默认升序,desc降序
[limit m,n] -- 查询结果指定记录数,从第m+1条查询n条数据
执行顺序: from指定表——>where筛选——>group by分组——>having分组结果筛选——>select选择字段(有分组只能选择分组字段和字段聚合结果)——>order by排序——>limit指定显示行数
分组之后,查询的字段一般为聚合函数和分组字段,查询其他字段无任何意义
where查询条件运算符:
比较运算符:
比较运算符 | 说明 |
---|---|
= | 等于 |
<>,!= | 不等于 |
< | 小于 |
<= | 小于等于 |
> | 大于 |
>= | 大于等于 |
least | 有两个或多个参数返回最小值 ,其中有值为NULL返回NULL |
greatest | 有两个或多个参数返回最大值 ,其中有值为NULL返回NULL |
[not] between…and… | 判断值是否处在两个值之间 |
is [not] null | 判断值是否非空 |
in(a,b,c…) | 判断值是否在一个列表内 |
[not] like… | 字符串通配符匹配(_代表一个字符;%代表任意字符) |
regexp | 字符是否匹配正则表达式,匹配返回0或1 |
select * from where 字段 regexp '正则表达式';
逻辑运算符:
逻辑运算符 | 说明 |
---|---|
not 或 !,| | 逻辑非 |
and 或 && | 逻辑与 |
or 或 || | 逻辑或 |
xor | 逻辑异或 #不同为真,相同为假 |
位运算符(二进制运算)
位运算符 | 说明 |
---|---|
| | 按位或 |
& | 按位与 |
^ | 按位异或 |
<< | 按位左移 |
>> | 按位右移 |
~ | 按位取反 |
将查询结果导入到另一张表
-- 要求table2 必须存在
insert into table2 select * from table1 where...group by...having...
-- 要求table2 不存在
select * into table2 from table1 where...group by...having...
**MySQL多表关系:**一对一(用于单表的拆分),一对多,多对多
多表之间根据外键约束添加联系
多表查询
多表查询:
1、交叉连接查询(得到两张表的乘积,笛卡尔积,会产生冗余数据):select * from A,B,...;
2、内连接查询:
隐式内连接:select * from A,B where 条件;
显示内连接:select * from A inner join B on 条件; -- on中相同的key匹配上时会产生笛卡尔积
3、外连接查询:outer join
左外连接:select * from A left [outer] join B on 条件;
右外连接:select * from A right [outer] join B on 条件;
满外连接查询:select * from A full outer join B on 条件;
4、子查询:一条select语句结果(值或者表)作为另一条select语句的输入
子查询位置:where之后,from之后,select之后(select后接子查询相当于两个表隐式内连接)
select d.id, d.name , ( select count(*) from emp e where e.dept_id = d.id ) '人数' from dept d;
子查询关键字:ALL:与子查询返回的所有值比较所有为true返回true where 字段名>all(select子查询)
ANY:与子查询返回的所有值比较一个为true返回true where 字段名>any(select子查询)
SOME:等价于ANY where 字段名>some(select子查询)
IN:判断值是否在返回结果的集合中 where 字段名 in (select子查询)
EXISTS:子查询结果返回至少一行数据EXISTS()返回true,外层查询执行
where exists(select子查询)
select * from table1 a where exists(select * from table1 where a.字段名>100);
标量子查询:子查询结果是单行单列(一个值)
常用操作符:= <> > >= < <= where =(select 子查询)
列子查询:子查询结果是多行单列
常用操作符:IN,NOT IN,ANY,SOME,ALL where in (select子查询)
行子查询:子查询结果是单行多列
常用操作符:=,<>,IN,NOT IN where (字段1,2,3) = (子查询)
表子查询:子查询结果是多行多列
常用操作符:IN,not in,exists where (字段1,2,3) in (子查询)
select * from (子查询结果表)tmp join table2 on
5、自关联查询:
-- 先添加自己表和自己表的外键约束
alter table tableName add constraint <约束名> foreign key (字段[,字段2,...]) references tableName (主键列[,主键列2,...]);
-- 自关联查询
select * from tableName t1 left join tableName t2 on t1.字段1=t2.字段2;
-- 联合查询:将两个select查询结果统一展示。
SELECT 字段列表 FROM 表A ...
UNION [ ALL ]
SELECT 字段列表 FROM 表B ....;
/*
注意:
* 对于联合查询的多张表的列数必须保持一致,字段类型也需要保持一致
* 使用`union`关键字把两个查询结果合并展示,去重;`union all`将两个查询结果上下拼接,不去重
*/
创建数据库用户,控制数据库的访问权限
-- 查询用户
select * from mysql.user;
-- 创建用户
CREATE USER '用户名'@'主机名' IDENTIFIED BY '密码';
-- 创建用户itcast, 只能够在当前主机localhost访问, 密码123456;
create user 'itcast'@'localhost' identified by '123456';
-- 创建用户heima, 可以在任意主机访问该数据库, 密码123456;
create user 'heima'@'%' identified by '123456';
-- 修改用户密码
ALTER USER '用户名'@'主机名' IDENTIFIED WITH mysql_native_password BY '新密码';
-- 修改用户heima的访问密码为1234;
alter user 'heima'@'%' identified with mysql_native_password by '1234';
-- 删除用户
DROP USER '用户名'@'主机名';
-- 删除 itcast@localhost 用户
drop user 'itcast'@'localhost';
-- 权限控制
-- 查询权限
SHOW GRANTS FOR '用户名'@'主机名' ;
-- 查询 'heima'@'%' 用户的权限
show grants for 'heima'@'%';
-- 授予权限。多个权限之间,使用逗号分隔;授权时, 数据库名和表名可以使用 * 进行通配,代表所有。
GRANT 权限列表 ON 数据库名.表名 TO '用户名'@'主机名';
-- 授予 'heima'@'%' 用户itcast数据库所有表的所有操作权限
grant all on itcast.* to 'heima'@'%';
-- 撤销权限
REVOKE 权限列表 ON 数据库名.表名 FROM '用户名'@'主机名';
-- 撤销 'heima'@'%' 用户的itcast数据库的所有权限
revoke all on itcast.* from 'heima'@'%';
权限列表说明
权限 | 说明 |
---|---|
ALL, ALL PRIVILEGES | 所有权限 |
SELECT | 查询数据 |
INSERT | 插入数据 |
UPDATE | 修改数据 |
DELETE | 删除数据 |
ALTER | 修改表 |
DROP | 删除数据库/表/视图 |
CREATE | 创建数据库/表 |
函数是一段可以被另一段程序直接调用的程序或代码。
聚合函数
select group_concat([distinct] 字段名 [order by 组内排序字段 asc/desc] [separatoe '分隔符']) from tableName group by 分组字段;
数学函数
round(3,141592,3) 保留几位小数,默认返回四舍五入整数
truncate(3.141592,3) 截取几位小数(不四舍五入)
rand() 返回0-1的随机数
select lpad(round(rand()*1000000,0),6,"0")
– 生成6位数随机验证码
abs() 返回绝对值
ceil() 向上取整
floor() 向下取整
greatest() 取列表最大值
least() 取列表最小值
max() 最大值
min() 最小值
mod(m,n) m/n后的余数
pi() 返回圆周率
power(x,y) 返回x的y次方
字符串函数
concat(字符串a,字符串b,字符串c) 字符串直接合并
concat_ws(‘分隔符’,字符串a,字符串b,字符串c) #字符串连接函数。concat_ws(‘-’,year,month,day)
substr(字符串,start,len) #将字符串从start开始截取len长度的子字符串——等价于substring()
char_length(字符串) 返回字符串的字符数
field(字符串,字符串列表) 返回字符串在列表中的位置
ltrim() 去除字符串左边空格
rtrim() 去除字符串右边空格
trim() 去除字符串两边空格
mid(字符串,m,n) 截取字符串从第m个共n个字符
position(a in b) 返回字符串a在字符串b中的位置
replace(字符串,子串1,子串2) 将字符串中子串1替换为子串2
reverse() 字符串反转
right(字符串,n) 返回字符串后n个字符
strcmp() 字符串比较
upper() 全部字符串小写转换为大写——等价于ucase()
lower() 全部字符串大写转换为小写——等价于lcase()
lpad(str,n,pad) 左填充,用字符串pad对str的左边进行填充,达到n个字符串长度
update tableName set id=lpad(id,8,0);
rpad(str,n,pad) 右填充,用字符串pad对str的右边进行填充,达到n个字符串长度
locate(str,字段名) > 0,表示sub字符串包含str字符串;Locate(str,字段名) = 0,表示字符串不包含str字符串
instr(字段名,str)函数:返回str子字符串在字符串的第一次出现位置
日期函数
控制流函数
IF逻辑判断语句
nullif(字段1,字段2) 字段1和字段2取值相同返回NULL,否则返回字段1的值
case when语句
select
case 字段名
when...then...
when...then...
else...
end as 别名
行转列:select 分组字段,concat_ws(‘|’,collect_set(聚合字段)) as 别名 from 表名 group by 分组字段;
窗口函数
rank()|dense_rank()|row_number() over (partition by 分组字段 order by 排序字段 desc|esc) as 别名
排序的窗口函数区别:
ROW_NUMBER() 这个函数赋予唯一的连续位次。
例如,有3条排在第1位时,排序为:1,2,3,4······
RANK() 在计算排序时,若存在相同位次,会跳过之后的位次。
例如,有3条排在第1位时,排序为:1,1,1,4······
DENSE_RANK() 在计算排序时,若存在相同位次,不会跳过之后的位次。
例如,有3条排在第1位时,排序为:1,1,1,2······
分组排序TopN:
select * from (select *,rank() over (partition by 分组字段 order by 排序字段 desc) as rank_1) t where t.rank_1<=N;
sum()|max()|min()|avg()|count() over (partition by 分组字段 order by 排序字段 desc|esc) as 别名
排序的窗口函数区别:
累加求和:sum(求和字段) over(partition by 分组字段 order by 排序字段 asc)
每一组的总和:sum(求和字段) over(partition by 分组字段)
#从开头累加到当前行
select *,sum(求和字段) over(partition by 分组字段 order by 排序字段 rows between unbounded preceding and current row) as 别名 from 表名;
#从前3行累加到当前行(共4行:-3,-2,-1,0)
select *,sum(求和字段) over(partition by 分组字段 order by 排序字段 rows between 3 preceding and current row) as 别名 from 表名;
#从前三行累加到后一行(共5行:-3,-2,-1,0,1)
select *,sum(求和字段) over(partition by 分组字段 order by 排序字段 rows between 3 preceding and 1 following) as 别名 from 表名;
#从当前行累加到最后一行
select *,sum(求和字段) over(partition by 分组字段 order by 排序字段 rows between current row and unbounded following) as 别名 from 表名;
分布函数
cume_dist() over(partition by 分组字段 order by 排序字段)
前后函数
lag(日期字段,n,'2020-02-02') over(partition by 分组字段 order by 排序字段)
返回前n行的日期值,没有返回默认值lead(日期字段,n,'2020-02-02') over(partition by 分组字段 order by 排序字段)
返回后n行的日期值,没有返回默认值头尾函数:返回组内最大、最小值
first_value(字段名) over(partition by 分组字段 order by 排序字段)
截止当前组内排序后第一个last_value(字段名) over(partition by 分组字段 order by 排序字段)
截止当前组内排序后最后一个事务是一组操作的集合,是一个不可分割的工作单位,事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求。
事务处理可以用来维护数据库的完整性,保证成批的 SQL 语句要么全部执行,要么全部不执行
事务的四大特性:
-- 查看事务状态(结果为1默认自动提交)
select @@autocommit
-- 关闭事务自动提交
set autocommit=0 -- 禁止自动提交
set autocommit=1 -- 开启自动提交 (默认自动提交)
-- 开启事务
begin; 或 start transaction;
-- update等SQL语句
-- 提交事务,关闭自动提交后只有提交事务才会生效
commit;
-- 回滚事务,失败的结束,将所有的DML语句操作历史记录全部清空
rollback;
-- 查看隔离级别
SELECT @@TRANSACTION_ISOLATION;
show variables like '%isolation%’;
-- 设置隔离级别
/*
set session transaction isolation level 级别字符串
级别字符串:read uncommitted、read committed、repeatable read(默认)、serializable,隔离级别越来越强,性能越来越低
*/
-- 设置read uncommitted,会引起脏读,A事务会读取到B事务未提交的数据
set session transaction isolation level read uncommitted;
-- 设置read committed,会引起不可重复读,A事务提交前后B事务读取数据是不同的
set session transaction isolation level read committed;
-- 设置repeatable read,会引起幻读,A事务提交前后看到的数据不同,查询时没有对应行,去插入发现存在
set session transaction isolation level repeatable read;
-- 设置serializable,A事务提交后B事务才可执行操作
set session transaction isolation level serializable;
存储引擎就是存储数据、建立索引、更新/查询数据等技术的实现方式 。存储引擎是基于表的,而不是
基于库的,所以存储引擎也可被称为表类型。
-- 查看MySQL所有执行引擎,默认innoDB
show engines
-- 创建新表时指定存储引擎:
create table(...) engine=INNODB ;
-- 修改数据库引擎
alter table student engine = INNODB;
alter table student engine = MyISAM;
存储引擎的选择:
-- 创建索引(index_name一般规范为idx_表名_字段名)
CREATE [ UNIQUE | FULLTEXT ] INDEX index_name ON table_name (index_col_name,... ) ;
-- 查看索引
SHOW INDEX FROM table_name;
-- 删除索引
DROP INDEX index_name ON table_name;
--索引在使用时可以在SQL语句中加入一些人为的提示来达到优化操作的目的。在from 表名之后加入
-- use index : 建议MySQL使用哪一个索引完成此次查询(仅仅是建议,mysql内部还会再次进行评估)。
explain select * from tb_user use index(idx_user_pro) where profession = '软件工程';
-- ignore index : 忽略指定的索引
explain select * from tb_user ignore index(idx_user_pro) where profession = '软件工程';
-- force index : 强制使用索引
explain select * from tb_user force index(idx_user_pro) where profession = '软件工程';
索引分类
单列索引
-- 方式1-创建表的时候直接指定
create table student(
sid int primary key,
card_id varchar(20),
name varchar(20),
gender varchar(20),
age int,
birth date,
phone_num varchar(20),
score double,
index index_name(name) -- 给name列创建索引
);
-- 方式2-直接创建
create index indexname on tablename(columnname);
-- 方式3-修改表结构(添加索引)
alter table tablename add index indexname(columnname);
-- 查看数据库所有索引
select * from mysql.`innodb_index_stats` a where a.`database_name` = '数据库名’;
-- 查看表中所有索引
select * from mysql.`innodb_index_stats` a where a.`database_name` = '数据库名' and a.table_name like '%表名%’;
-- 查看表中所有索引
show index from table_name;
-- 删除索引
drop index 索引名 on 表名
-- 或
alter table 表名 drop index 索引名
-- 方式1-创建表的时候直接指定
create table student2(
sid int primary key,
card_id varchar(20),
name varchar(20),
gender varchar(20),
age int,
birth date,
phone_num varchar(20),
score double,
unique index_card_id(card_id) -- 给card_id列创建索引
);
-- 方式2-直接创建
create unique index 索引名 on 表名(列名)
-- 方式3-修改表结构(添加索引)
alter table 表名 add unique [索引名] (列名)
组合索引(联合索引)顺序:从左到右
如果存在多个查询条件,考虑针对于查询字段建立索引时,建议建立联合索引,尽量减少回表查询。
-- 创建索引的基本语法
create [unique] index indexname on table_name(column1(length),column2(length));
全文索引:主要用来查找文本中的关键字
-- 创建表的时候添加全文索引(不推荐)
create table t_article (
id int primary key auto_increment ,
title varchar(255) ,
content varchar(1000) ,
writing_date date -- ,
-- fulltext (content) -- 创建全文检索
);
-- 修改表结构添加全文索引
alter table t_article add fulltext index_content(content)
-- 直接添加全文索引
create fulltext index index_content on t_article(content);
-- 索引使用
match (col1,col2,...) against(expr [search_modifier])
select * from t_article where match(content) against('you');
-- 查看搜索参数
show variables like '%ft%';
空间索引
create table shop_info (
id int primary key auto_increment comment 'id',
shop_name varchar(64) not null comment '门店名称',
geom_point geometry not null comment '经纬度’,
spatial key geom_index(geom_point)
);
前缀索引
/*
当字段类型为字符串(varchar,text,longtext等)时,有时候需要索引很长的字符串,这会让
索引变得很大,查询时,浪费大量的磁盘IO, 影响查询效率。此时可以只将字符串的一部分前缀,建
立索引,这样可以大大节约索引空间,从而提高索引效率。
*/
create index idx_xxxx on table_name(column(n)) -- n为索引长度
-- 索引长度可以根据索引的选择性来决定,而选择性是指不重复的索引值(基数)和数据表的记录总数的比值,索引选择性越高则查询效率越高, 唯一索引的选择性是1是最好的索引选择性,性能也是最好的。
select count(distinct email) / count(*) from tb_user; --不重复值所占比例
select count(distinct substring(email,1,5)) / count(*) from tb_user;
索引设计原则:
索引使用的原则:
首先通过以下命令查看SQL执行频率。查看当前数据库的INSERT、UPDATE、DELETE、SELECT的访问频次。如果是以增删改为主,我们可以考虑不对其进行索引的优化。 如果是以查询为主,那么就要考虑对数据库的索引进行优化。
show [session|global] status
-- session 是查看当前会话 ;
-- global 是查询全局数据 ;
SHOW GLOBAL STATUS LIKE 'Com_______';
慢查询日志。慢查询日志记录了所有执行时间超过指定参数(long_query_time,单位:秒,默认10秒)的所有SQL语句的日志。
-- MySQL的慢查询日志默认没有开启,查看是否开启
show variables like 'slow_query_log'
接下来需要在MySQL的配置文件(/etc/my.cnf)中配置如下信息
slow_query_log=1 #开启慢查询日志开关
long_query_time=2 #设置慢日志的时间为2秒,SQL语句执行时间超过2秒,就会视为慢查询,记录慢查询日志,记录位置/var/lib/mysql/localhost-slow.log
最后,重启sql服务。systemctl restart mysqld
profile详情。可以知道每条sql语句执行多长时间。
-- 查看当前MySQL是否支持profile操作
SELECT @@have_profiling;
-- 查看开关是否开启(默认关闭为0)
select @@profiling;
-- 开启profiling
SET [session|global] profiling = 1;
-- 查看每一条SQL的耗时基本情况
show profiles;
-- 查看指定query_id的SQL语句各个阶段的耗时情况
show profile for query query_id;
-- 查看指定query_id的SQL语句CPU的使用情况
show profile cpu for query query_id;
explain执行计划。查看令 MySQL 如何执行 SELECT 语句的信息,包括在 SELECT 语句执行过程中表如何连接和连接的顺序。
-- 直接在select语句之前加上关键字 explain / desc
EXPLAIN SELECT 字段列表 FROM 表名 WHERE 条件;
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 |
possible_key | 显示可能应用在这张表上的索引,一个或多个 |
key | 实际使用的索引,如果为NULL,则没有使用索引 |
key_len | 表示索引中使用的字节数, 该值为索引字段最大可能长度,并非实际使用长度,在不损失精确性的前提下, 长度越短越好 |
rows | MySQL认为必须要执行查询的行数,在innodb引擎的表中,是一个估计值,可能并不总是准确的。 |
filtered | 表示返回结果的行数占需读取行数的百分比, filtered 的值越大越好 |
Extra | 其他备注信息。Using where; Using Index说明查找使用了索引,但是需要的数据都在索引列中能找到,所以不需要回表查询数据 |
-- 一、性能分析
--下面的命令显示了当前 session 中所有统计参数的值
show session status like 'Com_______'; -- 查看当前会话统计结果
show global status like 'Com_______'; -- 查看自数据库上次启动至今统计结果
show status like 'Innodb_rows_%’; -- 查看针对Innodb引擎的统计结果
-- 定位运行效率低的SQL
-- 1、查看慢日志配置信息
show variables like '%slow_query_log%’;
-- 开启慢日志查询
set global slow_query_log=1;
-- 查看慢日志记录SQL的最低阈值时间
show variables like 'long_query_time%’;
-- 修改慢日志记录SQL的最低阈值时间
set global long_query_time=4;
-- 2、线程执行状态信息,低效率定位
show processlist;
-- explain分析执行计划 explain selct SQL语句
explain select * from user where uid = 1;
-- type结果值从好到坏:system->const->eq_ref->ref->range->index->ALL
-- eq_ref左表有主键列,且左表的每一行与右表每一行刚好匹配
-- ref左表是普通索引,且和右表匹配时可能匹配多行
-- range 范围查询
-- index 把索引列全部数据扫描 select 字段 from
-- ALL 把表中所有数据扫描 select * from
-- show profiles 能够在做SQL优化时帮助我们了解时间都耗费到哪里去了
select @@have_profiling;
set profiling=1; -- 开启profiling 开关;
-- 通过show profile for query query_id 语句可以查看到该SQL执行过程中每个线程的状态和消耗的时间
show profiles [cpu] for query 20;
-- 二、SQL优化
-- ①插入数据
-- 批量插入
insert into tb_test values(1,'Tom'),(2,'Cat'),(3,'Jerry');
-- 手动控制事务
start transaction;
insert into tb_test values(1,'Tom'),(2,'Cat'),(3,'Jerry');
insert into tb_test values(4,'Tom'),(5,'Cat'),(6,'Jerry');
insert into tb_test values(7,'Tom'),(8,'Cat'),(9,'Jerry');
commit;
-- 主键顺序插入
-- 大批量插入数据时使用load命令,不再使用insert
---- 客户端连接服务端时,加上参数 -–local-infile
mysql –-local-infile -u root -p
-- 检查一个全局系统变量 'local_infile' 的状态, 如果得到如下显示 Value=OFF,则说明这是不可用的
show global variables like 'local_infile';
-- 修改local_infile值为on,开启local_infile
set global local_infile=1;
-- 加载数据
-- 关闭唯一性校验。在导入数据前执行 SET UNIQUE_CHECKS=0,关闭唯一性校验,在导入结束后执行SET UNIQUE_CHECKS=1,恢复唯一性校验,可以提高导入的效率。
SET UNIQUE_CHECKS=0;
--导入本地数据
load data local infile 'D:\\sql_data\\sql1.log' into table tb_user fields terminated by ',' lines terminated by '\n';
load data local infile '/root/sql1.log' into table tb_user fields terminated by ',' lines terminated by '\n' ;
-- 查询时使用索引,减少回表查询
--索引使用原则(防止索引失效)
--1、条件and连接从左到右生效,中间不能是非索引;or连接条件索引不会用到
--2、范围查询右边的列不能使用索引,不要在索引列进行运算
--3、索引列查询效率高,(不使用*)
--4、用%开头的进行模糊匹配,索引失效
--5、尽量使用复合索引
--6、多表查询优于子查询
-- update更新根据索引字段更新:InnoDB的行锁是针对索引加的锁,不是针对记录加的锁 ,并且该索引不能失效,否则会从行锁升级为表锁
视图view是一个虚拟表,本质是根据SQL语句获取的动态数据集。数据库只记录了视图的定义。视图只保存了查询的SQL逻辑,不保存查询结果
视图的作用:
-- 视图创建
create [or replace]
view view_name
as
select * from
-- 查看表和视图
show full tables;
show create view view_name;
-- 视图使用
select * from view_name;
-- 视图插入数据,数据存进基表。定义视图时,如果指定了where条件,然后在插入、修改、删除数据时,可以做到必须满足条件才能操作
create [or replace]
view view_name
as
select * from where ... with local check option;
-- 修改视图
alter view view_name
as
select * from
-- 重命名视图
rename table view_name to new_name;
--删除视图
drop view [if exists] view_name;
/*
视图的更新
要使视图可更新,视图中的行与基础表中的行必须存在一对一的关系。如果视图包含以下任何一项,则该视图不可更新:
A. 聚合函数或窗口函数(SUM()、 MIN()、 MAX()、 COUNT()等)
B. DISTINCT
C. GROUP BY
D. HAVING
E. UNION 或者 UNION ALL
*/
存储过程是事先经过编译并存储在数据库中的一段 SQL 语句的集合,就是数据库SQL语言层面代码的封装与重用。可以接受参数,也可以返回数据,减少网络交互提升效率。
-- 存储过程格式
delimiter 自定义结束符号($$ 或者 \\)
-- 创建存储过程
create procedure 存储名称 ([in,out,inout] 参数名 数据类型,参数名1 数据类型...)
begin
-- 自定义局部变量
declare 局部变量名 varchar(20) default 'abc';
set 局部变量名 = 'cba'; -- 变量赋值 用户变量(在整个会话都能使用)set @变量 = 'cba';
-- 用户变量(在整个会话都能使用)set @变量 = 'cba';
-- 全局变量(系统默认)@@全局变量名 show global variables; -- 查看全局变量
select 字段名 [into out_参数名] from tableName where...[字段1=in_参数名];
end 自定义结束符号
delimiter;
-- 存储过程调用
call 存储名称([参数])
-- 查看
-- 查询指定数据库的存储过程及状态信息
SELECT * FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_SCHEMA = '指定数据库名称';
-- 查询某个存储过程的定义语句
SHOW CREATE PROCEDURE 存储过程名称;
-- 删除
DROP PROCEDURE [ IF EXISTS ] 存储过程名称;
############实例##################
-- 实例_1_in
delimiter $$
create procedure proc(in in_name_1 varchar(20),in in_name_2 int)
begin
select concat_ws('_',deptno,ename) from emp where emp.ename=in_name_1 and emp.deptno=in_name_2;
end $$
delimiter;
set @in_name_1 = '关羽'; -- 定义用户变量
set @in_name_2 = 3000; -- 定义用户变量
call proc(@in_name_1,@in_name_2); -- 调用存储过程,必须传入参数
-- 实例_2_out
delimiter $$
create procedure proc(in in_name varchar(20),out out_name int)
begin
select deptno into out_name from emp where emp.ename=in_name;
end $$
delimiter;
set @in_name = '关羽'; -- 定义用户变量
call proc(@in_name); -- 调用存储过程,必须传入参数
select @out_name
-- 实例_3_inout
delimiter $$
create procedure proc(inout inout_name_1 varchar(20),inout inout_name_2 int)
begin
select concat_ws('_',deptno,ename) into inout_name_1 from emp where emp.ename=inout_name_1;
set inout_name_2 = inout_name_2 * 12
end $$
delimiter;
set @inout_name_1 = '关羽'; -- 定义用户变量
set @inout_name_2 = 3000; -- 定义用户变量
call proc(@inout_name_1,@inout_name_2); -- 调用存储过程,必须传入参数
select @inout_name_1;
select @inout_name_2;
-- 实例4_流程判断if
delimiter $$
create procedure proc(in score int)
begin
if score < 60
then
-- select '不及格';
set result := '不及格'
elseif score < 80
then
-- select '及格';
set result := '及格'
elseif score < 100
then
-- select '优秀';
set result := '优秀'
else
-- select '成绩错误';
set result := '成绩错误'
end if;
select result
end $$
delimiter ;
set @score = 85;
call proc(100);
call proc(@score);
-- 实例5_流程分支case
delimiter $$
create procedure proc(in pay_type int)
begin
case pay_type
when 1 then select '微信支付';
when 2 then selct '支付宝支付';
when 3 then select '银行卡支付';
end case;
end $$
delimiter ;
call proc(2);
-- 实例6_流程循环while——向表中插入指定条数据
delimiter $$
create procedure proc(in insertCount int)
begin
declare i int default 1;
label:while i <= insertCount do
insert into user(uid,username,password) values(i,concat('user-',i),'123456');
if i =5 then
leave label
end if;
set i = i + 1;
end while label;
end $$
delimiter ;
call proc(10);
-- 实例7_loop_iterable跳出当前循环,循环插入数据,跳过一条
delimiter $$
create procedure proc(in insertCount int)
begin
declare i int default 1;
label:while i <= insertCount do
set i = i + 1;
if i =5 then
iterate label
end if;
insert into user(uid,username,password) values(i,concat('user-',i),'123456');
end while label;
select '循环结束';
end $$
delimiter ;
call proc(10);
-- 计算1到n的偶数累加值
create procedure proc(in n int)
begin
declare total int default 0;
sum:loop
if n<=0 then
leave sum;
end if;
if n%2 = 1 then
set n := n - 1;
iterate sum;
end if;
set total := total + n;
set n := n - 1;
end loop sum;
select total;
end;
call proc(100)
-- 实例8_loop_leave跳出当前循环,循环插入数据
delimiter $$
create procedure proc(in insertCount int)
begin
declare i int default 1;
label:loop
insert into user(uid,username,password) values(i,concat('user-',i),'123456');
set i = i + 1;
if i > insertCount then
leave label;
end if;
end loop label;
select '循环结束';
end $$
delimiter ;
call proc(10);
-- 实例9_repeate计算累加值,当满足until声明的条件的时候,则退出循环
create procedure proc(in n int)
begin
declare total int default 0;
repeat
set total := total + n;
set n := n - 1;
until n <= 0
end repeat;
select total;
-- cursor游标用来存储查询结果集的数据类型,Handler条件处理程序
-- 根据传入参数将查询结果插入到所建的一张新表
create procedure proc(in uage int)
begin
declare uname varchar(100);
declare upro varchar(100);
-- 声明游标
declare u_cursor cursor for select name,profession from tb_user where age <=uage;
-- 声明条件处理程序 : 当SQL语句执行抛出的状态码为02000时,将关闭游标u_cursor,并退出
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;
call proc(30);
##############################
-- 存储函数.存储函数是有返回值的存储过程,存储函数的参数只能是IN类型的
CREATE FUNCTION 存储函数名称 ([ 参数列表 ])
RETURNS type [characteristic ...]
BEGIN
-- SQL语句
RETURN ...;
END ;
/*
characteristic说明:
1、DETERMINISTIC:相同的输入参数总是产生相同的结果
2、NO SQL :不包含 SQL 语句。
3、READS SQL DATA:包含读取数据的语句,但不包含写入数据的语句。
*/
变量
MySQL中变量分为:系统变量、用户定义变量、局部变量。
系统变量:MySQL服务器提供,不是用户定义的。分为全局变量(GLOBAL)、会话变量(SESSION)
-- 查看系统变量
SHOW [ SESSION | GLOBAL ] VARIABLES ; -- 查看所有系统变量
SHOW [ SESSION | GLOBAL ] VARIABLES LIKE '......'; -- 可以通过LIKE模糊匹配方式查找变量
SELECT @@[SESSION | GLOBAL].系统变量名; -- 查看指定变量的值
-- 设置系统变量
SET [ SESSION | GLOBAL ] 系统变量名 = 值 ;
SET @@[SESSION | GLOBAL].系统变量名 = 值 ;
用户自定义变量:用户根据需要自己定义的变量,用户变量不用提前声明,使用时直接用 “@变量名” 就可以。作用范围为当前连接(会话)
-- 变量赋值
-- 方法一:
SET @var_name = expr [, @var_name = expr] ... ;
SET @var_name := expr [, @var_name := expr] ... ;
-- 方法二:
SELECT @var_name := expr [, @var_name := expr] ... ;
SELECT 字段名 INTO @var_name FROM 表名;
-- 使用
SELECT @var_name ;
局部变量:根据需要定义的在局部生效的变量,访问之前,需要DECLARE声明。范围是在其内声明的BEGIN… END块
-- 声明变量。变量类型就是数据库字段类型:INT、BIGINT、CHAR、VARCHAR、DATE、TIME等
DECLARE 变量名 变量类型 [DEFAULT ... ] ;
-- 变量赋值
SET 变量名 = 值 ;
SET 变量名 := 值 ;
SELECT 字段名 INTO 变量名 FROM 表名 ... ;
在MySQL,只有执行insert、delete、update操作时才能触发触发器的执行,是一种特殊的存储过程,无需手动调用。协助应用在数据库端确保数据的完整性, 日志记录 , 数据校验等操作。
--查看触发器
show triggers;
drop trigger if exists 触发器名;
-- 格式
delimiter $$
create trigger 触发器名 before|after 触发事件 [insert|delete|update]
on 表名 for each row -- 行级触发器
begin
执行语句列表 (NEW.字段名 OLD.字段名 获取执行(前、后)表的数据)
end;
delimiter ;
-- 案例
-- 1、插入数据
create trigger tb_user_insert_trigger
after insert on tb_user for each row
begin
insert into user_logs(id, operation, operate_time, operate_id, operate_params)
VALUES
(null, 'insert', now(), new.id, concat('插入的数据内容为:id=',new.id,',name=',new.name, ', phone=', NEW.phone, ', email=', NEW.email, ',
profession=', NEW.profession));
end;
-- 更新数据
create trigger tb_user_update_trigger
after update on tb_user for each row
begin
insert into user_logs(id, operation, operate_time, operate_id, operate_params)
VALUES
(null, 'update', now(), new.id,concat('更新之前的数据: id=',old.id,',name=',old.name, ', phone=',old.phone, ', email=', old.email, ', profession=', old.profession,
' | 更新之后的数据: id=',new.id,',name=',new.name, ', phone=',
NEW.phone, ', email=', NEW.email, ', profession=', NEW.profession));
end;
-- 删除数据
create trigger tb_user_delete_trigger
after delete on tb_user for each row
begin
insert into user_logs(id, operation, operate_time, operate_id, operate_params)
VALUES
(null, 'delete', now(), old.id,concat('删除之前的数据: id=',old.id,',name=',old.name, ', phone=',old.phone, ', email=', old.email, ', profession=', old.profession));
end;
保证数据并发访问的一致性。
-- 加读锁,只能自己只读,其他都不能读和修改
lock table table_name read;
-- 加写锁
lock table table_name write
-- 解除锁
unlock tables;
-- 全局锁
/*
全局锁就是对整个数据库实例加锁,加锁后整个实例就处于只读状态,后续的DML的写语句,DDL语句都将被阻塞。其典型的使用场景是做全库的逻辑备份
*/
-- 加全局锁
flush tables with read lock ;
-- 数据备份
mysqldump [--single-transaction] -uroot –p1234 itcast > itcast.sql --dos命令行中执行
-- 释放锁
unlock tables;
-- 行锁
共享锁(S):SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE
排他锁(X) :SELECT * FROM table_name WHERE ... FOR UPDATE
-- 查看错误日志文件位置
show variables like 'log_error%';
-- 二进制日志(BINLOG)记录了所有的 DDL(数据定义语言)语句和 DML(数据操纵语言)语句,对于灾难时的数据恢复起着极其重要的作用
-- 查看MySQL是否开启了binlog日志
show variables like 'log_bin';
-- 查看binlog日志的格式
show variables like 'binlog_format';
-- 查看所有日志
show binlog events;
-- 查看最新的日志
show master status;】
-- 查询指定的binlog日志
show binlog events in 'binlog.000010';
-- 从指定的位置开始,查看指定的Binlog日志
show binlog events in 'binlog.000010' from 156;
-- 从指定的位置开始,查看指定的Binlog日志,限制查询的条数
show binlog events in 'binlog.000010' from 156 limit 2;
--从指定的位置开始,带有偏移,查看指定的Binlog日志,限制查询的条数
show binlog events in 'binlog.000010' from 666 limit 1, 2;
-- 清空所有的 binlog 日志文件
reset master
#配置开启binlog日志,进入my.ini文件
log_bin=mysqlbin
#配置二进制日志的格式
binlog_format=STATEMENT; 或row,mixed
-- 查看MySQL是否开启了查询日志
show variables like 'general_log';
-- 开启查询日志
set global general_log=1;
JDBC是Java访问数据库的标准规范,可以为不同的关系型数据库提供统一访问,它由一组用Java语言编写的接口和类组成。
public class JdbcDemo1 {
public static void main(String[] args) throws Exception {
// 注意:使用JDBC规范,采用都是 java.sql包下的内容
//1 注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2 获得连接
String url = "jdbc:mysql://localhost:3306/mydb16_jdbc";
Connection conn = DriverManager.getConnection(url, "root", "123456");
//3获得执行sql语句的对象
Statement stmt = conn.createStatement();
//4执行SQL语句
ResultSet rs = stmt.executeQuery("select * from student");
//5处理结果集
while(rs.next()){
// 获得一行数据
Integer cid = rs.getInt("sid");
String cname = rs.getString("sname");
Integer age = rs.getInt("age");
System.out.println(cid + " , " + cname);
}
//6释放资源
rs.close();
stmt.close();
conn.close();
}
import pymysql
#获取MySQL连接
conn = pymysql.connect(host='localhost', port=3306, user='root',password='123456',database='mydb17_pymysql', charset='utf8')
# 获取游标
cursor = conn.cursor()
sql = "select * from student;"
row_count = cursor.execute(sql)
print("SQL语句执行影响的行数%d" % row_count)
# 取出结果集中一行 返回的结果是一行
# print(cursor.fetchone())
# 取出结果集中的所有数据 返回一行数据
for line in cursor.fetchall():
print(line)
# 关闭游标
cursor.close()
# 关闭连接
conn.close()
######插入数据
import pymysql
#获取MySQL连接
conn = pymysql.connect(host='localhost', port=3306, user='root',password='123456',database='mydb17_pymysql', charset='utf8')
# 获取游标
cursor = conn.cursor()
##########插入数据
# sql = "insert into student values(%s,%s,%s)"
# data = (4, '晁盖', 34)
# cursor.execute(sql, data)
data = [(1,'宋江',32),(2,'吴用',30)]
cursor.executemany(sql,data) #一次性插入多行
# 修改数据
# sql = "update student set sname=%s where sid=%s"
# data = ('李逵', 4)
# cursor.execute(sql, data)
############ 删除数据
sql = "delete from student where sid=%s"
data = (4)
cursor.execute(sql, data)
conn.commit() # 提交,不然无法保存插入或者修改的数据
# 关闭游标
cursor.close()
# 关闭连接
conn.close()