MySQL Study之--MySQL innodb存储与索引的总结

MySQL Study之--MySQL innodb存储与索引的总结

 转自:http://www.blogjava.net/happyenjoylife/archive/2011/12/17/366639.html

Innodb存储

表空间是逻辑存放所有数据的地方,默认情况下会共享一个表空间——ibdata1,但如果把innodb_file_per_table=ON后每张表可以单独放到一个表空间内,但还是有很多数据保存在共享的表ibdata1中,如undo信息等。

 

表空间由各种段(segment)组成,常见的段有数据段、索引段等。Innodb是索引组织的,数据段就是clustered index的叶结点。需要注意的是,不是每个对象都有段。

 

(extend)是由64个连续的页组成,每个页(page)固定为16KB,所以每个区总共为1M。页是innodb最小的磁盘管理单位。

 

Innodb是按行进行存放的,每个区最少可以保存2条记录,否则就成链式结构了。每行数据除了自定义列以外,还会增加事务id和回滚指针列。如果没有定义primary key也没有not nullunique,则会增加6字节的RowId列作为主键。
        MySQL Study之--MySQL innodb存储与索引的总结_第1张图片
            图片来自:http://www.cnblogs.com/chjw8016/archive/2011/03/08/1976891.html

Innodb表的限制

        一个表不能包含超过1000列。

  内部最大键长度是3500字节,但MySQL自己限制这个到1024字节。

  除了VARCHAR, BLOBTEXT列,最大行长度稍微小于数据库页的一半。即,最大行长度大约8000字节。LONGBLOBLONGTEXT列必须小于4GB, 总的行长度,页包括BLOBTEXT列,必须小于4GBInnoDB在行中存储VARCHARBLOBTEXT列的前768字节,余下的存储的分散的页中。

虽然InnoDB内部地支持行尺寸大于65535,你不能定义一个包含VARCHAR列的,合并尺寸大于65535的行。

·                mysql> CREATE TABLE t (a VARCHAR(8000), b VARCHAR(10000),

·                    -> c VARCHAR(10000), d VARCHAR(10000), e VARCHAR(10000),

·                    -> f VARCHAR(10000), g VARCHAR(10000));

·                ERROR 1118 (42000): Row size too large. The maximum row size for the

·                used table type, not counting BLOBs, is 65535. You have to change some

·                columns to TEXT or BLOBs

 在一些更老的操作系统上,数据文件必须小于2GB

 InnoDB日志文件的合并尺寸必须小于4GB

最小的表空间尺寸是10MB。最大的表空间尺寸是4,000,000,000个数据库页(64TB)。这也是一个表的最大尺寸。

 InnoDB表不支持FULLTEXT索引

 

Innodb索引

默认情况下Memory使用存储hash索引,但也支持b+tree索引。Hash索引只用于=或者<=>的等式比较,不能用来加速order by操作,只能通过关键字来搜索一行。innodb只支持b+树索引,进一步分为clustered index与 secondary index。在一次查询中,只能使用一个索引。

        

Innodb是索引组织表,clustered index的叶结点保存着整行的数据。如果,定义了primary key,则clustered index就是primary key的索引;如果没有定义primary key mysql会选中第一个仅有not null列的unique索引作为主键,并把此索引当作clustered index使用;如果没找到这样的列,innodb会创建一个6字节的RowId作为主键。所以每张表有且只有一个clustered index

 

         Secondary index的叶结点不包括行的全部数据,包含键值以外还包括一个bookmark,可以告诉innodb到什么地方可以找到相对应的完整行数据,还保存了主键的健值。Secondary index包含主键,但不包含完整的行数据,所以innodb总是会先从secondary index的叶节点判断是否能得到所需的数据。如,

         Create table t(a int, b varchar(20), primary key(a), key(b));

Explain select * from t;

         会发现mysql选择了索引b,而不是a.

复合索引

         复合索引是在多列(>=2)上建立的索引,又叫多列索引或联合索引。Innodb中的复合索引也是b+ tree结构。索引的数据包含多列(col1, col2, col3…),在索引中依次按照col1, col2, col3排序。如(1, 2), (1, 3),(2,0)…

 

         使用复合索引要充分利用最左前缀原则,顾名思义,就是最左优先。如创建索引ind_col1_col2(col1, col2),那么在查询where col1 = xxx and col2 = xx或者where col1 = xxx都可以走ind_col1_col2索引。

在创建多列索引时,要根据业务需求,where子句中使用最频繁且过滤效果好的的一列放在最左边。

索引操作

         可以通过DML语句操作innodb索引。因为innodb是索引组织的表,对索引的操作会造成锁表,先生成一张临时表,将数据从原始表中写到临时表,再将原始表删除,最后将临时表表名改为原始表表名!因增加、删除、修改字段会对主索引产生影响,所以也会锁表。对secondary indexInnodb plugin开始,支持快速索引创建的方法,在创建的过程中不需要重建表,所以速度会很快,同时引擎会在表上加S锁,在创建过程中只能进行读操作。

索引设计原则

1.       搜索的索引列,不一定是所要选择的列。也就是说,最适合索引的列是出现在where子句中的列,或者连接子句中指定的列,而不是出现在select关键字后的选择列表中的列。

2.       使用唯一索引。考虑某列的分布,索引的列的基数越大,索引的效果越好。例如,对性别M/F列做索引没多大用处。

3.       使用短索引。如果是对字符串进行索引,如果有可能应该指定前缀长度。

4.       利用最左前缀。尽量将使用频繁且过滤效果好的字段放“左边”

5.       不要过度索引。

6.       Innodb默认会按照一定的顺序保存数据,如果明确定义了主键,则按照主键顺序保存。如果没有主键,但有唯一索引,就按照唯一索引的顺序保存。如果有几个列都是唯一的,都可以作为主键的时候,为了提高查询效率,应选择最常用访问的列作为主键。另外,innodbsecondary index都会保存主键的键值,所有主键要尽可能选择较短的数据类型。可以看出,应当尽量避免对主键的修改。经过dba的测试,保证主键的递增可以提高插入性能。

 

Mysql如何使用索引

1.       对于创建的多列索引,只要查询的条件中用到了最左边的列,索引一般就会被使用。

2.       对于使用like的查询,后面如果是常量并且只有%号不在第一个字符,索引才可能被使用。

3.       如果对大文本进行搜索,应该使用全文索引,而不是使用like ‘%...%’. 但不幸的是innodb不支持全文索引。

4.       如果列名是索引,使用 index_column is null将使用索引。Oracle是不行的。

5.       如果mysql估计使用索引比全表扫描更慢,最不会使用索引。

6.       如果使用memory/head表并且where条件中不使用”=”进行索引列,那么不会用到索引。Head表只有在”=”的时候才会使用索引。

7.       or分割开的条件,如果or前的条件中的列有索引,而后面列中没有索引,那么涉及到的索引都不会被用到。

8.       不是多列索引的第一部分不会走索引。

9.       %开始的like不会走索引

10.   如果列是字符串,那么一定要在where条件中把字符串常量值用引号引起来,否则不能走索引。因为,mysql默认把输入的常量值进行转换以后才进行检索。

11.   经过普通运算或函数运算后的索引字段不能使用索引

12.   不等于操作不能使用索,<>not in

13.   Order by 优化:某些情况下,mysql可以使用一个索引满足order by,而不需要额外的排序。Where条件与order by 使用相同的索引,并且order by的顺序和索引顺序相同,并且order by的字段都是升序或者都是降序。

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     

 

可以使用explain查看sql的执行计划。

你可能感兴趣的:(mysql)