Mysql学习--索引(一)
2015-11-04 19:05
369 查看
推荐一篇博文,关于索引和引擎的:http://www.cnblogs.com/hustcat/archive/2009/10/28/1591648.html
对于mysql优化相关的信息,是对着韩顺平老师的mysql优化的视频来看的。现在把自己所了解的相关知识整理一下。
a. 越小的数据类型通常更好:越小的数据类型通常在磁盘、内存和CPU缓存中都需要更少的空间,处理起来更快。
b. 简单的数据类型更好:整型数据比起字符,处理开销更小,因为字符串的比较更复杂。在MySQL中,应该用内置的日期和时间数据类型,而不是用字符串来存储时间;以及用整型数据类型存储IP地址。
c. 尽量避免NULL:应该指定列为NOT NULL,除非你想存储NULL。在MySQL中,含有空值的列很难进行查询优化,因为它们使得索引、索引的统计信息以及比较运算更加复杂。你应该用0、一个特殊的值或者一个空串代替空值。
另外选择合适的标识符是非常重要的。选择时不仅应该考虑存储类型,而且应该考虑MySQL是怎样进行运算和比较的。一旦选定数据类型,应该保证所有相关的表都使用相同的数据类型。
a. 整型:通常是作为标识符的最好选择,因为可以更快的处理,而且可以设置为AUTO_INCREMENT。
b. 字符串:尽量避免使用字符串作为标识符,它们消耗更好的空间,处理起来也较慢。而且,通常来说,字符串都是随机的,所以它们在索引中的位置也是随机的,这会导致页面分裂、随机访问磁盘,聚簇索引分裂(对于使用聚簇索引的存储引擎)。
自动:当表上定义主键约束、唯一、外键约束时,该表会被系统自动添加上索引。
手动:手动在相关表或列上增加索引,提高查询速度。
Mysql中4中索引类型:
① 创建表的时候同时创建主键索引
#创建表的时候同时创建索引:向atable中添加主键索引 id列(自动创建)
② 修改表结构方式添加主键索引
格式:ALTER TABLE 表名 ADD PRIMARY KEY(列名);
② 直接创建普通索引
格式:CREATE INDEX 索引名 ON 表名(列名);
③ 修改表结构方式添加普通索引
格式:ALTER TABLE 表名 ADD INDEX 索引名(列名);
① 创建表的时候同时指定全文索引
② 直接创建全文索引
格式: CREATE FULLTEXT INDEX 索引名 ON 表名(列名);
③ 修改表结构方式添加全文索引
格式:ALTER TABLE 表名 ADD FULLTEXT INDEX 索引名(列名);
④ 使用全文索引查询
全文索引中有一个停止词的概念:在全文索引中,一些常用词和字符,就不会创建索引,这些词成为停止词。
查询文章中包含forever关键字的记录:
① 创建表的时候直接指定唯一索引
或
② 直接创建唯一索引
格式: CREATE UNIQUE INDEX 索引名 ON 表名(列名);
③ 修改表结构方式添加唯一索引
格式:ALTER TABLE 表名 ADD UNIQUE INDEX 索引名(列名);
建立这样的组合索引,其实是相当于分别建立了下面两组组合索引:
–title,body
–title
为什么没有body这样的组合索引呢?这是因为MySQL组合索引“最左前缀”的结果。简单的理解就是只从最左面的开始组合。并不是只要包含这两列的查询都会用到该组合索引,如下面的几个SQL所示:
使用到上面的索引:
不使用上面的索引:
如何得知是否使用了索引?可以使用explain关键字分析的SQL语句的执行情况,explain 可以帮助我们在不真正执行某个sql语句时,就知道mysql怎样执行,这样有利于我们去分析sql指令:
会产生如下信息:
select_type:表示查询的类型。
table:输出结果集的表
type:表示表的连接类型
possible_keys:表示查询时,可能使用的索引
key:表示实际使用的索引
key_len:索引字段的长度
rows:扫描出的行数(估算的行数)
Extra:执行情况的描述和说明(例如排序等信息)
ALTER TABLE 表名 DROP INDEX 索引名;
a. 在哪些列上适合添加索引?
① 较频繁的作为查询条件字段应该创建索引
② 唯一性太差的字段不适合单独创建索引,即使频繁作为查询条件
③ 更新非常频繁的字段不适合创建索引
b. 不会出现在WHERE子句中字段不该创建索引
总结: 满足以下条件的字段,才应该创建索引:
肯定在where条件中经常使用
该字段的内容不是唯一的几个值
字段内容不是频繁变化
2. 索引使用的注意事项
查询要使用索引最重要的条件是查询条件中需要使用索引。
下列几种情况下有可能使用到索引:
a. 对于创建的组合索引,只要查询条件使用了最左边的列(最左前缀),索引一般就会被使用。
b. 对于使用like的查询,查询如果是’%aaa’ 不会使用到索引(%、_不能在开头),’aaa%’会使用到索引。即在like查询时,’关键字’最前面,不能使用 % 或者 _这样的字符模糊匹配,如果一定要前面有模糊匹配的值,则考虑使用全文索引。
下列的表将不使用索引:
a. 如果条件中有or,即使其中有条件带索引也不会使用(必须条件中使用到的所有字段都建有索引,建议尽量避免使用or关键字)。
b. 对于组合索引,不是使用的第一部分,则不会使用索引。
c. like查询是以%或_开头
d. 如果列类型是字符串,那一定要在条件中将数据使用引号引用起来。否则不使用索引。(添加时,字符串必须’ ’)
e. 如果mysql估计使用全表扫描要比使用索引快,则不使用索引。
f. 使用group by 分组查询,默认分组后还会排序,可能会降低速度。如果查询中包括group by但用户想要避免排序结果的消耗,则可以使用order by null禁止
b980
排序。
g. 有些情况下,可以使用连接来替代子查询。因为使用join,MySQL不需要在内存中创建临时表。
使用join代替:
3. 查看索引的使用情况
大家可以发现:
handler_read_key:这个值越高越好,越高表示使用索引查询到的次数。
handler_read_rnd_next:这个值越高,说明查询低效。
过多的使用索引将会造成滥用。索引的代价:
a. 占用磁盘空间
b. 对增删改操作有影响,变慢
1. 何时使用聚集索引或非聚集索引?
2. 索引不会包含有NULL值的列
只要列中包含有NULL值都将不会被包含在索引中,复合索引中只要有一列含有NULL值,那么这一列对于此复合索引就是无效的。所以我们在数据库设计时不要让字段的默认值为NULL。
3. 使用短索引
对串列进行索引,如果可能应该指定一个前缀长度。例如,如果有一个CHAR(255)的列,如果在前10个或20个字符内,多数值是惟一的,那么就不要对整个列进行索引。短索引不仅可以提高查询速度而且可以节省磁盘空间和I/O操作。
4. 索引列排序
MySQL查询只使用一个索引,因此如果where子句中已经使用了索引的话,那么order by中的列是不会使用索引的。因此数据库默认排序可以符合要求的情况下不要使用排序操作;尽量不要包含多个列的排序,如果需要最好给这些列创建复合索引。
5. like语句操作
一般情况下不鼓励使用like操作,如果非使用不可,如何使用也是一个问题。like “%aaa%” 不会使用索引而like “aaa%”可以使用索引。
6. 不要在列上进行运算
例如:select * from users where YEAR(adddate)<2007,将在每个行上进行运算,这将导致索引失效而进行全表扫描,因此我们可以改成:
select * from users where adddate<’2007-01-01’。
对于mysql优化相关的信息,是对着韩顺平老师的mysql优化的视频来看的。现在把自己所了解的相关知识整理一下。
索引
一、索引的概念
索引是一种数据结构,是数据库中的对象,它用来快速地访问数据库中表或视图中的数据。索引对查询的速度有着至关重要的影响,理解索引也是进行数据库性能调优的起点。考虑如下情况,假设数据库中一个表有10^6条记录,DBMS的页面大小为4K,并存储100条记录。如果没有索引,查询将对整个表进行扫描,最坏的情况下,如果所有数据页都不在内存,需要读取10^4个页面,如果这10^4个页面在磁盘上随机分布,需要进行10^4次I/O,假设磁盘每次I/O时间为10ms(忽略数据传输时间),则总共需要100s(但实际上要好很多很多)。如果对之建立B-Tree索引,则只需要进行log100(10^6)=3次页面读取,最坏情况下耗时30ms。这就是索引带来的效果,很多时候,当你的应用程序进行SQL查询速度很慢时,应该想想是否可以建索引。二、索引的分类
索引分为聚簇索引和非聚簇索引两种,聚簇索引是按照数据存放的物理位置为顺序的,即该索引中键值的逻辑顺序与表中相应行的物理顺序一致,一个表中只能包含一个聚集索引,而非聚簇索引就不一样了,该索引中的逻辑顺序与磁盘上行的物理存储顺序不同;聚簇索引能提高多行检索的速度,而非聚簇索引对于单行的检索很快。三、选择索引的数据类型
MySQL支持很多数据类型,选择合适的数据类型存储数据对性能有很大的影响。通常来说,可以遵循以下一些指导原则:a. 越小的数据类型通常更好:越小的数据类型通常在磁盘、内存和CPU缓存中都需要更少的空间,处理起来更快。
b. 简单的数据类型更好:整型数据比起字符,处理开销更小,因为字符串的比较更复杂。在MySQL中,应该用内置的日期和时间数据类型,而不是用字符串来存储时间;以及用整型数据类型存储IP地址。
c. 尽量避免NULL:应该指定列为NOT NULL,除非你想存储NULL。在MySQL中,含有空值的列很难进行查询优化,因为它们使得索引、索引的统计信息以及比较运算更加复杂。你应该用0、一个特殊的值或者一个空串代替空值。
另外选择合适的标识符是非常重要的。选择时不仅应该考虑存储类型,而且应该考虑MySQL是怎样进行运算和比较的。一旦选定数据类型,应该保证所有相关的表都使用相同的数据类型。
a. 整型:通常是作为标识符的最好选择,因为可以更快的处理,而且可以设置为AUTO_INCREMENT。
b. 字符串:尽量避免使用字符串作为标识符,它们消耗更好的空间,处理起来也较慢。而且,通常来说,字符串都是随机的,所以它们在索引中的位置也是随机的,这会导致页面分裂、随机访问磁盘,聚簇索引分裂(对于使用聚簇索引的存储引擎)。
四、索引的创建和添加
创建索引方式:自动:当表上定义主键约束、唯一、外键约束时,该表会被系统自动添加上索引。
手动:手动在相关表或列上增加索引,提高查询速度。
Mysql中4中索引类型:
1.主键索引
建表时,将一个类设为主键,则该列就是主键索引(自动)。① 创建表的时候同时创建主键索引
#创建表的时候同时创建索引:向atable中添加主键索引 id列(自动创建)
CREATE TABLE atable( id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT , name VARCHAR(32) NOT NULL DEFAULT '');
② 修改表结构方式添加主键索引
格式:ALTER TABLE 表名 ADD PRIMARY KEY(列名);
CREATE TABLE atable( id INT UNSIGNED , name VARCHAR(32) NOT NULL DEFAULT '' ); ALTER TABLE atable ADD PRIMARY KEY(id);
2.普通索引
① 创建表的时候同时指定普通索引CREATE TABLE btable( id INT NOT NULL AUTO_INCREMENT , title VARCHAR(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NU 4000 LL , content TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NULL , time DATETIME NOT NULL, PRIMARY KEY (id), INDEX index_name(title) );
② 直接创建普通索引
格式:CREATE INDEX 索引名 ON 表名(列名);
DROP TABLE btable; CREATE TABLE btable( id INT NOT NULL AUTO_INCREMENT , title VARCHAR(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL , content TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NULL , time DATETIME NOT NULL, PRIMARY KEY (id) ); CREATE INDEX index_name ON btable(title);
③ 修改表结构方式添加普通索引
格式:ALTER TABLE 表名 ADD INDEX 索引名(列名);
ALTER TABLE btable ADD INDEX myindex (title);
3.全文索引
全文索引主要是针对文本、文字的检索,文章居多,全文索引只对MySIAM引擎有用。① 创建表的时候同时指定全文索引
CREATE TABLE articles ( id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, title VARCHAR(200), body TEXT, FULLTEXT myindex (title,body) )engine=MyISAM CHARSET=utf8;
② 直接创建全文索引
格式: CREATE FULLTEXT INDEX 索引名 ON 表名(列名);
CREATE TABLE articles ( id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, title VARCHAR(200), body TEXT )engine=MyISAM CHARSET=utf8; CREATE FULLTEXT INDEX myindex ON articles (title,body);
③ 修改表结构方式添加全文索引
格式:ALTER TABLE 表名 ADD FULLTEXT INDEX 索引名(列名);
ALTER TABLE articles ADD FULLTEXT INDEX myindex(title,body);
④ 使用全文索引查询
全文索引中有一个停止词的概念:在全文索引中,一些常用词和字符,就不会创建索引,这些词成为停止词。
查询文章中包含forever关键字的记录:
SELECT * FROM articles WHERE MATCH(title,body) AGAINST(‘forever’);
4.唯一索引
当表中某列被指定unique约束时,这列就是一个唯一索引列。① 创建表的时候直接指定唯一索引
CREATE TABLE ctable( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(32) UNIQUE );
或
CREATE TABLE ctable( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(32), UNIQUE myindex(name) );
② 直接创建唯一索引
格式: CREATE UNIQUE INDEX 索引名 ON 表名(列名);
CREATE TABLE ctable( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(32) ); CREATE UNIQUE INDEX myindex ON ctable(name);
③ 修改表结构方式添加唯一索引
格式:ALTER TABLE 表名 ADD UNIQUE INDEX 索引名(列名);
ALTER TABLE ctable ADD UNIQUE INDEX myindex(name);
5.单列索引、多列索引
多个单列索引与单个多列索引的查询效果不同,因为执行查询时,MySQL只能使用一个索引,会从多个索引中选择一个限制最为严格的索引。6.组合索引(最左前缀)
平时用的SQL查询语句一般都有比较多的限制条件,所以为了进一步榨取MySQL的效率,就要考虑建立组合索引。例如articles表中针对title和body建立一个组合索引:CREATE FULLTEXT INDEX myindex ON articles (title,body);
建立这样的组合索引,其实是相当于分别建立了下面两组组合索引:
–title,body
–title
为什么没有body这样的组合索引呢?这是因为MySQL组合索引“最左前缀”的结果。简单的理解就是只从最左面的开始组合。并不是只要包含这两列的查询都会用到该组合索引,如下面的几个SQL所示:
使用到上面的索引:
SELECT * FROM articles WHREE title='database' AND body=’something’; SELECT * FROM articles WHREE title='database' ;
不使用上面的索引:
SELECT * FROM articles WHREE body=’something’;
如何得知是否使用了索引?可以使用explain关键字分析的SQL语句的执行情况,explain 可以帮助我们在不真正执行某个sql语句时,就知道mysql怎样执行,这样有利于我们去分析sql指令:
会产生如下信息:
select_type:表示查询的类型。
table:输出结果集的表
type:表示表的连接类型
possible_keys:表示查询时,可能使用的索引
key:表示实际使用的索引
key_len:索引字段的长度
rows:扫描出的行数(估算的行数)
Extra:执行情况的描述和说明(例如排序等信息)
五、索引的查看和删除
1. 查看
SHOW INDEX FROM 表名;SHOW INDEX FROM articles;
2. 删除
DROP INDEX 索引名 ON 表名;DROP INDEX myindex ON articles;
ALTER TABLE 表名 DROP INDEX 索引名;
ALTER TABLE articles DROP INDEX myindex;
六、索引的使用和优化
1. 索引的使用场景a. 在哪些列上适合添加索引?
① 较频繁的作为查询条件字段应该创建索引
select * from user where id= 1;
② 唯一性太差的字段不适合单独创建索引,即使频繁作为查询条件
<pre name="code" class="sql">select * from user where sex = ‘女’;
③ 更新非常频繁的字段不适合创建索引
select * from user where logincount = 1;
b. 不会出现在WHERE子句中字段不该创建索引
总结: 满足以下条件的字段,才应该创建索引:
肯定在where条件中经常使用
该字段的内容不是唯一的几个值
字段内容不是频繁变化
2. 索引使用的注意事项
查询要使用索引最重要的条件是查询条件中需要使用索引。
下列几种情况下有可能使用到索引:
a. 对于创建的组合索引,只要查询条件使用了最左边的列(最左前缀),索引一般就会被使用。
b. 对于使用like的查询,查询如果是’%aaa’ 不会使用到索引(%、_不能在开头),’aaa%’会使用到索引。即在like查询时,’关键字’最前面,不能使用 % 或者 _这样的字符模糊匹配,如果一定要前面有模糊匹配的值,则考虑使用全文索引。
下列的表将不使用索引:
a. 如果条件中有or,即使其中有条件带索引也不会使用(必须条件中使用到的所有字段都建有索引,建议尽量避免使用or关键字)。
b. 对于组合索引,不是使用的第一部分,则不会使用索引。
c. like查询是以%或_开头
d. 如果列类型是字符串,那一定要在条件中将数据使用引号引用起来。否则不使用索引。(添加时,字符串必须’ ’)
EXPLAIN SELECT * FROM user WHERE NAME=’nihao’;
e. 如果mysql估计使用全表扫描要比使用索引快,则不使用索引。
f. 使用group by 分组查询,默认分组后还会排序,可能会降低速度。如果查询中包括group by但用户想要避免排序结果的消耗,则可以使用order by null禁止
b980
排序。
g. 有些情况下,可以使用连接来替代子查询。因为使用join,MySQL不需要在内存中创建临时表。
SELECT * FROM dept, emp WHERE dept.deptno=emp.deptno;
使用join代替:
SELECT * FROM dept LEFT JOIN emp ON dept.deptno=emp.deptno;
3. 查看索引的使用情况
show status like ‘Handler_read%’;
大家可以发现:
handler_read_key:这个值越高越好,越高表示使用索引查询到的次数。
handler_read_rnd_next:这个值越高,说明查询低效。
七、索引的优化
前面也提到了一些,现在补充总结一下。过多的使用索引将会造成滥用。索引的代价:
a. 占用磁盘空间
b. 对增删改操作有影响,变慢
1. 何时使用聚集索引或非聚集索引?
动作描述 | 使用聚集索引 | 使用非聚集索引 |
列经常被分组排序 | 使用 | 使用 |
返回某范围内的数据 | 使用 | 不使用 |
一个或极少不同值 | 不使用 | 不使用 |
小数目的不同值 | 使用 | 不使用 |
大数目的不同值 | 不使用 | 使用 |
频繁更新的列 | 不使用 | 使用 |
外键列 | 使用 | 使用 |
主键列 | 使用 | 使用 |
频繁修改索引列 | 不使用 | 使用 |
只要列中包含有NULL值都将不会被包含在索引中,复合索引中只要有一列含有NULL值,那么这一列对于此复合索引就是无效的。所以我们在数据库设计时不要让字段的默认值为NULL。
3. 使用短索引
对串列进行索引,如果可能应该指定一个前缀长度。例如,如果有一个CHAR(255)的列,如果在前10个或20个字符内,多数值是惟一的,那么就不要对整个列进行索引。短索引不仅可以提高查询速度而且可以节省磁盘空间和I/O操作。
4. 索引列排序
MySQL查询只使用一个索引,因此如果where子句中已经使用了索引的话,那么order by中的列是不会使用索引的。因此数据库默认排序可以符合要求的情况下不要使用排序操作;尽量不要包含多个列的排序,如果需要最好给这些列创建复合索引。
5. like语句操作
一般情况下不鼓励使用like操作,如果非使用不可,如何使用也是一个问题。like “%aaa%” 不会使用索引而like “aaa%”可以使用索引。
6. 不要在列上进行运算
例如:select * from users where YEAR(adddate)<2007,将在每个行上进行运算,这将导致索引失效而进行全表扫描,因此我们可以改成:
select * from users where adddate<’2007-01-01’。
相关文章推荐
- MySQL中的integer 数据类型
- MySQL存储过程
- Android之获取手机上的图片和视频缩略图thumbnails
- mysql中int、bigint、smallint 和 tinyint的区别与长度
- mysql load data 导出、导入 csv
- source命令执行SQL脚本文件
- MySQL创建用户及权限控制
- MySQL管理数据表
- linux下mysql添加用户
- mysql procedure
- mysql触发器
- 数据库链接字符串查询网站
- MySQL 备份和恢复策略
- mac下安装mysql(转载)
- mysql 修改编码 Linux/Mac/Unix/通用(杜绝修改后无法启动的情况!)
- MySQL数据的导出、导入(mysql内部命令:mysqldump、mysql)
- mysql数据行转列
- Linux下修改MySQL编码的方法