MySQL逻辑架构:mysql
第一层:客户端层,链接处理,受权认证,安全等功能。sql
第二层:核心层,查询解析,分析,优化,缓存,内置函数(时间,数学,加密),存储过程,触发器,视图数据库
第三层:存储引擎。负责MySQL中数据的存储和提取。缓存
MySQL查询过程安全
缓存对系统的额外消耗也不只仅在写操做,读操做也不例外:性能优化
任何的查询语句在开始以前都必须通过检查,即便这条 SQL 语句永远不会命中缓存。服务器
若是查询结果能够被缓存,那么执行完成后,会将结果存入缓存,也会带来额外的系统消耗。架构
基于此,咱们要知道并非什么状况下查询缓存都会提升系统性能,缓存和失效都会带来额外消耗,只有当缓存带来的资源节约大于其本 身消耗的资源时,才会给系统带来性能提高。函数
最后的忠告是不要轻易打开查询缓存,特别是写密集型应用。若是你实在是忍不住,能够将 query_cache_type 设置为 DEMAND。工具
这时只有加入 SQL_CACHE 的查询才会走缓存,其余查询则不会,这样能够很是自由地控制哪些查询须要被缓存。
解析语法,生成解析树。进行合法校验。
(不要听信你看到的关于优化的“绝对真理”,包括本文所讨论的内容,而应该是在实际的业务场景下经过测试来验证你关于执行计划以及响应时间的假设。)
1 学习使用EXPLAIN
2 建立正确的索引
数据库的索引像书的索引同样,他们的位置信息被保存,而且包含数据库的主要信息。可使用EXPLAIN来查找
缺失的索引。
3 拒绝默认的设置:有三个关于MySQL性能优化的设置:
innodb_buffer_pool_size:数据和索引被用做缓存的缓冲池。当数据库服务器有大量的系统内存时,能够用。
这个设置不要过大,也不要频繁的引发交换。
innodb_log_file_size:单个InnoDB日志文件大小。
max_connections:最大链接数
4 将数据库载入内存
将频繁访问的数据放入内存(好比30%的数据放入内存)
5 SSD存储
6 横向扩展??
纵向扩展
横向扩展
7 追求可视化
数据库受到流量负荷的影响,应用程序等致使的错误,为了快速、有效的解决问题,须要有监控机制。
经常使用的监测工具: MySQL企业监控器 / Monyog / Percona
8 Scheme设计与数据类型优化
选择数据类型只要遵循小而简单的原则就好,越小的数据类型一般会更快,占用更少的磁盘、内存,处理时须要的 CPU 周期也更少。好比,整型就比字符操做代价低,于是会使用整型来存储 ip 地址,使用 DATETIME 来存储时间,而不是使用字符串。
9 建立高性能索引
索引:一般说的索引时B-Tree索引。InnoDB用的是B+Tree.
平衡二叉树: 若是想二叉树的查询性能高,须要二叉树是平衡二叉树。
为何MYSQL不用平衡二叉树,而是用B+Tree树?随着数据库中数据的增长,索引自己大小随之增长,不可能所有存储在内存中,所以索引每每以索引文件的形式存储在磁盘上。这样的话,索引查找过程当中就要产生磁盘 I/O 消耗,相对于内存存取,I/O 存取的消耗要高几个数量级。能够想象一下一棵几百万节点的二叉树的深度是多少?若是将这么大深度的一颗二叉树放磁盘上,每读取一个节点,须要一次磁盘的 I/O 读取,整个查找的耗时显然是不可以接受的。那么如何减小查找过程当中的 I/O 存取次数?一种行之有效的解决方法是减小树的深度,将二叉树变为 m 叉树(多路搜索树),而 B+Tree 就是一种多路搜索树。
B+Tree树特征:
10 MySQL不使用索引的状况:非独立的列
“独立的列” :索引列不能是表达式的一部分,也不能是函数的参数。
11 前缀索引
列很长的状况下,索引开始的部分字符,有效节约索引空间(须要前面的部分有必定的区分度)
12 多列索引和索引顺序:
在多数状况下,在多个列上创建独立的索引并不能提升查询性能,理由很是简单,MySQL 不知道选择哪一个索引的查询效率更好(由于数据库中有多个索引的B+Tree, MySQL只能选择一个树作索引)。
多个列之间用AND时:联合索引优于独立索引。
多个列之间用OR、uniton时:每每会不走索引。
这种状况下,创建包含多个列的联合索引更加高效。
建立联合索引时, 把选择性更高的放在前面(由于这样,经过第一个过滤条件就能过滤掉大读书数据)。
13 避免多个范围条件
只能用其中一个索引。
14 覆盖索引
若是一个索引包含或者说覆盖全部须要查询的字段的值(就是select 后面的列),那么就没有必要再回表查询,这就称为覆盖索引。
15 使用索引扫描来排序:
扫描索引自己很快,由于只须要从一条索引记录移动到相邻的下一条记录。但若是索引自己不能覆盖全部须要查询的列,那么就不得不每扫描一条索引记录就回表查询一次对应的行。
在设计索引时,若是一个索引既可以知足排序,又知足查询,是最好的!!。只有当索引的列顺序和 ORDER BY 子句的顺序彻底一致,而且全部列的排序方向也同样时,才可以使用索引来对结果作排序。
若是查询须要关联多张表,则只有 ORDER BY 子句引用的字段所有为第一张表时,才能使用索引作排序。
ORDER BY 子句和查询的限制是同样的,都要知足最左前缀的要求。
16 避免冗余和重复索引
17 删除长期未使用的索引
18 查询优化
在关联查询的状况下:Group By中的表达式只涉及到一个表中的列。这样才有可能使用索引优化。
A和B表用c类关联时,不须要在A上创建索引,在B上建索引就OK(由于,A表不管是否有索引,都要遍历,B表和C表则须要走索引去寻找匹配的记录)。
19 优化LIMIT分页
LIMIT 10000 20 这样的查询,MySQL 须要查询 10020 条记录而后只返回 20 条记录,前面的 10000 条都将被抛弃,这样的代价很是高。
优化这种查询一个最简单的办法就是尽量的使用覆盖索引扫描,而不是查询全部的列。
20 优化UNION
除非确实须要服务器去重,不然就必定要使用 UNION ALL,若是没有 ALL 关键字,MySQL 会给临时表加上 DISTINCT 选项,这会致使整个临时表的数据作惟一性检查,这样作的代价很是高。
21 假设有联合索引 (user_name, sex, age), 如下三个查询,其实谓词的顺序不重要,都会用到联合索引的,这是由于MySQL作了优化。
可是联合索引的顺序却很重要,看下面22和23
select * from test where user_name=’test1’ and sex>0 and age =10
select * from test where sex>0 and user_name=’test1’ and age =10
select * from test where age =10 and user_name='test1' and sex>0
22 最左原则
mysql创建多列索引(联合索引)有最左前缀的原则,即最左优先,如:
若是有一个2列的索引(col1,col2),则已经对(col1)、(col1,col2)上创建了索引;
若是有一个3列索引(col1,col2,col3),则已经对(col1)、(col1,col2)、(col1,col2,col3)上创建了索引;
23 联合索引总结
(一直在思考,对于select 后面的字段是否须要创建索引, 对于上面的a,b,c索引,不须要回表;对于a,b索引,还须要回表。)
24 like
%xx -- 不走索引; XX% -- 走索引;
25 OR
OR操做致使,不容易优化。
26 避免 select *
27 知道什么时候使用临时表
防止对大表查询两次。还可使用临时表,大幅减小链接大表所需的处理能力。
若是你必须将一个表链接到大表,该大表上又有条件,只需将大表中所需的那部分数据提取到临时表中,而后再与该临时表链接,就能够提高查询性能(这个在实际项目中用到过,在表join以前,先把大表过滤掉尽量多的行)。
28 预暂存数据
若是你有一个报表或存储过程(或一组)要对大表执行相似的链接操做,经过提早链接表,并将它们持久化存储到一个表中来预暂存数据,就能够对你大有帮助。
29 批量删除和更新
30 避免嵌套视图
31 不要使用逆向搜索
SELECT * FROMCustomers WHERE RegionID <> 3
索引与该查询结合使用,由于它是逆向搜索,须要借助表扫描来逐行比较。
优化方法:SELECT * FROM Customers WHERE RegionID<3 UNION ALL SELECT * FROM Customers WHERE RegionID >3
32 索引的使用原则
33 使用UNION all, 尽可能避免UNION(Union须要排序,而后去重)
34 避免对索引列加函数修饰
where trunc(create_date)=trunc(:date1)
原本create_date建索引了,可是加上trunc后,索引失效,改为以下:
where create_date>=trunc(:date1) and create_date<trunc(:date1)+1< pre="">
where create_date between trunc(:date1) and trunc(:date1)+1-1/(24*60*60)
35 where子句中使用in, not in, or having.
使用exist , not exist代替in, not in
这个须要实践的检验,待续
36 排序
带有DISTINCT,UNION,MINUS,INTERSECT,ORDER BY的SQL语句会启动SQL引擎 执行,
耗费资源的排序(SORT)功能。 DISTINCT须要一次排序,其余的至少两次排序。
这个深有感触,MySQL的order by效率及其低下。
37 应尽可能避开where子句中进行null值判断:
select id from t where num is null 能够在num上设置默认值0,确保表中num列没有null值,而后这样查询: select id from t where num=0
38 并非全部索引对查询都有效:
SQL是根据表中数据来进行查询优化的,当索引列有大量数据重复时,查询可能不会去利用索引,如一表中有字段sex,male、female几乎各一半,那么即便在sex上建了索引也对查询效率起不了做用。
39 索引并非越多越好,索引当然能够提升相应的 select 的效率,但同时也下降了 insert 及 update 的效率
40 应尽量的避免更新索引数据列,由于索引数据列的顺序就是表记录的物理存储顺序,一旦该列值改变将致使整个表记录的顺序的调整,会耗费至关大的资源。若应用系统须要频繁更新索引数据列,那么须要考虑是否应将该索引建为索引。
41 尽可能使用数字型字段,若只含数值信息的字段尽可能不要设计为字符型,这会下降查询和链接的性能,并会增长存储开销。这是由于引擎在处理查询和链接时会逐个比较字符串中每个字符,而对于数字型而言只须要比较一次就够了。
42 尽量的使用 varchar/nvarchar 代替 char/nchar ,由于首先变长字段存储空间小,能够节省存储空间,其次对于查询来讲,在一个相对较小的字段内搜索效率显然要高些。
43 应尽可能避免在 where 子句中使用 or 来链接条件,不然将致使引擎放弃使用索引而进行全表扫描,如: select id from t where num=10 or num=20 能够这样查询: select id from t where num=10 union all select id from t where num=20
44 应尽可能避免在 where 子句中对字段进行表达式操做,这将致使引擎放弃使用索引而进行全表扫描。如: select id from t where num/2=100 应改成: select id from t where num=100*2
45 不少时候用 exists 代替 in 是一个好的选择: select num from a where num in(select num from b) 用下面的语句替换: select num from a where
exists(select 1 from b where num=a.num)
46 尽可能使用 TINYINT
、 SMALLINT
、 MEDIUM_INT
做为整数类型而非 INT
,若是非负则加上 UNSIGNED
47 VARCHAR
的长度只分配真正须要的空间
48 使用枚举或整数代替字符串类型
49OR
改写成 IN
: OR
的效率是n级别, IN
的效率是log(n)级别,in的个数建议控制在200之内