1. Mysql逻辑架构介绍

和其它数据库相比,MySQL有点与众不同,它的架构可以在多种不同场景中应用并发挥良好作用。主要体现在存储引擎的架构上,
插件式的存储引擎架构将查询处理和其它的系统任务以及数据的存储提取相分离。这种架构可以根据业务的需求和实际需要选择合适的存储引擎。

1.1 Mysql简介

MSQL概述

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB公司开发,目前属于Oracle公司。

MySQL是一种关联数据库管理系统,将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。

Mysql是开源的,所以你不需要支付额外的费用。

Mysql是可以定制的,采用了GPL协议,你可以修改源码来开发自己的Mysql系统。

Mysql支持大型的数据库。可以处理拥有上千万条记录的大型数据库。

MySQL使用标准的SQL数据语言形式。

Mysql可以允许于多个系统上,并且支持多种语言。这些编程语言包括C、C++、Python、Java、Perl、PHP、Eiffel、Ruby和Tcl等。

MySQL支持大型数据库,支持5000万条记录的数据仓库,32位系统表文件最大可支持4GB,64位系统支持最大的表文件为8TB。

Mysql高手是怎样炼成的

  • 数据库内部结构和原理
  • 数据库建模优化
  • 数据库索引建立
  • SQL语句优化
  • SQL编程
  • mysql服务器的安装配置
  • 数据库的性能监控分析与系统优化
  • 各种参数常量设定
  • 主从复制
  • 分布式架构搭建、垂直切割和水平切割
  • 数据迁移
  • 容灾备份和恢复
  • shell或python等脚本语言开发
  • 对开源数据库进行二次开发

1.2 MysqlLinux版的安装

MySQL的安装位置

  • 在linux下查看安装目录 ps -ef | grep mysql

参数 路径 解释 备注
–base dir /usr/bin 相关命令目录 mysqladmin mysqldump等命令
–data dir /var/lib/mysql/ mysql数据库文件的存放路径
–plugin-dir –plugin-dir mysql插件存放路径
–log-error /var/lib/mysql/jack.zzxx.err mysql错误日志路径
–pid-file /var/lib/mysql/jack.zzxx.pid 进程pid文件
–socket /var/lib/mysql/mysql.sock 本地连接时用的unix套接字文件
/usr/share/mysql 配置文件目录 配置文件目录 mysql脚本及配置文件
/etc/init.d/mysql 服务启停相关脚本

修改配置文件位置

修改字符集和数据存储路径

原因是字符集问题

1 查看字符集

show variables like 'character%'; 
show variables like '%char%';

看看出现的结果:

2 修改my.cnf

1
2
3
4
5
6
7
8
9
10
11
12
在/usr/share/mysql/ 中找到my.cnf的配置文件,
拷贝其中的my-huge.cnf 到 /etc/ 并命名为my.cnf
mysql 优先选中 /etc/ 下的配置文件
然后修改my.cnf:
[client]
default-character-set=utf8
[mysqld]
character_set_server=utf8
character_set_client=utf8
collation-server=utf8_general_ci
[mysql]
default-character-set=utf8

3、重新启动mysql

但是原库的设定不会发生变化,参数修改之对新建的数据库生效

4、已生成的库表字符集如何变更

1
2
3
4
修改数据库的字符集
mysql> alter database mytest character set 'utf8';
修改数据表的字符集
mysql> alter table user convert to character set 'utf8';

但是原有的数据如果是用非’utf8’编码的话,数据本身不会发生改变。

1.3 Mysql配置文件

二进制日志log-bin

log-bin 中存放了所有的操作记录(写?),可以用于恢复。相当于 Redis 中的 AOF
my.cnf中的log-bin配置(默认关闭)

错误日志log-error

默认是关闭的,记录严重的警告和错误信息,每次启动和关闭的详细信息等。

慢查询日志log

默认关闭,记录查询的sql语句,如果开启会减低mysql的整体性能,因为记录日志也是需要消耗系统资源的

数据文件

  • windows:….\MySQLServer5.5\data目录下很多数据库文件
  • linux:默认路径:/var/lib/mysql,可在配置文件中更改 /usr/share/mysql/ 下的 my-huge.cnf

Myisam存放方式

show create table mydb 查看创建 mydb 表的基本信息,其中包括了数据引擎。
自带的库 mysql 库中所有的表都是以 MyIsam 引擎存的。通过 myisam 引擎存的表都是 一式三份,放在库同名的文件夹下 /var/lib/mysql

  • frm文件(framework):存放表结构
  • myd文件(data):存放表数据
  • myi文件(index):存放表索引

innodb存放方式

Innodb引擎将所有表的的数据都存在这里面 /usr/share/mysql/ibdata1 而frm文件存放在库同名的包下

如何配置

  • windows:my.ini文件(配置文件)
  • Linux:/etc/my.cnf文件(配置文件)

1.4 Mysql 的用户与权限管理

1.5 Mysql逻辑架构介绍

总体架构

和其它数据库相比,MySQL有点与众不同,它的架构可以在多种不同场景中应用并发挥良好作用。主要体现在存储引擎的架构上,
插件式的存储引擎架构将查询处理和其它的系统任务以及数据的存储提取相分离。这种架构可以根据业务的需求和实际需要选择合适的存储引擎。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
1.连接层
最上层是一些客户端和连接服务,包含本地sock通信和大多数基于客户端/服务端工具实现的类似于tcp/ip的通信。主要完成一些类似于连接处理、授权认证、及相关的安全方案。在该层上引入了线程池的概念,为通过认证安全接入的客户端提供线程。同样在该层上可以实现基于SSL的安全链接。服务器也会为安全接入的每个客户端验证它所具有的操作权限。

2.服务层

2.1 Management Serveices & Utilities: 系统管理和控制工具
2.2 SQL Interface: SQL接口
接受用户的SQL命令,并且返回用户需要查询的结果。比如select from就是调用SQL Interface
2.3 Parser: 解析器
SQL命令传递到解析器的时候会被解析器验证和解析。
2.4 Optimizer: 查询优化器。
SQL语句在查询之前会使用查询优化器对查询进行优化。
用一个例子就可以理解: select uid,name from user where gender= 1;
优化器来决定先投影还是先过滤。

2.5 Cache和Buffer: 查询缓存。

如果查询缓存有命中的查询结果,查询语句就可以直接去查询缓存中取数据。
这个缓存机制是由一系列小缓存组成的。比如表缓存,记录缓存,key缓存,权限缓存等
缓存是负责读,缓冲负责写。


3.引擎层
存储引擎层,存储引擎真正的负责了MySQL中数据的存储和提取,服务器通过API与存储引擎进行通信。不同的存储引擎具有的功能不同,这样我们可以根据自己的实际需要进行选取。后面介绍MyISAM和InnoDB

4.存储层
数据存储层,主要是将数据存储在运行于裸设备的文件系统之上,并完成与存储引擎的交互。
  • 连接层

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

注:分配数据库连接线程池,控制数据库的连接和关闭等资源。

  • 业务逻辑处理层

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

注:提供SQL操作的接口,对SQL脚本按一定规则进行解析,并通过SQL优化器优化执行顺序,对于查询的语句还会进入缓存区,提升系统的性能。

  • 数据存储引擎层

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

注:存储引擎都是可插拔的,每个存储引擎所提供的服务都有所差异,所以我们需要根据具体的业务需要,选择合适的存储引擎,常用的只有两种MyISAM和lnnoDB,

  • 数据存储层

主要是将数据存储在运行于裸设备的文件系统上,并完成与存储引擎的交互。

注:将数据存储到磁盘上,并协同存储引擎对数据进行读写操作。

  • 总结

数据库逻辑结构共分为四层,分别是连接是(线程连接池)、业务逻辑处理层(SQL解析读取)、数据存储引擎层(存储引擎)、数据存储层(数据存储)

和其它的数据库相比,MySQL有点与众不同,它的架构可以在多种不同场景中应用并发挥良好作用,主要体现在存储引擎的架构上,插件式的存储引擎架构将查询处理和其它的系统任务以及数据的存储提取相分离,这种架构可以根据业务的需求和实际需要选择合适的存储引擎。

查询说明

首先,mysql的查询流程大致是:

  • mysql客户端通过协议与mysql服务器建连接,发送查询语句,先检查查询缓存,如果命中(一模一样的sql才能命中),直接返回结果,否则进行语句解析,也就是说,在解析查询之前,服务器会先访问查询缓存(query cache)——它存储SELECT语句以及相应的查询结果集。如果某个查询结果已经位于缓存中,服务器就不会再对查询进行解析、优化、以及执行。它仅仅将缓存中的结果返回给用户即可,这将大大提高系统的性能。

  • 语法解析器和预处理:首先mysql通过关键字将SQL语句进行解析,并生成一颗对应的“解析树”。mysql解析器将使用mysql语法规则验证和解析查询;预处理器则根据一些mysql规则进一步检查解析数是否合法。

  • 查询优化器当解析树被认为是合法的了,并且由优化器将其转化成执行计划。一条查询可以有很多种执行方式,最后都返回相同的结果。优化器的作用就是找到这其中最好的执行计划。

  • 然后,mysql默认使用的BTREE索引,并且一个大致方向是:无论怎么折腾sql,至少在目前来说,mysql最多只用到表中的一个索引。

1.6 Mysql存储引擎

查看命令

1 如何用命令查看

看你的mysql现在已提供什么存储引擎:
mysql> show engines;

看你的mysql当前默认的存储引擎:
mysql> show variables like ‘%storage_engine%’;

各个引擎简介

  • 1、InnoDB存储引擎

InnoDB是MySQL的默认事务型引擎,它被设计用来处理大量的短期(short-lived)事务。除非有非常特别的原因需要使用其他的存储引擎,否则应该优先考虑InnoDB引擎。行级锁,适合高并发情况

  • 2、MyISAM存储引擎

MyISAM提供了大量的特性,包括全文索引、压缩、空间函数(GIS)等,但MyISAM不支持事务和行级锁(myisam改表时会将整个表全锁住),有一个毫无疑问的缺陷就是崩溃后无法安全恢复。

  • 3、Archive引擎

Archive存储引擎只支持INSERT和SELECT操作,在MySQL5.1之前不支持索引。
Archive表适合日志和数据采集类应用。适合低访问量大数据等情况。
根据英文的测试结论来看,Archive表比MyISAM表要小大约75%,比支持事务处理的InnoDB表小大约83%。

  • 4、Blackhole引擎

Blackhole引擎没有实现任何存储机制,它会丢弃所有插入的数据,不做任何保存。但服务器会记录Blackhole表的日志,所以可以用于复制数据到备库,或者简单地记录到日志。但这种应用方式会碰到很多问题,因此并不推荐。

  • 5、CSV引擎

CSV引擎可以将普通的CSV文件作为MySQL的表来处理,但不支持索引。

CSV引擎可以作为一种数据交换的机制,非常有用。

CSV存储的数据直接可以在操作系统里,用文本编辑器,或者excel读取。

  • 6、Memory引擎

如果需要快速地访问数据,并且这些数据不会被修改,重启以后丢失也没有关系,那么使用Memory表是非常有用。Memory表至少比MyISAM表要快一个数量级。(使用专业的内存数据库更快,如redis)

  • 7、Federated引擎

Federated引擎是访问其他MySQL服务器的一个代理,尽管该引擎看起来提供了一种很好的跨服务器的灵活性,但也经常带来问题,因此默认是禁用的。

MyISAM和InnoDB

对比项 MyISAM InnoDB
外键 不支持 支持
事务 不支持 支持
锁表 表锁,即使操作一条记录也会锁住整个表,不适合高并发的操作 行锁,操作时只锁某一行,不对其它行有影响,适合高并发的操作
缓存 只缓存索引,不缓存真实数据 不仅缓存索引还要缓存真实数据,对内存要求较高,而且内存大小对性能有决定性的影响
占用空间 表空间占用小 表空间占用大
关注点 性能,查询速度快 事务
存储限制 256TB 64TB
数据压缩 支持 不支持
  • innodb 索引 使用 B+TREE myisam 索引使用 b-tree
  • innodb 主键为聚簇索引,基于聚簇索引的增删改查效率非常高。

阿里巴巴和淘宝的如何使用

  • 前期:阿里巴巴大部分MySQL数据库其实使用的是Percona的Xtradb原型加以修改。

  • Percona公司为MySQL数据库服务器进行了改进,新建了一款存储引擎叫Xtradb,这款存储引擎从性能上完全可以替代Innodb,在功能和性能上较MySQL有着很显著的提升,该版本提升了在高负载情况下的InnoDB的性能,为DBA提供一些非常有用的性能诊断工具;另外有更多的参数和命令来控制服务器行为。

  • 现在:2016年云栖大会·北京峰会上,阿里云宣布启动了 AliSQL、AliRedis 开源项目,AliSQL是基于MySQL官方版本的一个分支,由阿里云数据库团队维护,目前也应用于阿里巴巴集团业务以及阿里云数据库服务。

  • AliSQL的出现不仅从其他开源分支比如:Percona,MariaDB,WebScaleSQL等社区汲取精华,也沉淀了阿里巴巴多年在MySQL领域的经验和解决方案。该版本在社区版的基础上做了大量的性能与功能的优化改进,尤其适合电商、云计算以及金融等行业环境,针对电商秒杀场景,AliSQL有着特殊的优化,“在通用基准测试场景下,AliSQL版本比MySQL官方版本有着 70% 的性能提升,在秒杀场景下,性能提升 100倍”,可帮助中小企业和开发者提升数据运营能力。

  • 总结:通常在企业中,我们会使用InnoDB存储引擎,因为它支持事务,支持行锁,高并发处理性能更好,CPU及内存缓存页优化使得资源利用率更高。

  • 对于那种只需要较高的查询速度,没有什么其它特殊要求的,可以选择MyISAM存储引擎。

  • 但是需注意:MyISAM存储引擎 B-tree索引有一个很大的限制:参与一个索引的所有字段的长度之和不能超过1000字节。另外MyISAM数据和索引是分开,而InnoDB的数据存储是按聚簇(cluster)索引有序排列的,主键是默认的聚簇(cluster)索引,因此MyISAM虽然在一般情况下,查询性能比InnoDB高,但InnoDB的以主键为条件的查询性能是非常高的。

2.索引优化分析

2.1 性能下降SQL慢执行时间长等待时间长

查询数据过多

能不能拆,条件过滤尽量少

**关联了太多的表,太多join **

join 原理。用 A 表的每一条数据 扫描 B表的所有数据。所以尽量先过滤。

没有利用到索引
索引针对 列 建索引。但并不可能每一列都建索引

索引并非越多越好。当数据更新了,索引会进行调整。也会很消耗性能。

且 mysql 并不会把所有索引都用上,只会根据其算法挑一个索引用。所以建的准很重要。

服务器调优及各个参数设置(缓冲、线程数等)(不重要DBA的工作)

2.2 常见通用的Join查询

2.2.1 SQL执行顺序

手写

总结

2.2.2 Join图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 
1 A、B两表共有
select * from t_emp a inner join t_dept b on a.deptId = b.id;

2 A、B两表共有+A的独有
select * from t_emp a left join t_dept b on a.deptId = b.id;

3 A、B两表共有+B的独有
select * from t_emp a right join t_dept b on a.deptId = b.id;

4 A的独有
select * from t_emp a left join t_dept b on a.deptId = b.id where b.id is null;

5 B的独有
select * from t_emp a right join t_dept b on a.deptId = b.id where a.deptId is null;

6 AB全有
#MySQL Full Join的实现 因为MySQL不支持FULL JOIN,下面是替代方法
#left join + union(可去除重复数据)+ right join
SELECT * FROM t_emp A LEFT JOIN t_dept B ON A.deptId = B.id
UNION
SELECT * FROM t_emp A RIGHT JOIN t_dept B ON A.deptId = B.id
这里因为要联合的缘故,不能考虑到小表驱动大表的情况。只能用right join。要保证查询出来的数字要一致。
7 A的独有+B的独有
SELECT * FROM t_emp A LEFT JOIN t_dept B ON A.deptId = B.id WHERE B.`id` IS NULL
UNION
SELECT * FROM t_emp A RIGHT JOIN t_dept B ON A.deptId = B.id WHERE A.`deptId` IS NULL;

2.2.3 建表SQL

2.2.4 7种JOIN

2.3 索引简介

2.3.1 是什么

1
2
MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构。
可以得到索引的本质:索引是数据结构。

你可以简单理解为“排好序的快速查找数据结构”。

详解

在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)的数据,这样就可以再这些数据结构上实现高级查找算法。这种数据结构,就是索引。下图就是一种可能的索引方式示例:

左边是数据表,一共有两列七条记录,最左边的是数据记录的物理地址

为了加快Col2的查找,可以维护一个右边所示的二叉查找树,每个节点分别包含索引键值和一个指向对应数据记录物理地址的指针,这样就可以运用二叉查找在一定的复杂度内获取到相应数据,从而快速的检索出符合条件的记录。

二叉树弊端之一:二叉树很可能会发生两边不平衡的情况。

B-TREE: (B:balance) 会自动根据两边的情况自动调节,使两端无限趋近于平衡状态。可以使性能最稳定。(myisam使用的方式)

B-TREE弊端:(插入/修改操作多时,B-TREE会不断调整平衡,消耗性能)从侧面说明了索引不是越多越好。

B+TREE:Innodb 所使用的索引

一般来说索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储的磁盘上

我们平常所说的索引,如果没有特别指明,都是指B树(多路搜索树,并不一定是二叉的)结构组织的索引。其中聚集索引,次要索引,覆盖索引,复合索引,前缀索引,唯一索引默认都是使用B+树索引,统称索引。当然,除了B+树这种类型的索引之外,还有哈稀索引(hash index)等。

2.3.2 优势

  • 类似大学图书馆建书目索引,提高数据检索的效率,降低数据库的IO成本
  • 通过索引列对数据进行排序,降低数据排序的成本,降低了CPU的消耗

2.3.3 劣势

实际上索引也是一张表,该表保存了主键与索引字段,并指向实体表的记录,所以索引列也是要占用空间的

虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE。
因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件每次更新添加了索引列的字段,
都会调整因为更新所带来的键值变化后的索引信息

索引只是提高效率的一个因素,如果你的MySQL有大数据量的表,就需要花时间研究建立最优秀的索引,或优化查询语句

2.3.4 mysql索引分类

主键索引

设定为主键后数据库会自动建立索引,innodb为聚簇索引

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
语法
随表一起建索引:
CREATE TABLE customer (id INT(10) UNSIGNED AUTO_INCREMENT ,customer_no VARCHAR(200),customer_name VARCHAR(200),
PRIMARY KEY(id)
);
unsigned (无符号的)
使用 AUTO_INCREMENT 关键字的列必须有索引(只要有索引就行)。

CREATE TABLE customer2 (id INT(10) UNSIGNED ,customer_no VARCHAR(200),customer_name VARCHAR(200),
PRIMARY KEY(id)
);

单独建主键索引:
ALTER TABLE customer
add PRIMARY KEY customer(customer_no);

删除建主键索引:
ALTER TABLE customer
drop PRIMARY KEY ;

修改建主键索引:
必须先删除掉(drop)原索引,再新建(add)索引

单值索引

即一个索引只包含单个列,一个表可以有多个单列索引

索引建立成哪种索引类型?

根据数据引擎类型自动选择的索引类型

除开 innodb 引擎主键默认为聚簇索引 外。 innodb 的索引都采用的 B+TREE

myisam 则都采用的 B-TREE索引

1
2
3
4
5
6
7
8
9
10
11
12
13
语法
随表一起建索引:
CREATE TABLE customer (id INT(10) UNSIGNED AUTO_INCREMENT ,customer_no VARCHAR(200),customer_name VARCHAR(200),
PRIMARY KEY(id),
KEY (customer_name)
);
随表一起建立的索引 索引名同 列名(customer_name)
单独建单值索引:
CREATE INDEX idx_customer_name ON customer(customer_name);

删除索引:
DROP INDEX idx_customer_name ;

唯一索引

索引列的值必须唯一,但允许有空值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
语法
随表一起建索引:
CREATE TABLE customer (id INT(10) UNSIGNED AUTO_INCREMENT ,customer_no VARCHAR(200),customer_name VARCHAR(200),
PRIMARY KEY(id),
KEY (customer_name),
UNIQUE (customer_no)
);
建立 唯一索引时必须保证所有的值是唯一的(除了null),若有重复数据,会报错。

单独建唯一索引:
CREATE UNIQUE INDEX idx_customer_no ON customer(customer_no);

删除索引:
DROP INDEX idx_customer_no on customer ;

复合索引

即一个索引包含多个列

在数据库操作期间,复合索引比单值索引所需要的开销更小(对于相同的多个列建索引)

当表的行数远大于索引列的数目时可以使用复合索引

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
语法
复合索引与单值索引有什么区别?
复合索引:create index idx_no_name on emp(no,name); // no 与 name 有同一个索引 idx_no_name
单值索引:create index idx_no on emp(no);
create index idx_name on emp(name);

疑惑:同一数据引擎,都是采用一样的索引类型(B-TREE或B+TREE),复合索引与单值索引的区别是什么?该怎么使用?


随表一起建索引:
CREATE TABLE customer (id INT(10) UNSIGNED AUTO_INCREMENT ,customer_no VARCHAR(200),customer_name VARCHAR(200),
PRIMARY KEY(id),
KEY (customer_name),
UNIQUE (customer_name),
KEY (customer_no,customer_name)
);

单独建索引:
CREATE INDEX idx_no_name ON customer(customer_no,customer_name);

删除索引:
DROP INDEX idx_no_name on customer ;


基本语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
语法

创建:ALTER mytable ADD [UNIQUE ] INDEX [indexName] ON (columnname(length))

删除:DROP INDEX [indexName] ON mytable;

查看:SHOW INDEX FROM table_name\G


使用ALTER命令
有四种方式来添加数据表的索引:
ALTER TABLE tbl_name ADD PRIMARY KEY (column_list): 该语句添加一个主键,这意味着索引值必须是唯一的,且不能为NULL

ALTER TABLE tbl_name ADD UNIQUE index_name (column_list): 这条语句创建索引的值必须是唯一的(除了NULL外,NULL可能会出现多次)。

ALTER TABLE tbl_name ADD INDEX index_name (column_list): 添加普通索引,索引值可出现多次。

ALTER TABLE tbl_name ADD FULLTEXT index_name (column_list):该语句指定了索引为 FULLTEXT ,用于全文索引。


2.3.5 哪些情况需要创建索引

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1. 主键自动建立唯一索引

2. 频繁作为查询条件的字段应该创建索引(where 后面的语句)

3. 查询中与其它表关联的字段,外键关系建立索引

A 表关联 B 表:A join B 。 on 后面的连接条件 既 A 表查询 B 表的条件。所以 B 表被关联的字段建立索引能大大提高查询效率

因为在 join 中,join 左边的表会用每一个字段去遍历 B 表的所有的关联数据,相当于一个查询操作

4. 单键/组合索引的选择问题,who?(在高并发下倾向创建组合索引)

5. 查询中排序的字段,排序字段若通过索引去访问将大大提高排序速度
group by 和 order by 后面的字段有索引大大提高效率

6. 查询中统计或者分组字段

2.3.6 哪些情况不要创建索引

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
1. 表记录太少

2. 经常增删改的表
Why:提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE。
因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件

3. Where条件里用不到的字段不创建索引
索引建多了影响 增删改 的效率


4. 数据重复且分布平均的表字段,因此应该只为最经常查询和最经常排序的数据列建立索引。

注意,如果某个数据列包含许多重复的内容,为它建立索引就没有太大的实际效果。

假如一个表由10万记录,由一个字段A只有 T 和 F 两种值,且每个值的分布概率大约为 50%,
那么对这种表A字段建索引一般不会提高数据库的查询速度。

索引的选择性是指缩影列中不同值的数目与表中记录数相比。如果一个表中有2000条记录,表索引列有1980个不同的值,
那么这个缩影的选择性就是 1980/2000=0.99, 一个索引的选择性越接近于1,这个索引的效率就越高

2.4 mysql索引结构

2.4.1 BTree索引

原理图(Myisam普通索引)

1
2
3
4
5
6
7
8
9
10
11
12
【初始化介绍】 
一颗b树,浅蓝色的块我们称之为一个磁盘块,可以看到每个磁盘块包含几个数据项(深蓝色所示)和指针(黄色所示),
如磁盘块1包含数据项17和35,包含指针P1、P2、P3,
P1表示小于17的磁盘块,P2表示在17和35之间的磁盘块,P3表示大于35的磁盘块。
真实的数据存在于叶子节点即3、5、9、10、13、15、28、29、36、60、75、79、90、99。
非叶子节点不存储真实的数据,只存储指引搜索方向的数据项,如17、35并不真实存在于数据表中。

【查找过程】
如果要查找数据项29,那么首先会把磁盘块1由磁盘加载到内存,此时发生一次IO,在内存中用二分查找确定29在17和35之间,锁定磁盘块1的P2指针,内存时间因为非常短(相比磁盘的IO)可以忽略不计,通过磁盘块1的P2指针的磁盘地址把磁盘块3由磁盘加载到内存,发生第二次IO,29在26和30之间,锁定磁盘块3的P2指针,通过指针加载磁盘块8到内存,发生第三次IO,同时内存中做二分查找找到29,结束查询,总计三次IO。

真实的情况是,3层的b+树可以表示上百万的数据,如果上百万的数据查找只需要三次IO,性能提高将是巨大的,如果没有索引,每个数据项都要发生一次IO,那么总共需要百万次的IO,显然成本非常非常高。

2.4.2 B+Tree索引

B+TREE 第二级的 数据并不能直接取出来,只作索引使用。在内存有限的情况下,查询效率高于 B-TREE
B-TREE 第二级可以直接取出来,树形结构比较重,在内存无限大的时候有优势。

2.4.3 聚簇索引与非聚簇索引

聚簇索引并不是一种单独的索引类型,而是一种数据存储方式。

术语‘聚簇’表示数据行和相邻的键值进错的存储在一起。

如下图,左侧的索引就是聚簇索引,因为数据行在磁盘的排列和索引排序保持一致。

1
2
3
4
5
6
7
8
9
10
聚簇索引的好处:
按照聚簇索引排列顺序,查询显示一定范围数据的时候,由于数据都是紧密相连,数据库不用从多个数据块中提取数据,所以节省了大量的io操作。

聚簇索引的限制:
对于mysql数据库目前只有innodb数据引擎支持聚簇索引,而Myisam并不支持聚簇索引。

由于数据物理存储排序方式只能有一种,所以每个Mysql的表只能有一个聚簇索引。一般情况下就是该表的主键。

为了充分利用聚簇索引的聚簇的特性,所以innodb表的主键列尽量选用有序的顺序id,而不建议用无序的id,比如uuid这种。(参考聚簇索引的好处。)
这里说明了主键索引为何采用自增的方式:1、业务需求,有序。2、能使用到聚簇索引

2.4.4 full-text全文索引

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
全文索引(也称全文检索)是目前搜索引擎使用的一种关键技术。它能够利用【分词技术】等多种算法智能分析出文本文字中关键词的频率和重要性,然后按照一定的算法规则智能地筛选出我们想要的搜索结果。

CREATE TABLE `article` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(200) DEFAULT NULL,
`content` text,
PRIMARY KEY (`id`),
FULLTEXT KEY `title` (`title`,`content`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

不同于like方式的的查询:
SELECT * FROM article WHERE content LIKE ‘%查询字符串%’;
全文索引用match+against方式查询:
SELECT * FROM article WHERE MATCH(title,content) AGAINST (‘查询字符串’);

明显的提高查询效率。

限制:
mysql5.6.4以前只有Myisam支持,5.6.4版本以后innodb才支持,但是官方版本不支持中文分词,需要第三方分词插件。
5.7以后官方支持中文分词。

随着大数据时代的到来,关系型数据库应对全文索引的需求已力不从心,逐渐被 solr,elasticSearch等专门的搜索引擎所替代。

2.4.5 Hash索引

1
2
3
Hash索引只有Memory, NDB两种引擎支持,Memory引擎默认支持Hash索引,如果多个hash值相同,出现哈希碰撞,那么索引以链表方式存储。

NoSql采用此中索引结构。

2.4.6 R-Tree索引

1
2
3
4
R-Tree在mysql很少使用,仅支持geometry数据类型,支持该类型的存储引擎只有myisam、bdb、innodb、ndb、archive几种。

相对于b-tree,r-tree的优势在于范围查找。

2.5 性能分析

2.5.1 Msql Query Optimizer

  1. MySQL 中有专门负责优化 select 语句的优化器模块, 主要功能:通过计算分析系统中收集到的统计信息,为
    客户端请求的 Query 提供他认为最优的执行计划(他认为最优的数据检索方式, 但不见得是DBA 认为最优的, 这部分最耗费时间)

  2. 当客户端向 MySQL 请求一条 Query ,命令解析模块完成请求分类, 区别是select 并转发给 MySQL Query Optimizer 时,
    MySQL Query Optimizer 首先会对整条Query 进行优化,处理调一些常量表达式的预算,直接换算成常量值。
    并对Query 中查询条件进行简化和转换,如去掉一些无用或显而易见的条件、结构调整等,然后分析 Query 中的 Hint 信息
    (如果有),看显示 Hint 信息是否可以完全确定 Query 执行计划。如果没有 Hint 或 Hint 信息还不足以完全确定执行几乎,则会
    读取所涉及对象的统计信息,根据 Query 进行写相应的计算分析, 然后再得出最后的执行计划

2.5.2 MySQL常见瓶颈

  • CPU:CPU在饱和的时候一般发生在数据装入内存或从磁盘上读取数据的时候
  • IO:磁盘 I/O 瓶颈发生在装入数据远大于内存容量的时候
  • 服务器硬件的性能瓶颈:top, free, iostat 和 vmstat 来查看系统的性能状态

2.5.3 Explain

2.5.3-1 是什么(查看执行计划)

使用EXPLAIN关键字可以模拟优化器执行SQL查询语句,从而知道MySQL是

如何处理你的SQL语句的。分析你的查询语句或是表结构的性能瓶颈

官网介绍:https://dev.mysql.com/doc/refman/5.7/en/explain-output.html

2.5.3-2 能干嘛
  • 表的读取顺序
  • 哪些索引可以使用
  • 数据读取操作的操作类型
  • 哪些索引被实际使用
  • 表之间的引用
  • 每张表有多少行被优化器查询
2.5.3-3 怎么玩

Explain + SQL语句

执行计划包含的信息

建表脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
CREATE TABLE t1(id INT(10) AUTO_INCREMENT,content  VARCHAR(100) NULL ,  PRIMARY KEY (id));
CREATE TABLE t2(id INT(10) AUTO_INCREMENT,content VARCHAR(100) NULL , PRIMARY KEY (id));
CREATE TABLE t3(id INT(10) AUTO_INCREMENT,content VARCHAR(100) NULL , PRIMARY KEY (id));
CREATE TABLE t4(id INT(10) AUTO_INCREMENT,content VARCHAR(100) NULL , PRIMARY KEY (id));


INSERT INTO t1(content) VALUES(CONCAT('t1_',FLOOR(1+RAND()*1000)));

INSERT INTO t2(content) VALUES(CONCAT('t2_',FLOOR(1+RAND()*1000)));

INSERT INTO t3(content) VALUES(CONCAT('t3_',FLOOR(1+RAND()*1000)));

INSERT INTO t4(content) VALUES(CONCAT('t4_',FLOOR(1+RAND()*1000)));

2.5.3-4 各字段解释
1. id

select 查询的序列号,包含一组数字, 表示查询中执行 select 子句或操作表的顺序

id相同,执行顺序由上至下

id不同,如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行

id相同不同,同时存在

id 如果相同,可以认为是一组的,从上往下执行;
在所有组中,id 值越大,优先级越高,越先执行

衍生 = DERIVED

1
2
3
4
5
derived_merge是MySQL 5.7引入的,其会试图将Derived Table(派生表,from后面的子查询),视图引用,
公用表表达式(Common table expressions)与外层查询进行合并。

MySQL 5.7中不再兼容的实现方式,可以通过调整optimizer_switch来加以规避
set optimizer_switch='derived_merge=off';
2. select_type

有那些

查询的类型,主要是用于区别
普通查询,联合查询,子查询等复杂的查询

1
2
3
4
5
6
1. simple --简单的 select 查询,查询中不包含子查询或者union
2. primary --查询中若包含任何复杂的子部分,最外层查询则被标记为
3. subquery --在 select 或 where 列表中包含子查询
4. derived --在 from 列表中包含的子查询被标记为 derived (衍生) MySQL 会递归执行这些子查询,把结果放在临时表中。
5. union --若第二个 select 出现 union 之后,则被标记为 union , 若 union 包含在 from 子句查询中,外层 select 将被标记为 derived
6. union result --从 union 表获取结果的 select
3. table

这行数据是关于哪张表的(这个真没啥说的了…..)

4. type

访问类型排列

显示查询使用了何种类型,
从最好到最差依次是:
system>const>eq_ref>range>index>ALL

**system **

1
表只有一行记录(等于系统表),这是 const 类型的特列, 平时不会出现,这个也可以忽略不计

const

1
2
表示通过索引一次就找到了, const 用于比较 primary key 或者 unique 索引。 因为只匹配一行数据,所以很快如将
主键置于where 列表中, MySQL 就能将该查询转换为一个常量

eq_ref

1
唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键或唯一索引扫描

ref

1
2
3
非唯一性索引扫描, 返回匹配某个单独值的所有行,
本质上也是一种索引访问,它返回所有匹配某个单独的行,然而,
它可能会找到多个符合个条件的行,所以它应该属于查找和扫描的混合体

range

1
2
3
只检索给定范围内的行,使用一个索引来选择行。key 列显示使用了哪个索引
一般就是你在 where 语句中出现了 between、<、>、in 等的查询
这种范围扫描索引比全表扫描要好,因为它只需要开始于索引的某个点,而结束于另一个点,不用全表扫描

index

1
2
Full Index Scan , index 于 ALL的却别 ,index 类型只遍历索引树, 这通常比 ALL 快, 因为索引文件通常比数据文件小。
(也就是说虽然 all 和 index 都是读全表,但是index 是从索引中读取的, 而 all 是从硬盘中读取的 )

ALL

1
Full Table Scan 将遍历全表找到匹配的行

5. possible_keys

显示可能应用在这张表中的索引,一个或多个。
查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询实际使用

6. key

实际使用的缩影,如果为NULL,则没有使用索引

查询中若使用了覆盖索引,则该索引仅出现在KEY列表中

7. key_len
1
2
3
表示索引中使用的字节数,可通过该列计算查询中的使用的索引的长度,在不损失精确性的情况下,长度越短越好

key_len 显示的只为索引字段的最大可能长度, 并非实际使用长度。即 key_len e是更具表定义计算而得,不是通过表内检索出的。

总结:条件越多,付出的代价越大,key_len 的长度也就越大,建议在一定条件的情况下,key_len 越短,效率越高。

8. ref

显示索引的哪一列被使用了,如果可能的话,是一个常数。那些列或常量被用于查找索引列上的值

1
2
3
由,key_len 可知,t2 表的 idx_col1_col2 被从充分使用了, co1 匹配了 t1 表的 col1, t2 表的 col1 匹配了一个常量即 ‘ac’

查询中与其他表关联的字段,外键关系建立索引。(实际开发中不推荐)
9. rows

根据表统计信息及索引选用情况, 大致估算出找到所需的记录所需读取的行数

1.Using filesort

说明 mysql 会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取。
mysql 中无法利用索引完成的排序叫做 “文件排序”

2.Using temporary

1
2
使用了临时表保存中间结果, MySQL 在对查询结果排序时使用临时表。
常见于排序 order by 和分组查询 group by 。

3.Using index

1
2
3
表示相应的 select 操作使用了覆盖索引 (Covering Index), 避免了访问表的数据行,效率不错~
如果同时出现 using where , 表示索引被用来执行索引键值的查找;
如果没有同时出现 using where , 表明索引引用来读取数据而非执行查找动作。

覆盖索引 (Covering Index)

1
2
3
4
5
6
7
8
9
覆盖索引 (Covering Index), 一说为索引覆盖

理解方式一:就是 select 的数据列只用从索引中就能取得,不必读取数据行, MySQL 可以利用你索引返回 select 列表的字段, 而不必根据索引再次读取数据文件,换句话说查询列要被所建的索引覆盖

理解方式二:索引是高效找到的行的一个方法, 但是一般数据库也能使用索引找到一个列的数据, 因此它不必读取整个行,毕竟索引叶子节点存储了他们索引的数据;当能通过读取索引就可以得到想要的数据, 那就不需要读取行了。一个索引包含了(或覆盖了)满足查询结果的数据就叫做覆盖索引。

注意:
如果要使用覆盖索引,一定要注意 select 列表汇总只取出需要的列,不可 select *
因为如果将所有字段一起做索引将会导致索引文件过大,查询性能下降。

4.Using where

表明使用了 where 过滤

5.using join buffer

使用了链接缓存

6.impossible where

where 子句的值总是 false , 不能用来获取任何元组

7.select tbale optimized away

在没有 GROUPBY 子句的情况下,基于索引优化 MIN/MAX 操作或者对于 MyISAM 存储引擎优化 COUT(*) 操作
不必等到执行阶段再进行计算,查询执行计划生成的阶段即完成优化。

8.distinct

优化 distinct 操作 在找到第一匹配的元祖后立即停止找相同值的动作。

2.5.4 热身 CASE