数据库教程:MySQL中的联合索引学习教程分享

联合索引又叫复合索引。对于复合索引:Mysql从左到右的使用索引中的字段,一个查询可以只使用索引中的一部份,但只能是最左侧部分。例如索引是keyindex(a,b,c).可以支持a|a,b|a,b,c3种组合进行查找,但不支持b,c进行查找.当最左侧字段是常量引用时,索引就十分有效。

两个或更多个列上的索引被称作复合索引。
利用索引中的附加列,您可以缩小搜索的范围,但使用一个具有两列的索引不同于使用两个单独的索引。复合索引的结构与电话簿类似,人名由姓和名构成,电话簿首先按姓氏对进行排序,然后按免费精选名字大全对有相同姓氏的人进行排序。如果您知道姓,电话簿将非常有用;如果您知道姓和名,电话簿则更为有用,但如果您只知道名不姓,电话簿将没有用处。
所以说创建复合索引时,应该仔细考虑列的顺序。对索引中的所有列执行搜索或仅对前几列执行搜索时,复合索引非常有用;仅对后面的任意列执行搜索时,复合索引则没有用处。
如:建立姓名、年龄、性别的复合索引。

createtabletest( aint, bint, cint, KEYa(a,b,c) );

复合索引的建立原则:

 如果您很可能仅对一个列多次执行搜索,则该列应该是复合索引中的第一列。如果您很可能对一个两列索引中的两个列执行单独的搜索,则应该创建另一个仅包含第二列的索引。
如上图所示,如果查询中需要对年龄和性别做查询,则应当再新建一个包含年龄和性别的复合索引。
包含多个列的主键始终会自动以复合索引的形式创建索引,其列的顺序是它们在表定义中出现的顺序,而不是在主键定义中指定的顺序。在考虑将来通过主键执行的搜索,确定哪一列应该排在最前面。
请注意,创建复合索引应当包含少数几个列,并且这些列经常在select查询里使用。在复合索引里包含太多的列不仅不会给带来太多好处。而且由于使用相当多的内存来存储复合索引的列的值,其后果是内存溢出和性能降低。

         
 复合索引对排序的优化:

 复合索引只对和索引中排序相同或相反的orderby语句优化。
 在创建复合索引时,每一列都定义了升序或者是降序。如定义一个复合索引:

CREATEINDEXidx_example ONtable1(col1ASC,col2DESC,col3ASC)

 
 其中有三列分别是:col1升序,col2降序,col3升序。现在如果我们执行两个查询
 1:

Selectcol1,col2,col3fromtable1orderbycol1ASC,col2DESC,col3ASC

 和索引顺序相同
 2:

Selectcol1,col2,col3fromtable1orderbycol1DESC,col2ASC,col3DESC

 和索引顺序相反
 查询1,2都可以别复合索引优化。
 如果查询为:
 

Selectcol1,col2,col3fromtable1orderbycol1ASC,col2ASC,col3ASC

 排序结果和索引完全不同时,此时的 查询不会被复合索引优化。

查询优化器在在where查询中的作用:

 如果一个多列索引存在于列Col1和Col2上,则以下语句:Select  *fromtablewhere  col1=val1ANDcol2=val2查询优化器会试图通过决定哪个索引将找到更少的行。之后用得到的索引去取值。
 1.如果存在一个多列索引,任何最左面的索引前缀能被优化器使用。所以联合索引的顺序不同,影响索引的选择,尽量将值少的放在前面。
如:一个多列索引为(col1,col2,col3)
   那么在索引在列(col1)、(col1col2)、(col1col2col3)的搜索会有作用。

SELECT*FROMtbWHEREcol1=val1 SELECT*FROMtbWHEREcol1=val1andcol2=val2 SELECT*FROMtbWHEREcol1=val1andcol2=val2ANDcol3=val3

 

 2.如果列不构成索引的最左面前缀,则建立的索引将不起作用。
如:

SELECT*FROMtbWHEREcol3=val3 SELECT*FROMtbWHEREcol2=val2 SELECT*FROMtbWHEREcol2=val2andcol3=val3

 
 3.如果一个Like语句的查询条件不以通配符起始则使用索引。
如:%车或%车%  不使用索引。
   车%             使用索引。
索引的缺点:
1.      占用磁盘空间。
2.      增加了插入和删除的操作时间。一个表拥有的索引越多,插入和删除的速度越慢。如要求快速录入的系统不宜建过多索引。

下面是一些常见的索引限制问题

1、使用不等于操作符(<>,!=)
下面这种情况,即使在列dept_id有一个索引,查询语句仍然执行一次全表扫描
select*fromdeptwherestaff_num<>1000;
但是开发中的确需要这样的查询,难道没有解决问题的办法了吗?
有!
通过把用or语法替代不等号进行查询,就可以使用索引,以避免全表扫描:上面的语句改成下面这样的,就可以使用索引了。

select*fromdeptsherestaff_num<1000ordept_id>1000;

 

2、使用isnull或isnotnull
使用isnull或isnuonull也会限制索引的使用,因为数据库并没有定义null值。如果被索引的列中有很多null,就不会使用这个索引(除非索引是一个位图索引,关于位图索引,会在以后的blog文章里做详细解释)。在sql语句中使用null会造成很多麻烦。
解决这个问题的办法就是:建表时把需要索引的列定义为非空(notnull)

3、使用函数
如果没有使用基于函数的索引,那么where子句中对存在索引的列使用函数时,会使优化器忽略掉这些索引。下面的查询就不会使用索引:

select*fromstaffwheretrunc(birthdate)='01-MAY-82';

 
但是把函数应用在条件上,索引是可以生效的,把上面的语句改成下面的语句,就可以通过索引进行查找。

select*fromstaffwherebirthdate<(to_date('01-MAY-82')+0.9999);

 

4、比较不匹配的数据类型
比较不匹配的数据类型也是难于发现的性能问题之一。
下面的例子中,dept_id是一个varchar2型的字段,在这个字段上有索引,但是下面的语句会执行全表扫描。

select*fromdeptwheredept_id=900198;

 
这是因为oracle会自动把where子句转换成to_number(dept_id)=900198,就是3所说的情况,这样就限制了索引的使用。
把SQL语句改为如下形式就可以使用索引

select*fromdeptwheredept_id='900198';

 

恩,这里还有要注意的:

 比方说有一个文章表,我们要实现某个类别下按时间倒序列表显示功能:

SELECT*FROMarticlesWHEREcategory_id=...ORDERBYcreatedDESCLIMIT...

 这样的查询很常见,基本上不管什么应用里都能找出一大把类似的SQL来,学院派的读者看到上面的SQL,可能会说SELECT*不好,应该仅仅查询需要的字段,那我们就索性彻底点,把SQL改成如下的形式:

 

SELECTidFROMarticlesWHEREcategory_id=...ORDERBYcreatedDESCLIMIT...

 

 我们假设这里的id是主键,至于文章的具体内容,可以都保存到memcached之类的键值类型的缓存里,如此一来,学院派的读者们应该挑不出什么毛病来了,下面我们就按这条SQL来考虑如何建立索引:

 不考虑数据分布之类的特殊情况,任何一个合格的WEB开发人员都知道类似这样的SQL,应该建立一个”category_id,created“复合索引,但这是最佳答案不?不见得,现在是回头看看标题的时候了:MySQL里建立索引应该考虑数据库引擎的类型!

 如果我们的数据库引擎是InnoDB,那么建立”category_id,created“复合索引是最佳答案。让我们看看InnoDB的索引结构,在InnoDB里,索引结构有一个特殊的地方:非主键索引在其BTree的叶节点上会额外保存对应主键的值,这样做一个最直接的好处就是CoveringIndex,不用再到数据文件里去取id的值,可以直接在索引里得到它。

 如果我们的数据库引擎是MyISAM,那么建立”category_id,created”复合索引就不是最佳答案。因为MyISAM的索引结构里,非主键索引并没有额外保存对应主键的值,此时如果想利用上CoveringIndex,应该建立”category_id,created,id”复合索引。

 唠完了,应该明白我的意思了吧。希望以后大家在考虑索引的时候能思考的更全面一点,实际应用中还有很多类似的问题,比如说多数人在建立索引的时候不从Cardinality(SHOWINDEXFROM…能看到此参数)的角度看是否合适的问题,Cardinality表示唯一值的个数,一般来说,如果唯一值个数在总行数中所占比例小于20%的话,则可以认为Cardinality太小,此时索引除了拖慢insert/update/delete的速度之外,不会对select产生太大作用;还有一个细节是建立索引的时候未考虑字符集的影响,比如说username字段,如果仅仅允许英文,下划线之类的符号,那么就不要用gbk,utf-8之类的字符集,而应该使用latin1或者ascii这种简单的字符集,索引文件会小很多,速度自然就会快很多。这些细节问题需要读者自己多注意,我就不多说了。

您可能感兴趣的文章:MySQL联合索引用法示例MySQL联合索引与Where子句的优化提高数据库运行效率mysql添加索引mysql如何创建索引MySQL查看、创建和删除索引的方法MySQL创建索引(CreateIndex)的方法和语法结构及例子MySQL主键与索引的联系与区别分析基于mysql全文索引的深入理解MySQL索引分析和优化MYSQL索引无效和索引有效的详细介绍mysql下普通索引和唯一索引的效率对比MySQL联合索引功能与用法实例分析

标签: 教程 索引 学习 SQL

对MySQL日志操作的一些基本命令上述就是数据库技术:MySQL中的联合索引学习教程分享的全部内容,如果对大家有所用处且需要了解更多关于mysql数据库学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

ctvol管理联系方式QQ:251552304

本文章地址:https://www.ctvol.com/dtteaching/911873.html

(0)
上一篇 2021年10月25日
下一篇 2021年10月25日

精彩推荐