mysql性能优化

mysql 良好的安全链接,自带查询解析,sql语句优化,使用读写锁(细化到行),事务隔离和多版本并发控制提升并发,完备的事务日志记录,强大的存储引擎提供高效查询(表记录可达百万级)。若是是innerdb还可在崩溃后进行完整的恢复。优势很是多,可是仍是须要优化mysql

1,SQL优化的通常步棸算法

1.1,查看sql执行频率sql

show status like 'Com_%' ;  // Com_select :执行select操做的次数,一次累计加1。其余相似数据库

如下只针对InnoDB存储引擎,累加算法略有不一样  show status like 'innodb_rows_%'  windows

 

Innodb_rows_read:select 查询操做插入的行数安全

Innodb_rows_inserted/updated/deleted:执行insert/update/delete 操做的行数服务器

经过以上的参数,能够了解数据库应用是以查询为主仍是写入数据为主。session

对于事务性的应用,经过Com_commit和Com_rollback能够了解事务的提交和回滚状况,对于回滚操做很是的频繁的数据库,可能意味着应用编写的存在问题。并发

基本状况了解:函数

 

Connections:试图连接数据库服务的次数

Uptime:服务器工做时间

slow_queries:慢查询次数

1.2,定位执行效率比较低的sql语句 

经过慢查询日志定位慢的SQl语句,用--slow_query_log_file[=file_name](mysql5.6以后) 选项启动中,mysqld会写一个全部执行时间超过long_query_time秒的SQL语句的日志文件。

使用SHOW FULL PROCESSLIST:查看当前Mysql在进行的线程,同时对一些锁表操做进行优化

slow_query_log_file=/var/lib/mysql/Dragonwake-slow.log    //   # 将查询执行时间较慢的语句进行记录 mysql配置文件 /etc/my.cnf  。  若是未指定file_name,默认为host_name-slow.errmysql5.6以前 log-slow-queries 

long_query_time=1  # 执行超过1秒的sql会被log下来

日志查询 show variables like 'log_%'

 

二进制日志数目:show master logs;  // 必须使用二进制日志才可使用查询

1.3,经过explain分析慢SQLi

explain SQl语句

结果:

--select_type:表示select的类型,常见的类型是SIMPLE (既不是用表链接或子查询),PRIMARY(主查询,即外层的查询),UNION(Union中的第二个或后面的查询语句),SUBQUERY(子查询中的第一个select查询)等

--table:输出结果的表名

--type:表示MYSQL在表中找到行的方式,或者叫访问类型

 常见的有 ALl index range ref eq_ref const system NUll 从左到右性能由差到好

 type=all 全表扫描

 type=index 索引全扫描,mysql遍历全部索引来查询

 type=range:索引范围扫描,常见于<,<= ,> , >= between

 type=ref:使用非惟一索引扫描惟一索引的前缀扫描,返回匹配某个单独值得匹配

 type=eq_ref 相似ref 就在于使用得索引是惟一索引,对于每一个索引键值,表中只有一条记录匹配,简单来讲,就是多表链接中使用primary key(主键)unique index(惟一索引)做为关联条件

 type=const/system 但表中最多有一个匹配行,查询起来很是迅速,通常主键primary key惟一索引unique index进行得查询,经过惟一索引ek_email访问得时候,类型type为const;而从咱们构造的仅有一条记录得a表中检索时,类型type为system

 type=null :mysql不用访问表或索引,就获得就结果

 类型type还有其余值,如ref_or_null(与ref类似,区别在于条件包含对null的查询),index_merge(索引合并优化),unique_subquery( in 后面是一个查询主键字段的子查询 ),index_subquery(与unique_subquery类似,区别在于 in 后面时一个查询非惟一索引字段的子查询)

--possile-key:表示查询时可能使用的索引

--key:实际使用的索引

--key-len:使用到索引字段的长度

--rows :扫描行的数量

--Extra:执行状况的说明和描述,包含不适合在其余列中显示可是对执行计划很是重要的额外信息

   Using where :表示优化器除了利用索引来加速访问以外,还须要索引回表查询数据

 1.4,经过show profile 分析SQL

   查看当前mysql是否支持profile

 默认profile是关闭的,能够经过set语句在session级别开启profiling, set profiling=1

 使用方法:

-执行统计查询

查询上面的SQl query ID

查询上述执行过程当中每一个线程的状态和消耗时间

Sending data 表示mysql线程开始访问数据并行把结果返回客户端,而不只仅是返回结果给客户端。因为在Sending data 状态下,mysql线程每每须要大量的磁盘读取操做,因此是整个查询中耗时最长的。

 查看详细细节并排序

SELECT
STATE,
SUM(DURATION) AS TR,
ROUND(
100 * SUM(DURATION) / (
SELECT
SUM(DURATION)
FROM
information_schema.PROFILING
WHERE
QUERY_ID = 190
),
2
) AS PR,
COUNT(*) AS Calls,
SUM(DURATION) / COUNT(*) AS "R/Call"
FROM
information_schema.PROFILING
WHERE
QUERY_ID = 190
GROUP BY
STATE
ORDER BY
TR DESC;

 

进一步获取all,cpu,block io , context switch , page faults 等明细来查看mysql在使用什么资源时耗费了过多的时间

此时可经过获取Sending data 时间消耗在cpu

注:InnoDB引擎count(*)没有myISAM 执行速度快,就是由于InnoDB经历Sending data状态,存在访问数据的过程,而MyISAM引擎的表在executing(执行)以后就直接结束查询,彻底不须要访问数据。

2,索引问题

  索引是数据库里最多见也是最重要的手段之一,经过索引能够帮助用户解决大部分的SQL性能问题

2.1,存储引擎的分类

- B-Tree索引:最多见的索引类型,大部分引擎都支持B树索引

- Hash 索引:只有Memory引擎支持

- R-Tree索引:空间索引是MyISAM引擎的一个特殊索引类型,主要用于地理空间数据类型

- Full-text :全文索引是MyISAM的一种特殊的索引类型,主要用于全文索引,InnoDB从mysql5.6开始支持

Mysql不支持函数索引,可是能对列的前面一部分进行索引,例如:字段title,能够只取title字段前10个字符进行索引,只是在order by和group by 操做的时候没法使用。前缀索引建立例子:create index idx_title on film(title(10))

经常使用的索引是B-Tree和Hash。Hash是只有memory和Heap引擎支持。适用于key-value查询,一般Hash比B-Tree更迅速,Hash不使用范围索引。Memory和Heap只有在 = 条件下才能使用索引

2.2 如何使用索引

建立一个复合索引:alter table tb_name add index ids_rental_data(rental_data,inventory_id,customer_id)

2.2.1 mysql可以使用索引的典型场景

   - 匹配全值,对索引中全部列都指定具体值,既是对全部列都有等值匹配条件。

     好比上述的建立, ids_rental_data 包含rental_data,inventory_id,customer_id,若是此时where自句中包含三者,则为全值匹配

   - 匹配的值进行范围查找,对索引的值能进行范围查找

  -- 匹配最左前缀,意思是,在复合索引中,索引是从左边第一个查找的,不会跨过第一个从第二个查找。好比一个联合索引包含(c1 ,c2 ,c3),可不能呗c2和c2+c3利用到

 添加索引 alter table payment add index idx_payment_data(payment_date,amount,last_update) ; 此时第一个字段是payment-date

 若是查询条件包含索引的第一个 payment_date ,可以使用复合索引idx_payment_data 进行过滤

 若是使用第二个 amount没有使用第一个payment_date,则 不会使用索引

 -- 仅仅对索引字段进行查询,意思是查询的字段都在索引字段中,查询的效率更高。

 那么直接访问索引就能够获取所需的数据,不须要索引回表。此时的Extra 就变成了Using index。Using index表明覆盖索引扫描

- 匹配列前缀 ,仅仅使用索引中的第一列,而且只包含索引第一列的开头一部分进行查找;

例如:建立索引  alter table yk_book add index idx_book_diata(book(5),type(3));

查询能够看到idx_book_diata被使用,Using where 表示优化器须要索引回表来查询数据

 

-匹配部分精准,其余部分范围匹配

指定数量 ,不一样的客户编号

类型type为range说明优化器选择范围查询 ,索引key为idx_book_data表示优化器选择索引idx_book_data帮助加速查询,同时所查询的字段在索引中,索引Extra中能看到Using index

- 列名 is null 此种状况下会使用索引。

2.2.2存在索引但不能使用的典型场景

- 以 %开头的like查询,不能使用B-Tree索引

B-Tree索引,以%开头的like查询不能使用索引,咱们能够经过全文索引(Fulltext)来解决问题,或者使用InnoDB上的二级索引,首先获取知足条件的列表id,以后再根据主键回表去检索记录

- 数据类型出现隐式转换不会使用索引,有些列是字符串,再写where条件时,须要将常量值用引号括起来

- 复合索引查询条件必须包含最左部分,不然不会使用索引。即leftmost

- mysql 执行语句时会有优化器选择的过程,当全表扫描的代价小于索引扫描的代价时,会使用全表扫描,因此须要更换一个筛选性更高的条件

- 用or分开的条件,若是or前的条件有索引,or后的条件没有索引,则不会使用索引

2.3查看索引的使用状况

若是索引正在工做,Handle_read_key 的值将会很高,这个值表明了一行被索引值读的次数。若是很低说明增长索引增长的性能不高,由于索引并无被常用。

Handle_read_rnd_next的值高说明查询运行低效,而且应该创建索引补救。这个值的含义是在数据文件中读取下一行的请求数。若是值比较大,说明正在进行大量的表扫描,则一般说明表索引不正确或写入的查询没有利用索引。

 3,常见的SQL优化

3.1 大批量插入数据

--  MyISAM

-  打开或关闭MyISAM表 非惟一索引的更新,能够提升导入效率(导入数据到非空MyISAM表)

 步棸:一步:alter table tb_name disable key ;//disable关闭表的非惟一索引的使用  

           二步:导入数据 

          三步: alter table tb_name enable key // enable 开启表的非惟一索引的使用

 导入数据到一个空的MyISAM表,默认先导入数据在建立索引,因此不用设置

--  InnoDB

 - 由于InnoDB类型的表按照主键顺序保存的,因此导入的数据是按照主键顺序排列,能够有效的提升导入数据的效率

- 关闭惟一性效应,set unique_checks = 0,导入数据后再恢复

- 若是使用的是自动提交的方式,再导入前使用set AUTOCOMMIT = 0,导入结束后在恢复

3.2 优化 insert 语句

-  同一客户端插入不少行,应尽可能使用多个值的insert语句。例如,insert into tb_name (),(),(),();

-  不一样客户端插入不少行,可使用 insert delayed , delayed含义是让insert语句放置到内存的队列中,并无写入磁盘。

      low_priority是在全部其余用户对读写完成后才进行插入。  

     low_priority 低优先级  update [low_priority] tb_name set   col_name = exp1 ,col_name2 = exp2........        //mysql中update 用low_priority 不锁定表

     LOW_PRIORITY 关键字应用于 delete ,insert ,load data , update 和replace

     HIGH_PRIORITY 关键字应用于 select 和insert语句

      delayed 应用于insert和replace语句

- 将索引文件和数据文件分别放置在不一样的磁盘

-  MyISAM 若是进行批量插入,增长bulk_insert_buffer_size的值

- 从文件装载一个表时,使用Load data infile , 比insert语句快20倍

 3.3 优化 order by 语句 

 3.3.1 mysql排序方式

 - 经过有序索引顺序扫描直接返回有序数据。

在book表上有索引 uid 指向字段 uid   

查询表的索引信息

此时使用uid排序时,Extra 时Using index 无需进行回表操做,不须要额外的排序,操做效率高

-- 经过fileSort 排序,不经过索引直接返回排序结果的排序都叫作fileSort排序。mysql服务器对排序参数的设置和须要排序数据的大小来决定排序操做是否使用磁盘文件或临时表。

    fileSort是经过算法,将取得的数据在sort_buffer_size系统变量设置的内存排序区进行排序,若是内存装不下,就会将磁盘上的数据进行分块,在对各个数据块进行排序,而后合并。sort_buffer_size的排序区为线程独占,可能同时存在多个

    好比经过uid排序全部客户记录时,此时为全表扫描,而且使用了filesort

通常优化方式:减小额外的排序,经过索引直接返回有序数据。尽可能使where条件和order by使用相同的索引,而且order by顺序和索引数据相同,而且order by的字段都是升序或者降序,不然确定会出现fileSort

-- 不会使用索引的状况:

   - order by的字段混合使用asc和desc select * from tb_name order p_key1 desc,p_key2 asc

   - 对于查询的关键字和order by使用的不一样  select * from tb_name where key1=content order by key2

  -  对不一样的关键字使用order by   : select * from tb_name order by key1,key2

3.3.2 优化fileSort 

  fileSort 有两种排序算法

   -  两次扫描算法:首先根据条件取出排序字段和行指针信息,以后再排序区sort buffer中排序。若是排序区sort buffer不够,则在临时表Temporary Table中存储排序结果,完成排序后根据行指针回表读取记录。须要两次访问数据,第一次获取排序字段和行指针信息,第二次根据行指针获取记录,第二次读取操做可能致使大量随机I/O操做,优势是排序的时候内存开销比较少

   - 一次扫描算法:一次性取出知足条件行的全部字段,而后再排序区 sort buffer 中排序后直接输出结果集。排序的内存开销比较大,但排序效率比两次扫描算法高

   mysql 经过比较系统变量max_length_for_sort_data 的大小和query语句取出的字段总大小来判断使用哪一种算法,max_length_for_sort_data大使用第二种,不然使用第一种

   适当加大系统变量max_length_for_sort_data的值,可以让mysql选择更优化的fileSort的排序算法。可是过大会引发cpu的利用率太低和磁盘I/O太高

   适当加大sort_buffer_size排序区,尽可能让排序再内存区完成,而不是经过建立临时表放在文件中完成;该大小须要考虑数据库活动链接数服务器内存的大小来适当设置排序区。由于这个参数是每一个线程独占的,若是设置过大,会致使服务器swap严重。尽可能使用必要的字段而不是 select *

  3.3.3 优化group by

默认状况下,mysql对全部的group by的字段进行排序。若是查询包括group by 可是用户想要排除掉排序结果的消耗,则能够指定order by null禁止排序

select xxx from tb_name group by xxx order by null

3.3.4 优化嵌套查询

 使用子查询能够一次性完成不少逻辑上须要多个步棸才能完成的sql操做,同时能够避免事务或者表锁死。子查询能够被更有效的链接 join 代替

3.3.5 优化or条件

   对于含有or的查询子句,若是要利用索引,若是要利用索引,则or之间的每一个条件都要用到索引

3.3.6 优化分页索引

  通常分页查询时,经过建立覆盖索引可以比较好的提升性能,可是当分页为1000  20时,此时排序前1020条记录后返回1001到1020条记录,前1000条记录会被抛弃,查询和排序的代价很是高

   -  第一种优化思路:从索引完成排序分页的操做,最后根据主键回表查询所需的其余列内容

     例如:直接查询

   

  按照索引分页后回表方式改写sql

-  第二种优化思路:把limit查询转换为某个位置的查询

  假如须要查询第100页,则能够记录第99页最后一行的id(倒序或正序),而后查询时where 条件大于或者小于99页最后一行的id,而后直接limit  n就能够了,n为每页显示的行数

  比较

  


3.3.7 使用sql提示

 -  USE INDEX

  提示mysql参考使用索引,可让mysql不在考虑其余可用索引

   好比:select count(1) from tb_name use index(index_name ) where xxxx  ; 此时使用了index_name索引,其余索引忽略。

- ignore index 

 提示mysql忽略一个可用索引

 好比: select count(1) from tb_name ignore index(index_name);  此时忽略index_name索引

- force index 

  强制mysql使用某个索引,使用状况,当where自句取id>1的值,由于数据库中大部分库表都是大于1的,因此会全表扫描,此时使用use index不可用,因此使用force index

  好比; select * from tb_name force index(index_name) where id>1;

 4,经常使用的sql技巧

4.1 正则的使用

   

 
序列 序列说明
^ 在字符串的开始处进行匹配
$ 在字符串的末尾处进行匹配
. 匹配任意单个字符,包括换行符
[...] 匹配出括号内的任意字符
[^...] 匹配不出括号内的任意字符
a* 匹配零个或多个a(包括空串)
a+ 匹配一个或多个a (不包括空串)
a? 匹配一个或零个a
a1|a2 匹配a1或a2
a(m) 匹配m个a
a(m,) 匹配m个或多个a
a(m,n) 匹配m个到n个a
a(,n) 匹配0到n个a
(....) 将模式元素组成模式元素

 

 

 

 

 

 

 

 

 

 

 

 

 

-  ^ 在字符串开头匹配

   匹配是否以a开头 regexp

-  $在字符串的末尾处匹配

-  . 匹配单个任意字符,包括换行符

- [...] 匹配出括号内的任意字符

- [^...] 不匹配[]中的任意字符

 

4.2 利用rand()提取随机行

随机抽取n条数据:select * from tb_name order by rand() limit n

4.3 group bywith rollup

   WITH ROLLUP 能够检索出更多的分组聚合信息

好比:统计每日的商品数量 ,不加入with rollup

 

 

    加入with rollup

 

 

with rollup  反应的是一种OLAP思想,能够知足用户想要获得的任何一个分组以及分组组合的聚合信息。with rollup 统计了每日的总数全部的总数。注意:with rollup 不能和order by一块儿使用且limit在with  rollup后面

 4.4 数据库名和表名大小写问题

    因为windows,mac Os,Unix对库表名以及查询使用的大小写敏感不一致,因此最好将库表规范保存,且查询语句也规范使用

mysql经过存储引擎取 Innodb 索引目前有两种BTREE索引和HASH索引。

相关文章
相关标签/搜索