MySQL的架构介绍
MySQL的索引优化分析
MySQL的查询截取分析
MySQL的锁机制
MySQL的主从复制
一、MySQL的架构介绍
-
MySQL简介
* 概述 1、MySQL 由瑞典 MySQL AB公司开发,目前属于Oracle公司; 2、MySQL是一种关系型数据库管理系统,将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性; 3、MySQL是开源的免费的 4、MySQL支持大型的数据库,可以处理拥有上千万条记录的大型数据库,支持5000万条记录的数据仓库,32位系统表文件最大可支持4GB,64位系统支持最大的表文件8TB; 5、MySQL使用标准的SQL数据语言形式 6、MySQL可以允许在多个系统上,并且支持多种语言,如:C、C++、Python、Java、PHP等,MySQL对PHP有很好的支持,PHP是目前流行的Web开发语言 7、MySQL可以定制,采用了GPL协议,可以修改源码来开发自己的MySQL系统 * 高级MySQL 1、MySQL内核的优化,编码和改写 2、sql优化 3、MySQL服务器的优化 4、各种参数常量设定 5、查询语句优化 6、主从复制
-
MySQL Linux版的安装
1、下载地址 2、检查当前系统是否安装过MySQL ①、查询命令:rpm -qa|grep -i mysql ②、删除命令:rpm -e RPM软件包名(如果执行查询命令,发现安装过,删除时的软件包名为上一步查询出来的名字)
3、安装MySQL服务端
安装命令:rpm -ivh MySQL服务端的软件包名 【i表示安装, v表示日志, h表示进度条】
安装MySQL服务端.png
4、安装MySQL客户端
安装命令:rpm -ivh MySQL客户端的软件包名 【i表示安装, v表示日志, h表示进度条】
安装MySQL客户端.png
5、查看MySQL 安装时创建的MySQL用户和MySQL组
检查MySQL 是否安装成功,有两种方法:
①、MySQL 安装成功后,会创建MySQL用户和MySQL组,查看MySQL用户或MySQL组,如果有,则表示安装成功
cat /etc/passwd|grep mysql
cat /etc/group|grep mysql
②、执行 mysqladmin --version命令,如果显示除MySQL的安装版本,则表示安装成功
6、MySQL服务的启 + 停
service mysql start
service mysql stop
7、MySQL 服务启动后,开始连接
①、首次连接MySQL,只需输入mysql,无需输入密码即可连接成功,因为MySQL默认没有密码。
②、按照安装MySQL 服务端时的提示修改登陆密码:
执行命令:/usr/bin/mysqladmin -u root password 123456 即可
③、设置登陆密码成功之后,再次连接MySQL 需要输入:mysql -u用户名 -p密码
8、自启动MySQL服务
①、设置开机自启动MySQL:chkconfig mysql on
②、查看:chkdinfig --list|grep mysql
③、执行:ntsysv 【看到[*] mysql 这一行,表示开机后自启动mysql, 按 F1可获取关于某项服务的详情】
9、MySQL的安装位置
①、在linux 下查看MySQL 的安装目录:ps -ef|grep mysql
②、 路径 解释
/var/lib/mysql/ mysql数据库文件的存放路径
/usr/share/mysql mysql配置文件目录
/usr/bin mysql相关命令目录
/etc/init.d/mysql mysql启停相关脚本
10、修改配置文件位置
5.5 版本:cp /usr/share/mysql/my-huge.cnf /etc/my.cnf
5.6 版本:cp /usr/share/mysql/my-default.cnf /etc/my.cnf
【注意:版本不一样,配置文件的名称可能不一样】
11、修改字符集和数据存储路径
①、向MySQL中新建数据库,新建表,插入中文数据后,发现乱码,则需要修改复制到etc中的mysql配置文件,向其中添加指定的字符集
②、配置文件中有三处需要修改:
[client]
#password=your_password
port=3306
socket=/var/lib/mysql/mysql.sock
【】中为添加内容:
【default-character-set=utf8】
[mysqld]
port=3306
【character_set_server=utf8
character_set_client=utf8
collation-server=utf8_general_ci】
socket=/var/lib/mysql/mysql.sock
skip-external-locking
key_buffer_size=384M
max_allowed_packet=1M
table_open_cache=512
sort_buffer_size=2M
read_buffer_size=2M
read_rnd_buffer_size=8M
myisam_sort_buffer_size=64M
thread_cache_size=8
query_cache_size=32M
#Try number of CPU`s*2 for thread_concurrency
thread_concurrency=8M
[mysql]
no-auto-rehash
【default-character-set=utf8】
③、修改配置完成之后,需要重启服务,然后重新创建数据库,重新创建表,因为修改之后的配置文件对修改之前创建的库和表不起作用
-
MySQL主要配置文件
1、二进制日志 log-bin ①、主要用于主从复制 #Replication Master Server(default) #binary logging is required for replication log-bin=mysql-bin 2、错误日志 log-error ①、默认是关闭的,记录严重的警告和错误信息,每次启动和关闭的详细信息等。 3、查询日志 log ①、默认是关闭的,记录查询的sql语句,如果开启会减低mysql的整体性能,因为记录日志也是需要消耗系统资源的 4、数据文件 ①、两系统: Windows ----> MySQL数据库的安装目录下的data目录下可以创建很多库 Linux ----> 默认路径:/var/lib/mysql ; 查看当前系统中【即/var/lib/mysql 中】的全部库:ls -lF|grep ^d ②、frm 文件:存放表结构 ③、myd 文件:存放表数据 ④、myi 文件:存放表索引 5、如何配置 ①、windows ---> my.ini 文件 ②、Linux ---> /etc/my.cnf 文件
-
MySQL逻辑架构介绍
1、总体概述: 和其他数据库相比,MySQL有点与众不同,它的架构可以在多种不同场景中应用并发挥良好作用。 主要体现在存储引擎的架构上,插件式的存储引擎架构将查询处理和其它的系统任务以及数据的存储提取相分离。 这种架构可以根据业务的需求和实际需要选择合适的存储引擎。
①、连接层:
最上层是一些客户端和连接服务,包含本地sock通信和大多数基于客户端/服务端工具的类似于tcp/ip的通信。主要完成一些类似于连接处理、授权认证、及相关的安全方案。
在该层上引入了线程池的概念,为通过认证安全接入的客户端提供线程,同样在该层上可以实现基于SSL的安全链接。服务器也会为安全接入的每个客户端验证它所具有的操作权限。
②、服务层:
第二层架构主要完成大多数的核心服务功能,如SQL接口,并完成缓存的查询,SQL的分析和优化及部分内置函数的执行。所有跨存储引擎的功能也在这一层实现,如过程、函数等。
在该层,服务器会解析查询并创建相应的内部解析树,并对其完成相应的优化,如确定查询表的顺序,是否利用索引等,最后生成相应的执行操作。
如果是select 语句,服务器还会查询内部的缓存,如果缓存空间足够大,这样在解决大量读操作的环境中能够很好的提升系统的性能。
③、引擎层:
存储引擎层,存储引擎真正的负责了MySQL中数据的存储和提取,服务器通过API与存储引擎进行通信。不同的存储引擎具有的功能不同,这样我们可以根据自己的实际需要进行选取。【MyISAM、InnoDB】
④、存储层:
数据存储层,主要是将数据存储在运行于裸设备的文件系统之上,并完成于存储引擎的交互。
-
MySQL存储引擎
①、查看mysql提供的所有存储引擎: show engines; ②、查看mysql当前默认的存储引擎: show variables like '%storage_engine%'; ③、MyISAM 与 InnoDB 的区别: 对比项 MyISAM InnoDB 主外键 不支持 支持 事务 不支持 支持 行表锁 表锁,即使操作一条记录也会锁住整个表,不适合高并发的操作 行锁,操作时只锁某一行,不对其它行有影响,适合高并发的操作 缓存 只缓存索引,不缓存真实数据 不仅缓存索引还要缓存真实数据,对内存要求较高,而且内存大小对性能有决定性的影响 表空间 小 大 关注点 性能 事务 默认安装 Y Y
二、MySQL的索引优化分析
-
性能下降SQL慢:执行时间长 or 等待时间长 ?
1、主要常见原因如下: ①、查询语句写的不好 ②、索引失效 索引包含两种:单值索引 和 复合索引 ③、关联查询太多join (设计缺陷或不得已的需求) ④、服务器调优 及 各个参数的设置(缓冲、线程数等)
-
常见通用的Join查询
1、SQL的执行顺序: * 手写顺序
* 机读顺序
SQL机读顺序.png
* 总结
SQL执行顺序总结.png
2、Join图 【七种JOIN的SQL编写】
SQL JOINS
①、内连接
SQL: SELECT <select_list>
FROM TableA A
INNER JOIN TableB B
ON A.Key = B.Key;
内连接.png
②、左外连接
SQL: SELECT <select_list>
FROM TableA A
LEFT JOIN TableB B
ON A.Key = B.Key;
左外连接.png
③、右外连接
SQL: SELECT <select_list>
FROM TableA A
RIGHT JOIN TableB B
ON A.Key = B.Key;
右外连接.png
④、左外连接去交集
SQL: SELECT <select_list>
FROM TableA A
LEFT JOIN TableB B
ON A.Key = B.Key
WHERE B.Key IS NULL;
左外连接去交集.png
⑤、右外连接去交集
SQL: SELECT <select_list>
FROM TableA A
RIGHT JOIN TableB B
ON A.Key = B.Key
WHERE A.Key IS NULL;
右外连接去交集.png
⑥、全外连接 【注意:MySQL不支持全外连接】
SQL: SELECT <select_list>
FROM TableA A
FULL OUTER JOIN TableB B
ON A.Key = B.Key;
因为MySQL不支持,所以需要使用 UNION 联合查询,【UNION 可以去重】:
SELECT <select_list>
FROM TableA A
LEFT JOIN TableB B
ON A.Key = B.Key
UNION
SELECT <select_list>
FROM TableA A
ROGHT JOIN TableB B
ON A.Key = B.Key;
全外连接.png
⑦、全外连接去交集【注意:MySQL不支持全外连接】
SQL: SELECT <select_list>
FROM TableA A
FULL OUTER JOIN TableB B
ON A.Key = B.Key
WHERE A.Key IS NULL OR B.Key IS NULL;
因为MySQL不支持,所以需要使用 UNION 联合查询,【UNION 可以去重】:
SELECT <select_list>
FROM TableA A
LEFT JOIN TableB B
ON A.Key = B.Key
WHERE B.Key IS NULL
UNION
SELECT <select_list>
FROM TableA A
ROGHT JOIN TableB B
ON A.Key = B.Key
WHERE A.Key IS NULL;
全外连接去交集.png
-
索引简介
1、索引是什么? ①、MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构。 * 可以得到索引是本质:索引是一种数据结构 * 索引的目的在于提高查询效率,可以类比字典 ②、可以简单理解为:"排好序的快速查找数据结构" 详解: 在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法,这种数据结构,就是索引。 索引示例图如下:
左表是数据表,一共有两列七条记录,最左边的是数据记录的物理地址
为了加快Col2的查找,可以维护一个右边所示的二叉查找树,每个节点分别包含索引键值和一个指向对应数据记录物理地址的指针,
这样就可以运用二叉查找在一定的复杂度内获取到相应数据,从而快速的检索出符合条件的记录。
结论:数据本身之外,数据库还维护着一个满足特定查找算法的数据结构,这些数据结构以某种方式指向数据,这样就可以在这些数据结构的基础上实现高级查找算法,这种数据结构就是索引。
③、一般来说,索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储在磁盘上
④、平常所说的索引,如果没有特别指明,都是指B树(多路搜索树,并不一定是二叉树)结构组织的索引。
其中聚集索引,次要索引,覆盖索引,复合索引,前缀索引,唯一索引默认都是B+树索引,统称索引。当然,除了B+树这种类型的索引之外,还有哈希索引(hash index)等。
2、索引的优势
①、类似大学图书馆建书目索引,提高数据检索的效率,降低数据库的IO成本;
②、通过索引列对数据进行排序,降低数据排序的成本,降低了CPU的消耗。
3、索引的劣势
①、实际上索引也是一张表,该表保存了主键与索引字段,并指向实体表的记录,所以索引列也是要占用空间的;
②、虽然索引大大提高了查询速度,同时却会降低更新表的速度
如:对表进行 INSERT、UPDATE、DELETE,因为更新表时,MySQL不仅要保存数据,
还要保存一下索引文件每次更新添加了索引列的字段,都会调整因为更新所带来的键值变化后的索引信息
③、索引只是提高效率的一个因素,如果MySQL有大数据量的表,就需要花时间研究建立最优秀的索引,或优化查询语句
4、MySQL索引分类 【复合索引优于单值索引】
①、单值索引:即一个索引只包含单个列,一个表可以有多个单列索引
②、唯一索引:索引列的值必须唯一,但允许有空值
③、复合索引:即一个索引包含多个列
④、基本语法:
创建:
CREATE [UNIQUE] INDEX indexName ON mytable(columnname(length));
ALTER mytable ADD [UNIQUE] INDEX [indexName] ON (columnname(length));
* 注意:如果是CHAR、VARCHAR类型,length可以小于字段实际长度,
如果是BLOB或TEXT类型,必须指定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,用于全文索引
5、MySQL索引结构
①、BTree索引
检索原理
检索原理图.png
【初始化介绍】
一颗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,显然成本非常非常高。
②、Hash索引
③、full-text 全文索引
④、R-Tree 索引
6、哪些情况下需要创建索引
①、主键自动建立唯一索引
②、频繁作为查询条件的字段应该创建索引
③、查询中与其它表关联的字段,外键关系建立索引
④、频繁更新的字段不适合创建索引,因为每次更新不单单是更新了记录,还会更新索引,加重了IO负担
⑤、where条件里用不到的字段不创建索引
⑥、单键/组合索引的选择问题,who? (在高并发下倾向创建组合索引)
⑦、查询中排序的字段,排序字段若通过索引去访问将大大提高排序速度
⑧、查询中统计或者分组字段
7、哪些情况下不需要创建索引
①、表记录太少
②、经常增删改的表
原因:提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE,因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件
③、数据重复且分布平均的表字段,因此应该只为最经常查询和最经常排序的数据列建立索引。
注意:如果某个数据列包含许多重复的内容,为它建立索引就没有太大的实际效果
【假如一个表有10万行记录,有一个字段A只有T和F两种值,且每个值的分布概率大约为50%,那么对这种话表A字段建索引一般不会提高数据库的查询速度。
索引的选择性是指索引列中不同值的数目与表中记录数的比。如果一个表中有2000条记录,表索引列有1980个不同的值,那么这个索引的选择性就是1980/2000=0.99.
一个索引的选择性越接近于1,这个索引的效率就越高。】
-
性能分析
1、MySQL Query Optimizer(MySQL查询优化器) MySQL中有专门负责优化select语句的优化器模块,主要功能:通过计算分析系统中收集到的统计信息, 为客户端请求的Query提供它认为最优的执行计划(它认为最优的数据检索方式,但不见得是DBA认为最优的,这部分最耗费时间) 当客户端向MySQL请求一条Query,命令解析器模块完成请求分类,区别出是select并转发给MySQL Query Optimizer时, MySQL Query Optimizer 首先会对整条Query进行优化,处理掉一些常量表达式的预算,直接换算成常量值。 并对Query中的查询条件进行简化和转换,如去掉一些无用或显而易见的条件、结构调整等。然后分析Query中的Hint信息(如果有),看显示Hint信息是否可以完全确定该Query的执行计划。 如果没有Hint或Hint信息还不足以完全确定执行计划,则会读取所涉及对象的统计信息,根据Query进行写相应的计算分析,然后再得出最后的执行计划。 2、MySQL常见瓶颈 CPU:CPU在饱和的时候一般发生在数据装入内存或从磁盘上读取数据的时候 IO:磁盘I/O瓶颈发生在装入数据远大于内存容量的时候 服务器硬件的性能瓶颈:top、free、idstat和vmstat来查看系统的性能状态 3、Explain 是什么(查看执行计划)? 使用Explain关键字可以模拟优化器执行SQL查询语句,从而知道MySQL是如何处理SQL语句的。分析查询语句或是表结构的性能瓶颈。 能做什么? 表的读取顺序 数据读取操作的操作类型 哪些索引可以使用 哪些索引被实际使用 表之间的引用 每张表有多少行被优化器查询 怎么玩? Explain + 查询语句; 执行计划包含的信息: id select_type table type possible_keys key key_len ref rows Extra 各字段解释 id (1)、select 查询的序列号,包含一组数字,表示查询中执行select子句或操作表的顺序 (2)、三种情况: id相同,执行顺序由上至下 id不同,如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行 id相同又不同,同时存在
select_type
(1)、有六个:
id select_type
1 SIMPLE
2 PRIMARY
3 SUBQUERY
4 DERIVED
5 UNION
6 UNION RESULT
(2)、查询的类型,主要是用于区别普通查询、联合查询、子查询等的复杂查询
1、SIMPLE:简单的select查询,查询中不包含子查询或者UNION
2、PRIMARY:查询中若包含任何复杂的子查询,最外层查询则被标记为PRIMARY
3、SUBQUERY:在SELECT或WHERE列表中包含了子查询
4、DERIVED:在FROM列表中包含的子查询被标记为DERIVED(衍生),MySQL会递归执行这些子查询,把结果放在临时表里。
5、UNION:若第二个SELECT出现在UNION之后,则被标记为UNION,若UNION包含在FROM子句的子查询中,外层SELECT将被标记为:DERIVED
6、UNION RESULT:从UNION表获取结果的SELECT
table
显示这一行的数据是关于哪张表的
type【显示查询使用了何种类型】
(1)、type有8种值:
ALL、index、range、ref、eq_ref、const,system、NULL
(2)、访问类型排列:
type显示的是访问类型,是较为重要的一个指标,结果值从最好到最坏依次是:
system>const>eq_ref>ref>fulltext>ref_or_null>index_merge>unique_subquery>index_subquery>range>index>ALL
最常用的,从最好到最差依次是:system>const>eq_ref>ref>range>index>all
一般来说,得保证查询至少达到range级别,最好能达到ref
(3)、各种类型的解释:
system:表只有一行记录(等于系统表),这是const类型的特例,平时不会出现,也可以忽略不计
const:表示通过索引一次就找到了,const用于比较primary key或者unique索引,因为只匹配一行数据,所以很快
如:将主键置于where列表中,MySQL就能将该查询转换为一个常量
eq_ref:唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配,常见于主键或唯一索引扫描
ref:非唯一性索引扫描,返回匹配某个单独值的所有行。本质上也是一种索引访问,
它返回所以匹配某个单独值的行,然而,它可能会找到多个符合条件的行,所以它应该属于查找和扫描的混合体
range:只检索给定范围的行,使用一个索引来选择行,key列显示使用了哪个索引,
一般就是在你的where语句中出现了between、<、>、in等查询,这种范围扫描索引扫描比全表扫描要好,
因为它只需要开始于索引的某一点,而结束于另一点,不用扫描全部索引。
index:Full Index Scan,index与All区别为index类型只遍历索引树,这通常比all块,
因为索引文件通常比数据文件小(也就是说虽然all和index都是读全表,但index是从索引中读取的,而all是从硬盘中读的)
all:Full Table Scan,将遍历全表以找到匹配的行
possible_keys
(1)、显示可能应用在这张表中的索引,一个或多个
查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询实际使用
key
(1)、实际使用的索引,如果为NULL,则没有使用索引或索引没建
查询中若使用了覆盖索引,则该索引仅出现在key列表中
ley_len
(1)、表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度。在不损失精确性的情况下,长度越短越好。
key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的
ref
(1)、显示索引的哪一列被使用了,如果可能的话,是一个常数,哪些列或常量被用于查找索引列上的值
rows
(1)、根据表统计信息及索引选用情况,大致估算出找到所需的记录所需要读取的行数
Extra
(1)、包含不适合在其它列中显示但十分重要的额外信息
1、* Using filesort:说明mysql会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取。
MySQL中无法利用索引完成的排序操作称为"文件排序"
Using filesort.png
2、* Using temporary:使用了临时表保存中间结果,MySQL在对查询结果排序时使用临时表,
常见于排序order by 和分组查询group by
using temporary.png
3、USING index:表示相应的SELECT操作中使用了覆盖索引(Covering Index),避免访问了表的数据行,效率不错!
- 如果同时出现using where,表明索引被用来执行索引键值的查找;
- 如果没有同时出现using where,表明索引用来读取数据而非执行查找操作
- 覆盖索引(索引覆盖):
就是select的数据列只用从索引中就能取得,不必读取数据行,MySQL可以利用索引返回select列表中的字段,
而不必根据索引再次读取数据文件,即建的索引name,age,select 查找的字段刚到也是name,age。
4、Using where:表明使用了where过滤
5、Using join buffer:使用了连接缓存
6、impossible where:where子句的值总是false,不能用来获取任何元素
7、select tables optimized away:在没有GROUP by子句的情况下,基于索引优化MIN\MAX操作或者对于MyISAM存储引擎优化COUNT(*)操作,
不必等到执行阶段进行计算,查询执行计划生产的阶段即完成优化
8、distinct:优化distinct操作,在找到第一匹配的元素后即停止找同样值的动作
-
索引优化
1、索引分析 (1)、单张表:where条件中用到字段应该建立索引,除去求范围的字段 (2)、两张表:左连接,由左连接的特性决定,LEFT JOIN条件用于确定如何从右表搜索行, 左边一定都有,所以索引应该建立在右表; 右连接,由右连接的特性决定,RIGHT JOIN条件用于确定如何从左表搜索行, 右边一定都有,所以索引应该建立在左表 (3)、三张表: 2、索引失效(应该避免) (1)、全值匹配 (2)、最佳左前缀法则 如果索引了多列,要遵守最左前缀法则。指的是查询从索引的最左前列开始并且不能跳过索引中的列。 (3)、不在索引列上做任何操作(计算、函数、(自动or手动)类型转换),会导致索引失效而转向全表扫描 (4)、存储引擎不能使用索引中范围条件右边的列【范围之后全失效,范围之前的用于查询,范围用于排序】 (5)、尽量使用覆盖索引(只访问索引的查询(索引列和查询列一致)),减少select * (6)、mysql在使用不等于(!=或<>)的时候无法使用索引会导致全表扫码 (7)、is null,is not null 也无法使用索引 (8)、like以通配符开头('%abc...'),mysql索引失效会变成全表扫描的操作,但是like 以通配符开头('abc%')这种形式索引不会失效 【问题】:解决like'%字符串%'时索引失效问题? 使用覆盖索引 (9)、字符串不加单引号索引失效 (10)、少用or,用它来连接时会使索引失效 【总结】 假设index(a,b,c) where语句 索引是否被使用 where a = 3 Y,使用到a where a = 3 and b = 5 Y,使用到a,b where a = 3 and b = 5 and c = 4 Y,使用到a,b,c where b = 3 或者 where b = 3 and c = 4 或者 where c = 4 N where a = 3 and c = 5 使用到a,但是c不可以,因为b中间断了 where a = 3 and b > 4 and c = 5 使用到a,b,c不能用在范围之后,b断了 where a = 3 and b like 'kk%' and c = 4 Y,使用到a,b,c where a = 3 and b like '%kk' and c = 4 Y ,只用到a where a = 3 and b like '%kk%' and c = 4 Y ,只用到a where a = 3 and b like 'k%kk%' and c = 4 Y,使用到a,b,c 【面试题分析】 创建索引c1,c2,c3,c4,即创建了复合索引 index_test03_c1234,根据以下SQL分析索引的使用情况? (1)、where c1='a1' and c2='a2' and c3='a3' and c4='a4' 使用到索引 c1,c2 ,c3, c4 (2)、where c1='a1' and c2='a2' and c4='a4' and c3='a3' 使用到索引 c1,c2 ,c3, c4 (3)、where c4='a4' and c3='a3' and c2='a2' and c1='a1' 使用到索引 c1,c2 ,c3, c4 (4)、where c1='a1' and c2='a2' and c3>'a3' and c4='a4' 使用到索引 c1,c2 ,c3(c3只能部分用于排序,用不到查找), 使用不到索引c4 (5)、where c1='a1' and c2='a2' and c4>'a4' and c3='a3' 使用到索引 c1,c2 ,c3, c4 (6)、where c1='a1' and c2='a2' and c4='a4' order by c3 使用到索引 c1,c2 ,使用不到索引c3, c4 [严格的说用到c3,c3的作用是排序而不是查找] (7)、where c1='a1' and c2='a2' order by c3 使用到索引 c1,c2 ,使用不到索引c3, c4 [严格的说用到c3,c3的作用是排序而不是查找] (8)、where c1='a1' and c2='a2' order by c4 使用到索引 c1,c2 ,使用不到索引c3, c4 [出现了filesort] (9)、where c1='a1' and c5='a5' order by c2,c3 使用到索引 c1 ,使用不到索引c2,c3, c4 [但是c2和c3用于排序,没有出现filesort] (10)、where c1='a1' and c5='a5' order by c3,c2 使用到索引 c1 ,使用不到索引c2,c3, c4 [出现filesort,因为我们建的索引顺序是c1,c2,c3,c4, 它没有按照顺序来,order by c3,c2,顺序颠倒了] (11)、where c1='a1' and c2='a2' order by c2,c3 使用到索引 c1,c2,使用不到索引c3, c4 [但是c2和c3用于排序,没有出现filesort] (12)、where c1='a1' and c2='a2' and c5='a5' order by c2,c3 使用到索引 c1,c2,使用不到索引c3, c4 [但是c2和c3用于排序,没有出现filesort] (13)、where c1='a1' and c2='a2' and c5='a5' order by c3,c2 使用到索引 c1,c2,使用不到索引c3, c4 [但是c2和c3用于排序,没有出现filesort, 原因是前面有c2='a2'是一个常量,所以只剩下c3一个,不会出现filesort] (14)、where c1='a1' and c4='a4' group by c2,c3 使用到索引 c1,使用不到索引c2,c3, c4 (15)、where c1='a1' and c4='a4' group by c3,c2 使用到索引 c1,使用不到索引c2,c3, c4 [出现filesort和temporary] ■ 分析索引时,记住:定值是常量,范围之后是失效,最终看排序,一般order by是给了一个范围 ■ group by基本上都需要进行排序,会有临时表产生 3、一般性建议 (1)、对于单键索引,尽量选择针对当前Query过滤性更好的索引 (2)、在选择组合索引的时候,当前Query中过滤性最好的字段在索引字段顺序中,位置越靠前越好 (3)、在选择组合索引的时候,尽量选择能够包含当前Query中的where子句中更多字段的索引 (4)、尽可能通过分析统计信息和调整Query的写法来达到选择合适索引的目的 4、优化总结口诀 ■ 全值匹配我最爱,最左前缀要遵守; ■ 带头大哥不能死,中间兄弟不能断; ■ 索引列上少计算,范围之后全失效; ■ LIKE百分写最右,覆盖索引不写星; ■ 不等空值还有or,索引失效要少用; ■ VAR引号不可丢,SQL高级也不难!
三、MySQL的查询截取分析
-
查询优化
1、永远小表驱动大表(类似嵌套循环Nested Loop) 例如: select * from A where id in (select id from B) 当B表的数据集小于A表的数据集时,用in优于exists select * from A where exists (select 1 from B where B.id=A.id) 当B表的数据集大于A表的数据集时,用exists 优于 in 提示: ①、EXISTS()只返回TRUE或FALSE,因此子查询中的select * 也可以是select 1或select ‘X’,官方说实际执行时会忽略select 清单,因此没有区别 ②、EXISTS子查询的实际执行过程可能经过了优化而不是我们理解上的逐条对比 ③、EXISTS子查询往往也可以用条件表达式,其它子查询或JOIN来代替,何种最优具体分析 2、order by 关键字优化 (1)、ORDER BY 子句,尽量使用index方式排序,避免使用FIleSort方式排序 MySQL支持两种方式的排序,FileSort和Index,Index效率高,它指MySQL扫描索引本身完成排序。FileSort方式效率较低。 ORDER BY满足两情况,会使用Index方式排序: ①、ORDER BY语句使用索引最左前列 ②、使用where子句与order by子句条件列组合满足索引最左前列 (2)、尽可能在索引列上完成排序操作,遵照索引建的最佳左前缀 (3)、如果不在索引列上,filesort有两种算法:双路排序和单路排序 双路排序:MySQL4.1之前是使用双路排序,字面意思就是两次扫描磁盘,最终得到数据。 读取行指针和order by列,对它们进行排序,然后扫描已经排序好的列表,按照列表中的值重新从列表中读取对应的数据输出 从磁盘取排序字段,在buffer进行排序,再从磁盘取其它字段 * 取一批数据,要对磁盘进行两次扫描,众所周知,I\O是很耗时的,所以在mysql4.1之后,出现了第二种改进的算法,就是单路排序 单路排序: 从磁盘读取查询需要的所有列,按照order by列在buffer对它们进行排序,然后扫描排序后的列表进行输出, 它的效率更快一些,避免了第二次读取数据,并且把随机IO变成了顺序IO,但是它会使用更多的空间, 因为它把每一行都保存在内存中。 结论及引申出的问题:由于单路是后出的,总体而言好过双路,但是用单路也有问题: 在sort_buffer中,单路比双路要多占用很多空间,因为单路是把所有字段都取出,所以有可能取出的数据的总大小超出了sort_buffer的容量, 导致每次只能sort_buffer容量大小的数据,进行排序(创建tmp文件,多路合并),排完再取sort_buffer容量大小,再排,从而多次I/O. 本想省一次I/O操作,反而导致了大量的I/O操作,得不偿失。 (4)、优化策略 增大sort_buffer_size 参数的设置 增大max_length_for_sort_data 参数的设置 why? 提高Order by 的速度 ①、Order by 时,select * 是一个大忌,只查询需要的字段,这点非常重要,在这里影响是: * 当Query的字段大小总和小于max_length_for sort_data,而且排序字段不是TEXT|BOLB类型时,会用单路算法,否则使用双路排序 * 两种算法的数据都有可能超出sort_buffer的容量,超出之后,会创建tmp文件进行合并排序,导致多次I/O,但是用单路排序算法风险会更大一些,所以要提高sort_buffer_size ②、尝试提高sort_buffer_size 不管用哪种算法,提高这个参数都会提高效率,当然,要根据系统的能力去提高,因为这个参数是针对每个进程的 ③、尝试提高max_length_for_sort_data 提高这个参数,会增加用改进算法的概率,但是如果设的太高,数据总容量超出sort_buffer_size的概率就增大,明显症状是高的磁盘I/O活动和低的处理器使用率 (5)、总结: ①、为排序使用索引 MySQL两种排序方式:文件排序 或 扫描有序索引排序 MySQL能为排序与查询使用相同的索引 举例:索引 a_b_c(a, b, c) order by 能使用索引最左前缀 - order by a - order by a, b - order by a, b, c - order by a DESC, b DESC, c DESC 如果where使用索引的最左前缀定义为常量,则order by能使用索引 - where a=const order by b, c - where a=const and b=const order by c - where a=const and b>const order by b, c 不能使用索引进行排序 - order by a asc, b desc, c desc /* 排序不一致 */ - where g=const order by b, c /* 丢失a索引 */ - where a=const order by c /* 丢失b索引 */ - where g=const order by a, d /* d不是索引的一部分 */ - where a in(...) order by b, c /* 对于排序来说,多个相等条件也是范围查询 */ 3、GROUP BY 关键字优化 (1)、group by实质是先排序后进行分组,遵照索引建的最佳左前缀原则 (2)、当无法使用索引列,增大max_length_for_sort_data参数的设置 + 增大 sort_buffer_size 参数的设置 (3)、where高于having,能写在where限定的条件就不要去having限定了
-
慢查询日志
1、是什么? MySQL的慢查询日志是MySQL提供的一种日志记录,它用来记录在MySQL中响应时间超过阈值的语句, 具体指运行时间超过long_query_time指的sql,则会被记录到慢查询日志中。 long_query_time的默认值为10,意思是运行10秒以上的语句为慢查询语句 由它查看哪些sql超过了我们设置的阈值,然后结合explain进行全面分析 2、怎么玩? 说明 ①、默认情况下,MySQL数据库没有开启慢查询日志,需要我们手动设置这个参数 当然,如果不是调优需要的话,一般不建议启动该参数,因为开启慢查询日志会或多或少带来一定性能的影响。 慢查询日志支持将日志记录写入文件 查看是否开启及如何开启 ①、默认:SHOW VARIABLES LIKE '%slow_query_log%'; ②、开启:SET global slow_query_log=1; 【注意】:使用SET global slow_query_log=1;开启慢查询日志只对当前数据库生效,如果mysql重启后则会失效 * 如果要永久生效,就必须修改配置文件my.cnf(其它系统变量也是如此) 修改my.cnf,[mysql]下增加或修改参数: slow_query_log 和 slow_query_log_file后,然后重启mysql服务器,即将如下两行配置进my.cnf文件: slow_query_log =1; slow_query_log_file=/var/lib/mysql/host_name-slow.log 关于慢查询的参数slow_query_log_file,它指定慢查询日志文件的存放路径, 系统默认会给一个缺省的文件host_name-slow.log(如果没有指定参数slow_query_log_file的话) 开启慢查询日志后,什么样的SQL才会记录在慢查询日志中呢? ①、这个是由参数long_query_time控制,默认情况下,long_query_time的值是10秒 查看命令:show variables like 'long_query_time%'; ②、可以使用命令修改,也可以在my.cnf参数中修改 ③、在mysql源码里是判断大于long_query_time,而非大于等于(如果运行时间正好等于long_query_time,则不会被记录下来) 设置了之后没有效果: - 需要重新连接或断开一个会话才能看到修改值 show variables like 'long_query_time%'; - 或者使用命令: show global variables like 'long_query_time%'; 查询当前系统中有多少条慢查询记录:show global like '%Slow_queries%'; 配置版: my.cnf配置文件中的【mysqld】下配置: slow_query_log=1; slow_query_log_file=/var/lib/mysql/慢日志文件名; long_query_time=时间(秒); log_output=FILE 3、日志分析工具 mysqldumpslow (1)、查看mysqldumpslow的帮助信息:mysqldumpslow --help; s :表示按照何种方式排序; c :访问次数; l :锁定时间; r :返回记录; t :查询时间; al :平均锁定时间; ar :平均返回记录数; at :平均查询时间; g :后边搭配一个正则表达式,大小写不敏感; (2)、工作常用参考: ①、得到返回记录集最多的10个SQL mysqldumpslow -s r -t 10 /var/lib/mysql/日志名 ②、得到访问次数最多的10个SQL mysqldumpslow -s c -t 10 /var/lib/mysql/日志名 ③、得到按照时间排序的前10条里面含有左连接的查询语句 mysqldumpslow -s t -t 10 -g "left join" /var/lib/mysql/日志名 ④、另外建议在使用这些命令时结合 | 和 more使用,否则有可能出现爆屏情况 mysqldumpslow -s r -t 10 /var/lib/mysql/日志名 | more
-
批量插入数据脚本
1、 ①、创建函数,假如报错:This function has none of DETERMINISTIC...... 由于开启过慢查询日志,因为我们开启了bin-log,就必须为我们的function指定一个参数: show variables like 'log_bin_trust_function_creators'; set global log_bin_trust_function_creators=1; 这样添加了参数后,如果mysql重启,会失效 * 永久生效方法:在mysql配置文件的【mysqld】中添加: log_bin_trust_function_creators=1;
-
Show Profile
1、是什么? 是mysql提供可以用来分析当前会话中语句执行的资源消耗情况。 可以用于SQL的调优测量。 2、默认情况下,参数处于关闭状态,并保存最近15次的运行结果 3、分析步骤: ①、是否支持,看看当前的mysql版本是否支持 show variables like 'profiling'; 【默认是关闭的】 ②、开启功能,默认是关闭的,使用前需要开启 set profiling = on; ③、运行SQL ④、查看结果 show profiles; ⑤、诊断SQL show profile cpu,block io for query (执行show profiles中结果的Query_ID值); type: ALL:显示所有的开销信息 BLOCK IO:显示块IO相关开销 CONTEXT SWITCHES:上下文切换相关开销 CPU:显示CPU相关开销信息 IPC:显示发送和接收相关开销信息 MEMORY:显示内存相关开销信息 PAGE FAULTS:显示页面错误相关开销信息 SOURCE:显示和Source_function,Source_file,Source_line相关的开销信息 SWAPS:显示交换次数相关开销的信息 ⑥、日常开发需要注意的结论 convering HEAP to MyISAM 查询结果太大,内存都不够用了,往磁盘上写了 Creating tmp table 创建临时表 【拷贝数据到临时表,用完再删除】 Copying to tmp table on disk 把内存中临时表复制到磁盘 locked
-
全局查询日志
1、配置启用 在mysql的my.cnf中,设置如下: 开启: general_log=1; 记录日志文件的路径: general_log_file=/path/logfile 输出格式: log_output=FILE 2、编码启用 命令: set global general_log=1; set global log_output='TABLE'; 设置成功后,之后所编写的sql语句,将会记录到mysql库中的general_log表中,可以使用以下命令查看: select * from mysql.general_log; 3、永远不要在生产环境开启这个功能
四、MySQL的锁机制
-
概述
1、锁的定义: 锁是计算机协调多个进程或线程并发访问某一资源的机制 2、锁的分类: ①、从对数据操作的类型(读/写)分 读锁(共享锁): 针对同一份数据,多个读操作可以同时进行而不会互相影响 写锁(排它锁): 当前写操作没有完成前,它会阻断其它写锁和读锁 ②、从对数据操作的粒度分 表锁 行锁
-
三锁
1、表锁(偏读) ①、特点: - 偏向MyISAM存储引擎,开销小,加锁快; - 无死锁; - 锁定粒度大,发生锁冲突的概率最高,并发度最低 ②、手动添加表锁:lock table 表名 read(write), 表2名 read(write),...; 查看表中的锁:show open tables; 释放表锁:unlock tables; ③、案例: (1)、加读锁: 给session1的mylock表添加读锁,则只可以对该表进行读操作,不能对该表进行插入更新操作,也不能读其它没有加锁的表; 同时其它session可以读取session1中加锁的表,也可以读取和更新其它没有加锁的表,如果要对加锁的表进行插入更新操作, 则会出现阻塞情况,一直等待获得锁,直到该加锁的表释放锁,则阻塞立即消失,更新成功! (2)、加写锁:给session1的mylock表添加写锁,则可以对该表进行读插入更新等操作,不可以对其它没有加锁的表进行读插入更新操作; 同时其它session如果读取、插入更新session1中加锁的表,则会出现阻塞情况,一直等待session1加锁的表释放锁, 如果释放锁了,则其它session会立即执行成功,其它session可以查询插入更新其它没有加锁的表 ③、结论: MyISAM在执行查询语句前,会自动给涉及的所有表加读锁,在执行增删改前,会自动给涉及的表添加写锁; MySQL的表级锁有两种模式: 表共享读锁(Table Read Lock) 表独占写锁(Table Write Lock) 对MyISAM表进行操作,会有以下情况: 对MyISAM表的读操作(加读锁),不会阻塞其它进程对同一表的读请求,但会阻塞对同一表的写请求, 只有当读锁释放后,才会执行其它进程的写操作; 对MyISAM表的写操作(加写锁),会阻塞其它进程对同一表的读和写操作, 只有当写锁释放后,才会执行其它进程的读写操作 简而言之,就是读锁会阻塞写,但是不会阻塞读,而写锁则会把读和写都阻塞 ④、如何分析表锁: 可以通过命令:show status like 'table%'; 获取table_locks_waited和table_locks_immediate 可以通过检查上面两个值的状态变量来分析系统上的表锁定 这里有两个状态变量记录mysql内部表级锁定的情况,两个变量说明如下: table_locks_immediate:产生表级锁定的次数,表示可以立即获取锁的查询次数,每立即获取锁值加1; table_locks_waited:出现表级锁定争用而发生等待的次数 (不能立即获取锁的次数,每等待一次锁值加1) 此值高则说明存在着较严重的表级锁争用情况。 * 此外,MyISAM的读写锁调度是写优先,这也是MyISAM不适合做写为主表的引擎, 因为写锁后,其它线程不能做任何操作,大量的更新会使查询很难得到锁,从而造成永远阻塞。 2、行锁(偏写) ①、特点: - 偏向InnoDB存储引擎,开销大,加锁慢; - 会出现死锁; - 锁定粒度最小,发生锁冲突的概率最低,并发度最高 - InnoDB与MyISAM的最大不同有两点: 一是支持事务(Transaction) 二是采用了行级锁 ②、无索引或者索引失效,会导致行锁升级为表锁 ③、间隙锁的危害: 什么是间隙锁? 当用范围条件而不是相等条件检索数据,并请求共享或排它锁时,InnoDB会给符合条件的已有数据记录的索引项加锁; 当对于键值在条件范围内但并不存在的记录,叫做"间隙(GAP)". InnoDB也会对这个"间隙"加锁,这种锁机制就是所谓的间隙锁(Next-Key锁) 危害: 因为Query执行过程中通过范围查找的话,会锁定整个范围内所有的索引键值,即使这个键值并不存在。 间隙锁有一个比较致命的弱点,就是当锁定一个范围键值之后,即使某些不存在的键值也会被无辜的锁定, 而造成在锁定的时候无法插入锁定键值范围内的任何数据。在某些场景下这可能会对性能造成很大的危害。 ④、【面试题】如何锁定一行?
⑤、案例总结:
InnoDB存储引擎由于实现了行级锁定,虽然在锁定机制的实现方面所带来的性能损耗可能比表级锁定会要更高一些,
但是在整体并发处理能力方面要远远优于MyISAM的表级锁定。当系统并发量较高的时候,InnoDB的整体性能和MyISAM相比就会有比较明显的优势了。
但是,InnoDB的行级锁定同样也有弱点,当使用不当的时候,可能会让InnoDB的整体性能表现不仅不能比MyISAM高,甚至可能会更差。
⑥、如何分析行锁定?
通过 show status like 'innodb_row_lock%';检查状态变量来分析系统上的行锁的争夺情况
各个状态变量的说明如下:
innodb_row_lock_current_waits:当前正在等待锁定的数量;
innodb_row_lock_current_waits:当前正在等待锁定的数量;
* innodb_row_lock_time:从系统启动到现在锁定总时间长度;
* innodb_row_lock_time_avg:每次等待所花平均时间;
innodb_row_lock_time_max:从系统启动到现在等待最常的一次所花的时间;
* innodb_row_lock_waits:系统启动后到现在总共等待的次数;
尤其是当等待次数很高,而且每次等待时长也不小的时候,就需要分析系统中为什么会有如此多的等待,然后根据分析结果着手制定优化计划。
⑦、优化建议:
尽可能让所有数据检索都通过索引来完成,避免无索引行锁升级为表锁
合理设计索引,尽量缩小锁的范围
尽可能较少检索条件,避免间隙锁
尽量控制事务大小,减少锁定资源量和时间长度
尽可能低级别事务隔离
3、页锁
①、特点:
- 开销和加锁时间介于表锁和行锁之间;
- 会出现死锁;
- 锁定粒度介于表锁和行锁之间,并发度一般
五、MySQL的主从复制
-
复制的基本原理
1、MySQL复制过程分为三步: ①、master将改变记录到二进制日志(binary log),这些记录过程叫做二进制日志事件,binary log events; ②、slave将master的binary log events 拷贝到它的中继日志(relay log); ③、slave重做中继日志中的事件,将改变应用到自己的数据库中。MySQL复制是异步的且串行化的 2、slave会从master读取binlog来进行数据同步
-
复制的基本原则
1、每个slave只有一个master 2、每个slave只能有一个唯一的服务器ID 3、每个master可以有多个slave
-
复制的最大问题
延时
-
一主一从常见配置
1、mysql版本一致且后台以服务运行 2、主从都配置在[mysqld]节点下,都是小写 3、主机修改my.ini(windows)配置文件 ①、【必须】主服务器唯一ID:server-id=1; ②、【必须】启用二进制日志: log-bin=自己本地的路径/mysqlbin ③、【可选】启用错误日志 log-err=自己本地的路径/mysqlerr ④、【可选】根目录 basedir="自己本地路经" ⑤、【可选】临时目录 tmpdir="自己本地路经" ⑥、【可选】数据目录 datadir="自己本地路径/Data" ⑦、read-only=0 -----> 主机,读写都可以 ⑧、【可选】设置不要复制的数据库 binlog-ignore-db=mysql ⑨、【可选】设置需要复制的数据库 binlog-do-db=需要复制的主数据库名字 4、从机修改my.cnf(linux)配置文件 ①、【必须】从服务器唯一ID ②、【可选】启用二进制日志 5、因修改过配置文件,需要主机+从机都重启后台mysql服务 6、主机从机都关闭防火墙 ①、windows手动关闭 ②、关闭虚拟机linux防火墙:service iptables stop; 7、在Windows主机上建立账户并授权slave ①、GRANT REPLICATION SLAVE ON *.* TO '用户名'@'从机数据库IP' IDENTIFIED BY '密码'; ②、flush privileges; ③、查询master的状态:show master status; 记录下FIle和Position的值 ④、执行完此步骤后不要再操作主服务器MySQL,防止主服务器状态值变化 8、在linux从机上配置需要复制的主机 ①、GRANT MASTER TO MASTER_HOST='主机IP', MASTER_USER='用户名', MASTER_PASSWORD='密码', MASTER_LOG_FILE='FILE名', MASTER_LOG_POS=Position数字; ②、启动从服务复制功能:start slave; ③、查询master的状态:show slave status; 下面两个参数都是YES,则说明主从配置成功! Slave_IO_Running:YES Slave_SQL_Running:YES
9、主机新建库,新建表,INSERT记录,从机复制
10、如何停止从服务复制功能: stop slave;
网友评论