《MYSQL教程MySQL中的联合索引学习教程》要点:
本文介绍了MYSQL教程MySQL中的联合索引学习教程,希望对您有用。如果有疑问,可以联系我们。
MYSQL学习联合索引又叫复合索引.对于复合索引:Mysql从左到右的使用索引中的字段,一个查询可以只使用索引中的一部份,但只能是最左侧部分.例如索引是key index (a,b,c). 可以支持a | a,b| a,b,c 3种组合进行查找,但不支持 b,c进行查找 .当最左侧字段是常量引用时,索引就十分有效.
MYSQL学习
两个或更多个列上的索引被称作复合索引.
利用索引中的附加列,您可以缩小搜索的范围,但使用一个具有两列的索引 不同于使用两个单独的索引.复合索引的结构与电话簿类似,人名由姓和名构成,电话簿首先按姓氏对进行排序,然后按名字对有相同姓氏的人进行排序.如果您知 道姓,电话簿将非常有用;如果您知道姓和名,电话簿则更为有用,但如果您只知道名不姓,电话簿将没有用处.
所以说创建复合索引时,应该仔细考虑列的顺序.对索引中的所有列执行搜索或仅对前几列执行搜索时,复合索引非常有用;仅对后面的任意列执行搜索时,复合索引则没有用处.
如:建立 姓名、年龄、性别的复合索引.
MYSQL学习
create table test(
a int,
b int,
c int,
KEY a(a,b,c)
);
MYSQL学习复合索引的建立原则:
MYSQL学习 如果您很可能仅对一个列多次执行搜索,则该列应该是复合索引中的第一列.如果您很可能对一个两列索引中的两个列执行单独的搜索,则应该创建另一个仅包括第二列的索引.
如上图所示,如果查询中需要对年龄和性别做查询,则应当再新建一个包括年龄和性别的复合索引.
包括多个列的主键始终会自动以复合索引的形式创建索引,其列的顺序是它们在表定义中出现的顺序,而不是在主键定义中指定的顺序.在考虑将来通过主键执行的搜索,确定哪一列应该排在最前面.
请注意,创建复合索引应当包括少数几个列,并且这些列经常在select查询里使用.在复合索引里包括太多的列不仅不会给带来太多好处.而且由于使用相当多的内存来存储复合索引的列的值,其后果是内存溢出和性能降低.
MYSQL学习
复合索引对排序的优化:
MYSQL学习 复合索引只对和索引中排序相同或相反的order by 语句优化.
在创建复合索引时,每一列都定义了升序或者是降序.如定义一个复合索引:
MYSQL学习
CREATE INDEX idx_example
ON table1 (col1 ASC, col2 DESC, col3 ASC)
MYSQL学习
其中 有三列分别是:col1 升序,col2 降序, col3 升序.现在如果我们执行两个查询
1:
MYSQL学习
Select col1, col2, col3 from table1 order by col1 ASC, col2 DESC, col3 ASC
MYSQL学习 和索引顺序相同
2:
MYSQL学习
Select col1, col2, col3 from table1 order by col1 DESC, col2 ASC, col3 DESC
MYSQL学习 和索引顺序相反
查询1,2 都可以别复合索引优化.
如果查询为:
MYSQL学习
Select col1, col2, col3 from table1 order by col1 ASC, col2 ASC, col3 ASC
MYSQL学习 排序结果和索引完全不同时,此时的 查询不会被复合索引优化.
MYSQL学习
查询优化器在在where查询中的作用:
MYSQL学习 如果一个多列索引存在于 列 Col1 和 Col2 上,则以下语句:Select * from table where col1=val1 AND col2=val2 查询优化器会试图通过决定哪个索引将找到更少的行.之后用得到的索引去取值.
1. 如果存在一个多列索引,任何最左面的索引前缀能被优化器使用.所以联合索引的顺序不同,影响索引的选择,尽量将值少的放在前面.
如:一个多列索引为 (col1 ,col2, col3)
那么在索引在列 (col1) 、(col1 col2) 、(col1 col2 col3) 的搜索会有作用.
MYSQL学习
SELECT * FROM tb WHERE col1 = val1
SELECT * FROM tb WHERE col1 = val1 and col2 = val2
SELECT * FROM tb WHERE col1 = val1 and col2 = val2 AND col3 = val3
MYSQL学习
MYSQL学习 2. 如果列不构成索引的最左面前缀,则建立的索引将不起作用.
如:
MYSQL学习
SELECT * FROM tb WHERE col3 = val3
SELECT * FROM tb WHERE col2 = val2
SELECT * FROM tb WHERE col2 = val2 and col3=val3
MYSQL学习
3. 如果一个 Like 语句的查询条件不以通配符起始则使用索引.
如:%车 或 %车% 不使用索引.
车% 使用索引.
索引的缺点:
1. 占用磁盘空间.
2. 增加了插入和删除的操作时间.一个表拥有的索引越多,插入和删除的速度越慢.如 要求快速录入的系统不宜建过多索引.
MYSQL学习下面是一些常见的索引限制问题
MYSQL学习1、使用不等于操作符(<>, !=)
下面这种情况,即使在列dept_id有一个索引,查询语句仍然执行一次全表扫描
select * from dept where staff_num <> 1000;
但是开发中的确需要这样的查询,难道没有解决问题的方法了吗?
有!
通过把用 or 语法替代不等号进行查询,就可以使用索引,以避免全表扫描:上面的语句改成下面这样的,就可以使用索引了.
MYSQL学习
select * from dept shere staff_num < 1000 or dept_id > 1000;
MYSQL学习
MYSQL学习2、使用 is null 或 is not null
使用 is null 或is nuo null也会限制索引的使用,因为数据库并没有定义null值.如果被索引的列中有很多null,就不会使用这个索引(除非索引是一个位图索引,关于位图索引,会在以后的blog文章里做详细解释).在sql语句中使用null会造成很多麻烦.
解决这个问题的方法就是:建表时把需要索引的列定义为非空(not null)
MYSQL学习3、使用函数
如果没有使用基于函数的索引,那么where子句中对存在索引的列使用函数时,会使优化器忽略掉这些索引.下面的查询就不会使用索引:
MYSQL学习
select * from staff where trunc(birthdate) = '01-MAY-82';
MYSQL学习
但是把函数应用在条件上,索引是可以生效的,把上面的语句改成下面的语句,就可以通过索引进行查找.
MYSQL学习
select * from staff where birthdate < (to_date('01-MAY-82') + 0.9999);
MYSQL学习
MYSQL学习4、比较不匹配的数据类型
比较不匹配的数据类型也是难于发现的性能问题之一.
下面的例子中,dept_id是一个varchar2型的字段,在这个字段上有索引,但是下面的语句会执行全表扫描.
MYSQL学习
select * from dept where dept_id = 900198;
MYSQL学习
这是因为oracle会自动把where子句转换成to_number(dept_id)=900198,就是3所说的情况,这样就限制了索引的使用.
把SQL语句改为如下形式就可以使用索引
MYSQL学习
select * from dept where dept_id = '900198';
MYSQL学习
MYSQL学习恩,这里还有要注意的:
MYSQL学习
比方说有一个文章表,我们要实现某个类别下按时间倒序列表显示功能:
MYSQL学习
SELECT * FROM articles WHERE category_id = ... ORDER BY created DESC LIMIT ...
MYSQL学习 这样的查询很常见,基本上不管什么应用里都能找出一大把类似的SQL来,学院派的读者看到上面的SQL,可能会说SELECT *不好,应该仅仅查询需要的字段,那我们就索性彻底点,把SQL改成如下的形式:
MYSQL学习
MYSQL学习
SELECT id FROM articles WHERE category_id = ... ORDER BY created DESC LIMIT ...
MYSQL学习
MYSQL学习 我们假设这里的id是主键,至于文章的具体内容,可以都保留到memcached之类的键值类型的缓存里,如此一来,学院派的读者们应该挑不出什么毛病来了,下面我们就按这条SQL来考虑如何建立索引:
MYSQL学习 不考虑数据分布之类的特殊情况,任何一个合格的WEB开发人员都知道类似这样的SQL,应该建立一个”category_id, created“复合索引,但这是最佳答案不?不见得,现在是回头看看标题的时候了:MySQL里建立索引应该考虑数据库引擎的类型!
MYSQL学习 如果我们的数据库引擎是InnoDB,那么建立”category_id, created“复合索引是最佳答案.让我们看看InnoDB的索引结构,在InnoDB里,索引结构有一个特殊的地方:非主键索引在其BTree的叶节点上会额外保留对应主键的值,这样做一个最直接的好处就是Covering Index,不用再到数据文件里去取id的值,可以直接在索引里得到它.
MYSQL学习 如果我们的数据库引擎是MyISAM,那么建立"category_id, created"复合索引就不是最佳答案.因为MyISAM的索引结构里,非主键索引并没有额外保留对应主键的值,此时如果想利用上Covering Index,应该建立"category_id, created, id"复合索引.
MYSQL学习 唠完了,应该明白我的意思了吧.希望以后大家在考虑索引的时候能思考的更全面一点,实际应用中还有很多类似的问题,比如说多数人在建立索引的时候不从Cardinality(SHOW INDEX FROM ...能看到此参数)的角度看是否合适的问题,Cardinality表示唯一值的个数,一般来说,如果唯一值个数在总行数中所占比例小于20%的话,则可以认为Cardinality太小,此时索引除了拖慢insert/update/delete的速度之外,不会对select产生太大作用;还有一个细节是建立索引的时候未考虑字符集的影响,比如说username字段,如果仅仅允许英文,下划线之类的符号,那么就不要用gbk,utf-8之类的字符集,而应该使用latin1或者ascii这种简单的字符集,索引文件会小很多,速度自然就会快很多.这些细节问题需要读者本身多注意,我就不多说了.
《MYSQL教程MySQL中的联合索引学习教程》是否对您有启发,欢迎查看更多与《MYSQL教程MySQL中的联合索引学习教程》相关教程,学精学透。维易PHP学院为您提供精彩教程。