Mysql性能优化(三) - 索引及查询优化
## 索引
大多数MySQL索引(PRIMARY KEY、UNIQUE、INDEX和FULLTEXT)使用B树中存储,空间列类型的索引使用R-树,MEMORY表支持hash索引。
### 索引的类型
* 普通索引
* 这是最基本的索引类型,没唯一性之类的限制。
* 唯一性索引
* 和普通索引基本相同,但所有的索引列值保持唯一性。
* 主键
* 主键是一种唯一索引,但必须指定为”PRIMARY KEY”。
* 全文索引
* MYSQL从3.23.23开始支持全文索引和全文检索。在MYSQL中,全文索引的索引类型为FULLTEXT。全文索引可以在VARCHAR或者TEXT类型的列上创建。
### 单列索引和多列索引(复合索引)
索引可以是单列索引,也可以是多列索引,对相关的列使用索引是提高SELECT操作性能的最佳途径之一。
#### 多列索引
MySQL可以为多个列创建索引,一个索引可以包括15个列,对于某些列类型,可以索引列的左前缀,列的顺序非常重要。
多列索引可以视为包含通过连接索引列的值而创建的值的排序的数组,一般来说,即使是限制最严格的单列索引,它的限制能力也远远低于多列索引。
#### 最左前缀
多列索引有一个特点,即最左前缀(Leftmost Prefixing)。假如有一个多列索引为key(firstname lastname age),当搜索条件是以下各种列的组合和顺序时,MySQL将使用该多列索引:
```
firstname, lastname, age
firstname, lastname
firstname
```
也就是说,相当于还建立了key(firstname lastname)和key(firstname)。
**索引主要用于下面的操作**
* 快速找出匹配一个WHERE子句的行。
* 删除行。当执行联接时,从其它表检索行。
* 对具体有索引的列key\_col找出MAX()或MIN()值。由预处理器进行优化,检查是否对索引中在key\_col之前发生所有关键字元素使用了WHERE key\_part\_# = constant。在这种情况下,MySQL为每个MIN()或MAX()表达式执行一次关键字查找,并用常数替换它。如果所有表达式替换为常量,查询立即返回。例如:
```
SELECT MIN(key2), MAX (key2) FROM tb WHERE key1=10;
```
* 如果对一个可用关键字的最左面的前缀进行了排序或分组(例如,ORDER BY key\_part\_1,key\_part\_2),排序或分组一个表。如果所有关键字元素后面有DESC,关键字以倒序被读取。
* 在一些情况中,可以对一个查询进行优化以便不用查询数据行即可以检索值。如果查询只使用来自某个表的数字型并且构成某些关键字的最左面前缀的列,为了更快,可以从索引树检索出值。
```
SELECT key_part3 FROM tb WHERE key_part1 = 1;
```
有时MySQL不使用索引,即使有可用的索引。一种情形是当优化器估计到使用索引将需要MySQL访问表中的大部分行时。(在这种情况下,表扫描可能会更快些)。然而,如果此类查询使用LIMIT只搜索部分行,MySQL则使用索引,因为它可以更快地找到几行并在结果中返回。
### 合理的建立索引的建议
1. 越小的数据类型通常更好:越小的数据类型通常在磁盘、内存和CPU缓存中都需要更少的空间,处理起来更快。
2. 简单的数据类型更好:整型数据比起字符,处理开销更小,因为字符串的比较更复杂。在MySQL中,应该用内置的日期和时间数据类型,而不是用字符串来存储时间;以及用整型数据类型存储IP地址。
3. 尽量避免NULL:应该指定列为NOT NULL,除非你想存储NULL。在MySQL中,含有空值的列很难进行查询优化,因为它们使得索引、索引的统计信息以及比较运算更加复杂。你应该用0、一个特殊的值或者一个空串代替空值
### 关于索引和写SQL语句时应当注意的一些琐碎建议和注意点
1. 当结果集只有一行数据时使用LIMIT 1
2. 避免SELECT *,始终指定你需要的列
从表中读取越多的数据,查询会变得更慢。他增加了磁盘需要操作的时间,还是在数据库服务器与WEB服务器是独立分开的情况下。你将会经历非常漫长的网络延迟,仅仅是因为数据不必要的在服务器之间传输。
3. 使用连接(JOIN)来代替子查询(Sub-Queries)
连接(JOIN).. 之所以更有效率一些,是因为MySQL不需要在内存中创建临时表来完成这个逻辑上的需要两个步骤的查询工作。
4. 使用ENUM、CHAR 而不是VARCHAR,使用合理的字段属性长度
5. 尽可能的使用NOT NULL
6. 固定长度的表会更快
7. 拆分大的DELETE 或INSERT 语句
8. 查询的列越小越快
## 查询优化
在查询中,WHERE条件也是一个比较重要的因素,尽量少并且是合理的where条件是很重要的,尽量在多个条件的时候,把会提取尽量少数据量的条件放在前面,减少后一个where条件的查询时间。
### where条件导致索引无效的情况
* where子句的查询条件里有!=,MySQL将无法使用索引。
* where子句使用了mysql函数的时候,索引将无效。比如:select * from tb where left(name, 4) = ‘xxx’
* 使用LIKE进行搜索匹配的时候,这样索引是有效的:select * from tbl1 where name like 'xxx%',而like '%xxx%' 时索引无效。