MySQL优化-1-索引

 MySQL 索引
所有MySQL 列类型可以被索引。对相关列使用索引是提高SELECT 操作性能的最佳途径。根据存储引擎定义每个表的最大索引数和最大索引长度。所有存储引擎支持每个表至少16 个索引,总索引长度至少为256 字节。大多数存储引擎有更高的限制。

在MySQL 5.1 中,对于MyISAM 和InnoDB 表,前缀可以达到1000 字节长。请注意前缀的限制应以字节为单位进行测量,而CREATE TABLE 语句中的前缀长度解释为字符数。当为使用多字节字符集的列指定前缀长度时一定要加以考虑。
  • 还可以创建FULLTEXT 索引。该索引可以用于全文搜索。只有MyISAM 存储引擎支持FULLTEXT 索引,并且只为CHAR、VARCHAR 和TEXT 列。索引总是对整个列进行,不支持局部(前缀)索引。
  • 也可以为空间列类型创建索引。只有MyISAM 存储引擎支持空间类型。空间索引使用R-树。
  • 默认情况MEMORY(HEAP)存储引擎使用hash 索引,但也支持B-树索引。
索引的存储分类
myisam 表的数据文件和索引文件是自动分开的;
innodb 的数据和索引是存储在同一个表空间里面,但可以有多个文件组成。

创建索引语法如下
CREATE [UNIQUE|FULLTEXT|SPATIAL] INDEX index_name
[USING index_type]
ON tbl_name (index_col_name,...)
index_col_name:
col_name [(length)] [ASC | DESC]

索引的存储类型
目前只有两种(btree 和hash),具体和表的模式相关:
myisam:  btree
innodb:  btree
memory/heap:  hash,btree

Btree 索引与Hash 索引
对于BTREE 和HASH 索引,当使用=、<=>、IN、IS NULL 或者IS NOT NULL 操作符时,关键元素与常量值的比较关系对应一个范围条件。Hash 索引还有一些其它特征:它们只用于使用=或<=>操作符的等式比较(但很快)。优化器不能使用hash 索引来加速ORDER BY 操作。如果你将一个MyISAM 表改为hash-索引的MEMORY表,会影响一些查询。只能使用整个关键字来搜索一行。(用B-树索引,任何关键字的最左面的前缀可用来找到行)。

对于BTREE 索引,当使用>、<、>=、<=、BETWEEN、!=或者<>,或者LIKE 'pattern'(其中'pattern'不以通配符开始)操作符时,关键元素与常量值的比较关系对应一个范围条件。“常量值”系指:查询字符串中的常量、同一联接中的const 或system 表中的列、无关联子查询的结果、完全从前面类型的子表达式组成的表达式

下面是一些WHERE 子句中有范围条件的查询的例子:
下列范围查询适用于btree 索引和hash 索引
SELECT * FROM t1 WHERE key_col = 1 OR key_col IN (15,18,20);
下列范围查询适用于btree 索引
SELECT * FROM t1 WHERE key_col > 1 AND key_col < 10;
SELECT * FROM t1 WHERE key_col LIKE 'ab%' OR key_col BETWEEN 'bar' AND 'foo';

查看索引使用情况
如果索引正在工作,Handler_read_key 的值将很高,这个值代表了一个行被索引值读的次数,很低的值表明增加索引得到的性能改善不高,因为索引并不经常使用。
Handler_read_rnd_next 的值高则意味着查询运行低效,并且应该建立索引补救。这个值的含义是在数据文件中读下一行的请求数。如果你正进行大量的表扫描,该值较高。通常说明表索引不正确或写入的查询没有利用索引。
语法:mysql> show status like 'Handler_read%';


设计索引的原则
1. 为Where子句中的列创建索引。
a. 最适合索引的列是出现在WHERE 子句中的列,或连接子句中的列,而不是出SELECT 关键字后的选择列表中的列。
b.  索引可用于“ <”、“ < = ”、“ = ”、“ > =”、“ >”和BETWEEN 运算。
c. 在模式具有一个直接量前缀时,索引也用于LIKE 运算。但如果like以%开始,则不使用索引。
d. 如果在WHERE子句中对某些列使用函数,那么将不会使用该列的索引。 
例如:select * from employee where left(name,6)=’FOOBAR’将不能利用name列的索引。
又例如:select * from employee where name like ‘%FOOBAR’也不利用name列的索引.
相反,如果模式中有字符串前缀,则LIKE运算符将使用索引。如:
select * from employee where name like ‘FOOBAR%’
2. 使用惟一索引。 
对于具有惟一值的列,索引的效果最好,而具有多个重复值的列,其索引效果最差。
例如,性别的列,只含有M和F,则对此列进行索引没有多大用处(不管搜索哪个值,都会得出大约一半的行)。
3. 使用短索引(前缀)。
如果对串列进行索引,应该指定一个前缀长度,只要有可能就应该这样做。
例如,如果有一个CHAR(200) 列,如果在前10 个或20 个字符内,多数值是惟一的,那么就不要对整个列进行索引。对前10 个或20 个字符进行索引能够节省大量索引空间,也可能会使查询更快。较小的索引涉及的磁盘I/O 较少,较短的值比较起来更快。更为重要的是,对于较短的键值,索引高速缓存中的块能容纳更多的键值。当然,如仅用列值的第一个字符进行索引是不可能有多大好处的,因为这个索引中不会有许多不同的值。
4. 利用最左前缀。
在创建一个n 列的索引时,实际是创建了MySQL 可利用的n 个索引。多列索引可起几个索引的作用,因为可利用索引中最左边的列集来匹配行。这样的列集称为最左前缀。(这与索引一个列的前缀不同,索引一个列的前缀是利用该的前n 个字符作为索引值。) 
设计良好的多列索引可以减少所需索引的总数量。如果合适,MYSQL将使用多列索引的左边部分。设计很差的索引带来的后果是从不使用或极少使用。熟悉应用查询情况对于确定多列索引是非常重要的。可以使用EXPLAIN SELECT工具验证结果(此工具很好用)。
5. 不要过度索引。
不要以为索引“越多越好”。每个额外的索引都要占用额外的磁盘空间,并降低写操作的性能。在修改表的内容时,索引必须进行更新,有时可能需要重构,因此,索引越多,所花的时间越长。
创建多余的索引给查询优化带来了更多的工作, 索引太多,也可能会使MySQL 选择不到所要使用的最好索引。此外,MySQL 在生成一个执行计划时,要考虑各个索引,这也要费时间。
如果想给已索引的表增加索引,应该考虑所要增加的索引是否是现有多列索引的最左索引。如果是,则就不要费力去增加这个索引了,因为已经有了。

mysql 目前不支持函数索引,只能对列的前一部分(length)进行索引,
例:create index ind_test on table1(name(5))。
对于char 和varchar 列,使用前缀索引将大大节省空间。

MySQL 如何使用索引
索引用于快速找出在某个列中有一特定值的行。对相关列使用索引是提高SELECT 操作性能的最佳途径。
查询要使用索引最主要的条件是查询条件中需要使用索引关键字,如果是多列索引,那么只有查询条件使用了多列关键字最左边的前缀时,才可以使用索引,否则将不能使用索引。
大多数MySQL 索引(PRIMARY KEY、UNIQUE、INDEX 和FULLTEXT)在B 树中存储。只是空间列类型的索引使用R-树,并且MEMORY 表还支持hash 索引。
下列情况下,Mysql 不会使用已有的索引:
1. 如果mysql 估计使用索引比全表扫描更慢,则不使用索引。例如:如果key_part1均匀分布在1 和100 之间,下列查询中使用索引就不是很好:SELECT * FROM table_name where key_part1 > 1 and key_part1 < 90
2. 如果使用heap 表并且where 条件中不用=索引列,其他> 、<、>=、<=均不使用索引;
3. 如果不是索引列的第一部分;
4. 如果like 是以%开始;
5. 对where 后边条件为字符串的一定要加引号,字符串如果为数字mysql 会自动转为字符串,但是不使用索引。

检索索引中的字段

索引不仅是主键或唯一键。如果你想搜索表中的任何列,你应该一直指向索引。

 


避免在索引列上使用计算。如(WHERE SAL  > 25000/12) 

保证连接的索引是相同的类型

如果应用程序中包含多个连接查询,你需要确保你链接的列在两边的表上都被索引。

这会影响MySQL如何优化内部联接操作。此外,加入的列,必须是同一类型。例如,你加入一个DECIMAL列,而同时加入另一个表中的int列,MySQL将无法使用其中至少一个指标。即使字符编码必须同为字符串类型。 

例如:

SELECT company_name FROM users  

LEFT JOIN companies ON (users.state = companies.state)    

WHERE users.id = $user_id");   

两边的state字段都需要创建索引,并且两个字段的类型和使用的字符集编码都需要相同,否则MySQL就可能做全表扫描。 


ORDER BY语句:
任何在Order by语句的非索引项或者有计算表达式都将降低查询速度。
在某些情况中,MySQL 可以使用一个索引来满足ORDER BY 子句,而不需要额外的排序。where 条件和order by 使用相同的索引,并且order by 的顺序和索引顺序相同,并且order by 的字段都是升序或者都是降序。
例如:
下列sql 可以使用索引。
SELECT * FROM t1 ORDER BY key_part1,key_part2,... ;
SELECT * FROM t1 WHERE key_part1=1 ORDER BY key_part1 DESC, key_part2 DESC;
SELECT * FROM t1 ORDER BY key_part1 DESC, key_part2 DESC;
但是以下情况不使用索引:
SELECT * FROM t1 ORDER BY key_part1 DESC, key_part2 ASC;
--order by 的字段混合ASC 和DESC。
SELECT * FROM t1 WHERE key2=constant ORDER BY key1;
--用于查询行的关键字与ORDER BY 中所使用的不相同。
SELECT * FROM t1 ORDER BY key1, key2;
--对不同的关键字使用ORDER BY。

is null或is not null
在where子句中使用is null或is not null的语句优化器是不允许使用索引的,尽量不用,少使用或不使用NOT。
 



你可能感兴趣的:(MySQL优化-1-索引)