MySQL笔记

基础篇

MySQL概述

SQL

SQL分类

DDL 数据定义语言,用来定义数据库对象(数据库,表,字段)

DML 数据操作语言,用来对数据库表中的数据进行增删改

DQL 数据查询语言,用来查询数据库中表的记录

DCL 数据操作语言,用来创建数据库用户、控制数据库的访问权限

SQL语句

INSERT INTO

INSERT INTO 表名 (字段名1, 字段名2, ...) VALUES (值1, 值2, ...);

UPDATE

UPDATE 表名 SET 字段名1 = 值1 , 字段名2 = 值2 , .... [ WHERE 条件 ] ;

DELETE

DELETE FROM 表名 [ WHERE 条件 ] ;

SELECT
查询多个字段

SELECT 字段1, 字段2, 字段3 ... FROM 表名 ;

SELECT * FROM 表名 ;

注意 : * 号代表查询所有字段,在实际开发中尽量少用(不直观、影响效率)。

字段设置别名

SELECT 字段1 [ AS 别名1 ] , 字段2 [ AS 别名2 ] ... FROM 表名;

SELECT 字段1 [ 别名1 ] , 字段2 [ 别名2 ] ... FROM 表名;

去除重复记录

SELECT DISTINCT 字段列表 FROM 表名;

条件查询(WHERE)

SELECT 字段列表 FROM 表名 WHERE 条件列表 ;

常用条件
常用逻辑判断

聚合函数(count、max、min、avg、sum)

SELECT 聚合函数(字段列表) FROM 表名 ;

常见聚合函数

注意 : NULL值是不参与所有聚合函数运算的。

分组查询(group by)
语法

SELECT 字段列表 FROM 表名 [ WHERE 条件 ] GROUP BY 分组字段名 [ HAVING 分组后过滤条件 ];

where与having区别
  • 执行时机不同:where是分组之前进行过滤,不满足where条件,不参与分组;而having是分组之后对结果进行过滤。

  • 判断条件不同:where不能对聚合函数进行判断,而having可以。

注意事项

• 分组之后,查询的字段一般为聚合函数和分组字段,查询其他字段无任何意义。

• 执行顺序: where > 聚合函数 > having 。

• 支持多字段分组, 具体语法为 : group by columnA,columnB

排序查询(order by)
语法

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

排序方式

ASC : 升序(默认值)

DESC: 降序

注意事项

• 如果是升序, 可以不指定排序方式ASC ;

• 如果是多字段排序,当第一个字段值相同时,才会根据第二个字段进行排序 ;

分页查询(limit)
语法

SELECT 字段列表 FROM 表名 LIMIT 起始索引, 查询记录数 ;

注意事项

• 起始索引从0开始,起始索引 = (查询页码 - 1)* 每页显示记录数。

• 分页查询是数据库的方言,不同的数据库有不同的实现,MySQL中是LIMIT。

• 如果查询的是第一页数据,起始索引可以省略,直接简写为 limit 10。

执行顺序
编写顺序
  1. SELECT 字段列表

  1. FROM 表名列表

  1. WHERE 条件列表

  1. GROUP BY 分组字段列表

  1. HAVING 分组后条件列表

  1. ORDER BY 排序字段列表

  1. LIMIT 分页参数

执行顺序
  1. FROM 表名列表

  1. WHERE 条件列表

  1. GROUP BY 分组字段列表

  1. HAVING 分组后条件列表

  1. SELECT 字段列表

  1. ORDER BY 排序字段列表

  1. LIMIT 分页参数

函数

字符串函数

CONCAT(S1,S2,...Sn)

字符串拼接,将S1,S2,... Sn拼接成一个字符串

LOWER(str)

将字符串str全部转为小写

UPPER(str)

将字符串str全部转为大写

LPAD(str,n,pad)

左填充,用字符串pad对str的左边进行填充,达到n个字符串长度

RPAD(str,n,pad)

右填充,用字符串pad对str的右边进行填充,达到n个字符串长度

TRIM(str)

去掉字符串头部和尾部的空格

SUBSTRING(str,start,len)

返回从字符串str从start位置起的len个长度的字符串

数值函数

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之间的天数

多表查询

事务

约束

进阶篇

存储引擎

MySQL体系结构

1). 连接层

最上层是一些客户端和链接服务,包含本地sock 通信和大多数基于客户端/服务端工具实现的类似于TCP/IP的通信。主要完成一些类似于连接处理、授权认证、及相关的安全方案。在该层上引入了线程池的概念,为通过认证安全接入的客户端提供线程。同样在该层上可以实现基于SSL的安全链接。服务器也会为安全接入的每个客户端验证它所具有的操作权限。

2). 服务层

第二层架构主要完成大多数的核心服务功能,如SQL接口,并完成缓存的查询,SQL的分析和优化,部分内置函数的执行。所有跨存储引擎的功能也在这一层实现,如 过程、函数等。在该层,服务器会解析查询并创建相应的内部解析树,并对其完成相应的优化如确定表的查询的顺序,是否利用索引等,最后生成相应的执行操作。如果是select语句,服务器还会查询内部的缓存,如果缓存空间足够大,这样在解决大量读操作的环境中能够很好的提升系统的性能。

3). 引擎层

存储引擎层, 存储引擎真正的负责了MySQL中数据的存储和提取,服务器通过API和存储引擎进行通信。不同的存储引擎具有不同的功能,这样我们可以根据自己的需要,来选取合适的存储引擎。数据库中的索引是在存储引擎层实现的。

4). 存储层

数据存储层, 主要是将数据(如: redolog、undolog、数据、索引、二进制日志、错误日志、查询日志、慢查询日志等)存储在文件系统之上,并完成与存储引擎的交互。和其他数据库相比,MySQL有点与众不同,它的架构可以在多种不同场景中应用并发挥良好作用。主要体现在存储引擎上,插件式的存储引擎架构,将查询处理和其他的系统任务以及数据的存储提取分离。这种架构可以根据业务的需求和实际需要选择合适的存储引擎。

索引

1.索引概述

索引(index)是帮助MySQL高效获取数据的数据结构(有序)。在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据, 这样就可以在这些数据结构上实现高级查找算法,这种数据结构就是索引。

特点
优势

提高数据检索的效率,降低数据库的IO成本

通过索引对数据进行排序,降低数据排序的成本,降低CPU的消耗

劣势

索引也是要占用空间的

虽然大大提高了查询效率,但是对于增删改的操作效率降低了

2.索引结构

索引是根据存储引擎实现的,不同的存储引擎有不同的索引结构,主要包含以下几种:

B+Tree索引

最常见的索引类型,大部分引擎都支持B+树索引

Hash索引

底层数据结构是用哈希表实现的,只有精确匹配索引列的查询才有效,不支持范围查询

R-Tree(空间索引)

空间索引是MyISAM引擎的一个特殊索引类型,主要用于地理空间数据类型,通常使用较少

Full-Text(全文索引)

是一种通过建立了倒排索引,快速匹配文档的方式。类似于Lucene,Solr,Es

以上是所有的索引结构,下面是各个引擎对索引结构的支持情况

索引

InnoDB

MyISAM

Memory

B+Tree索引

支持

支持

支持

Hash索引

不支持

不支持

支持

R-Tree(空间索引)

不支持

支持

不支持

Full-Text(全文索引)

5.6版本以后支持

支持

不支持

3.索引分类

3.1索引分类

MySQL数据库中,将索引的具体类型分为以下几类:主键索引、唯一索引、常规索引、全文索引

分类

含义

特点

关键字

主键索引

针对于表中主键创建的索引

默认自动创建, 只能有一个

PRIMARY

唯一索引

避免同一个表中某数据列中的值重复

可以有多个

UNIQUE

常规索引

快速定位特定数据

可以有多个

全文索引

全文索引查找的是文本中的关键词,而不是比较索引中的值

可以有多个

FULLTEXT

聚集索引

将数据存储与索引放到了一块,索引结构的叶子节点保存了行数据

必须有,而且只有一个

非聚集索引

将数据与索引分开存储,索引结构的叶子节点关联的是对应的主键

可以存在多个

3.2聚集索引与非聚集索引

在InnoDB存储引擎中,根据索引的存储形式,又可以分为以下两种:

分类

含义

特点

聚集索引(ClusteredIndex)

将数据存储与索引放到了一块,索引结构的叶子节点保存了行数据

必须有,而且只有一个

二级索引(SecondaryIndex)

将数据与索引分开存储,索引结构的叶子节点关联的是对应的主键

可以存在多个

3.2.1聚集索引选取规则

如果存在主键,主键索引就是聚集索引

如果不存在主键,将使用第一个唯一索引作为聚集索引

如果没有主键,或没有合适的唯一索引,则InnoDB会自动生成一个rowid作为隐藏的聚集索引

3.2.2聚集索引与非聚集索引的区别

聚集索引的叶子节点下挂的是这一行的数据

非聚集索引的叶子节点下挂的是该字段对应的主键值

3.2.3回表查询

当使用非聚集索引进行查找的时候,比如根据名称查找,查找到名称字段对应的主键值,会回到聚集索引根据主键值查询到这一行的数据。这种方式叫做回表查询。

4.索引语法

4.1创建索引

CREATE [ UNIQUE | FULLTEXT ] INDEX index_name ON table_name (index_col_name,... ) ;

4.2查看索引

SHOW INDEX FROM table_name ;

4.3删除索引

DROP INDEX index_name ON table_name ;

5.SQL性能分析

5.1 查看执行频次

MySQL客户端连接成功后,通过show[session | global] status 命令可以提供服务器状态信息。通过如下指令,可以查看当前数据库的INSERT、UPDATE、DELETE、SELECT的访问频次

-- session 是查看当前会话 ;

-- global 是查询全局数据 ;

SHOW GLOBAL STATUS LIKE 'Com_______';

通过上述指令,我们可以查看到当前数据库到底是以查询为主,还是以增删改为主,从而为数据库优化提供参考依据。 如果是以增删改为主,我们可以考虑不对其进行索引的优化。 如果是以查询为主,那么就要考虑对数据库的索引进行优化了。

5.2 慢查询日志

慢查询日志记录了所有执行时间超过指定参数(long_query_time,单位:秒,默认10S)的所有SQL语句的日志。

慢查询日志默认是没有开启。

查看慢日志信息

show variables like 'slow_query%';

查看慢日志超过多少秒记录日志

show variables like 'long_query_time';

开启慢日志,临时生效,mysql重启后就会失效

set global slow_query_log='ON';

设置慢日志存放位置

set global slow_query_log_file='D:\\Data\\mysql.log';

5.3 profile详情

慢查询日志是当查询时间超过了设定的时间后,会出现日志,可以锁定。但是如果一个简单的查询,时间大于1S的时候,没有超过我们设置的慢日志的时间,但是这个也算一个慢查询的例子,这时候我们就可以使用profile详情来查看。

show profiles 能够在SQl优化时帮助我们了解时间都耗费到哪里去了。

查看当前MySQL是否支持profile操作

SELECT @@have_profiling;

查看profile的开启状态

SELECT @@profiling;

如果是0是关闭状态,如果是1是开启状态。如果是关闭状态,通过 SET profiling=1;来开启profile

使用方式

--查看每一条SQL的耗时基本情况
show profiles;

--查看指定query_id的SQL语句各个阶段的耗时情况
show profile for query query_id;

--查看指定query_id的SQL语句CPU的使用情况
show profile cpu for query query_id;
5.4 explain

EXPLAIN或者DESC命令获取MySQL如何执行SELECT语句的信息,包括在SELECT语句执行过程中表如何连接和连接的顺序。

语法:直接在select语句之前加上关键字 explain/desc

explain select 字段列表 from 表名 where 条件;

explain的各个字段的含义,其中标红部分为主要关注的地方,

type连接类型最好的null是不涉及表,system是查询系统表,所以一般都向const程度优化

字段

含义

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 的值越大越好。

6.索引使用

6.1最左前缀法则

如果索引是多列索引(联合索引),要遵守最左前缀法则。最左前缀法则指的是查询从索引的最左列开始,并且不跳过索引中的列,如果跳跃某一列,索引将会部分失效(后面的字段索引失效)。

举个例子,比如一个索引是 idx_user_pro_age_sta,索引是由pro与age与sta联合。
1.如果查询索引的时候没有pro那么这个索引就会失效
2.如果查询索引的时候有pro但是没有age,那么后面的sta索引就失效,其就是部分索引失效,索引长度为pro
3.如果查询索引的时候有pro,age没有sta,那么索引长度为pro+age,sta索引不计入
4.如果查询索引的时候顺序为sta,age,pro那么索引也会成立,最左前缀法则规定要最左边的索引存在,并且没有跳跃某一列,并不指定顺序
6.2范围查询

联合索引中,出现范围查询(<>),范围查询右侧的列索引失效

如何进行规避这个索引失效的场景,就是在业务允许的范围内采用>=或者=<来进行代替><。

6.3 索引失效情况
6.3.1索引列运算

不要再索引列上进行运算操作,否则索引会失效

6.3.2 字符串不加''

字符串类型字段使用时,不加引号,索引将失效

6.3.3 模糊查询

如果仅仅时尾部模糊匹配,索引不会失效。如果是头部模糊匹配,索引失效。

explain select * from tb_user where profession like '软件%';    索引不失效
explain select * from tb_user where profession like '%工程';    索引失效
explain select * from tb_user where profession like '%工%';     索引失效
6.3.4 or连接的条件

用or分隔开的条件,如果or前的条件中的列有索引,而后面的列中没有索引,那么涉及的索引都不会被用到

6.3.5 数据分布影响

如果MySQL评估使用索引比全表更慢,则不使用索引。

如果一张表内有23条数据,当查询数据的数量大于13的时候,会放弃索引,走全表扫描,如果查询的数据的数量小于10的时候,索引不会失效
6.4 SQL提示

SQL提示,是优化数据库的一个重要手段,简单来说,就是在SQL语句中加入一些人为的提示来达到优化操作的目的。

use index: 使用这个索引

explain select * from tb_user use index(idx_user_pro) where profession=1;

ignore index: 忽视这个索引

explain select * from tb_user ignore index(idx_user_pro) where profession=1;

force index: 强制使用这个索引

explain select * from tb_user force index(idx_user_pro) where profession=1;

6.5覆盖索引

尽量使用覆盖索引,减少select * 。覆盖索引是指 查询使用了索引,并且需要返回的列,在该索引中已经全部能够找到。

在上面索引分类中我们了解到了聚集索引与非聚集索引,我们也了解到聚集索引中数据实在其叶子节点中,非聚集索引的叶子节点只存粗了主键id。如果我们查询聚集索引可以直接查出那一行的数据,但是根据非聚集索引查出来的数据,想要知道其他数据则需要回表查询(根据非聚集索引查出来的主键id在聚集索引里进行查询)。覆盖索引就是尽量避免回表查询。

Using where; Using Index

查找使用了索引,但是需要的数据都在索引列中能找到,所以不需要回表查询数据

Using index condition

查找使用了索引,但是需要回表查询数据

6.6前缀索引
6.6.1 前缀索引语法

当字段类型为字符串时,有时候需要索引很长的字符串,这会让索引变得很大,查询时,浪费大量的磁盘IO,影响查询效率。此时可以只将字符串的一部分前缀,建立索引,这样可以大大节约索引空间,从而提高索引效率。

语法

create index idx_xxxx on table_name(colume(n));

6.6.2 前缀长度

可以根据索引的选择性来决定,而选择性是指不重复的索引值(基数)和数据表的记录总数的比值,索引选择性越高则查询效率越高,唯一索引的选择性是1,这是最好的索引选择性,性能也是最好的。

6.7单列索引与联合索引

单列索引:即一个索引只包含单个列

联合索引:即一个索引包含了多个列

在业务场景中,如果存在多个查询条件,考虑针对于查询字段建立索引时,建议建立联合索引,而非单列索引

7.索引设计原则

1. 针对于数据量较大(大于一百万的数据),且查询比较频繁的表建立索引

2. 针对于常作为查询条件(where)、排序(order by)、分组(group by)操作的字段建立索引

3. 尽量选择区分度高的列作为索引,尽量建立唯一索引,区分度越高,使用索引的效率越高

4. 如果时字符串类型的字段,字段的长度较长,可以针对于字段的特点,建立前缀索引

5. 尽量使用联合索引,减少单列索引,查询时,联合索引很多时候可以覆盖索引,节约存储空间,避免回表,提高查询效率

6. 要控制索引的数量,索引并不是多多益善,索引越多,维护索引结构的代价也就越大,会影响增删改的效率

7.如果索引列不能存储NULL值,请在创建表时使用NOT NULL约束它。当优化器知道每列是否包含NULL值时,它可以更好地确定哪个索引更有效地用于查询

SQL优化

1.插入数据

1.1插入优化

当我们在数据库中插入数据时,可以通过以下三种方式优化

1.批量插入

一次性的提交多个数据。

Insert into tb_test values(1,'Tom'),(2,'Cat'),(3,'Jerry');

2.手动控制事务

手动开启与关闭事务,这样的话可以在一次事务中就提交数据。不至于提交一次开启一次事务。

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;

3.主键顺序插入,性能要高于乱序插入

主键乱序插入 : 8 1 9 21 88 2 4 15 89 5 7 3
主键顺序插入 : 1 2 3 4 5 7 8 9 15 21 88 89
1.2大批量插入数据

如果一次性需要插入大批量数据(比如:几百万的记录),使用insert语句插入性能较低,此时可以使用MySQL数据库提供的load指令进行插入。

-- 客户端连接服务端时,加上参数 -–local-infile
mysql –-local-infile -u root -p
--  查看全局local_infile参数
select @@local_infile
-- 设置全局参数local_infile为1,开启从本地加载文件导入数据的开关
set global local_infile = 1;
-- 执行load指令将准备好的数据,加载到表结构中
load data local infile '/root/sql1.log' into table tb_user fields terminated by ',' lines terminated by '\n' ;

在load时,主键顺序插入性能高于乱序插入

2.主键优化

2.1主键设计

在Innodb存储引擎中,表数据都是根据主键顺序组织存放的,这种存储方式的表为索引组织表。

在上面索引分类中我们了解到了聚集索引与非聚集索引,其中在聚集索引中,我们提到在聚集索引的叶子节点中存放的都是一行的行数据。

如果主键乱序插入的话会导致一种页分裂现象的出现

2.1.1页分裂

根据InnoDB引擎中我们得知,InnoDB的逻辑存储结构为表空间>段>区>页>行,其中页为最小单位。每一个页的最大存储空间为16K,一个区的最大存储单位为1M。

如果乱序插入的话,第一页存储满1到5的数据,第二页存储满9到12的数据,当要存储一个8的数据的时候,第一页会进行判定,将存储容量50%往后的数据存放到第三页,将8的数据也存放在第三页,同时进行更新页与页之间的双向连接,让第一页连接第三页,第三页连接第二页。

上述的操作就叫做页分裂,是一种比较消耗性能的操作

2.1.2页合并

就是一页中删除的数据达到了阈值,就会进行判断与前一页或者后一页是否能后进行合并,如果可以就进行合并

知识小贴士:
MERGE_THRESHOLD:合并页的阈值,可以自己设置,在创建表或者创建索引时指定。
2.2主键设计原则

满足业务需求的情况下,尽量降低主键的长度

插入数据时,尽量选择顺序插入,选择使用AUTO_INCREMENT自增主键

尽量不要使用UUID做主键或者其他自然主键,如身份证号

业务操作时,避免对主键的修改

3.order by优化

MySQL的排序,有两种方式:

1.Using filesort:通过表的索引或全表扫描,读取满足条件的数据行,然后再排序缓冲区sort buffer中完成排序操作,所有不是通过所以因直接返回排序结构的排序都叫FileSort排序

2.Using index:通过有序索引顺序扫描直接返回有序数据,这种情况即为using index,不需要额外排序,操作效率高

以上的两种方式Using index的性能高,在优化排序操作的时候尽量优化为Using index。

优化原则

1.根据排序字段建立合适的索引,多字段排序时,也遵循最左前缀法则

2.尽量使用覆盖索引

3.多字段排序,一个升序一个降序,此时需要注意联合索引在创建时的规则(ASC/DESC)

4.如果不可避免的出现Filesort,大数据量排序时,可以适当增大排序缓冲区大小sort_buffer_size(默认256K)

-- 查看缓冲区大小
show variables like 'sort_buffer_size';

4.group by优化

5.limit优化

6.count优化

7.update优化

视图/存储过程/触发器

InnoDB引擎

MySQL管理

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值