思路:分析慢查询日志 - 查看表结构、表状态 - 查看表索引 - 分析 sql 语句 -explain- 修改 sql 语句 - 验证修改结果

打开慢查询日志
my.cnf 置文件中修改

log-slow-queries
打开慢查询日志
long_query_time
设一个阀值,要大于这个值才会记录,等于该值时不记录。
log_queries_not_using_indexes
如果运行的 SQL 语句没有使用索引,则 MySQl 数据库同样会将这条 SQL 语句记录到慢查询日志文件
也可以在 MySQL 中直接设置 long_query_time 的值

mysql> set long_query_time=2;
Query OK, 0 rows affected (0.02 sec)
mysql> show variables like 'long%';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| long_query_time | 2     |
+-----------------+-------+
1 row in set (0.00 sec)
查看慢查询日志

默认情况下,在数据库目录下,例如 /var/lib/mysql ,在数据库运行时,可动态观察
tail -f slowquery.log
……
# Time: 110523  9:58:35 时间
# User@Host: grid[grid] @  [203.100.192.66] 连接信息
# Query_time: 4  Lock_time: 0  Rows_sent: 1  Rows_examined: 4815
查询时间 锁时间 返回行数 总共查询行数
select count(*) from table_name wher e ……
利用 mysqldumpslow 分析慢查询日志

mysqldumpslow -s c -t 10 输出记录次数最多的10条SQL语句
mysqldumpslow -s r -t 10 返回记录集最多的10个查询
mysqldumpslow -s t -t 10 -g ' left join ' 按照时间排序的前10条里面含有左连接的查询语句
-s, 是表示按照何种方式排序
c 记录次数、t 时间、l 查询时间、r 返回的记录数 ac、at、al、ar,表示相应的倒叙;
-t, 是top n的意思,即为返回前面多少条的数据;
-g, 后边可以写一个正则匹配模式,大小写不敏感的;

-s t

按总query time排序

-s at

按平均query time排序

-s l

按总locktime排序

-s al

按平均lock time排序

-s s

按总row send排序

-s as

按平均row send排序

-s c

按count排序



注意:在默认情况下
mysqlslowdump的输出结果会使用N和S代替SQL中出现的数字和字符串
mysqlslowdump输出结果是按照count(SQL出现的次数)排序的
mysqldumpslow 结果分析

# mysqldumpslow -s c -t 10 slowquery.log

Reading mysql slow query log from slowquery.log
Count: 147973  Time=4.64s (686449s)  Lock=0.34s (51032s)  Rows=1.0 (147687), grid[grid]@[203.100.192.66]
  select count(*) from table_name where ((newsT = ' S ' and …………用 S 代表字符串
平均执行 147973 次,每次耗时 4.64
分析问题

show create table table_name 查看表结构
分析问题 查看当期表都有哪些索引

mysql> show index from t \G
*************************** 1. row ***************************
       Table: t 索引所在的表名
   Non_unique: 0 非唯一索引, 0 代表唯一,可以看到主键名字是 PRIMARY ,因此必须唯一。
    Key_name: PRIMARY 索引的名称,可以通过这个名称来 DROP INDEX
Seq_in_index: 1 索引中 该列的位置(注意理解是“索引中”),参考联合索引就容易理解了。
  Column_name: a 索引的列
   Collation: A 列以什么方式存储在索引中,可以是 A 或者 NULL B+ 树索引总是 A ,即排序的。如果使用了 heap 存储引擎,并建立了 hash 索引,这里就会显示 NULL 。因为 hash 根据 hash 桶来存放数据,而不是对数据进行排序。
  Cardinality: 5 非常关键的值!!!表示索引中唯一值的数据的估计值。 Cardinality / 表的行数,应尽可能接近 1 ,如果非常小,那么考虑是否还需要这个索引???
    Sub_part: NULL 是否是列的部分被索引,如果是整个列,则该字段为 NULL
      Packed: NULL 关键字如何被压缩,如果没有被压缩,则为 NULL
        Null: 是否索引的列含有 NULL 值。
   Index_type: BTREE 索引的类型。
      Comment: 注释
Index_comment:

Cardinality 值(大概的值)非常关键,优化器会根据这个值来判断是否使用这个索引。但是这个值并不是实时更新的,并非每次索引的更新都会更新该值,因为代价太大。
更新索引的Cardinality 信息
mysql> analyze table t \G
*************************** 1. row ***************************
  Table: test.t
     Op: analyze
Msg_type: status
Msg_text: OK
1 row in set (0.04 sec)
注意:不是每个系统上都得到同样的结果,目前 (MySQL5.1) analyze table 还存在一些问题。
建议:在非高峰时间,对应用程序下的几张核心表做analyze table 操作,这能使优化器和索引更好的工作。
分析问题 explain

mysql> explain select * from t where a=1 \G
*************************** 1. row ***************************
          id: 1
 select_type: SIMPLE
       table: t
        type: const
possible_keys: PRIMARY,idx_a_b
         key: PRIMARY 优化器实际使用的索引
     key_len: 4
         ref: const
        rows: 1
       Extra:
1 row in set (0.00 sec)

select_type :表示 SELECT 的类型,常见的取值有 SIMPLE (简单表,即不使用表连接或者子查询)、 PRIMARY (主查询,即外层的查询)、 UNION UNION 中的第二个或者后面的查询语句)、 SUBQUERY (子查询中的第一个 SELECT )等。
table :输出结果集的表。
type :表示表的连接类型,性能由好到差的连接类型为
system (表中仅有一行,即常量表)、
const (单表中最多有一个匹配行,例如 primary key 或者 unique index )、
eq_ref (对于前面的每一行,在此表中只查询一条记录,简单来说,就是多表连接中使用 primary key 或者 unique index )、
ref (与 eq_ref 类似,区别在于不是使用 primary key 或者 unique index ,而是使用普通的索引)、
ref_or_null (与 ref 类似,区别在于条件中包含对 NULL 的查询)、
index_merge( 索引合并优化 )
unique_subquery in 的后面是一个查询主键字段的子查询)、
index_subquery (与 unique_subquery 类似,区别在于 in 的后面是查询非唯一索引字段的子查询)、
range (单表中的范围查询)、
index (对于前面的每一行,都通过查询索引来得到数据)、
all (对于前面的每一行,都通过全表扫描来得到数据)。
possible_keys :表示查询时,可能使用的索引。
key :表示实际使用的索引。
key_len :索引字段的长度。
rows 扫描行的数量
Extra :执行情况的说明和描述。
Distinct

一旦MYSQL 找到了与行相联合匹配的行,就不再搜索了
Not exists

MYSQL 优化了LEFT JOIN ,一旦它找到了匹配LEFT JOIN 标准的行, 就不再搜索了
Range checked for each

Record index map:#
没有找到理想的索引,因此对于从前面表中来的每一个行组合,MYSQL 检查使用哪个索引,并用它来从表中返回行。这是使用索引的最慢的连接之一
Using filesort

看到这个的时候,查询就需要优化了。 MySQL 需要进行额外的步骤来发现如何对返回的行排序。它根据连接类型以及存储排序键值和匹配条件的全部行的行指针来排序全部行
Using index

列数据是从仅仅使用了索引中的信息而没有读取实际的行动的表返回的,这发生在对表的全部的请求列都是同一个索引的部分的时候
Using temporary

看到这个的时候,查询需要优化了。这里, M y SQL 需要创建一个临时表来存储结果,这通常发生在对不同的列集进行 ORDER BY 上,而不是 GROUP BY
Using where

使用了WHERE 从句来限制哪些行将与下一张表匹配或者是返回给用户。如果不想返回表中的全部行,并且连接类型ALL index ,这就会发生,或者是查询有问题
分析问题 查看表状态

mysql> show table status like ' table_name ' \G
解决问题

修改 sql 语句,每次改动,都要 explain 测试一下。后续研究 SQL 语句优化。
参考:

源文档 < http://www.ccvita.com/410.html>
源文档 < http://www.orczhou.com/index.php/2010/01/mysql-slow-log-1/>
源文档 < http://www.orczhou.com/index.php/2010/01/mysql-slow-log-1/>
源文档 < http://www.cnitblog.com/aliyiyi08/archive/2011/05/01/48878.html>