龙盟编程博客 | 无障碍搜索 | 云盘搜索神器
快速搜索
主页 > 数据库类 > MySQL 技术 >

MySQL索引和查询优化的实际操作(1)(2)

时间:2011-04-12 23:18来源:未知 作者:admin 点击:
分享到:
选择索引: 1.) 有查询需要使用索引(比如where从句中条件的域)的时候,要创建索引;不要不使用的域(不如第一个字符是通配符的)创建索引。 2.) 创建的索

选择索引:

1.) 有查询需要使用索引(比如where从句中条件的域)的时候,要创建索引;不要不使用的域(不如第一个字符是通配符的)创建索引。

2.) 创建的索引返回的行越少越好,主键最好,枚举类型的索引不什么用处。

3.) 使用短索引(比如,名字的头十个字符而不是全部)。

4.) 不要创建太多的MySQL索引,虽然加快了查询的速度,但增加了更新的添加记录的时间。如果索引在查询中很少使用,而没有索引只是轻微的影响速度,就不要创建索引。

最左边规则:这种情况发生在多个有索引的域上,MySQL从索引列表的最左边开始,按顺序使用他们。

  1. alter table customer add initial varchar(5);   
  2. alter table customer add index(surname,initial,first_name);   
  3. update customer set initial='x' where id=1;   
  4. update customer set initial='c' where id=2;   
  5. update customer set initial='v' where id=3;   
  6. update customer set initial='b' where id=4;   
  7. update customer set initial='n' where id=20;   
  8. update customer set initial='m' where id=21

如果在查询中使用了这三个域,那就最大限度的利用了索引:select * from customer where surname='clegg' and initial='x' and first_name='yvonne';

或者是利用MySQL索引的大部分:select * from customer where surname='clegg' and initial='x';

或仅仅是surname:select * from customer where surname='clegg';

如果打破最左边规则,下面的例子就不会用到索引:select * from customer where initial='x' and first_name='yvonne';

select * from customer where initial='x' ;

select * from customer where first_name='yvonne';

select * from customer where surname='clegg' and first_name='yvonne';

使用explain-解释MySQL如何使用索引来处理select语句及连接表的。

输入 explain select * from customer; 后,出现一张表,个行的意思如下:

table-显示此行数据属于哪张表;type-重要的一列,显示使用了何种连接,从好到差依次为const、eq_ref、ref、range、index、all,下面会详细说明;possible_keys-可以应用在这张表中的索引,如果为null,则表示没有可用索引;key-实际使用的索引,如为null,表示没有用到索引;key_len-索引的长度,在不损失精确度的情况下,越短越好;ref-显示索引的哪一列被使用了,如果可能的话,是个常数;rows-返回请求数据的行数;extra-关于MySQL如何解析查询的额外信息,下面会详细说明。

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-看到这个就需要优化查询了,MySQL需要创建一个临时表来查询存储结果,这通常发生在多不同的列表进行order by时,而不是group by;

where used-使用了where从句来限制哪些行将与下一张表匹配或是返回给用户。如不想返回表中用的全部行,并连接类型是all或index,这就会发生,也可能是查询有问题。

type的描述:system-表只有一行,这是const连接类型的特例;const-表中一个记录的最大值能够匹配这个查询(索引可以是主键或唯一索引)。因为只有一行,这个值实际就是常数,因为MySQL先读这个值,再把它当作常数对待;eq_ref-从前面的表中,对每一个记录的联合都从表中读取一个记录。在查询使用索引为主键或唯一索引的全部时使用;ref-只有使用了不是主键或唯一索引的部分时发生。

对于前面表的每一行联合,全部记录都将从表中读出,这个连接类型严重依赖索引匹配记录的多少-越少越好;range-使用索引返回一个范围中的行,比如使用>或<查找时发生;index-这个连接类型对前面的表中的每一个记录联合进行完全扫描(比all好,因为索引一般小于表数据);all-这个连接类型多前面的表中的每一个记录联合进行完全扫描,这个比较糟糕,应该尽量避免。

举个例子:create index sales_rep on sales(sales_rep); // 可以比较一下创建MySQL索引前后的变化

explain select * from sales_rep left join sales on sales.sales_rep = sales_rep.employee_number;

结果如下:

  1. table type possible_keys key key_len ref rows extra   
  2. sales_rep all null null null null 5   
  3. sales ref sales_rep sales_rep 5 sales_rep.employee_number 2  

这个结果表示sales_rep表有个不好的连接类型-all,没用到索引,要查询的行数为5;sales的连接类型为ref,可用的索引是sales_rep,实际也使用sales_rep索引,这个索引的长度是5,对应的列是employee_number,要查询的行数为2,所以这次查询对表共进行了5×2次查询。

查看索引信息:show index from tablename;

列的描述:table-正在查看的表名;non_unique-1或1.0表示索引不能包含重复值(主键和唯一索引),1表示可以;key_name-索引名;seq_in_index-索引中列的顺序,从1开始;column_name-列名;collation-a或null,a表示索引以序升排列,null表示不排序;

cardinality-索引中唯一值的个数;sub_part-如果整个列为MySQL索引,值为null,否则以字符表示索引的大小;packed-是否打包;null-如果列能包含null,则为yes;comment-各种注释。


精彩图集

赞助商链接