MySQL

Posted 秃头专业计算机

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL相关的知识,希望对你有一定的参考价值。

SQL和NoSQL

关系型数据库(SQL)

  • mysql、Oracle、Sql Server

  • 通过表和表之间,行和列之间的关系进行数据的存储。

非关系型数据库(NoSQL)

  • Redis、MongDB

  • 非关系型数据库严格上不是一种数据库,应该是一种数据结构化存储方法的集合,可以是文档或者键值对等。NoSQL全称是 Not Only SQL

数据库引擎

1. InnoDB 支持事务,MyISAM 不支持事务。这是 MySQL 将默认存储引擎从 MyISAM 变成 InnoDB 的重要原因之一;

2. InnoDB 支持外键,而 MyISAM 不支持。对一个包含外键的 InnoDB 表转为 MyISAM 会失败;

3. InnoDB 是聚集索引,MyISAM 是非聚集索引。聚簇索引的文件存放在主键索引的叶子节点上,因此 InnoDB 必须要有主键,通过主键索引效率很高。但是辅助索引需要两次查询,先查询到主键,然后再通过主键查询到数据。因此,主键不应该过大,因为主键太大,其他索引也都会很大。而 MyISAM 是非聚集索引,数据文件是分离的,索引保存的是数据文件的指针。主键索引和辅助索引是独立的。

4. InnoDB 不保存表的具体行数,执行 select count(*) from table 时需要全表扫描。而MyISAM 用一个变量保存了整个表的行数,执行上述语句时只需要读出该变量即可,速度很快;

5. InnoDB 最小的锁粒度是行锁,MyISAM 最小的锁粒度是表锁。一个更新语句会锁住整张表,导致其他查询和更新都会被阻塞,因此并发访问受限。这也是 MySQL 将默认存储引擎从 MyISAM 变成 InnoDB 的重要原因之一;

索引(Index)

MySQL官方对索引的定义为是帮助MySQL高效获取数据的数据结构。索引是在数据库表的字段上添加的,一张表的一个字段可以添加一个索引,也可以多个字段联合起来添加索引。举个例子,对于一本字典来说,查找一个汉字有两种方式,第一种方式是一页一页挨着找,第二种就是通过目录查找一个大概的位置。这就对应MySQL的两种查询方式,全表扫描和根据索引检索。毫无疑问,肯定是第二种方式效率高。

在mysql当中,索引是一个单独的对象,不同的存储引擎以不同的形式存在,在MyISAM存储引擎中,索引存储在一个.MYI文件中。在InnoDB存储引擎中

索引存储在一个逻辑名称叫做tablespace的当中。在MEMORY存储引擎当中索引被存储在内存当中。不管索引存储在哪里,索引在mysql当中都是一个树的形式存在(B+树)。

虽然索引这好那好的,但是我们还是建议不要随意添加索引,因为索引也是需要维护的,太多的话反而会降低系统性能。那什么情况下考虑添加索引呢?

  • 数据量庞大

  • 经常出现在where后面,也就说这个字段经常被扫描

  • DML操作少(insert、delete、update),因为DML后索引需要重新排序

索引按功能划分分为:主键索引(PRIMARY KEY)、唯一索引(UNIQUE KEY)、常规索引(KEY/INDEX)、全文索引(FullText,仅可用于引擎为MyISAM的表)。其中主键索引和唯一索引在主键和unique字段上都会自动添加索引。

首先我们来看看普通索引普通索引(由关键字KEY或INDEX定义的索引)的唯一任务是加快对数据的访问速度。因此,应该只为那些最经常出现在查询条件(WHERE column = …)或排序条件(ORDER BY column)中的数据列创建索引。

# 修改表结构的方式添加索引 ALTER TABLE 表名 ADD INDEX 索引名 ON (列名)  # 创建表的时候同时创建索引  CREATE TABLE table_name ( id int(11) NOT NULL AUTO_INCREMENT , title char(255) NOT NULL , PRIMARY KEY (id), INDEX index_name (title) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; #直接创建普通索引create index 索引名 on 表名(字段名)#删除索引drop index 索引名 on 表名

以下内容需要使用到explain模拟优化器执行SQL语句,可以查看sql的执行情况。可以用于优化SQL,因为优化SQL必须清楚知道SQL的执行顺序。

未用索引

扫描全部记录,type=ALL,说明并没有使用索引。

使用索引

MySQL(7)

是需要扫描一次,这就大大增加了查询效率。

索引失效

第一种情况

MySQL(7)

username上即使添加了索引,也不会走索引。走的是全局扫描。这是因为模糊查询以%开头,无法匹配。当我们不将%放在前面,我们就可以使用索引查询。所以模糊查询尽量避免以%开头,这是一种优化手段

第二种情况

使用or的时候会失效。如果使用or那么就要要求两边的条件字段都要有索引才会走索引。如果其中一边字段没有索引,那么另一个字段上的索引也会实现。所以尽量少用or也是一种优化手段。

MySQL(7)

但是我们可以使用union,union不会让索引失效

MySQL(7)

第三种情况

使用复合索引的时候,没有使用左侧的列查找,索引失效。复合索引就是两个或更多的字段联合起来添加一个索引叫做复合索引。

MySQL(7)

第四种情况

在where中索引列参加了运算,索引失效。在做这步前,我先将上一步的联合索引删除再创建一个新的索引。

MySQL(7)

第五种情况

在where索引列使用了函数,索引失效

MySQL(7)

唯一索引

与普通索引类似,不同的就是:索引列的值必须唯一,但允许有空值(注意和主键不同)。如果是组合索引,则列值的组合必须唯一,创建方法和普通索引类似。

# 创建唯一索引  CREATE UNIQUE INDEX index_name ON table_name(column_name) # 修改表结构  ALTER TABLE table_name ADD UNIQUE index_name ON (column_name) # 创建表的时候直接指定  CREATE TABLE table_name ( id int(11) NOT NULL AUTO_INCREMENT , title char(255) NOT NULL , PRIMARY KEY (id), UNIQUE index_name (title) );  

底层原理

mysql的底层是使用B+ Tree实现的。我们一起来看一下推倒过程

首先插入数据

INSERT INTO btest(id,NAME) VALUES(3,'c'),(2,'b'),(5,'e'),(7,'g'),(4,'d'),(1,'a'),(6,'f')


MySQL(7)

乱序插入数据,会自动按照id进行升序排列,这是因为主键自带索引。数据

存储的内部结构类似于链表的格式,通过指针关联数据。

MySQL(7)

但是链表的查询是比较慢的,所以MySQL提供了page,相当于给数据分页。把一部分数据存入一个page中

MySQL(7)

每个page可以存放16kb的数据。假如我们现在不用page查找索引为200多的数据,我们需要一个个找。假如一个page存放100条数据,使用了page后我们直接去第三页找就好了,因为前两页存放的是前200条。然后MySQL还为page提供了page目录,将数据的索引和指针存入page目录

MySQL(7)

查询数据的时候,先找到它的page。比如查询id=4的数据,我们可以在第一个page目录中的第二页找到。如果是id=6就可以在第二个page目录中第一页找到。一个page目录中也可以存储16kb的数据。如果是海量数据,还可以分更多层,也就是给page目录再加一层目录

MySQL(7)

我们需要查找数据的时候,就一层一层往下找。这个结构就是B+树。三层已经可以存放很多数据了,一般的应用两层就够了。

举个例子:

假设一条数据为64byte,一个page可以存储数据16*1024/64=256条,page目录只需要存id和指针,假设是12byte,则可以保存的数据是16*1024/12=1365条。第三层也是存放16*1024/12=1365条。所以这个三层架构存放的数据条数256*1365*1365=476985600=4.7亿。

三大范式

目前关系数据库有六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴斯-科德范式(BCNF)、第四范式(4NF)和第五范式(5NF,又称完美范式)。

而通常我们用的最多的就是第一范式(1NF)、第二范式(2NF)、第三范式(3NF),也就是我们常说的“三大范式”。

第一范式

要求数据库表的每一列都是不可分割的原子数据项。

MySQL(7)

在上面的表中,“家庭信息”和“学校信息”列均不满足原子性的要求,故不满足第一范式,调整如下:

MySQL(7)

第二范式
在第一范式的基础上,属性完全依赖于主键。比如一个订单信息表

MySQL(7)

从上表可以看出,一个订单可能有多个商品。那这时我们就不能仅仅使用订单作为主键,而是要使用订单号+商品编号联合起来作为主键。此时客户、所属单位、联系方式就和商品编号没有什么联系,而仅仅与订单编号有关。这就违反了第二范式的设计原则。所以我们要将这个表分离,实现每张表只描述一件事情。

MySQL(7)

第三范式

在第二范式的基础上,确保数据表中的每一列数据都和主键直接相关,而不能间接相关。比如在设计一个订单数据表的时候,可以将客户编号作为一个外键和订单表建立相应的关系。而不可以在订单表中添加关于客户其它信息(比如姓名、所属公司等)的字段。如下就是一个不满足第三范式的表

改进后

以上是关于MySQL的主要内容,如果未能解决你的问题,请参考以下文章

从mysql的片段中加载ListView

连接MySQL出现错误:ERROR 1045 (28000): Access denied for user ‘root‘@‘localhost‘ (using password: YES)(代码片段

使用 json rereiver php mysql 在片段中填充列表视图

关于mysql驱动版本报错解决,Cause: com.mysql.jdbc.exceptions.jdbc4Unknown system variable ‘query_cache_size(代码片段

修改MySQL密码报错“ERROR 1819 (HY000): Your password does not satisfy the current policy requirements“(代码片段

mysql查看版本的四种方法