MySQL 性能优化---索引及优化

Posted

tags:

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

博主QQ:819594300

博客地址:http://zpf666.blog.51cto.com/

有什么疑问的朋友可以联系博主,博主会帮你们解答,谢谢支持!

一、mysql性能优化之-影响性能的因素

1、商业需求的影响

Myisam存储引擎内置一个计数器,count(*)时直接从计数器读取;而通过innodb存储引擎查找某个数据时,是必须扫描全表的,所以当执行对表的统计(即使用count(*)函数)时,myisam要比innodb要快的很多。所以一般在innodb上执行count(*)时一般要伴随where,且where中要包含主键以外的索引列。

2、系统架构及实现的影响

以下几类数据不适合存放在数据库:

①二进制多媒体数据:包括图片、音频、视频和其他一些相关的二进制文件。

②超大文本数据:从5.0.3版本开始,varchar类型最大长度调整到64KB。

3、查询语句对性能的影响

最大的性能瓶颈就是在于磁盘IO。

下面我们通过用explain来查看执行sql语句的行计划

技术分享

还可以打开mysql的profiling 功能,来查看sql的实际执行计划

技术分享

Explain与profiling的区别:

Explain只是预计、估计、估算执行这个计划sql语句需要花费多长时间,并没有真正的执行;而profiling则是实际执行了该命令,后者的准确度更高。

通过执行“SHOWPROFILE” 命令获取当前系统中保存的多个Query 的profile(配置文件)的概要信息。

技术分享

4、数据库schema(架构)设计对性能的影响

5、硬件选择对性能的影响

①数据库主机IO性能是优先考虑的,IO性能主要是由磁盘、内存、网卡共同决定。

②数据库主机的CPU的处理能力也必须考虑。

③还要考虑网络设备(比如说路由器、交换机)。

总结:四句话来概括:商业需求合理化、系统架构最优化、逻辑实现精简化、硬件设施理性化

 

二、MySQL性能优化之-索引

说明:索引优化了查询,但是降低了增、改、删的效率。

“Show index from   表名” 或者 “show  keys  from  表名”     //查询一个表有哪些索引

索引的指针类型于书本的目录页码。

做一个简单测试,假如我们创建了一个tb1表,向表中插入20000行数据,表的创建和数据插入用如下脚本实现

技术分享

再手动插入一行数据:

技术分享

下面开始测试,查询stuname=’admin’的记录:

情况1:stuname列上没有创建索引的情况

技术分享

情况2:stuname列上创建索引的情况再查询

技术分享

总结:在查找stuname="admin"的记录时,如果在stuname上已经建立了索引,MySQL无须任何扫描全表,即准确可找到该记录。相反,MySQL会扫描所有记录。

所以在数据库表中,对字段建立索引可以大大提高查询速度。

索引是在存储引擎中实现的,而不是在服务器层中实现的。所以,每种存储引擎的索引都不一定完全相同,并不是所有的存储引擎都支持所有的索引类型。

什么是索引?

索引能够帮助我们快速定位数据,可以提高查询的速度,它存在的形式是文件。

这里主介绍B-tree索引的结构

技术分享

技术分享

总结:B树索引又称平衡树索引。

磁盘块I又称根节点。

磁盘块包括数据项和指针。

数据项类似于书本章节的标题;

指针类似于书本章节所在的页码。

真实的数据存放于叶子节点,非叶子节点不存储真实数据,只存储指引搜索方向的数据项和指针。

索引对数据的排序只有升序和降序。

为什么使用索引?

索引可以让mysql高效运行,可以大大提高mysql的查询(包括排序,分组)效率;数据约束(唯一索引的建立)。

索引给我带来什么好处?

提高查询效率,快速定位数据。

使用索引产生的代价?

①磁盘的开销

②写数据:需要更新索引,对数据库是个很大的开销,降低表更新、添加和删除的速度。

不建议使用索引的情况:

①数据1000字以下的表不需要建索引

②一列中选择性较低的不建索引(比如这一列是性别的,可能的值只有男和女)(所谓索引的选择性,是指不重复的索引值与表记录数的比值,取值范围(0-1)。选择性越高,索引的价值越大)

索引的类型?

索引包括单列索引和组合索引。

说明:单列索引,即一个索引只包含单个列,一个表可以有多个单列索引,但这不是组合索引。组合索引,即一个索包含多个列。

1、 普通索引

这是最基本的索引,它没有任何限制

技术分享

2、 唯一索引

它与前面的普通索引类似,不同的就是索引列的值必须唯一,但允许空值,空值是指null。如果是组合索引,组合列的值必须唯一

技术分享

主键索引:一种特殊的唯一索引,不允许有空值,一般在建表的时候自动建立主键索引。

技术分享

3、组合索引

为了进一步提升MySQL的效率,就要考虑建立组合索引。

例如:创建一个表,包含如下字段:

技术分享

将 username, city, age建到一个索引里:

技术分享

说明:如果分别在 usernname,city,age上建立单列索引,让该表有3个单列索引,查询时和上述的组合索引效率也会大不一样,远远低于组合索引。虽然此时有了三个索引,但MySQL只能用到其中那个它认为似乎是最有效率的单列索引

建立一个这样的组合索引=其实是相当于分别建立了下面三组组合索引:

usernname,city,age   usernname,city   username没有 city,age这样的组合索引。

Mysql组合索引遵循“最左前缀”原则。简单的理解就是只从最左面的开始组合。并不是只要包含这三列的查询都会用到该组合索引。

下面的几个SQL就会用到这个组合索引:

技术分享

技术分享

而下面几个则不会用到:

技术分享

技术分享

如果对多列进行索引(组合索引),列的顺序非常重要,MySQL仅能对索引最左边的前缀进行有效的查找。

技术分享

4、 全文索引(用的非常的少)

只用于MyISAM表 对文本域进行索引。字段类型包括char、varchar、text

不过切记对于大容量的数据表,生成全文索引是一个非常消耗时间非常消耗硬盘空间的做法。

技术分享

查看索引

技术分享

或者

技术分享

在什么情况下建立索引?

一般来说,在WHERE和JOIN子句中出现的列需要建立索引。

例如:在username上创建索引

技术分享

技术分享

此时就需要对两个表的userame上建立索引。

使用索引的注意事项

①在用like模糊查询时,以通配符%和_开头作查询时,MySQL不会使用索引,而是默认全表扫描。

例如下句会使用索引:

技术分享

而下句就不会使用:

技术分享

不要在有索引的列上进行运算(运算:即使用函数,加、减、乘、除、统计等等)

技术分享

将在每个行上进行运算,这将导致索引失效而进行全表扫描,因此我们可以改成

技术分享

技术分享

三、mysql性能优化-慢查询分析、优化索引和配置

基本思路:

1)性能瓶颈定位

Show命令

慢查询日志

explain分析查询

profiling分析查询

2)索引及查询优化

3)配置优化

技术分享

1、查询与索引优化分析

说明:在优化MySQL时,通常需要对数据库进行分析,常见的分析手段有慢查询日志,EXPLAIN 分析查询,profiling分析以及show命令查询系统状态及系统变量,通过定位分析性能的瓶颈,才能更好的优化数据库系统的性能。

show命令:

可以通过show命令查看MySQL状态及变量,找到系统的瓶颈:

查看MySQL服务器配置信息:

技术分享

查看MySQL服务器运行的各种状态值:

技术分享

显示系统变量:

技术分享

显示状态信息:

技术分享

比较全的show命令的使用可参考:

技术分享

或者http://dev.mysql.com/doc/refman/5.7/en/show.html

慢查询日志

慢查询日志开启:

技术分享

技术分享

慢查询日志开启方法二:

技术分享

查看慢查询的设置信息

技术分享

我们可以通过打开log文件查看得知哪些SQL执行效率低下

技术分享

下面是一个例子:

技术分享

如果慢查询日志中记录内容很多,可以使用mysqldumpslow工具(MySQL客户端安装自带)来对慢查询日志进行分类汇总。

mysqldumpslow对日志文件进行了分类汇总,显示汇总后摘要结果。

有关mysqldumpslow命令的用法可以参考其帮助:#mysqldumpslow --help

技术分享

下面是一个例子:

技术分享

上面显示结果中就是一条慢查询,如何优化呢?

一是在entertime列上创建索引优化查询:

技术分享

二是优化这个sql查询语句:

技术分享

从下图可以看查询0.00秒:

技术分享

总结:使用mysqldumpslow命令可以非常明确的得到各种我们需要的查询语句,对MySQL查询语句的监控、分析、优化是MySQL优化非常重要的一步。开启慢查询日志后,由于日志记录操作,在一定程度上会占用CPU资源影响mysql的性能,但是可以阶段性开启来定位性能瓶颈。

 

explain分析查询

可以模拟优化器执行SQL查询语句。

技术分享

优化方法:在stuname列上创建索引:

技术分享

再次执行explain。

技术分享

profiling分析查询

用过慢查询我们可以自动哪些SQL局域执行效率低下,然后我们再通过explain可以得知SQL语句的具体执行情况、索引的使用等。还可以结合show来查看执行状态。

如果觉得explain不够详细,则可以通过profiling来得到更准确的SQL执行信息。

1)profiling默认是关闭的,我们先来看一下profiling是开启还是关闭的

技术分享

或者

技术分享

2)开启profiling功能

技术分享

3)执行要测试的sql语句

技术分享

技术分享

4)对于show profile我们还可以查看到更多的信息如内存和CPU。

技术分享

5)测试完成以后,一定记住不要忘记关闭调试功能,以免影响数据库的正常使用

技术分享


配置优化

下面列出了对性能优化影响较大的主要变量,

主要分为连接请求的变量和缓冲区变量

1、连接请求的变量

1)max_connections           //设置mysql的最大连接数

什么时候用到:如果服务器并发连接请求量较大,建议增大该值。

注意:如果连接数越多,mysql会为每个连接提供连接缓冲区,会开销更多的内存,所以要适当调整该值。

数值过小会报错:error 1040:too many  connections

①通过mysql>show status like ‘connections’;来查看mysql服务器当前的连接数(不管成功连接与否,即使失败了记录),如果想看准确的数目,则命令是:“showprocesslist;”

技术分享

②mysql>show variables like‘max_connections’     //查询最大连接数

技术分享

③mysql>show status like ‘max_used_connections’ //查询响应的连接数

技术分享

④max_used_connections / max_connections * 100%(当结果≈ 85%的时候为最佳),如果两者两同,就是

max_connections设置的过低或者服务器负载已经超上限了。如果结果低于10%,则说明max_connection设置过大。

⑤那么如何修改max_connections呢?

修改/etc/my.cnf配置文件,添加如下配置:

技术分享

技术分享

2)back_log    //设置mysql的请求队列数量

什么时候起作用:当一个mysql线程在很短时间内收到非常多的连接请求是用到。

                Mysql的连接数达到max_connections的时候,新来的请求就放在队列中,当等待连接的数目超过了back_log则忽视多余的请求。

①查看当前主机的mysql进程列表

技术分享

②mysql> show variables like ‘back_log‘;      //查看back_log的设置

技术分享

③如何设置back_log?

修改/etc/my.cnf配置文件,添加如下配置:

技术分享

技术分享

3)wait_timeout和interactive_timeout

wait_timeout:就是好久没操作了,该连接会被断开,这里设置的就是秒数,用于非交互式模式。

Interactive_timeout:跟上面 意思是一样的,不过它使用的是交互式模式,即“mysql>”模式。

Interactive_timeout默认的时间数值是28800秒(即8个小时),我们可以把它调优成7200秒(即2小时)。

①对性能的影响:

(1)如果设置太小,连接会很快关闭

(2)如果设置太大,容易造成连接打开时间过长,在show processlist的时候,可以看见很多sleep状态的连接从而造成too many connections错误。

(3)一般情况下wait_timeout的值低一些

②查看wait_timeout和interactive_timeout的值

技术分享

③如何修改wait_timeout和interactive_timeout的值

修改/etc/my.cnf配置文件,手动添加以下两行配置项

技术分享

技术分享

技术分享

2、缓冲区的变量

1)key_buffer_size    //设置索引缓冲区大小。决定了索引的处理速度。

①可通过检查Key_read_requests和Key_reads,可以知道key_buffer_size设置是否合理。

技术分享

说明:key_reads / key_read_requests应该尽可能的低,至少是1:100,1:1000更好。

Key_read_requests:所有索引的读请求

Key_reads:索引未命中缓存数(即不是通过缓存的索引读请求,而是直接通过读取硬盘)。

注意:key_buffer_size只对myisam存储引擎表起作用。即使你不使用myisam表,但是内部的临时磁盘表还是myisam表,它也要使用该值。

②检查状态值,查看created_tmp_disk_tables的值

技术分享

③如何调整key_buffer_size的值,默认是8M。

修改/etc/my.cnf配置文件,添加下面这一行配置项

技术分享

技术分享

2)query_cache_size   //简称(QC),设置查询缓冲区的大小,并将查询的结果直接存放在缓存区中。

说明:今后执行同样(同样:是字母大小写法也一样,有无空格也一

样,空几个格也要严格一样)的select语句,则直接从缓冲区中读取。

①通过检查状态值’Qcache%’,可以知道query_cache_size设置是否合理

技术分享

碎片过多了,需要清理。通过“flush  query   cache”命令对缓存碎片进行清除。注意:当一个表更新后,则与它相关的cache_blocks(缓存块)都被清空,但是这个缓存快还是不能用,必须通过“flush  query cache”命令清除后才能被使用。

Qcache_free_memory:是query_cache_size的剩余的还未被使用缓存区大小。通过该值可以知道缓存区是否够用还是过多造成浪费了。

Qcache_hits:有多少次查询是从缓存区直接查询到的。该值越大,明缓存的效果越明显。

Qcache_inserts:有多少次查询不是从缓存区查询到的,而是从硬中查找的,查询到结果后,把结果插入到缓存区里面,为了下次查时候用。该值越大,说明缓存区使用的较少。

Qcache_lowmem_prunes:有多少条sql缓存是因为缓存区大小不足而被新的sql缓存给挤出了缓存区。通过qcache_lowmem_prunes和qcache_free_memory相互结果,更能真实的反映出缓存区大小是否真的够用。如qcache_lowmem_prunes这个数值不断增长,说明碎片非常的严重者缓存区太小了(可以通过查看qcache_free_blocks qcache_free_memory来判断到底是属于哪一种)

Qcache_not_cached:是指不适合缓存的查询SQL语句的数量,这些询语句不是select语句,而是像now()之类的函数(now是一个数,作用是获取当前mysql服务器的系统时间,因为时间是一个变的量,所以不适合做缓存插入到缓存区)

Qcache_queries_in_cache:是指当前缓存区中缓存的SQL语句数量。

Qcache_total_blocks:是指当前缓存区中缓存块(blocks)的数量。

②查询mysql服务器的query_cache的配置:

技术分享

Query_cache_type:返回的值是off表示不缓存任何查询,即查询缓存功能没有开启

Query_cache_limit:超过该值大小的查询结果不会缓存(默认值是1M,即超过1M的查询缓存结果不缓存到缓存区)

Query_cache_min_res_unit:缓存块的最小大小,默认是4KB一个块。

Query_cache_size:查询的缓存区的大小(注意:QC存储最小单位是1024字节,你设定的QC的值必须是1024字节的倍数)

Query_cache_type:缓存的类型,即决定缓存什么样的查询,这个值必须是数字。(一般我们设置为1就可以了)

技术分享

技术分享

Query_cache_wlock_invalidate:当有其他客户端正在对MyISAM表进行写操作时,如果查询在缓存区中,是否返回缓存的结果还是等写操作完成再读表获取结果,默认是等写操作完成后再向表读取结果。  

技术分享

③修改query_cache_size 的大小以及缓存的类型

修改/etc/my.cnf配置文件,添加下面两行配置项:

技术分享

技术分享

④验证是否真正开启了

技术分享

技术分享

⑤缓存区中缓存的限制:

技术分享

建议通过精确设置的方式,仅仅让合适的表的数据可以进入查询缓存区,仅仅让某些查询语句的查询结果被缓存。


3)max_connect_errors                //设置最大失败连接次数

①目的:阻止过多尝试失败的客户端以防止暴力破解密码的情况。

当超过指定次数,则禁止该主机登录mysql,而不是禁止该用户登录,禁止有效期是永久的,但是可以通过重启mysql服务或通过“flush  hosts”命令清空主机的相关信息。

②怎么添加max_connect_errors的值

修改/etc/my.cnf配置文件,添加下面的一行配置项:

技术分享

技术分享

4)sort_buffer_size             //为order  by或group  by语句的结果分配一个缓冲区

①目的是加快下次order by、group  by语句的查询速度,是一个connection级参数,当这些SQL语句第一次把结果存入到该order  by或group  by语句专享额缓冲区里面的时候,mysql就会一次性的为该SQL语句分配设置好缓存大小。

②怎么添加sort_buffer_size的值

修改/etc/my.cnf配置文件,添加下面的一行配置项:

技术分享

技术分享

例如:500个连接(即有500个order  by或group  by语句)将会消耗 500*sort_buffer_size(2M)=1G内存

 

5)max_allowed_packet=32M //限制mysql服务器接收的客户端发来的数据包的大小(即客户端存入的数据的大小)

该配置项的最大值是1G,但是设置的值必须是1024字节的整数倍。 

6)join_buffer_size=2M  //用于表间关联的缓存的大小

和sort_buffer_size一样,该参数对应的分配缓存大小也是每个连接独享。

7)thread_cache_size=300  //服务器线程数量的缓存

这个值表示可以重新利用保存在缓存中线程的数量,当断开连接时,那么客户端的线程将被放到缓存中以响应下一个客户而不是销毁(前提是缓存数未达上限),如果线程重新被请求,那么请求将从缓存中读取,如果缓存中是空的(即缓存数量名额以用完),那么这个线程将被退回去并重新创建(再来进行线程缓存数请求,如果还没有名额,再退回去),如果有很多新的线程,增加这个值可以改善系统性能。

技术分享

技术分享

技术分享

说明:因为我没有在my.cnf文件开启这个配置项,所以空闲线程是为0。

3、配置innodb的几个变量

1)innodb_buffer_pool_size       //相当于key_buffer_size对myisam的作用

①作用:InnoDB使用该参数指定缓冲区的大小来缓冲数据和索引。

对于单独的MySQL数据库服务器,最大可以把该值设置成物理内存的80%。

建议:对于2G内存的机器,推荐值是1G(50%)。

②修改my.cnf配置文件

技术分享

技术分享

2)innodb_flush_log_at_trx_commit     //主要控制了innodb将日志缓冲区中的数据写入日志文件并刷新磁盘的时间点,取值分别为0、1、2三个

说明:

①0、1、2的说明

0,表示当事务提交时,并不立即任何操作,而是每秒钟将日志缓冲区中的数据直接写入日志文件并刷新磁盘一次;

1,每次事物的提交都会引起日志文件写入、刷新磁盘的操作,确保了事务的ACID;

2,每次事务提交先把日志从日志缓冲区写入到操作系统的缓冲区,然后每秒钟完成一次刷新到的磁盘操作。

②实际测试

设置为2时插入10000条记录只需要2秒,设置为0时只需要1秒,而设置为1时则需要229秒。

③mysql官方建议

尽量将插入操作合并成一个事务,这样可以大幅提高速度。

3)innodb_thread_concurrency = 0   //设置innodb线程的并发数量,默认为0,即不限制。

说明:若要设置则与服务器的CPU核数相同或是cpu的核数的2倍,建议的设置为8。

4)innodb_log_buffer_size          //确定日志文件所用的缓存大小

以M为单位。缓冲区越大越能提高性能,对于较大的事务,可以增大缓存大小。

建议设置为32M

5)innodb_log_file_size = 50M       //确定数据日志文件的大小

以M为单位。更大的设置可以提高性能。

6)innodb_log_files_in_group=3        //循环方式将日志文件写到多个文件中

为提高性能,MySQL可以以循环方式将日志文件写到多个文件。推荐设置为3

7)read_buffer_size = 1M         //mysql读入缓冲区大小

对表进行顺序扫描的请求将分配一个读入缓冲区,MySql会为它分配一段内存缓冲区。

和 sort_buffer_size一样,该参数对应的分配缓存是每个连接独享。

8)read_rnd_buffer_size = 16M       //MySql 的随机读(查询操作)缓冲区大小

当按任意顺序如,按照排序顺序),将分配一个随机读缓存区。

MySql会为每个客户连接发放该缓冲空间,所以应尽量适当设置该值,以避免内存开销过大。

9)bulk_insert_buffer_size = 64M   //批量插入数据缓存大小

批量插入数据缓存大小,可以有效提高插入效率,默认为8M。

10)binary log

①binlog_cache_size = 2M          //为每个连接分配的内存,在事务过程中用来存储二进制日志的缓存, 提高记录bin-log的效率。没有什么大事务,dml也不是很频繁的情况下可以设置小一点,如果事务大而且多,dml操作也频繁,则可以适当的调大一点。前者建议是--1M,后者建议是:即 2--4M

②max_binlog_cache_size = 8M //表示的是binlog 能够使用的最大缓存的大小。

③max_binlog_size = 512M  //指定binlog日志文件的大小,如果当前的日志大小达到max_binlog_size,还会自动创建新的二进制日志。你不能将该变量设置为大于1GB或小于4096字节。 默认值是1GB。在导入大容量的sql文件时,建议关闭sql_log_bin,否则硬盘扛不住,而且建议定期做删除。

④expire_logs_days = 7  //定义了mysql清除过期日志的时间。二进制日志自动删除的天数。默认值为0,表示“没有自动删除”。mysqladmin flush-logs 命令也可以重新开始新的binary log。



下面进行一个额外的测试

在优化之前执行mysqlslap工具进行测试

[[email protected] ~]#mysqlslap --defaults-file=/etc/my.cnf--concurrency=10 --iterations=1 --create-schema=‘test1‘ --query=‘select * fromtest1.tb1‘ --engine=innodb --number-of-queries=2000 -uroot -p123456 –verbose

显示结果:

Benchmark

   Running forengine innodb

   Average numberof seconds to run all queries: 13.837seconds

   Minimum numberof seconds to run all queries: 13.837 seconds

   Maximum numberof seconds to run all queries: 13.837 seconds

   Number ofclients running queries: 10

   Average numberof queries per client: 200

优化之后执行mysqlslap工具进行测试

[[email protected] ~]#mysqlslap --defaults-file=/etc/my.cnf--concurrency=10 --iterations=1 --create-schema=‘test1‘ --query=‘select * fromtest1.tb1‘ --engine=innodb --number-of-queries=2000 -uroot -p123456 –verbose

显示结果:

Benchmark

   Running forengine innodb

   Average numberof seconds to run all queries: 4.199seconds

   Minimum numberof seconds to run all queries: 4.199 seconds

   Maximum numberof seconds to run all queries: 4.199 seconds

   Number ofclients running queries: 10

   Average numberof queries per client: 200

 

相关优化参数总结:

[mysqld]

slow_query_log = 1

slow_query_log_file =/usr/local/mysql/data/slow-query.log

long_query_time = 1

log-queries-not-using-indexes

max_connections = 1024

back_log = 128

wait_timeout = 60

interactive_timeout = 7200

key_buffer_size=256M

query_cache_size = 256M

query_cache_type=1

query_cache_limit=50M

max_connect_errors=20

sort_buffer_size = 2M

max_allowed_packet=32M

join_buffer_size=2M

thread_cache_size=200

innodb_buffer_pool_size = 2048M

innodb_flush_log_at_trx_commit = 1

innodb_log_buffer_size=32M

innodb_log_file_size=128M

innodb_log_files_in_group=3

log-bin=mysql-bin

binlog_cache_size=2M

max_binlog_cache_size=8M

max_binlog_size=512M

expire_logs_days=7

read_buffer_size=1M

read_rnd_buffer_size=16M

bulk_insert_buffer_size=64M

log-error = /usr/local/mysql/data/mysqld.err

本文出自 “IT技术助手” 博客,请务必保留此出处http://zpf666.blog.51cto.com/11248677/1911477

以上是关于MySQL 性能优化---索引及优化的主要内容,如果未能解决你的问题,请参考以下文章

mysql性能优化-慢查询分析优化索引和配置

mysql性能优化-慢查询分析优化索引和配置

mysql性能优化-慢查询分析优化索引和配置

mysql性能优化-慢查询分析,优化索引最佳实践

mysql性能优化-自我总结

MySQL性能优化---优化方案