MySql数据库中建立索引

数据库 专栏收录该内容
4 篇文章 0 订阅

创建索引:
CREATE INDEX 索引名称ON 表名(元素...);
如: create index idx_apply_id_arent_app_id on change_apply_info(apply_id ,parent_apply_id)
alter table表名 add index索引名称(元素...);
如: alter table change_apply_info add index idx_apply_id_parent_apply_id_a1111pply_date(apply_id ,parent_apply_id);

查询表已经创建的相关索引:
show index from 表名
删除索引:
drop index 索引名称 on 表名
alter table 表名drop index 索引名称 如: alter table change_apply_info drop index IDX_PIN

查看相关表结构:
desc 表名 如:desc change_apply_info
explain 表名 如:explain change_apply_info

 最普通的情况,是为出现在where子句的字段建一个索引。为方便讲述,我们先建立一个如下的表。
Code代码如下:
CREATE TABLE mytable (
 id serial primary key,
 category_id int not null default 0,
 user_id int not null default 0,
 adddate int not null default 0
);


  很简单吧,不过对于要说明这个问题,已经足够了。如果你在查询时常用类似以下的语句:

SELECT * FROM mytable WHERE category_id=1; 

  最直接的应对之道,是为category_id建立一个简单的索引:

OK,搞定?先别高兴,如果你有不止一个 选择 条件呢?例如:

SELECT * FROM mytable WHERE category_id=1 AND user_id=2;

  你的第一反应可能是,再给user_id建立一个索引。不好,这不是一个最佳的方法。你可以建立多重的索引。

CREATE INDEX mytable_categoryid_userid ON mytable (category_id,user_id);

  注意到我在命名时的习惯了吗?我使用"表名_字段1名_字段2名"的方式。你很快就会知道我为什么这样做了。

  现在你已经为适当的字段建立了索引,不过,还是有点不放心吧,你可能会问,数据库会真正用到这些索引吗?测试一下就OK,对于大多数的数据库来说,这是很容易的,只要使用EXPLAIN命令(SQL执行计划):

EXPLAIN

 SELECT * FROM mytable 
  WHERE category_id=1 AND user_id=2;

This is what Postgres 7.1 returns (exactly as I expected) 

 NOTICE: QUERY PLAN:

Index Scan using mytable_categoryid_userid on 
  mytable (cost=0.00..2.02 rows=1 width=16)

EXPLAIN

  以上是postgres的数据,可以看到该数据库在查询的时候使用了一个索引(一个好开始),而且它使用的是我创建的第二个索引。看到我上面命名的好处了吧,你马上知道它使用适当的索引了。
如果有个ORDER BY字句呢?大多数的数据库在使用order by的时候,都将会从索引中受益。

SELECT * FROM mytable 
  WHERE category_id=1 AND user_id=2
    ORDER BY adddate DESC;

  有点迷惑了吧?很简单,就象为where字句中的字段建立一个索引一样,也为ORDER BY的字句中的字段建立一个索引:

CREATE INDEX mytable_categoryid_userid_adddate
  ON mytable (category_id,user_id,adddate);

  注意: "mytable_categoryid_userid_adddate" 将会被截短为

"mytable_categoryid_userid_addda"

CREATE

  EXPLAIN SELECT * FROM mytable
  WHERE category_id=1 AND user_id=2
   ORDER BY adddate DESC;

 NOTICE: QUERY PLAN:

 Sort (cost=2.03..2.03 rows=1 width=16)
  -> Index Scan using mytable_categoryid_userid_addda 
    on mytable (cost=0.00..2.02 rows=1 width=16)

EXPLAIN

  看看EXPLAIN的输出,好象有点恐怖啊,数据库多做了一个我们没有要求的排序这下知道性能如何受损了吧,看来我们对于数据库的自身运作是有点过于乐观了,那么,给数据库多一点提示吧。

  为了跳过排序这一步,我们并不需要其它另外的索引,只要将查询语句稍微改一下。这里用的是postgres,我们将给该数据库一个额外的提示--在ORDER BY语句中, 加入 where语句中的字段。这只是一个技术上的处理,并不是必须的,因为实际上在另外两个字段上,并不会有任何的排序操作,不过如果加入,postgres将会知道哪些是它应该做的。

EXPLAIN SELECT * FROM mytable 
  WHERE category_id=1 AND user_id=2
  ORDER BY category_id DESC,user_id DESC,adddate DESC;

NOTICE: QUERY PLAN:

Index Scan Backward using 
 mytable_categoryid_userid_addda on mytable 
   (cost=0.00..2.02 rows=1 width=16)

EXPLAIN

  现在使用我们料想的索引了,而且它还挺 聪明 ,知道可以从索引后面开始读,从而避免了任何的排序。

  以上说得细了一点,不过如果你的数据库非常巨大,并且每日的页面请求达上百万算,我想你会获益良多的。不过,如果你要做更为复杂的查询呢,例如将多张表结合起来查询,特别是where限制字句中的字段是来自不止一个表格时,应该怎样处理呢?我通常都尽量避免这种做法,因为这样数据库要将各个表中的东西都结合起来,然后再排除那些不合适的行,搞不好开销会很大。

   如果不能避免,你应该查看每张要结合起来的表,并且使用以上的策略来建立索引,然后再用EXPLAIN命令验证一下是否使用了你料想中的索引。如果是的话,就OK。不是的话,你可能要建立临时的表来将他们结合在一起,并且使用适当的索引。

  要注意的是,建立太多的索引将会 影响 更新和插入的速度,因为它需要同样更新每个索引文件。对于一个经常需要更新和插入的表格,就没有必要为一个很少使用的where字句单独建立索引了,对于比较小的表,排序的开销不会很大,也没有必要建立另外的索引。

  以上介绍的只是一些十分基本的东西,其实里面的学问也不少,单凭EXPLAIN我们是不能判定该方法是否就是最优化的,每个数据库都有自己的一些优化器,虽然可能还不太完善,但是它们都会在查询时对比过哪种方式较快,在某些情况下,建立索引的话也未必会快,例如索引放在一个不连续的存储空间时,这会 增加 读磁盘的负担,因此,哪个是最优,应该通过实际的使用环境来检验。

  在刚开始的时候,如果表不大,没有必要作索引,我的意见是在需要的时候才作索引,也可用一些命令来优化表,例如MySQL可用"OPTIMIZE TABLE"。

MySQL性能分析及explain的使用
本文我们主要介绍了MySQL性能分析以及explain的使用,包括:组合索引、慢查询分析、MYISAM和INNODB的锁定、MYSQL的事务配置项等,希望能够对您有所帮助。

MySQL性能分析 explain 用法的知识是本文我们主要要介绍的内容,接下来就让我们通过一些实际的例子来介绍这一过程,希望能够对您有所帮助。
1.使用explain语句去查看分析结果
如explain select * from test1 where id=1;会出现:id  selecttype  table  type possible_keys  key key_len  ref rows  extra各列。
其中,
type=const表示通过索引一次就找到了;
key=primary的话,表示使用了主键;
type=all,表示为全表扫描;
key=null表示没用到索引。
type=ref,因为这时认为是多个匹配行,在联合查询中,一般为REF
key 一般为使用索引的名称
2.MYSQL中的组合索引
假设表有id,key1,key2,key3,把三者形成一个组合索引,则
如:
  1. where key1=....  
  2.    where key1=1 and key2=2  
  3.    where key1=3 and key3=3 and key2=2 
根据最左原则,这些都是可以使用索引的,如from test where key1=1 order by key3,用explain分析的话,只用到了normal_key索引,但只对where子句起作用,而后面的order by需要排序。
3.使用慢查询分析
在my.ini中:
long_query_time=1
log-slow-queries=d:\mysql5\logs\mysqlslow.log
把超过1秒的记录在慢查询日志中
可以用mysqlsla来分析之。也可以在mysqlreport中,有如
DMS分别分析了select ,update,insert,delete,replace等所占的百份比
4.MYISAM和INNODB的锁定
myisam中,注意是表锁来的,比如在多个UPDATE操作后,再SELECT时,会发现SELECT操作被锁定了,必须等所有UPDATE操作完毕后,再能SELECT
innodb的话则不同了,用的是行锁,不存在上面问题。
5.MYSQL的事务配置项
innodb_flush_log_at_trx_commit=1
表示事务提交时立即把事务日志写入磁盘,同时数据和索引也更新。
innodb_flush_log_at_trx_commit=0
事务提交时,不立即把事务日志写入磁盘,每隔1秒写一次
innodb_flush_log_at_trx_commit=2
事务提交时,立即写入磁盘文件(这里只是写入到内核缓冲区,但不立即刷新到磁盘,而是每隔1秒刷新到盘,同时更新数据和索引
explain用法
EXPLAIN tbl_name或:EXPLAIN [EXTENDED] SELECT select_options
前者可以得出一个表的字段结构等等,后者主要是给出相关的一些索引信息,而今天要讲述的重点是后者。
举例
  1. mysql> explain select * from event;  
  2. +—-+————-+——-+——+—————+——+———+——+——+——-+  
  3. | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |  
  4. +—-+————-+——-+——+—————+——+———+——+——+——-+  
  5. | 1 | SIMPLE | event | ALL | NULL | NULL | NULL | NULL | 13 | |  
  6. +—-+————-+——-+——+—————+——+———+——+——+——-+  
  7. 1 row in set (0.00 sec) 
各个属性的含义
id
select查询的序列号
select_type
select查询的类型,主要是区别普通查询和联合查询、子查询之类的复杂查询。
table
输出的行所引用的表。
type
联合查询所使用的类型。
type显示的是访问类型,是较为重要的一个指标,结果值从好到坏依次是:
system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
一般来说,得保证查询至少达到range级别,最好能达到ref。
possible_keys
指出MySQL能使用哪个索引在该表中找到行。如果是空的,没有相关的索引。这时要提高性能,可通过检验WHERE子句,看是否引用某些字段,或者检查字段不是适合索引。
key
显示MySQL实际决定使用的键。如果没有索引被选择,键是NULL。
key_len
显示MySQL决定使用的键长度。如果键是NULL,长度就是NULL。文档提示特别注意这个值可以得出一个多重主键里mysql实际使用了哪一部分。
ref
显示哪个字段或常数与key一起被使用。
rows
这个数表示mysql要遍历多少数据才能找到,在innodb上是不准确的。
Extra
如果是Only index,这意味着信息只用索引树中的信息检索出的,这比扫描整个表要快。
如果是where used,就是使用上了where限制。
如果是impossible where 表示用不着where,一般就是没查出来啥。
如果此信息显示Using filesort或者Using temporary的话会很吃力,WHERE和ORDER BY的索引经常无法兼顾,如果按照WHERE来确定索引,那么在ORDER BY时,就必然会引起Using filesort,这就要看是先过滤再排序划算,还是先排序再过滤划算。
关于MySQL性能分析及explain用法的知识就介绍到这里了,希望本次的介绍能够对您有所收获!
原文出处:http://blog.sina.com.cn/s/blog_4586764e0100o9s1.html。
【编辑推荐】
  1. 适合初学者的MySQL学习笔记之MySQL管理心得
  2. 适合初学者的MySQL学习笔记之MySQL查询示例
  3. 适合初学者的MySQL学习笔记之管理员常用操作总结
  4. 适合初学者的MySQL学习笔记之SELECT语句使用详解
  5. 适合初学者的MySQL学习笔记之ORDER BY子句使用详解


命名规则:表名_字段名
1、需要加索引的字段,要在where条件中
2、数据量少的字段不需要加索引
3、如果where条件中是 OR 关系,加索引不起作用
4、符合最 原则
https://segmentfault.com/q/1010000003984016/a-1020000003984281
联合索引又叫复合索引。对于复合索引:Mysql从左到右的使用索引中的字段,一个查询可以只使用索引中的一部份,但只能是最左侧部分。例如索引是key index (a,b,c). 可以支持 a  |  a,b a,b,c  3种组合进行查找,但不支持 b,c进行查找 .当最左侧字段是常量引用时,索引就十分有效。

两个或更多个列上的索引被称作复合索引。
利用索引中的附加列,您可以缩小搜索的范围,但使用一个具有两列的索引 不同于使用两个单独的索引。复合索引的结构与电话簿类似,人名由姓和名构成,电话簿首先按姓氏对进行排序,然后按名字对有相同姓氏的人进行排序。如果您知 道姓,电话簿将非常有用;如果您知道姓和名,电话簿则更为有用,但如果您只知道名不姓,电话簿将没有用处。
所以说创建复合索引时,应该仔细考虑列的顺序。对索引中的所有列执行搜索或仅对前几列执行搜索时,复合索引非常有用;仅对后面的任意列执行搜索时,复合索引则没有用处。
http://blog.csdn.net/lmh12506/article/details/8879916
 
 
当一个表有多条索引可走时,  Mysql  根据查询语句的成本来选择走哪条索引, 联合索引的话, 它往往计算的是第一个字段(最左边那个), 这样往往会走错索引. 如: 
索引Index_1(Create_Time, Category_ID), Index_2(Category_ID) 

如果每天的数据都特别多, 而且有很多category, 但具体每个category的记录不会很多.
当查询SQL条件为select …where create_time ….and category_id=..时, 很可能不走索引Index_1, 而走索引Index_2, 导致查询比较慢.
解决办法是将索引字段的顺序调换一下.
http://www.cnblogs.com/krisy/archive/2013/07/12/3186258.html
 
 创建索引
在执行CREATE TABLE语句时可以创建索引,也可以单独用CREATE INDEX或ALTER TABLE来为表增加索引。
1.ALTER TABLE
ALTER TABLE用来创建普通索引、UNIQUE索引或PRIMARY KEY索引。
 
ALTER TABLE table_name ADD INDEX index_name (column_list)
ALTER TABLE table_name ADD UNIQUE (column_list)
ALTER TABLE table_name ADD PRIMARY KEY (column_list)
 
其中table_name是要增加索引的表名,column_list指出对哪些列进行索引,多列时各列之间用逗号分隔。索引名index_name可选,缺省时,MySQL将根据第一个索引列赋一个名称。另外,ALTER TABLE允许在单个语句中更改多个表,因此可以在同时创建多个索引。
2.CREATE INDEX
CREATE INDEX可对表增加普通索引或UNIQUE索引。
 
CREATE INDEX index_name ON table_name (column_list)
CREATE UNIQUE INDEX index_name ON table_name (column_list)
 
table_name、index_name和column_list具有与ALTER TABLE语句中相同的含义,索引名不可选。另外,不能用CREATE INDEX语句创建PRIMARY KEY索引。
3.索引类型
在创建索引时,可以规定索引能否包含重复值。如果不包含,则索引应该创建为PRIMARY KEY或UNIQUE索引。对于单列惟一性索引,这保证单列不包含重复的值。对于多列惟一性索引,保证多个值的组合不重复。
PRIMARY KEY索引和UNIQUE索引非常类似。
事实上,PRIMARY KEY索引仅是一个具有 名称PRIMARY 的UNIQUE索引。这表示一个表只能包含一个PRIMARY KEY,因为一个表中不可能具有两个同名的索引。
下面的SQL语句对students表在sid上添加PRIMARY KEY索引。
 
ALTER TABLE students ADD PRIMARY KEY (sid)
 
4.  删除索引
可利用ALTER TABLE或DROP INDEX语句来删除索引。类似于CREATE INDEX语句,DROP INDEX可以在ALTER TABLE内部作为一条语句处理,语法如下。
DROP INDEX index_name ON talbe_name
ALTER TABLE table_name DROP INDEX index_name
ALTER TABLE table_name DROP PRIMARY KEY
 
其中,前两条语句是等价的,删除掉table_name中的索引index_name。
第3条语句只在删除PRIMARY KEY索引时使用,因为一个表只可能有一个PRIMARY KEY索引,因此不需要指定索引名。如果没有创建PRIMARY KEY索引,但表具有一个或多个UNIQUE索引,则MySQL将删除第一个UNIQUE索引。
如果从表中删除了某列,则索引会受到影响。对于多列组合的索引,如果删除其中的某列,则该列也会从索引中删除。如果删除组成索引的所有列,则整个索引将被删除。
 
5.查看索引
mysql> show index from tblname;
mysql> show keys from tblname;
  · Table

  表的名称。

  · Non_unique

  如果索引不能包括重复词,则为0。如果可以,则为1。

  · Key_name

  索引的名称。

  · Seq_in_index

  索引中的列序列号,从1开始。

  · Column_name

  列名称。

  · Collation

  列以什么方式存储在索引中。在MySQL中,有值‘A’(升序)或NULL(无分类)。

  · Cardinality

  索引中唯一值的数目的估计值。通过运行ANALYZE TABLE或myisamchk -a可以更新。基数根据被存储为整数的统计数据来计数,所以即使对于小型表,该值也没有必要是精确的。基数越大,当进行联合时,MySQL使用该索引的机会就越大。

  · Sub_part

  如果列只是被部分地编入索引,则为被编入索引的字符的数目。如果整列被编入索引,则为NULL。

  · Packed

  指示关键字如何被压缩。如果没有被压缩,则为NULL。

  · Null

  如果列含有NULL,则含有YES。如果没有,则该列含有NO。

  · Index_type

  用过的索引方法(BTREE, FULLTEXT, HASH, RTREE)。

  · Comment

6.什么情况下使用索引
       表的主关键字
自动建立唯一索引
如zl_yhjbqk(用户基本情况)中的hbs_bh(户标识编号)
表的字段唯一约束
ORACLE利用索引来保证数据的完整性
如lc_hj(流程环节)中的lc_bh+hj_sx(流程编号+环节顺序)
直接条件查询的字段
在SQL中用于条件约束的字段
如zl_yhjbqk(用户基本情况)中的qc_bh(区册编号)
select * from zl_yhjbqk where qc_bh=’<????甼曀???>7001’
查询中与其它表关联的字段
字段常常建立了外键关系
如zl_ydcf(用电成份)中的jldb_bh(计量点表编号)
select * from zl_ydcf a,zl_yhdb b where a.jldb_bh=b.jldb_bh and b.jldb_bh=’540100214511’
查询中排序的字段
排序的字段如果通过索引去访问那将大大提高排序速度
select * from zl_yhjbqk order by qc_bh(建立qc_bh索引)
select * from zl_yhjbqk where qc_bh=’7001’ order by cb_sx(建立qc_bh+cb_sx索引,注:只是一个索引,其中包括qc_bh和cb_sx字段)
查询中统计或分组统计的字段
select max(hbs_bh) from zl_yhjbqk
select qc_bh,count(*) from zl_yhjbqk group by qc_bh
什么情况下应不建或少建索引
表记录太少
如果一个表只有5条记录,采用索引去访问记录的话,那首先需访问索引表,再通过索引表访问数据表,一般索引表与数据表不在同一个数据块,这种情况下ORACLE至少要往返读取数据块两次。而不用索引的情况下ORACLE会将所有的数据一次读出,处理速度显然会比用索引快。
如表zl_sybm(使用部门)一般只有几条记录,除了主关键字外对任何一个字段建索引都不会产生性能优化,实际上如果对这个表进行了统计分析后ORACLE也不会用你建的索引,而是自动执行全表访问。如:
select * from zl_sybm where sydw_bh=’5401’(对sydw_bh建立索引不会产生性能优化)
经常插入、删除、修改的表
对一些经常处理的业务表应在查询允许的情况下尽量减少索引,如zl_yhbm,gc_dfss,gc_dfys,gc_fpdy等业务表。
数据重复且分布平均的表字段
假如一个表有10万行记录,有一个字段A只有T和F两种值,且每个值的分布概率大约为50%,那么对这种表A字段建索引一般不会提高数据库的查询速度。
经常和主字段一块查询但主字段索引值比较多的表字段
如gc_dfss(电费实收)表经常按收费序号、户标识编号、抄表日期、电费发生年月、操作 标志来具体查询某一笔收款的情况,如果将所有的字段都建在一个索引里那将会增加数据的修改、插入、删除时间,从实际上分析一笔收款如果按收费序号索引就已 经将记录减少到只有几条,如果再按后面的几个字段索引查询将对性能不产生太大的影响。
对千万级MySQL数据库建立索引的事项及提高性能的手段
一、注意事项:
首先,应当考虑表空间和磁盘空间是否足够。我们知道索引也是一种数据,在建立索引的时候势必也会占用大量表空间。因此在对一大表建立索引的时候首先应当考虑的是空间容量问题。
其次,在对建立索引的时候要对表进行加锁,因此应当注意操作在业务空闲的时候进行。
二、性能调整方面:
首当其冲的考虑因素便是磁盘I/O。物理上,应当尽量把索引与数据分散到不同的磁盘上(不考虑阵列的情况)。逻辑上,数据表空间与索引表空间分开。这是在建索引时应当遵守的基本准则。
其次,我们知道,在建立索引的时候要对表进行全表的扫描工作,因此,应当考虑调大初始化参数db_file_multiblock_read_count的值。一般设置为32或更大。
再次,建立索引除了要进行全表扫描外同时还要对数据进行大量的排序操作,因此,应当调整排序区的大小。
    9i之前,可以在session级别上加大sort_area_size的大小,比如设置为100m或者更大。
    9i以后,如果初始化参数workarea_size_policy的值为TRUE,则排序区从pga_aggregate_target里自动分配获得。
最后,建立索引的时候,可以加上nologging选项。以减少在建立索引过程中产生的大量redo,从而提高执行的速度。
 
MySql在建立索引优化时需要注意的问题
 
设计好MySql的索引可以让你的数据库飞起来,大大的提高数据库效率。设计MySql索引的时候有一下几点注意:
1,创建索引
对于查询占主要的应用来说,索引显得尤为重要。很多时候性能问题很简单的就是因为我们忘了添加索引而造成的,或者说没有添加更为有效的索引导致。如果不加
索引的话,那么查找任何哪怕只是一条特定的数据都会进行一次全表扫描,如果一张表的数据量很大而符合条件的结果又很少,那么不加索引会引起致命的性能下降。
但是也不是什么情况都非得建索引不可,比如性别可能就 只有两个值 ,建索引不仅没什么优势,还会影响到更新速度,这被称为 过度 索引。
2,复合索引
比如有一条语句是这样的:select * from users where area=’beijing’ and age=22;
如果我们是在area和age上 分别创建 单个索引的话,由于mysql查询每次只能使用 一个索引 ,所以虽然这样已经相对不做索引时全表扫描提高了很多效
率,但是如果在area、age两列上创建复合索引的话将带来更高的效率。如果我们创建了(area, age,salary)的复合索引,那么其实相当于创建了(area,age,salary)、(area,age)、(area)三个索引,这被称为最佳左前缀特性。
因此我们在创建复合索引时应该将 最常用 作限制条件的列放在 最左边 ,依次递减。
3,索引不会包含有NULL值的列
只要列中包含有NULL值都将不会被包含在索引中,复合索引中只要有 一列 含有 NULL值 ,那么这一列对于此复合索引就是 无效 的。所以我们在数据库设计时不要让字段的默认值为NULL。
4,使用短索引
对串列进行索引,如果可能应该指定一个 前缀长度 。例如,如果有一个CHAR(255)的 列,如果在前10 个或20 个字符内,多数值是惟一的,那么就不要对整个列进行索引。 短索引 不仅可以提高查询速度而且可以节省磁盘空间和I/O操作。
5,排序的索引问题
mysql查询只使用一个索引,因此如果where子句中已经使用了索引的话,那么order by中的列是不会使用索引的。因此数据库默认排序可以符合要求的情况下不要使用排序操作;尽量不要包含 多个列的排序 ,如果需要最好给这些列创建 复合索引
6,like语句操作
一般情况下不鼓励使用like操作,如果非使用不可,如何使用也是一个问题。like “%aaa%” 不会使用索引而 like “ aaa %” 可以使用索引。
7,不要在列上进行运算
select * from users where
YEAR(adddate)
8,不使用NOT IN和操作
NOT IN和操作都不会使用索引将进行全表扫描。NOT IN可以 NOT EXISTS代替 ,id3则可使用id>3 or id
http://www.cnblogs.com/alazalazalaz/p/4083696.html
很多时候,我们在mysql中创建了索引,但是某些查询还是很慢,根本就没有使用到索引!一般来说,可能是某些字段没有创建索引,或者是组合索引中字段的顺序与查询语句中字段的顺序不符。

看下面的例子:
假设有一张订单表(orders),包含order_id和product_id二个字段。
一共有31条数据。符合下面语句的数据有5条。执行下面的sql语句:
1
2
3
select product_id
from orders
where order_id in ( 123 312 223 132 224 );
这条语句要mysql去根据order_id进行搜索,然后返回匹配记录中的product_id。所以组合索引应该按照以下的顺序创建:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
create index orderid_productid on orders(order_id, product_id)
mysql> explain select product_id from orders where order_id in ( 123 312 223 132 224 ) \G
***************************  1 . row ***************************
           id:  1
  select_type: SIMPLE
        table: orders
         type: range
possible_keys: orderid_productid
          key: orderid_productid
      key_len:  5
          ref: NULL
         rows:  5
        Extra: Using where; Using index
1  row in set ( 0.00  sec)
可以看到,这个组合索引被用到了,扫描的范围也很小,只有5行。如果把组合索引的顺序换成product_id, order_id的话,mysql就会去索引中搜索 *123 *312 *223 *132 *224,必然会有些慢了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
mysql> create index orderid_productid on orders(product_id, order_id);                                                      
Query OK,  31  rows affected ( 0.01  sec)
Records:  31   Duplicates:  0   Warnings:  0
 
mysql> explain select product_id from orders where order_id in ( 123 312 223 132 224 ) \G
 
***************************  1 . row ***************************
 
           id:  1
  select_type: SIMPLE
        table: orders
         type: index
possible_keys: NULL
          key: orderid_productid
      key_len:  10
          ref: NULL
         rows:  31
        Extra: Using where; Using index
1  row in set ( 0.00  sec)
这次索引搜索的性能显然不能和上次相比了。rows:31,我的表中一共就31条数据。索引被使用部分的长度:key_len:10,比上一次的key_len:5多了一倍。不知道是这样在索引里面查找速度快,还是直接去全表扫描更快呢?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
mysql> alter table orders add modify_a  char ( 255 default   'aaa' ;
Query OK,  31  rows affected ( 0.01  sec)
Records:  31   Duplicates:  0   Warnings:  0
 
mysql>
mysql>
mysql> explain select modify_a from orders where order_id in ( 123 312 223 132 224 ) \G         
***************************  1 . row ***************************
           id:  1
  select_type: SIMPLE
        table: orders
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows:  31
        Extra: Using where
1  row in set ( 0.00  sec)
这样就不会用到索引了。 刚才是因为select的product_id与where中的order_id都在索引里面的。

为什么要创建组合索引呢?这么简单的情况直接创建一个order_id的索引不就行了吗?果只有一个order_id索引,没什么问题,会用到这个索引,然后mysql要去磁盘上的表里面取到product_id。如果有组合索引的话,mysql可以完全从索引中取到product_id,速度自然会快。再多说几句组合索引的最左优先原则:
组合索引的第一个字段必须出现在查询组句中,这个索引才会被用到。果有一个组合索引(col_a,col_b,col_c),下面的情况都会用到这个索引:
1
2
3
4
col_a =  "some value" ;
col_a =  "some value"  and col_b =  "some value" ;
col_a =  "some value"  and col_b =  "some value"  and col_c =  "some value" ;
col_b =  "some value"  and col_a =  "some value"  and col_c =  "some value" ;
对于最后一条语句,mysql会自动优化成第三条的样子~~。下面的情况就不会用到索引:
1
2
col_b =  "aaaaaa" ;
col_b =  "aaaa"  and col_c =  "cccccc" ;
通过实例理解单列索引、多列索引以及最左前缀原则。实例:现在我们想查出满足以下条件的用户id:
mysql>SELECT `uid` FROM people WHERE lname`='Liu'  AND `fname`='Zhiqun' AND `age`=26
因为我们不想扫描整表,故考虑用索引。

单列索引:
ALTER TABLE people ADD INDEX lname (lname);
将lname列建索引,这样就把范围限制在lname='Liu'的结果集1上,之后扫描结果集1,产生满足fname='Zhiqun'的结果集2,再扫描结果集2,找到 age=26的结果集3,即最终结果。

由 于建立了lname列的索引,与执行表的完全扫描相比,效率提高了很多,但我们要求扫描的记录数量仍旧远远超过了实际所需 要的。虽然我们可以删除lname列上的索引,再创建fname或者age 列的索引,但是,不论在哪个列上创建索引搜索效率仍旧相似。

2.多列索引:
ALTER TABLE people ADD INDEX lname_fname_age (lame,fname,age);
为了提高搜索效率,我们需要考虑运用多列索引,由于索引文件以B-Tree格式保存,所以我们不用扫描任何记录,即可得到最终结果。

注:在mysql中执行查询时,只能使用一个索引,如果我们在lname,fname,age上分别建索引,执行查询时, 只能使用一个索引,mysql会选择一个最严格(获得结果集记录数最少)的索引。

3.最左前缀:顾名思义,就是最左优先,上例中我们创建了lname_fname_age多列索引,相当于创建了(lname)单列索引,(lname,fname)组合索引以及(lname,fname,age)组合索引。

注:在创建多列索引时,要根据业务需求,where子句中使用最频繁的一列放在最左边。
建立索引的时机
到这里我们已经学会了建立索引,那么我们需要在什么情况下建立索引呢?一般来说,在WHERE和JOIN中出现的列需要建立索引,但也不完全如此,因为MySQL只对<,<=,=,>,>=,BETWEEN,IN,以及某些时候的LIKE才会使用索引。例如:
1
SELECT t.Name FROM mytable t LEFT JOIN mytable m ON t.Name=m.username WHERE m.age= 20  AND m.city= '郑州'
此时就需要对city和age建立索引,由于mytable表的userame也出现在了JOIN子句中,也有对它建立索引的必要。
刚才提到只有某些时候的LIKE才需建立索引。因为在以通配符%和_开头作查询时,MySQL不会使用索引。例如下句会使用索引:
1
SELECT * FROM mytable WHERE username like 'admin%'
下句就不会使用:
1
SELECT * FROM mytable WHEREt Name like '%admin'
因此,在使用LIKE时应注意以上的区别。
索引的不足之处
上面都在说使用索引的好处,但过多的使用索引将会造成滥用。因此索引也会有它的缺点:
  • 虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE。因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件。
  • 建立索引会占用磁盘空间的索引文件。一般情况这个问题不太严重,但如果你在一个大表上创建了多种组合索引,索引文件的会膨胀很快。索引只是提高效率的一个因素,如果你的MySQL有大数据量的表,就需要花时间研究建立最优秀的索引,或优化查询语句。
使用索引的注意事项
使用索引时,有以下一些技巧和注意事项:
  • 索引不会包含有NULL值的列
只要列中包含有NULL值都将不会被包含在索引中,复合索引中只要有一列含有NULL值,那么这一列对于此复合索引就是无效的。所以我们在数据库设计时不要让字段的默认值为NULL。
  • 使用短索引
对串列进行索引,如果可能应该指定一个前缀长度。例如,如果有一个CHAR(255)的列,如果在前10个或20个字符内,多数值是惟一的,那么就不要对整个列进行索引。短索引不仅可以提高查询速度而且可以节省磁盘空间和I/O操作。
  • 索引列排序
MySQL查询只使用一个索引,因此如果where子句中已经使用了索引的话,那么order by中的列是不会使用索引的。因此数据库默认排序可以符合要求的情况下不要使用排序操作;尽量不要包含多个列的排序,如果需要最好给这些列创建复合索引。
  • like语句操作
一般情况下不鼓励使用like操作,如果非使用不可,如何使用也是一个问题。like “%aaa%” 不会使用索引而like “aaa%”可以使用索引。
  • 不要在列上进行运算
select  *  from  users  where   YEAR (adddate)<2007; 
将在每个行上进行运算,这将导致索引失效而进行全表扫描,因此我们可以改成
select  *  from  users  where  adddate<‘2007-01-01’;  
  • 不使用NOT IN和<>操作

SQL创建索引:
select a.apply_id as origin_apply_id,a.origin_card_id as origin_origin_card_id,a.card_id as origin_card_id,a.card_uniqueId as origin_card_uniqueId,
a.pin as origin_pin ,a.card_no as origin_card_no,a.card_mobile as origin_card_mobile,a.bank_code as origin_bank_code,a.holder_name as origin_holder_name,
a.holder_id as origin_holder_id,a.holder_type as origin_holder_type,a.apply_dateTime as origin_apply_dateTime ,a.launch_moudle as origin_launch_moudle,a.launch_sys_no as origin_launch_sys_no,
a.launch_moudle_id as origin_launch_moudle_id, a.`status` as origin_status,
b.*,c.*
FROM
change_apply_info a
LEFT JOIN change_apply_info b ON a.apply_id = b.parent_apply_id and b.full_validate='1'
LEFT JOIN change_apply_check_record c ON c.apply_info_id = b.apply_id
WHERE
a.parent_apply_id IS NULL
order by c.apply_check_dateTime ,a.apply_dateTime desc

创建索引:

alter table change_apply_info add index idx_apply_id_parent_apply_id_apply_date(apply_id ,parent_apply_id,full_validate,apply_dateTime); 执行计划不会使用索引

alter table change_apply_info add index idx_apply_id_parent_apply_id_apply_date(parent_apply_id,apply_id,apply_dateTime,full_validate);

执行计划:

相关转载:
http://www.cnblogs.com/cy163/archive/2008/10/27/1320798.html


  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值