MySQL中的联合索引学习教程 |
联合索引又叫复合索引 。对于复合索引:Mysql从左到右的使用索引中的字段,一个查询可以只使用索引中的一部份,但只能是最左侧部分 。例如索引是key index (a,b,c). 可以支持a | a,b| a,b,c 3种组合进行查找,但不支持 b,c进行查找 .当最左侧字段是常量引用时,索引就十分有效 。
create table test( a int, b int, c int, KEY a(a,b,c) ); 复合索引的建立原则: 如果您很可能仅对一个列多次执行搜索,则该列应该是复合索引中的第一列 。如果您很可能对一个两列索引中的两个列执行单独的搜索,则应该创建另一个仅包含第二列的索引 。 复合索引只对和索引中排序相同或相反的order by 语句优化 。
CREATE INDEX idx_example ON table1 (col1 ASC, col2 DESC, col3 ASC) Select col1, col2, col3 from table1 order by col1 ASC, col2 DESC, col3 ASC 和索引顺序相同 Select col1, col2, col3 from table1 order by col1 DESC, col2 ASC, col3 DESC 和索引顺序相反 Select col1, col2, col3 from table1 order by col1 ASC, col2 ASC, col3 ASC 排序结果和索引完全不同时,此时的 查询不会被复合索引优化 。
如果一个多列索引存在于 列 Col1 和 Col2 上,则以下语句:Select * from table where col1=val1 AND col2=val2 查询优化器会试图通过决定哪个索引将找到更少的行 。之后用得到的索引去取值 。 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
2. 如果列不构成索引的最左面前缀,则建立的索引将不起作用 。 SELECT * FROM tb WHERE col3 = val3 SELECT * FROM tb WHERE col2 = val2 SELECT * FROM tb WHERE col2 = val2 and col3=val3 下面是一些常见的索引限制问题 1、使用不等于操作符(<>, !=) select * from dept shere staff_num < 1000 or dept_id > 1000;
2、使用 is null 或 is not null 3、使用函数 select * from staff where trunc(birthdate) = 01-MAY-82; select * from staff where birthdate < (to_date(01-MAY-82) + 0.9999);
4、比较不匹配的数据类型 select * from dept where dept_id = 900198; select * from dept where dept_id = 900198;
恩,这里还有要注意的:
SELECT * FROM articles WHERE category_id = ... ORDER BY created DESC LIMIT ... 这样的查询很常见,基本上不管什么应用里都能找出一大把类似的SQL来,学院派的读者看到上面的SQL,可能会说SELECT *不好,应该仅仅查询需要的字段,那我们就索性彻底点,把SQL改成如下的形式:
SELECT id FROM articles WHERE category_id = ... ORDER BY created DESC LIMIT ...
我们假设这里的id是主键,至于文章的具体内容,可以都保存到memcached之类的键值类型的缓存里,如此一来,学院派的读者们应该挑不出什么毛病来了,下面我们就按这条SQL来考虑如何建立索引: 不考虑数据分布之类的特殊情况,任何一个合格的WEB开发人员都知道类似这样的SQL,应该建立一个”category_id, created“复合索引,但这是最佳答案不?不见得,现在是回头看看标题的时候了:MySQL里建立索引应该考虑数据库引擎的类型! 如果我们的数据库引擎是InnoDB,那么建立”category_id, created“复合索引是最佳答案 。让我们看看InnoDB的索引结构,在InnoDB里,索引结构有一个特殊的地方:非主键索引在其BTree的叶节点上会额外保存对应主键的值,这样做一个最直接的好处就是Covering Index,不用再到数据文件里去取id的值,可以直接在索引里得到它 。 如果我们的数据库引擎是MyISAM,那么建立"category_id, created"复合索引就不是最佳答案 。因为MyISAM的索引结构里,非主键索引并没有额外保存对应主键的值,此时如果想利用上Covering Index,应该建立"category_id, created, id"复合索引 。 唠完了,应该明白我的意思了吧 。希望以后大家在考虑索引的时候能思考的更全面一点,实际应用中还有很多类似的问题,比如说多数人在建立索引的时候不从Cardinality(SHOW INDEX FROM ...能看到此参数)的角度看是否合适的问题,Cardinality表示唯一值的个数,一般来说,如果唯一值个数在总行数中所占比例小于20%的话,则可以认为Cardinality太小,此时索引除了拖慢insert/update/delete的速度之外,不会对select产生太大作用;还有一个细节是建立索引的时候未考虑字符集的影响,比如说username字段,如果仅仅允许英文,下划线之类的符号,那么就不要用gbk,utf-8之类的字符集,而应该使用latin1或者ascii这种简单的字符集,索引文件会小很多,速度自然就会快很多 。这些细节问题需要读者自己多注意,我就不多说了 。 |