MySQL索引的创建对于MySQL的高效运行是很重要的,索引能够大大提升MySQL的检索速度。mysql
1.实际上,索引也是一张表,该表保存了主键与索引字段,并指向实体表的记录。sql
2.索引分单列索引和组合索引。单列索引,即一个索引只包含单个列,一个表能够有多个单列索引,但这不 是组合索引。组合索引,即一个索引包含多个列。函数
3.普通索引性能
建立索引:最基本的索引,它没有任何限制。它有如下几种建立方式:大数据
3.一、优化
CREATE INDEX indexName ON mytable(username(length));
若是是CHAR,VARCHAR类型,length能够小于字段实际长度;若是是BLOB和TEXT类型,必须指定 length。spa
3.二、修改表结构添加索引.net
ALTER table tableName ADD INDEX indexName(columnName)
3.三、建立表的时候直接指定unix
CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, INDEX [indexName](username(length)));
4.惟一索引code
它与前面的普通索引相似,不一样的就是:索引列的值必须惟一,但容许有空值。若是是组合索引,则列值的组合必须惟一。UNIQUE 修饰索引便可;建立略;
一、最左前缀匹配原则,联合索引,mysql会从作向右匹配直到遇到范围查询(>、<、between、like)就中止匹配,好比a = 1 and b = 2 and c > 3 and d = 4 若是创建(a,b,c,d)顺序的索引,d是用不到索引的,若是创建(a,b,d,c)的索引则均可以用到,a,b,d的顺序能够任意调整。
二、=和in能够乱序,好比a = 1 and b = 2 and c = 3 创建(a,b,c)索引能够任意顺序,mysql的查询优化器会帮你优化成索引能够识别的形式。
三、索引列不能参与计算,保持列“干净”,好比from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,缘由很简单,b+树中存的都是数据表中的字段值,但进行检索时,须要把全部元素都应用函数才能比较,显然成本太大。因此语句应该写成create_time = unix_timestamp(’2014-05-29’)。
四、尽可能的扩展索引,不要新建索引。好比表中已经有a的索引,如今要加(a,b)的索引,那么只须要修改原来的索引便可,创建没必要要索引会增长MySQL空间。
五、尽可能选择区分度高的列做为索引 区分度的公式是count(distinct col)/count(*),表示字段不重复的比例,比例越大咱们扫描的记录数越少,惟一键的区分度是1,而一些状态、性别字段可能在大数据面前区分度就是0,那可能有人会问,这个比例有什么经验值吗?使用场景不一样,这个值也很难肯定,通常须要join的字段咱们都要求是0.1以上,即平均1条扫描10条记录。
六、若是肯定有多少条数据,使用 limit 限制一下,MySQL在查找到对应条数的数据的时候,会中止继续查找。
七、join 语法,尽可能将小的表放在前面,在须要on的字段上,数据类型保持一致,并设置对应的索引,不然MySQL没法使用索引来join查询
使用explain关键字能够模拟优化器执行SQL查询语句,从而知道MySQL是如何处理你的SQL语句的,分析你的查询语句或是表结构的性能瓶颈。
Explain包含信息
其中最重要的字段为:id、type、key、rows、Extra
Id表示查询中执行select字句或者操做表顺序
Id相同:执行顺序由上至下
id不一样:若是是子查询,id的序号会递增,id值越大优先级越高,越先被执行
查询的类型,主要是用于区分普通查询、联合查询、子查询等复杂的查询
一、SIMPLE:简单的select查询,查询中不包含子查询或者union
二、PRIMARY:查询中包含任何复杂的子部分,最外层查询则被标记为primary
三、SUBQUERY:在select 或 where列表中包含了子查询
四、DERIVED:在from列表中包含的子查询被标记为derived(衍生),mysql或递归执行这些子查询,把结果放在零时表里
五、UNION:若第二个select出如今union以后,则被标记为union;若union包含在from子句的子查询中,外层select将被标记为derived
六、UNION RESULT:从union表获取结果的select
访问类型,sql查询优化中一个很重要的指标,结果值从好到坏依次是:
system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL;
通常来讲,好的sql查询至少达到range级别,最好能达到ref
一、system:表只有一行记录(等于系统表),这是const类型的特例,平时不会出现,能够忽略不计
二、const:表示经过索引一次就找到了,const用于比较primary key 或者 unique索引。由于只需匹配一行数据,全部很快。若是将主键置于where列表中,mysql就能将该查询转换为一个const
三、eq_ref:惟一性索引扫描,对于每一个索引键,表中只有一条记录与之匹配。常见于主键 或 惟一索引扫描
四、ref:非惟一性索引扫描,返回匹配某个单独值的全部行。本质是也是一种索引访问,它返回全部匹配某个单独值的行,然而他可能会找到多个符合条件的行,因此它应该属于查找和扫描的混合体
五、range:只检索给定范围的行,使用一个索引来选择行。key列显示使用了那个索引。通常就是在where语句中出现了bettween、<、>、in等的查询。这种索引列上的范围扫描比全索引扫描要好。只须要开始于某个点,结束于另外一个点,不用扫描所有索引
六、index:Full Index Scan,index与ALL区别为index类型只遍历索引树。这一般为ALL块,应为索引文件一般比数据文件小。(Index与ALL虽然都是读全表,但index是从索引中读取,而ALL是从硬盘读取)
七、ALL:Full Table Scan,遍历全表以找到匹配的行
查询涉及到的字段上存在索引,则该索引将被列出,但不必定被查询实际使用;
key
实际使用的索引,若是为NULL,则没有使用索引。
查询中若是使用了覆盖索引,则该索引仅出如今key列表中
ref
显示索引的那一列被使用了,若是可能,是一个常量const。
1.对查询进行优化,应尽可能避免全表扫描,首先应考虑在 where 及 order by 涉及的列上创建索引。
2.应尽可能避免在 where 子句中对字段进行 null 值判断,不然将致使引擎放弃使用索引而进行全表扫描,如:
select id from t where num is null
能够在num上设置默认值0,确保表中num列没有null值,而后这样查询:
select id from t where num=0
3.应尽可能避免在 where 子句中使用!=或<>操做符,不然引擎将放弃使用索引而进行全表扫描
4.应尽可能避免在 where 子句中使用or 来链接条件,不然将致使引擎放弃使用索引而进行全表扫描,如:
select id from t where num=10 or num=20
能够这样查询:
select id from t where num=10 union all select id from t where num=20
5.in 和 not in 也要慎用,不然会致使全表扫描,如:
select id from t where num in(1,2,3)
对于连续的数值,能用 between 就不要用 in 了:
select id from t where num between 1 and 3
6.下面的查询也将致使全表扫描:select id from t where name like ‘%李%’若要提升效率,能够考虑全文检索
7. 若是在 where 子句中使用参数,也会致使全表扫描。由于SQL只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。然 而,若是在编译时创建访问计划,变量的值仍是未知的,于是没法做为索引选择的输入项。以下面语句将进行全表扫描:select id from t where num=@num能够改成强制查询使用索引:select id from t with(index(索引名)) where num=@num
8.应尽可能避免在 where 子句中对字段进行表达式操做,这将致使引擎放弃使用索引而进行全表扫描。如:select id from t where num/2=100应改成:select id from t where num=100*2
9.应尽可能避免在where子句中对字段进行函数操做,这将致使引擎放弃使用索引而进行全表扫描。如:
select id from t where substring(name,1,3)=’abc’
,name以abc开头的id应改成:
select id from t where name like ‘abc%’
10.不要在 where 子句中的“=”左边进行函数、算术运算或其余表达式运算,不然系统将可能没法正确使用索引。
11.在使用索引字段做为条件时,若是该索引是复合索引,那么必须使用到该索引中的第一个字段做为条件时才能保证系统使用该索引,不然该索引将不会被使用,而且应尽量的让字段顺序与索引顺序相一致。
12.不要写一些没有意义的查询,如须要生成一个空表结构:select col1,col2 into #t from t where 1=0
这类代码不会返回任何结果集,可是会消耗系统资源的,应改为这样:
create table #t(…)
13.不少时候用 exists 代替 in 是一个好的选择:
select num from a where num in(select num from b)
用下面的语句替换:
select num from a where exists(select 1 from b where num=a.num)
14.并非全部索引对查询都有效,SQL是根据表中数据来进行查询优化的,当索引列有大量数据重复时,SQL查询可能不会去利用索引,如一表中有字段sex,male、female几乎各一半,那么即便在sex上建了索引也对查询效率起不了做用。
20.尽可能使用表变量来代替临时表。若是表变量包含大量数据,请注意索引很是有限(只有主键索引)。
21.避免频繁建立和删除临时表,以减小系统表资源的消耗。
22.在新建临时表时,若是一次性插入数据量很大,那么可使用 select into 代替 create table,避免形成大量 log ,以提升速度;若是数据量不大,为了缓和系统表的资源,应先create table,而后insert。
23.若是使用到了临时表,在存储过程的最后务必将全部的临时表显式删除,先 truncate table ,而后 drop table ,这样能够避免系统表的较长时间锁定。