【无标题】MySQL知识点总结

MySQL有哪些数据库类型

  • 数值类型
  • 字符串类型
  • 日期和时间类型

char和varchar区别

1)首先可以明确的是char是定长的,而varchar是可变长。

2)在存储方式上,char对英文字符(ASCII)占用1字节,对一个汉字使用用2字节。而varchar对每个字符均使用2字节。

三大范式

  • 第一范式(1NF):字段(或属性)是不可分割的最小单元,即不会有重复的列,体现原子性
  • 第二范式(2NF):满足1NF前提下,存在一个候选码,非主属性全部依赖该候选码,即存在主键,体现唯一性。
  • 第三范式(3NF):满足2NF前提下,非主属性必须互不依赖,消除传递依赖。

索引 

        索引是对数据库表中一列或多列的值进行排序的数据结构,用于快速访问数据库表中的特定信息。

索引的几种类型 

1)从物理结构上可以分为聚集索引非聚集索引两类:

  • 聚簇索引指索引的键值的逻辑顺序与表中相应行的物理顺序一致,即每张表只能由一个聚簇索引,也就是我们常说的主键索引;
  • 非聚簇索引的逻辑顺序与数据行的物理顺序不一致。

2)从应用上可以分为:

  • 普通索引:MySQL中的基本索引类型,没有什么限制,允许在定义索引的列中插入重复值和空值,纯粹为了提高拆线呢效率。通过以下代码创建:
    ALTER TABLE table_name ADD INDEX index_name (column)
  • 唯一索引:索引列中的值必须是唯一的,但是允许为空值。通过以下代码创建:
    ALTER TABLE table_name ADD INDEX index_name (column)
  • 主键索引:特殊的唯一索引,也成聚簇索引,不允许有空值,并由数据库帮我们自动创建。
  • 组合索引:组合表中多个字段创建的索引,遵守最左前缀匹配规则。
  • 全文索引:只有在MylSAM引擎上才能使用,同时只支持 CHAR、VARCHAR、TEXT类型字段上使用。 

索引的优缺点 

优点: 创建索引可以大大提高系统的性能。

  • 提高检索的速度
  • 索引列对数据排序降低排序成本
  • mysql 8之后引入了 隐蔽索引,当一个索引被隐蔽就不会被优化器所使用,就可以看出来索引对数据库的影响,有利于调优

缺点:

  • 创建和维护索引需要耗费时间,这种时间随着数据量的增加而增加,这样就降低了数据的维护速度。
  • 索引需要占物理空间,除了数据表占数据空间外,每一个索引还要占一定的物理空间。如果要建立聚簇索引,那么需要的空间就会更大。 

索引的设计原则 

  • 选择唯一性索引;
  • 为常作为查询条件的字段建立索引;
  • 为经常需要排序、分组和联合操作的字段建立索引;(经常需要 ORDER BY、GROUP BY、DISTINCT 和 UNION 等操作的字段,排序操作会浪费很多时间。如果为其建立索引、可以有效地避免排序操作。)
  • 限制索引的数目
  • 小表不建议索引(汝数量级在百万以内)
  • 尽量使用数据量少的索引
  • 删除不再使用或者很少的索引 

索引的优化

  1. 选择唯一性索引:值是唯一的,查询更快
  2. 经常作为查询条件的字段加索引
  3. 为经常需要排序、分组和联合操作的字段建立索引:order by、group by、union(联合)、distinct(等)
  4. 限制索引个数:索引多,需要的磁盘空间就多,更新表是,对索引的重构和更新就很费劲
  5. 表数据少的不建议使用索引(百万级以内)
  6. 删除不常用和不再使用的索引
  7. 用类型小的类型做索引
  8. 使用前缀索引:要是字符串越长、那么索引占的空间越大,并且比较起来时间就越长 

索引的数据结构 

索引的数据结构和具体存储引擎的实现有关,MySQL中常用的是 Hash 和 B+树 索引。

  • Hash索引 底层就是 Hash 表,进行查询时调用 Hash 函数获取到相应的键值(对应地址),然后回表查询获得实际数据。
  • B+树索引 底层实现原理是多路平衡查找树,对于每一次的查询都是从根节点出发,查询到叶子节点方可获得所查键值,最后查询判断是否需要回表查询。 

索引的数据类型 

Hash查询时调用Hash函数获得地址,回表查询实际数据。(InnoDB和MylSAM不支持,Memory支持)

B+Tree:每次从根节点出发去查询,然后得到地址,回表查询实际数据。

索引为什么使用树结构

因为可以加速查询效率,而且可以保持有序。 

二叉查找树、B树、B+树

二叉查找树:一个节点最多两个子节点(左小右大),查询次数和比较次数都是最小的,但是索引是存在磁盘的,当数据量过大时,不能直接把整个索引文件加载到内存,需要分多次IO,最坏的情况IO的次数就是树的高度,为了减少IO,需要把树从竖向变为横向。

B树(B-):是一种多路查询树,每个节点包含K个子节点节点都存储索引值数据,K是B树的阶(树高被称为树的阶)。虽然比较的次数比较多,但是是在内存的比较,可以忽略不记,但是B树IO的次数要比二叉查找树,因为B树的高度可以更低。

B+树:B树的升级版,只有叶子节点存储的是索引值指向的数据库的数据。

为什么使用B+树不用B树

        1)B树只适合随机检索,而B+树同时支持随机检索和顺序检索因为叶子节点相当于链表,保存索引值都是有序的

        顺序检索:按照序列顺序遍历比较找到给定值。

        随机索引:不断从序列中随机抽取数据进行比较,最终找到结果。 

        2)减少了磁盘IO,提高空间利用率:因为B+树非叶子节点不会存放数据,只有索引值,所以非叶子节点可以保存更多的索引值,这样B+树就可以更矮,减少IO次数。

        3)B+树适合范围查找:这是关键,数据库大部分都是范围查找。B+树的叶子节点是有序链表,直接遍历就行,而B树的范围查找可能两个节点距离很远,只能通过中序遍历去查找,索引使用B+树更合适。

存储结构 

什么是 InnoDB 的页、区、段? 

页(Page):

        首先 InnoDB 将物理磁盘划分为页(page),每页的大小默认 16KB,页是最小的存储单位。页根据上层应用的需要,如索引、日志等,分为很多的格式。我们主要说数据页,也就是存储实际数据的页。

区(Extent):

         如果只有页这一个层次的话,页的个数是非常多的,存储空间的分配和回收都会很麻烦,因为要维护这么多的页的状态是非常麻烦的。所以,InnoDB 又引入了区的概念。一个区默认64个连续的页组成,也就是1MB.

段(Segment):

        为什么要引入段呢,这要从索引说起。我们都知道索引的目的是为了加快查找速度,是一种典型的用空间换时间的方法。 B+ 树的叶子节点存放的是我们的具体数据,非叶子节点是索引页。所以B+树将数据分为了两部分,叶子节点部分和非叶子节点部分,也就是段。

事务

什么是数据库的事务

        数据库的事务是一个不可分割的数据库操作序列,也是数据库并发控制的基本单位,其执行的结果必须使数据库从一种一致性状态变到另一种一致性状态。事务是逻辑上的一组操作要么都执行,要么都不执行

        事务是对数据库中一系列操作进行统一的回滚或者提交操作,主要用来保证数据的完整性和一致性。

事务的四大特性(ACID)

  • 原子性:事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用。
  • 一致性:事务执行前后,数据保持一致,多个事务对同一个数据读取的结果是相同的。
  • 隔离性:并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间的数据库是独立的。
  • 持久性:一个事务被提交之后,他对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。

事务的并发问题(脏读、幻读、不可重复读) 

  • 脏读:一个事务读取另一个事务尚未提交的数据。事务A读取事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据。
  • 不可重复读: 一个事务中两次读取的数据的内容不一致。事务A多次读取同一数据,事务B在事务A多次读取的过程中,对数据做了更新并提交,导致事务A多次读取同一数据时,结果不一致。
  • 幻读:一个事务中两次读取的数据量不一致。系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A该结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。

不可重复读和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增和删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表。

事务的隔离级别

隔离级别 脏读 不可重复读 幻读
读未提交(Read uncommitted)
读已提交(Read committed) ×
可重复读(Repeatable read) × ×
可串行化(Serializable) × × ×

 锁

数据库锁的作用以及有哪些锁

        当数据库有并发事务的时候,可能会产生数据的不一致,这时候需要一些机制来保证访问的次序,锁机制就是这样的一个机制。即锁的作用是解决并发问题。

从锁的粒度分

  • 行级锁:锁定粒度最细的一种锁,表示只针对当前操作的行进行加锁。(开销大,枷锁慢,会出现死锁。但锁定粒度最小,发生锁冲突的概率最低,并发度最高)
  • 表级锁:粒度最大的一种锁,表示对当前操作的整张表加锁。(实现简单,资源消耗较少)
  • 页级锁:是粒度介于中间的一种锁。这种以上两种锁,依次锁定相邻的一组数据。

从使用性质划分

  •  共享锁(Share Lock):S锁,有称读锁,用于所有的只读数据操作。S锁并非独占,允许多个并发事务对同一资源加锁,但加S锁的同时不允许加X锁,即资源不能被修改。S锁通常读取结束后立即释放,无需等待事务结束。

  • 排他锁(Exclusive Lock):X锁,又称写锁,表示对数据进行写操作。X锁仅允许一个事务对同一资源加锁,且直到事务结束才释放,其他任何事务必须等到X锁被释放才能对该页进行访问。使用以下语句产生X锁。

    select * from table_name for update;
  • 更新锁:U锁,用来预定要对资源施加X锁,允许其他事务读,但不允许再施加U锁或X锁。

从主观上划分 

  • 乐观锁(Optimistic Lock):从主观上认定资源是不会被修改的,所以不加锁读取数据,仅当更新时版本号机制等确认资源是否被修改
  • 悲观锁(Pessimistic Lock):具有强烈的独占和排它特性,每次读取数据时都会认为会被其他事务修改,所以每次操作都需要加上锁

视图

SQL

语法

通常SQL语句可以分为两类:

  • 数据操作语言(DML):SELECT、DELETE、INSERT INTO、UPDATE
  • 数据定义语言(DDL):CREATE、DROP、ALTER 

常见的聚合查询

sum(列名) 求和
max(列名) 最大值
min(列名) 最小值
avg(列名) 平均值
first(列名) 第一条记录
last(列名) 最后一条记录
count(列名) 统计记录数

几种关联查询

  • 内连接 (自然连接):查询两个表匹配数据。只返回匹配的行,如 Inner Join、Union Join。

  • 外连接:返回一个表的全集,如 Left、Right、Full 和 Cross.

  • 左连接:查询左表全部行以及右表匹配的行

  • 右连接:查询右表全部行以及左表匹配的行

Where 和 Having 区别 

        where 子句的作用是对查询结果进行分组前,将不符合条件的行去掉,即在分组之前过滤数据,where条件中不能包含聚组函数,使用where条件过滤出特定的行。

        having 子句的作用是筛选满足条件的组,即在分组之后过滤数据,条件中经常包含聚组函数,使用having条件过滤出特定的组,也可以使用多个分组标准进行分组。

总结下条件的过滤顺序:on -> join -> where -> group by -> having

SQL关键字执行顺序 

from -> ON 主表过滤 -> join 外部连接 -> where -> group by 分组 ->   having 分组后 -> select -> distict 去重 -> order by 排序 -> limit(分页)  0,10

Union 和 Union All 区别

  • Union:对两个结果集进行并集操作,不包括重复行,同时进行默认规则的排序
  • Union All:对两个结果集进行并集操作,包括重复行,进行排序。 

in和exists的区别

in():适合子表(子查询)比主表数据小的情况

exists():适合子表(子查询)比主表数据大的情况 

SQL的执行顺序

  1. from 表1
  2. on(连接条件)  表1.字段 = 表2.字段
  3. [inner join | left join | right join](连接) 表2
  4. where 查询条件
  5. group

优化

如何判断 SQL 是否走了索引 

explain命令是查看查询优化器如何决定执行查询的主要方法,使用explain只需在查询语句开头增加explain这个关键字即可。

索引失效的几种情况

  1. like 以 % 开头,索引无效;当like前缀没有%,后缀有%时,索引有效。
  2. or 语句前后没有同时使用索引。当 or 左右查询字段只有一个时索引,该索引失效,只有左右查询字段均为索引时,才会生效。
  3. 联合索引不使用第一列,索引失效。
  4. 数据类型出现隐式转化。如 varchar 不加单引号的话可能会自动转换为 int 型,使索引无效,产生全表扫描。
  5. 在索引列上使用 IS NULL 或 IS NOT NULL操作。最好给列设置默认值。
  6. 在索引字段上使用not,<>,!=,不等于 操作符是永远不会用到索引的,因此对它的处理只会产生全表扫描。优化方法:key<>0 改为 key>0 or key < 0。
  7. 对索引字段进行计算操作、字段上使用函数。
  8. 当 MySQL 觉得全表扫描更快时(数据少)

where 子句如何优化

超大分页或深度分页如何处理

        说到MySQL的分页,我们首先想到的就是 offset、limit 操作,但随着页数的增加,查询性能指数级增大。

        这是由于MySQL并不是跳过 offset 的行数,而是取 offset + limit 行,然后丢弃前 offset 行,返回 limit 行,当 offset 特别大的时候,效率就非常低下。

        此处我们采用 覆盖索引+延迟关联 技术来减少偏移量的定位进行优化。

##查询语句
select id from product limit 10000000, 10
##优化方式一
SELECT * FROM product WHERE ID > =(select id from product limit 10000000, 1) limit 10
##优化方式二
SELECT * FROM product a JOIN (select id from product limit 10000000, 10) b ON a.ID = b.id

大表查询如何优化 

        可以从SQL优化分库分表读写隔离以及缓存个维度分别阐述

 SQL优化

  1. 不要使用select *,要使用具体字段
  2. 使用数值代替字符串,比如:0=唱,1=跳,2=rap
  3. 避免返回大量数据,采用分页最好
  4. 使用索引,提升查询速度,不宜建太多索引,不能建在重复数据比较多的字段上
  5. 批量插入比单条插入快,因为事务只需要开启一次,数据量太小体现不了
  6. 避免子查询,优化为多表连接查询
  7. 尽量使用 union all 替代 union,因为union会自动去重。

一条sql查询非常慢,怎么去排查和优化

排查:

  1. 开启慢查询
  2. 查看慢查询日志(定位低效率sql,命令:show processlist)
  3. 使用explain查看sql的执行计划(看看索引是否失效或者性能低)

优化: 

        sql优化 + 索引 + 数据库结构优化 + 优化器优化

SQL语法 

drop table if exists 

        一般drop table if exists是数据库里面的,后面接表名如:drop table if exists xxx_book意思就是:如果数据库中存在xxx_book表,就把它从数据库中drop掉。
  备份sql中一般都有这样的语句,如果是数据库中有这个表,先drop掉,然后create表,然后再进行数据插入。

查看所有列

select * from 表名

查找并去重

二种方式:

1.distinct 关键字select distinct university from user_profile distinct去重,放在列的前面使用。2.分组select university from user_profile group by university;以分组来筛选出去重的结果 

 查询结果限制返回行数 

例如返回前两个用户设备ID【无标题】MySQL知识点总结_第1张图片

select device_id from user_profile limit 0,2---运行效率更高

select device_id from user_profile limit 2 ---运行效率低

也可结合 limit offset: 一起使用时,limit表示要取的数量,offset表示跳过的数量

select device_id from user_profile limit 2 offset 0 // 跳过0条,从第一条数据开始取,取两条数据 ---运行效率中

将查询后的列重新命名 

select device_id as user_infors_example from user_profile limit 0,2;
这里主要是用到了 起别名关键字 as 以及组合限制查询 limit 索引,个数
其中as可以省略,索引为0可以省略
select device_id user_infors_example from user_profile limit 2; 

查找除复旦大学的用户信息

SELECT device_id, gender,age,university FROM user_profile WHERE university NOT IN ("复旦大学") 

查看学校名称中含北京的用户 

字符匹配

一般形式为:列名 [NOT ] LIKE

匹配串中可包含如下四种通配符:

  • _:匹配任意一个字符;
  • %:匹配0个或多个字符;
  • [ ]:匹配[ ]中的任意一个字符(若要比较的字符是连续的,则可以用连字符“-”表 达 );
  • [^ ]:不匹配[ ]中的任意一个字符。

例:查询学生表中姓‘张’的学生的详细信息。

SELECT * FROM 学生表 WHERE 姓名 LIKE ‘张%’

例:查询姓“张”且名字是3个字的学生姓名。

SELECT * FROM 学生表 WHERE 姓名 LIKE '张__’

例:查询学生表中姓‘张’、姓‘李’和姓‘刘’的学生的情况

SELECT * FROM 学生表 WHERE 姓名 LIKE '[张李刘]%’

例:查询学生表表中名字的第2个字为“小”或“大”的学生的姓名和学号。

SELECT 姓名,学号 FROM 学生表 WHERE 姓名 LIKE '_[小大]%'

例:从学生表表中查询学号的最后一位不是2、3、5的学生信息。

SELECT * FROM 学生表 WHERE 学号 LIKE '%[^235]'

SELECT device_id,age,university FROM user_profile
WHERE university LIKE '%北京%' 

查找GPA最高值 

# 方法1
select max(gpa) as gpa
from user_profile
where university='复旦大学';

# 方法2
select gpa
from user_profile
where university='复旦大学'
order by gpa desc limit 1     (desc升序,asc降序)

计算男生人数以及平均GPA

问题分解:

  1. 限定条件为 男性用户;
  2. 有多少人,明显是计数,count函数;
  3. 平均gpa,求平均值用avg函数;

细节问题:根据输出示例,有两个问题需要注意:

  1. 表头重命名,用as语法
  2. 浮点数的平均值可能小数点位数很多,按照示例保存一位小数,用round函数

 select 
         count(gender) as male_num,
         round(avg(gpa), 1) as avg_gpa
 from user_profile where gender="male";

分组过滤

现在运营想查看每个学校用户的平均发贴和回帖情况,寻找低活跃度学校进行重点运营,请取出平均发贴数低于5的学校或平均回帖数小于20的学校。

 

你可能感兴趣的:(mysql,数据库)