mysql优化相关
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mysql优化相关相关的知识,希望对你有一定的参考价值。
一 SQL 语句优化相关
1 许可的重要性
影响所有语句的一个因素是:你的许可设置的越复杂,所需要的开销也会越多,执行grant 语句时使用简单的许可,当客户端执行语句时,可以是mysql降低许可检查开销,未授权的表或列级资源,服务器不需要检查tables_priv和columns_priv 表的内容。
同样,如果不对任何账号进行限制,服务器不需要对资源进行统计,如果查询量很高,可以花费一些时间使用简化的授权结构来降低许可检查开销。
如果你的问题是与具体mysql表达式或函数有关,可以使用mysql客户端程序所带的benchmark()函数执行定时测试。
其语法问benchnark(loop_count,expression),如
上面的结果显示mysql在该系统上再0.13秒内可以执行1000,000个简单的+表达式运算
所有mysql函数应该被高度优化,但总是有可能有一些例外,benchmark()是一个找出是否查询有问题的工具
2 explain 工具
1 作用
如果在select语句前面放上相关词explain,mysql将解释他如何处理select,提供有关如何连接和连接次序,借助于explain,可以知道什么时候必须为表加入索引已得到一个使用索引来寻找记录的更快的select。
2 语法格式
explain tabl_name 或 explain [extended] select selectoption
explain 语句可以用作describe 的一个同义词,或者获取关于mysql如何执行select语句的信息
3 explain 和 describe ,columnsfrom 的区别和联系
explain table_name 是 describe table_name 或 show columnsfrom tab_name 的一个同义词
如果由于使用了不正确的索引出现了问题,应运行analyze table 更新表的统计,这样会影响优化器的选择
还可以知道优化器是否以一个最佳次序连接表,为了强制优化器让一个select 语句按照表命名顺序被列出,
mysql用一遍扫描多次连接的方式来解决所有的链接,这意味着mysql从第一个表中读取一行,然后找到第二个表中的一个匹配行,然后在第3个表中等,当所有的表都处理完成之后,他输出选中的列并且返回表清单知道找到一个有更多匹配的行的表,从该表读入下一行并继续处理下一个表。
当使用extended关键字时,explain 产生附加信息,可以用show warnings 浏览,该信息显示优化器限定select语句中的表和列名,重写并且执行优化规则后select语句是什么样子,并且还可能包括优化过程的其他注解。
4 explain 各列的含义
explain 的每个输出行提供一个表的相关信息,并且每个行包括下面的列
1. id
select 识别符,这是select的查询序号
select_type select 类型,可以是一下的任何一种
1 simple 简单的(不使用union或子查询)
2 primary 最外面的select
3 union 中的第二个或后面的select
4 dependent union union 中的第二个或后面的select 语句,取决于外面的查询
5 union result union 的结果
6 subquery 子查询中的第一个select
7 dependent subquery 子查询中的第一个select,取决于外面的查询
8 derived 导出表的select(from 子句的子查询)
2. table
输出的行所引用的表
3. type
连接类型,下面给出各种连接类型,按照从最佳类型到最坏类型的排序,扫描的方式
1 system
表仅有一行(=系统表),这是const连接类型的一个特例
2 const
最多有一个匹配行,他讲在查询开始时被读取,因为仅有一行,在这行的列值可被优化器剩余部分认为是常数,const表很快,因为他们只读取一次
const 用于常数值比较primary key 或 unique 索引的所有部分时
3 eq_ref
对于每个来自于前面的表的行组合,从该表中读取一行,这可能是最好的链接类型,除了const类型,他用在一个索引的所有部分被关联使用并且索引是unique或primary key
eq_ref 可以用于使用= 操作符比较的带索引的列,比较值可以为常量或一个使用该表前面所读取的表的列的表达式。
select * from ref_table,other_table where ref_tablekey_column=other_table colm;
select * from ref_table,other_table where ref_tablekey_column_part1=other_tablecolumn and ref_tablekey_column_part2=1;
对于每个来自于前面的表的行组合,所有匹配索引值的行将从这张表中读取,如果连接只使用键的最左边的前缀,或如果键不是unique或primary key ,则使用ref,如果使用的键仅仅匹配少量行,该连接类型是不错的。
ref 可以用于使用=或<=>操作符的带索引的列
SELECT * FROM ref_table WHERE key_column=expr;
SELECT * FROM ref_table,other_table
WHERE ref_table.key_column=other_table.column;
SELECT * FROM ref_table,other_table
WHERE ref_table.key_column_part1=other_table.column
AND ref_table.key_column_part2=1;
4 ref_or_null
该连接类型如同ref,但是添加了mysql可以专门搜索包括null值的行,在解决子查询中经常使用该连接类型的优化
SELECT * FROM ref_table
WHERE key_column=expr OR key_column IS NULL;
5 index_merge
该联合类型表示使用了索引合并优化方法,在这种情况下,key列包含了使用的索引的清单,key_len包含了使用的索引的最长的关键元素
6 unique_subquery
该类型替换了下面形式的IN子查询的ref
value IN (SELECT primary_key FROM single_table WHERE some_expr)
unique_subquery是一个索引查找函数,可以完全替换子查询,效率更高
7 index_subquery
该连接类型类似于unique_subquery,可以替换IN子查询,但只适合下列形式的子查询中的非唯一索引:
value IN (SELECT key_column FROM single_table WHERE some_expr)
8 range
值检索给定范围的行,使用一个索引来选择行,key 列显示了使用哪个索引,key_lan 包含了所使用的索引的最长关键元素,在该类型中的ref列为NULL
当使用=、 <>、 >、 >=、 <、 <=、 IS NULL、 <=>、 BETWEEN或者IN操作符,用常量比较关键字列时,可以
使用range:
SELECT * FROM tbl_name
WHERE key_column = 10;
SELECT * FROM tbl_name
WHERE key_column BETWEEN 10 and 20;
SELECT * FROM tbl_name
WHERE key_column IN (10,20,30);
SELECT * FROM tbl_name
WHERE key_part1= 10 AND key_part2 IN (10,20,30);
9 index
该连接类型与ALL相同,除了只有索引数被扫描。这通常被ALL快,因为索引文件通常比数据文件小,当查询只使用作为单一索引部分的列时,mysql可以使用该连接类型
10 all
对于每个来自于先前的表的行组合,进行完成的表扫描,如果表是第一个没标记的const的表,这通常不好,并且通常在他的情况下很差,通常可以增加更多的索引而不是要使用all,使得行能基于前面的表中的常数值或列值被检索4. possible_keys
列指出mysql能使用哪个索引在该表中找到行,该列完全独立于explain输出所示的表的次序,这意味着在possibe_keys中的某些键实际上不能按生成的表次序使用,如果该列是NULL,则没有相关的索引,这种情况下,可以通过检查where字句查看那是否引用某些列或者适合索引的列来提高性能。
扫描时可能使用的索引
看表的索引 show index from X;5. key
实际使用的索引
key 列显示了mysql实际决定使用的键(索引),如果没有选择索引,则是null,要想前置mysql是使用或忽视possible_keys列中的索引,在查询中使用FORCE INDEX, USER INDEX 或者 IGNORE INDEX
对于myisam和BDB表,运行analyze table 可以帮助优化器选择更好的索引,对于myisam表,可以使用myisamchk-analyze6. key_len
显示了mysql决定使用的键的长度,如果键是NULL,则长度为NULL,通过此列可以确定mysql将实际使用一个多部分关键字的几个部分
7. ref
显示使用了那个列或常数与key一起从表中选择行
8. rows
显示了mysql认为他执行查询时必须检查的行数
9. extra
该列包含了mysql解决查询的详细信息,SQL语句的额外信息,如排序方式
1 distinct
mysl发现第一个批判行后,停止了为当前行组合搜索更多的行
2 not exists
mysql能够对查询进行 left join优化,发现一个匹配left join标准的行后,不再为前面的行组合在该表内检索更多的行
3 range checked for each record (index map:#)
mysql没有发现好的可以使用的索引,但发现如果来自前面的表的列已知,可能部分索引可以使用,对前面的表的每行组合,mysql检查是否可以使用range或index_merge访问方法来索取行
4 using filesort
mysql需要额外的一次传递,以找出如何按排序检索行,通过根据连接类型浏览所有行并为所有匹配where字句的行保存排序关键字和行的指针来完成排序,然后关键字被排序,并按排序检索行
5 Using index
从只使用索引树中的信息而不需要进一步搜索读取实际的行来检索表中的列信息。当查询只使用作为
单一索引一部分的列时,可以使用该策略。
6 Using temporary
为了解决查询,MySQL需要创建一个临时表来容纳结果。典型情况如查询包含可以按不同情况列出列
的GROUP BY和ORDER BY子句时。
7 Using where
WHERE子句用于限制哪一个行匹配下一个表或发送到客户。除非你专门从表中索取或检查所有行,如果Extra值不为Using where并且表联接类型为ALL或index,查询可能会有一些错误。
如果想要使查询尽可能快,应找出Using filesort 和Using temporary的Extra值。
8 Using sort_union(...), Using union(...), Using intersect(...)
这些函数说明如何为index_merge联接类型合并索引扫描。
9 Using index for group-by
类似于访问表的Using index方式, Using index for group-by表示MySQL发现了一个索引,可以用来查询GROUP BY或DISTINCT查询的所有列,而不要额外搜索硬盘访问实际的表。并且,按最有效的方式使用索引,以便对于每个组,只读取少量索引条目。
5 估计查询性能
在大多数情况下,可以通过计算磁盘搜索来估计性能,对于小的表,通常能在1次磁盘搜索中找到的行(因为索引可能被缓存),对于更大的表,可以使用B-树索引进行估计,将需要log(row_count)/log(index_block_length/3*2/(index_length+data_pointer_length))+1次才能搜索找到行。
在mysql中,索引块通常是1024个字节,数据指针通常是4字节,这对于有一个长度为3的索引500000行的表,通过公式可以计算出log(500000)/log(1024/3*2/(3+4))+1=4次搜索。
上面的索引需要大约50000073/2=5.2MB,可以将大部分索引保存在内存中,仅需要1-2次调用从OS读取数据来找到行
然而对于写,将需要4次收缩请求来找到在哪儿存放新索引,并且通常需要2次搜索来更新这个索引并写入行。
当表格变得更大时,所有内容缓存到OS或SQL服务
器后,将仅仅或多或少地更慢。在数据变得太大不能缓存后,将逐渐变得更慢,直到应用程序只能进行磁盘搜索(以logN增加)。为了避免这个问题,随数据增加而增加 键高速缓冲区大小。对于MyISAM表, 由key_buffer_size系统变量控制 键高速缓冲区大小。
技巧:
1 通过查看线程任务得到慢查询语句
show processlist;
2 通过开启慢查询进行
3 通过explain 进行对查询语句质量的定位。(查询是否使用索引)
4 查看某一列的重复度,越小重复越多,越不适合创建索引
5 进行创建联合索引
create table key_name on tabe_name (id,name,pw);
6 通过explain 进行扫描查询;
3 部分SQL 语句使用小技巧
1 group by 语句注意事项
默认会对文件进行排序,如此会影响其速度
使用order by null 可以将group by 后面的排序去掉,默认只对指定的列进行排序。
2 使用join链接代替子查询
Select * from X left join on Y.b=X.a;(左外连接) 此方式更优化!
二 索引相关
1 索引基本原理
索引的原理:
为什么创建索引后查询的速度就会变快
传统的顺序是按照一个一个的方式进行检索的,如果找到,则会继续向后面执行,因为其不敢保证后面是否还有相同的数据被存储,因此只有全部检索才能返回。
加上索引后,在二叉树的原理下,根据折中的方式进行计算,首先会扫描全表,构建二叉树并保存其数据存储的物理位置,进行左右查找,最终锁定其位置形成索引。
其相同的记录会在同一节点进行
有索引的情况下检索1024个条数据,只需要检索10次,默认是log2(x) =y 2^y=X
其中X 是数据的量,y 是检索的次数
索引查询:
2 主键索引
当一张表中把某个字段设置为主键的时候,该列就是主键索引。
主键字段不但不能为空,而且不能重复
主键添加方式:
1 建表时添加:
2 建表后添加
3 索引的删除
3 普通索引
普通索引可以同时创建多个
删除索引
另一种方式添加索引
4 全文索引添加(mysql5.6开始支持全文索引)
全文索引,主要是针对文件
创建:
查看
如何使用全文索引:
错误的使用方式:
正确的使用方式
注意事项
1 在mysql中fulltext 索只针对myisam存储引擎生效
2 针对英文生效 中文使用sphinx
3 使用方法为match(字段名,字段名) against(‘关键字‘)
4 全文索引有停止词
65% 表示第一条记录的匹配度
而针对于a 经常发生的,则没有创建索引,这就被称为停止词
其索引的建立是通过比较生僻的词进行创建的,
全文索引的删除
5 唯一索引
唯一索引不能重复,但可以为空
建表成功后添加索引:
删除索引
6 外键
其原理是student的classid不能添加class表中ID 字段不存在的值进入student表中。
7 分析索引使用率
Read_key值越高越好
read_rnd_next 值越高越不好,越低越好
8 使用索引的注意事项
1 索引的代价
1 对磁盘占用较严重
2 对DML语句有影响,修改、添加和删除的速度会变慢,因为其需要检索索引,因此其速度会变慢
2 索引添加的原则
1 在较为频繁的查询字段上创建索引
2 唯一性太差的字段上不适合创建索引
3 更新非常频繁的字段不能创建索引
4 在where条件中经常出现的适合创建索引
5 该字段的内容有多个
3 使用索引的注意事项
1 对于创建了多列的索引,主要查询添加使用了最左端的列,则索引一般会被使用,索引做用在多个列上,如果不是使用最左列索引,则用不上。
如我们对title,content 添加了复合索引
select from table_name where title=‘test‘; 会用到索引
select from tbale_name where content=‘test‘ ; 不会用到索引
2 对于使用like的查询,查询中如果是%aaa则不会使用索引,‘aaa%‘则会使用到索引。如果一定要使用%,则索引不能使用。
3 在进行查询的时候,如果条件中有or,则该语句中的所有字段都必须创建索引,否则索引不能使用,如果是复合索引,则必须是最左边的索引,如果两个条件一个是左边索引,一个是右边索引,则不能使用索引。
4 如果列类型是字符串,那么一定要在添加中的数字加上单引号,否则索引不能使用。
5 如果mysql 发现全表扫描更快,则不会使用索引。
三 存储引擎相关
1 各存储引擎的特点
如果表对事物回滚要求不高,同时是以查询和添加为主的表,对安全要求不高的情况下,我们考虑使用myisam存储引擎,如BBS中的帖子表等
innodb存储:对事物的要求高,保存的数据都是重要的数据,建议使用innodb存储引擎,如支付表,订单表,余额账户表
myisam 插入的速度高于innodb,myisam不会再添加时进行排序和事物安全的查询
myisam支持全文索引,innodb不支持
myisam支持表锁,innodb支持行锁
myisam和innodb的区别
1 事物安全方面
2 查询和添加速度
3 锁粒度
4 外键 innodb支持,myisam不支持
2 memory 速度很快
重启则消失,因为其是存储在内存中,而不是磁盘中,因此重启服务则会消失
选择数据类型时,需要选择最贴近于存储的数据类型
3 myisam 存储引擎碎片整理
如果数据库的表的存储引擎时myisam,则请一定要注意定时进行碎片整理
1 数据删除前:
2 删除数据但未收集碎片
3 收集碎片
4 查看大小
四 水平分割与垂直分割概念
1 水平分割
水平分割是按照某种规则将数据划分到不同的表或数据库中,如计费系统,通过按时间来划分较合适,因为系统都是处理某一时间段的数据。
分割原则:
表的结构不会发生变化,用户根据需要分割的表的数量进行计算如
需要将一个表分成3个则
id=1 1%3=1
id=2 2%3=2
id=3 3%3=0
以此类推
表名最好使用X.0 X.1 X.2 通过id与表取模获取到的结果来存储
2 垂直分割
垂直分割就是要把表按照模块划分到不同的数据库中,这种拆分在大型网站演变过程中很常见,当网站很小时,只有少量的人进行开发和维护,各模块和表放在一起,当网站不断壮大丰富时,需要很多子系统和模块,此时需要把相同功能的模块进行统一管理个建表,并进行分类,简单的说就是把原来强耦合的系统拆分成多个弱耦合的服务,通过对服务键的调用来满足业务需求。
以上是关于mysql优化相关的主要内容,如果未能解决你的问题,请参考以下文章