您的位置:首页 > 数据库

使用索引优化查询

2013-07-19 18:13 190 查看
        
首先说明一下为什么要使用索引。数据行在数据库中是无序存储的,对于一组无序的数据,要想从中找出对我们有用的数据,唯一的办法就是遍历,而对于海量数据来说,遍历无疑是耗时费力的选择,其效率可能会让我们无法忍的。为了能让我们有的所矢,像卫星定位一样一下子就找到我们所需要的数据,而不用花费大量的时间和精力去遍历那些无用的数据,就要用到索引。

      举个简单的例子。比如我们的英文字典,如果把所有的单词无序的放置在字典中,现在我们要找一个单词name就要遍历所有的单词,那可能一个月才能找到。幸好我们的字典给我们建立了索引,它将所有单词按照首字母进行排序。于是我们就知道在索引表里从N开头的单词开始寻找,然后找到name所在的页面,找到我们要找的单词,如果在所有以N开头的单词中没有找到,那我们也就不用再费力气继续寻找了,因为下面的单词里再也没有以N开头的单词了,继续找下去也是徒劳无功。有了这个索引我们查找起来就有的所矢了,首先我们跳过了所有首字母排在N前面的单词,省略了所有首字母排在N后面的单词,只要寻找以字母N开头的单词就可以了,这样就节省了百分之90多的工作量,对于海量数据来说,可能查询效率会提高上百万倍。

      数据库虽然不是实体字典,但是基本原理跟字典的索引是一个道理,对于你要建立索引的字段,首先数据库会为我们建立一张索引表,里面把该字段里的所有值都录入到这张索引表,并把每个数据行的地址与这个值对应起来,然后对这些值进行排序,当你要根据这个字段查找数据行的时候,数据库就会先在索引表里查找到该字段的值,然后根据其对应的地址到数据表里找到该行。这样就不会盲目遍历了,对于海量数据来说自然会大大提高查询的效率。特别是对于多表关联查询,其效率的提升更加明显,因为多表关联实际是把每张表的数据行数相乘得到笛卡尔积,然后再进行遍历,数据量会成亿万倍的增加。下面图解一下一个具体的实例

     以下有两张表省表,和市表,市表的外键provinceId关联到省表





      我们需要两张表关联查询看看某个省下边的所有市,也就是需要以下的数据



     然而数据库在帮我们查询的时候其首先遍历的确实下面这张表,也就是两张表所有行的笛卡尔积。



    如果我们将provinceId设置为索引字段,那么查询就会大大加快,首先数据库会在省表中遍历所有省,先是山东省,其id =1,于是就到市表中provinceId字段的索引表中找provinceId=1的市,发现没有于是停止关联查询,然后再从省表中找到了浙江省,其id
=2,再到市表中provinceId字段的索引表中找provinceId=2的市,找到两条,然后根据索引表指向的地址到市表中查出这两条,也就是说额外的查询时间仅仅是在索引表中,其他的查询时间都是有效时间,这样就大大加快了查询的速度。查询效率是原来的4倍,如果两张表中的数据量成百万条的话,那么加快的速度将变得十分明显。

    
当然,索引虽然大大加快了查询的速度,但是它也有弊端。

     首先索引会降低数据的增删改操作,因为在对数据进行增删改的时候,除了要多原数据行进行操作外,还有对索引表进行修改,这样就增加了操作的时间。对于增删改操作非常频繁的表,要在增删改和查两者之间进行权衡,看看建索引是利大还是弊大。

    其次是占用存储空间,当然这只是一个重要的问题。

    既然索引对于优化查询,提高查询速度那么有用,是不是随便建索引就可以呢?答案是不行。必须要按照一定的规则,下面我们就来讲一下建索引的规则。

    要想使索引只发挥优点而避开缺点就要遵循一定的规则。

    1.尽量为用来搜索、分类或者分组的数据列编制索引,不要为作为输出显示的数据列编制索引。换
4000
句话说,最适合有索引的数据列是那些在WHERE子句中出现的数据列,在联接子句中给出的数据列,或者是在ORDER BY或GROUP BY子句中出现的数据列。根据SELECT关键字仅出现在输出数据列清单里的数据列最好不要有索引。

    2.综合考虑数据列的维度势。这里要先解释一下什么是维度,数据列的维度等于它所容纳的非重复值的个数。比如一个数据列的值包含a,b,c,d,a,b那么它的维度就是4,而它的列数是6,维度数越高,越应该使用索引,当一个字段值在数据列中出现的频率超过30%的时候,查询优化程序就会跳过索引,而直接进行全表扫描,这样建立索引就失去了意义(当然现在的查询优化程序做的更加智能化,可能对这种算法进行了改进,但这种因素必须考虑)。举个更简单的例子:性别字段,其字段值除了男就是女,像这种字段就没有必要建立索引。

   3.对短小的值进行索引。意思是对要建立索引的字段应该尽量让它的数据类型小一些。这样有以下好处(1)短小值可以让比较操作更快的完成,加快索引的查找速度。(2)短小的值可以让索引的体积更小,减少磁盘的I/O活动。(3)短小的键值意味着键缓存里的索引块可以容纳更多的键值,这样就将加大在不需要从磁盘读取更多索引块的前提下在内存里找到键值的概率。

   4.为字符串值的前缀编索引。比如,你有一个CHAR(200)的数据列,大多数的值的前10个或者20个字符就能唯一区分该字段,那么你就用不着为整个数据列编索引。仅为前20或者30个字符编索引就可以节省索引中大量空间,而且会使查询速度进行的更快。为较小的值编索引可以减少磁盘的I/O操作,加快比较速度。

   5.充分利用最左边的前缀。假设有个符合索引,state,city,zip那么当你查询条件为state,ctity和单独一个state时,这两个查询条件仍然可以使用该索引。但是其他的组合,索引就没有用了。

   6.适可而止,不要建立过多的索引。索引过多不但会占据而外的的磁盘空间,而且会影响写入操作的性能。当你修改数据表的内容后,索引必须更新以及重新编排,使用的索引越多,这个过程占据的时间就越长。如果你有一个很少使用的索引,你就无谓的降低了数据表修改的数度。

    
上面讲到了索引的优缺点以及创建规则,那么索引有哪些类型,又如何创建索引呢?下面讲继续介绍。

      1.唯一索引。这种索引要求索引项中不能有重复值。对于涉及多个数据列的索引(复合索引)来说,意味着几个数据列组合值不能重复。

       alter table ? add primary key(?);第一个问号是表名,第二个是主键字段名。

      2.普通索引。索引项中可以出现重复值。

       alter table ? add index ? (?);第一个问号表示表名,第二个表示索引的名称,第三个是索引字段名。

      3.FULLTEXT索引 。用来进行全文检索,这种索引只适用于MyISAM存储引擎中的数据表。

      
alter table ? add fulltext ? (?);第一个问号表示表名,第二个表示索引的名称,第三个是索引字段名。

      4.SPATIAL索引。只适用于MyISAM数据表和空间(spatial)数据类型。

       alter table ? add
spatial ? (?);第一个问号表示表名,第二个表示索引的名称,第三个是索引字段名。

      5.HASH索引。这是MEMORY数据表的默认索引类型,但你可以改用BTREE索引来代替默认索引。

      
alter table ? add unique ? (?);第一个问号表示表名,第二个表示索引的名称,第三个是索引字段名。

      其中唯一索引和SPATIAL索引必须具备NOT NULL属性。其它索引可以。如果要保证一个索引中无重复值,那么就是用唯一索引或者HASH索引两者相似但存在两点区别。(1)唯一索引的名字只能是primary
,而同一张数据表不允许出现同名索引,也就是说一张表只能有一个唯一索引。(2)唯一索引不允许NULL值,但是HASH索引可以。

    除了唯一索引外,其他索引都可以使用create语句来创建索引,其格式是:

    create 索引类型     索引名   on  表名(字段名);这里不再赘述。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  数据库 索引