设为首页 收藏本站
查看: 605|回复: 0

[经验分享] mysql性能优化

[复制链接]

尚未签到

发表于 2015-12-22 12:36:45 | 显示全部楼层 |阅读模式
  目录
  一、优化概述
  二、查询与索引优化分析
  1性能瓶颈定位
  Show命令
  慢查询日志
  explain分析查询
  profiling分析查询
  一、 优化概述
DSC0000.png
  MySQL数据库是常见的两个瓶颈是CPU和I/O的瓶颈,CPU在饱和的时候一般发生在数据装入内存或从磁盘上读取数据时候。磁盘I/O瓶颈发生在装入数据远大于内存容量的时候,如果应用分布在网络上,那么查询量相当大的时候那么平瓶颈就会出现在网络上,我们可以用mpstat, iostat, sar和vmstat来查看系统的性能状态。
  除了服务器硬件的性能瓶颈,对于MySQL系统本身,我们可以使用工具来优化数据库的性能,通常有三种:使用索引,使用EXPLAIN分析查询以及调整MySQL的内部配置。
  二、查询与索引优化分析
  在优化MySQL时,通常需要对数据库进行分析,常见的分析手段有慢查询日志,EXPLAIN 分析查询,profiling分析以及show命令查询系统状态及系统变量,通过定位分析性能的瓶颈,才能更好的优化数据库系统的性能。
  1 性能瓶颈定位Show命令
  我们可以通过show命令查看MySQL状态及变量,找到系统的瓶颈:
  Mysql> show status ——显示状态信息(扩展show status like ‘XXX’)
  Mysql> show variables ——显示系统变量(扩展show variables like ‘XXX’)
  Mysql> show innodb status ——显示InnoDB存储引擎的状态
  Mysql> show processlist ——查看当前SQL执行,包括执行状态、是否锁表等
  Shell> mysqladmin variables -u username -p password——显示系统变量
  Shell> mysqladmin extended-status -u username -p password——显示状态信息
  查看状态变量及帮助:
  Shell> mysqld –verbose –help [|more #逐行显示]
  
  
  比较全的Show命令的使用可参考: http://blog.phpbean.com/a.cn/18/
  慢查询日志
  慢查询日志开启:
  在配置文件my.cnf或my.ini中在[mysqld]一行下面加入两个配置参数
  log-slow-queries=/data/mysqldata/slow-query.log           
  long_query_time=2                                                                 
  注:log-slow-queries参数为慢查询日志存放的位置,一般这个目录要有mysql的运行帐号的可写权限,一般都将这个目录设置为mysql的数据存放目录;
  long_query_time=2中的2表示查询超过两秒才记录;
  在my.cnf或者my.ini中添加log-queries-not-using-indexes参数,表示记录下没有使用索引的查询。
  log-slow-queries=/data/mysqldata/slow-query.log           
  long_query_time=10                                                               
  log-queries-not-using-indexes                                             
  慢查询日志开启方法二:
  我们可以通过命令行设置变量来即时启动慢日志查询。由下图可知慢日志没有打开,slow_launch_time=# 表示如果建立线程花费了比这个值更长的时间,slow_launch_threads 计数器将增加
DSC0001.png
  设置慢日志开启
DSC0002.png
  MySQL后可以查询long_query_time 的值 。
DSC0003.png
  
  
  为了方便测试,可以将修改慢查询时间为5秒。
DSC0004.png
  慢查询分析mysqldumpslow
  我们可以通过打开log文件查看得知哪些SQL执行效率低下
  [iyunv@localhost mysql]# more slow-query.log                            
  # Time: 081026 19:46:34                                                                          
  # User@Host: root[root] @ localhost []                                                           
  # Query_time: 11 Lock_time: 0 Rows_sent: 1 Rows_examined: 6552961        
  select count(*) from t_user;                                                                                
  从日志中,可以发现查询时间超过5 秒的SQL,而小于5秒的没有出现在此日志中。
  如果慢查询日志中记录内容很多,可以使用mysqldumpslow工具(MySQL客户端安装自带)来对慢查询日志进行分类汇总。mysqldumpslow对日志文件进行了分类汇总,显示汇总后摘要结果。
  进入log的存放目录,运行
  [iyunv@mysql_data]#mysqldumpslow  slow-query.log                                 
  Reading mysql slow query log from slow-query.log                            
  Count: 2 Time=11.00s (22s) Lock=0.00s (0s) Rows=1.0 (2), root[root]@mysql    
  select count(N) from t_user;                                                
  mysqldumpslow命令
  /path/mysqldumpslow -s c -t 10 /database/mysql/slow-query.log                      
  这会输出记录次数最多的10条SQL语句,其中:
  -s, 是表示按照何种方式排序,c、t、l、r分别是按照记录次数、时间、查询时间、返回的记录数来排序,ac、at、al、ar,表示相应的倒叙;
  -t, 是top n的意思,即为返回前面多少条的数据;
  -g, 后边可以写一个正则匹配模式,大小写不敏感的;
  例如:
  /path/mysqldumpslow -s r -t 10 /database/mysql/slow-log                                 
  得到返回记录集最多的10个查询。
  /path/mysqldumpslow -s t -t 10 -g “left join” /database/mysql/slow-log       
  得到按照时间排序的前10条里面含有左连接的查询语句。
  使用mysqldumpslow命令可以非常明确的得到各种我们需要的查询语句,对MySQL查询语句的监控、分析、优化是MySQL优化非常重要的一步。开启慢查询日志后,由于日志记录操作,在一定程度上会占用CPU资源影响mysql的性能,但是可以阶段性开启来定位性能瓶颈。
  explain分析查询
  使用 EXPLAIN 关键字可以模拟优化器执行SQL查询语句,从而知道MySQL是如何处理你的SQL语句的。这可以帮你分析你的查询语句或是表结构的性能瓶颈。通过explain命令可以得到:
  – 表的读取顺序
  – 数据读取操作的操作类型
  – 哪些索引可以使用
  – 哪些索引被实际使用
  – 表之间的引用
  – 每张表有多少行被优化器查询
DSC0005.png
  EXPLAIN字段:
  ?Table:显示这一行的数据是关于哪张表的
  ?possible_keys:显示可能应用在这张表中的索引。如果为空,没有可能的索引。可以为相关的域从WHERE语句中选择一个合适的语句
  ?key:实际使用的索引。如果为NULL,则没有使用索引。MYSQL很少会选择优化不足的索引,此时可以在SELECT语句中使用USE INDEX(index)来强制使用一个索引或者用IGNORE INDEX(index)来强制忽略索引
  ?key_len:使用的索引的长度。在不损失精确性的情况下,长度越短越好
  ?ref:显示索引的哪一列被使用了,如果可能的话,是一个常数
  ?rows:MySQL认为必须检索的用来返回请求数据的行数
  ?type:这是最重要的字段之一,显示查询使用了何种类型。从最好到最差的连接类型为system、const、eq_reg、ref、range、index和ALL

  nsystem、const:可以将查询的变量转为常量.  如id=1;>  neq_ref:访问索引,返回某单一行的数据.(通常在联接时出现,查询使用的索引为主键或惟一键)
  nref:访问索引,返回某个值的数据.(可以返回多行) 通常使用=时发生
  nrange:这个连接类型使用索引返回一个范围中的行,比如使用>或
  nindex:以索引的顺序进行全表扫描,优点是不用排序,缺点是还要全表扫描
  nALL:全表扫描,应该尽量避免
  ?Extra:关于MYSQL如何解析查询的额外信息,主要有以下几种
  nusing index:只用到索引,可以避免访问表. 
  nusing where:使用到where来过虑数据. 不是所有的where clause都要显示using where. 如以=方式访问索引.
  nusing tmporary:用到临时表
  nusing filesort:用到额外的排序. (当使用order by v1,而没用到索引时,就会使用额外的排序)
  nrange checked for eache record(index map:N):没有好的索引.
DSC0006.png
  
  
  profiling分析查询
  通过慢日志查询可以知道哪些SQL语句执行效率低下,通过explain我们可以得知SQL语句的具体执行情况,索引使用等,还可以结合show命令查看执行状态。
  如果觉得explain的信息不够详细,可以同通过profiling命令得到更准确的SQL执行消耗系统资源的信息。
  profiling默认是关闭的。可以通过以下语句查看
DSC0007.png
  
  
  打开功能: mysql>set profiling=1; 执行需要测试的sql 语句:
DSC0008.png
  mysql> show profiles\G; 可以得到被执行的SQL语句的时间和ID
  mysql>show profile for query 1; 得到对应SQL语句执行的详细信息
  Show Profile命令格式:
  SHOW PROFILE [type [, type] … ]                                    
  [FOR QUERY n]                                                            
  [LIMIT row_count [OFFSET offset]]                             
  type:                                                                                  
  ALL                                                                               
  | BLOCK IO                                                                      
  | CONTEXT SWITCHES                                                   
  | CPU                                                                              
  | IPC                                                                                
  | MEMORY                                                                            
  | PAGE FAULTS                                                               
  | SOURCE                                                                        
  | SWAPS                
  
  
  
  
  
  
  
  
  以上的16rows是针对非常简单的select语句的资源信息,对于较复杂的SQL语句,会有更多的行和字段,比如converting HEAP to MyISAM 、Copying to tmp table等等,由于以上的SQL语句不存在复杂的表操作,所以未显示这些字段。通过profiling资源耗费信息,我们可以采取针对性的优化措施。
  
  
  测试完毕以后 ,关闭参数:mysql> set profiling=0
  
  
  
  
  2     索引及查询优化
  
  
  关于MySQL索引的好处,如果正确合理设计并且使用索引的MySQL是一辆兰博基尼的话,那么没有设计和使用索引的MySQL就是一个人力三轮车。对于没有索引的表,单表查询可能几十万数据就是瓶颈,而通常大型网站单日就可能会产生几十万甚至几百万的数据,没有索引查询会变的非常缓慢。还是以WordPress来说,其多个数据表都会对经常被查询的字段添加索引,比如wp_comments表中针对5个字段设计了BTREE索引。
  一个简单的对比测试
  以我去年测试的数据作为一个简单示例,20多条数据源随机生成200万条数据,平均每条数据源都重复大概10万次,表结构比较简单,仅包含一个自增ID,一个char类型,一个text类型和一个int类型,单表2G大小,使用MyIASM引擎。开始测试未添加任何索引。
  执行下面的SQL语句:
  mysql> SELECT id,FROM_UNIXTIME(time) FROM article WHERE a.title='测试标题'
  查询需要的时间非常恐怖的,如果加上联合查询和其他一些约束条件,数据库会疯狂的消耗内存,并且会影响前端程序的执行。这时给title字段添加一个BTREE索引:
  mysql> ALTER TABLE article ADD INDEX index_article_title ON title(200);
  再次执行上述查询语句,其对比非常明显:

  MySQL索引的概念

  索引是一种特殊的文件(InnoDB数据表上的索引是表空间的一个组成部分),它们包含着对数据表里所有记录的引用指针。更通俗的说,数据库索引好比是一本书前面的目录,能加快数据库的查询速度。上述SQL语句,在没有索引的情况下,数据库会遍历全部200条数据后选择符合条件的;而有了相应的索引之后,数据库会直接在索引中查找符合条件的选项。如果我们把SQL语句换成“SELECT * FROM article WHERE>  索引分为聚簇索引和非聚簇索引两种,聚簇索引是按照数据存放的物理位置为顺序的,而非聚簇索引就不一样了;聚簇索引能提高多行检索的速度,而非聚簇索引对于单行的检索很快。
  MySQL索引的类型
  1. 普通索引
  这是最基本的索引,它没有任何限制,比如上文中为title字段创建的索引就是一个普通索引,MyIASM中默认的BTREE类型的索引,也是我们大多数情况下用到的索引。
  
–直接创建索引  
CREATE INDEX index_name ON table(column(length))  
–修改表结构的方式添加索引  
ALTER TABLE table_name ADD INDEX index_name ON (column(length))  
创建表的时候同时创建索引  
CREATE TABLE `table` (  
`id` int(11) NOT NULL AUTO_INCREMENT ,  
`title` char(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ,  
`content` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL ,  
`time` int(10) NULL DEFAULT NULL ,  
PRIMARY KEY (`id`),  
INDEX index_name (title(length)))  
–删除索引  
DROP INDEX index_name ON table  2. 唯一索引
  与普通索引类似,不同的就是:索引列的值必须唯一,但允许有空值(注意和主键不同)。如果是组合索引,则列值的组合必须唯一,创建方法和普通索引类似。
  
–创建唯一索引CREATE UNIQUE INDEX indexName ON table(column(length))03–修改表结构04ALTER TABLE table_name ADD UNIQUE indexName ON (column(length))05–创建表的时候直接指定06CREATE TABLE `table` (07`id` int(11) NOT NULL AUTO_INCREMENT ,08`title` char(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ,09`content` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL ,10`time` int(10) NULL DEFAULT NULL ,11PRIMARY KEY (`id`),12UNIQUE indexName (title(length))13);  3. 全文索引(FULLTEXT)
  MySQL从3.23.23版开始支持全文索引和全文检索,FULLTEXT索引仅可用于 MyISAM 表;他们可以从CHAR、VARCHAR或TEXT列中作为CREATE TABLE语句的一部分被创建,或是随后使用ALTER TABLE 或CREATE INDEX被添加。////对于较大的数据集,将你的资料输入一个没有FULLTEXT索引的表中,然后创建索引,其速度比把资料输入现有FULLTEXT索引的速度更为快。不过切记对于大容量的数据表,生成全文索引是一个非常消耗时间非常消耗硬盘空间的做法。
  
–创建表的适合添加全文索引  
CREATE TABLE `table` (  
`id` int(11) NOT NULL AUTO_INCREMENT ,  
`title` char(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ,  
`content` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL ,  
`time` int(10) NULL DEFAULT NULL ,  
PRIMARY KEY (`id`),  
FULLTEXT (content)  
);  
–修改表结构添加全文索引  
ALTER TABLE article ADD FULLTEXT index_content(content)  
–直接创建索引  
CREATE FULLTEXT INDEX index_content ON article(content)  4. 单列索引、多列索引
  多个单列索引与单个多列索引的查询效果不同,因为执行查询时,MySQL只能使用一个索引,会从多个索引中选择一个限制最为严格的索引。
  5. 组合索引(最左前缀)
  平时用的SQL查询语句一般都有比较多的限制条件,所以为了进一步榨取MySQL的效率,就要考虑建立组合索引。例如上表中针对title和time建立一个组合索引:ALTER TABLE article ADD INDEX index_titme_time (title(50),time(10))。建立这样的组合索引,其实是相当于分别建立了下面两组组合索引:
  –title,time
  –title
  为什么没有time这样的组合索引呢?这是因为MySQL组合索引“最左前缀”的结果。简单的理解就是只从最左面的开始组合。并不是只要包含这两列的查询都会用到该组合索引,如下面的几个SQL所示:
1–使用到上面的索引2SELECT * FROM article WHREE>3SELECT * FROM article WHREE utitle='测试';4–不使用上面的索引5SELECT * FROM article WHREE time=1234567890;  MySQL索引的优化
  上面都在说使用索引的好处,但过多的使用索引将会造成滥用。因此索引也会有它的缺点:虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE。因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件。建立索引会占用磁盘空间的索引文件。一般情况这个问题不太严重,但如果你在一个大表上创建了多种组合索引,索引文件的会膨胀很快。索引只是提高效率的一个因素,如果你的MySQL有大数据量的表,就需要花时间研究建立最优秀的索引,或优化查询语句。下面是一些总结以及收藏的MySQL索引的注意事项和优化方法。
  1. 何时使用聚集索引或非聚集索引?
  
动作描述使用聚集索引使用非聚集索引列经常被分组排序使用使用返回某范围内的数据使用不使用一个或极少不同值不使用不使用小数目的不同值使用不使用大数目的不同值不使用使用频繁更新的列不使用使用外键列使用使用主键列使用使用频繁修改索引列不使用使用  事实上,我们可以通过前面聚集索引和非聚集索引的定义的例子来理解上表。如:返回某范围内的数据一项。比如您的某个表有一个时间列,恰好您把聚合索引建立在了该列,这时您查询2004年1月1日至2004年10月1日之间的全部数据时,这个速度就将是很快的,因为您的这本字典正文是按日期进行排序的,聚类索引只需要找到要检索的所有数据中的开头和结尾数据即可;而不像非聚集索引,必须先查到目录中查到每一项数据对应的页码,然后再根据页码查到具体内容。其实这个具体用法我还不是很理解,只能等待后期的项目开发中慢慢学学了。
  2. 索引不会包含有NULL值的列
  只要列中包含有NULL值都将不会被包含在索引中,复合索引中只要有一列含有NULL值,那么这一列对于此复合索引就是无效的。所以我们在数据库设计时不要让字段的默认值为NULL。
  3. 使用短索引
  对串列进行索引,如果可能应该指定一个前缀长度。例如,如果有一个CHAR(255)的列,如果在前10个或20个字符内,多数值是惟一的,那么就不要对整个列进行索引。短索引不仅可以提高查询速度而且可以节省磁盘空间和I/O操作。
  4. 索引列排序
  MySQL查询只使用一个索引,因此如果where子句中已经使用了索引的话,那么order by中的列是不会使用索引的。因此数据库默认排序可以符合要求的情况下不要使用排序操作;尽量不要包含多个列的排序,如果需要最好给这些列创建复合索引。
  5. like语句操作
  一般情况下不鼓励使用like操作,如果非使用不可,如何使用也是一个问题。like “%aaa%” 不会使用索引而like “aaa%”可以使用索引。
  6. 不要在列上进行运算
  例如:select * from users where YEAR(adddate)一个单引号引发的MYSQL性能损失。
  最后总结一下,MySQL只对一下操作符才使用索引:,>=,between,in,以及某些时候的like(不以通配符%或_开头的情形)。而理论上每张表里面最多可创建16个索引,不过除非是数据量真的很多,否则过多的使用索引也不是那么好玩的,比如我刚才针对text类型的字段创建索引的时候,系统差点就卡死了。
  
  
  
  
  
  
  
  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-154765-1-1.html 上篇帖子: MySQL 中 show full processlist 详解 下篇帖子: MySQL中修改密码及访问限制设置详解
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表