mysql优化-----多列索引的左前缀规则
- 索引优化策略
- 1:索引类型
- 1.1B-tree索引
- 关注的是:Btree索引的左前缀匹配规则,索引在排序和分组上发挥的作用。
- 注:名叫btree索引,大的方面看都用的二叉树、平衡树。但具体的实现上,各引擎稍有不同。比如,严格的说,NDB引擎,使用的是T-tree。Myisam,innodb中,默认用B-tree索引。
- 凡是tree系列的,可理解为”排好序的、快速查找、的结构”。是排好序的,所以查询某个范围就很快。
- btree索引的常见误区:在where条件常用的列上都加上索引,
- 例: where cat_id=3 and price>100 ; //查询第3个栏目,100元以上的商品
- 误: cat_id上,和, price上都加上索引.
- 错:只能用上cat_id或Price索引,因为是独立的索引,同时只能用上1个,因为每个索引都是针对整个表建的,而where and查询是在排好序的大范围内再查找小的。(mysql5.6以后做了稍微改进,把多列索引进行merge但是效果不好),因此要使用多列索引。
- 在多列上建立索引后,查询哪个列,索引都将发挥作用:
- 误: 多列索引上,索引发挥作用,需要满足左前缀要求(btree索引的左前缀规则)
- B-tree多列索引:
- a,b列各加上索引:index(a)和index(b)
- Where a=3 and b=5 ,首先根据a查找到a=3的一小段,然后在从这小段中查找b=5的,此时b的索引已经发挥不了作用了。因为b的索引就不是在a的那一小段里面建的。b是针对整个表建的索引。
- 以 index(a,b,c) ,Where a=3 and b=5 and c=4 为例,联合索引是先根据a划分大类(a是有序的),再根据b在a里面划分小的(a里面的b是有序的),在根据c在b里面划分更小的(c在b里面是有序的)。就是这样查找的(这是tree系列的索引和查找方式)。
- Where b=5 and c=4,索引就用不到了,因为首先是根据a分的大类。现在找b=5的,每一个a的区间都可能有b=5的所以首先排好序的a就进不去。
- Where a=4 and c=4,a索引用到,c用不到。每段b里面都可能有c=4的。
- 多列索引:左前缀规则,中间断线就不行了。否则只能使用到部分。
- index(a,b,c):
- 语句 索引是否发挥作用
- Where a=3 是,只使用了a列
- Where a=3 and b=5 是,使用了a,b列
- Where a=3 and b=5 and c=4 是,使用了abc
- Where b=3 or where c=4 否
- Where a=3 and c=4 a列能发挥索引,c索引也就不能使用了
- Where a=3 and b>10 and c=7 A能利用,b能利用, b是一个范围,在这个范围里面的b[10,20]b[20,30]里面都有可能c=7,所以C不能利用
- 同上,where a=3 and b like ‘xxxx%’ and c=7 A能用,B能用,C不能用
- 多列索引经典题目:
- http://www.zixue.it/thread-9218-1-4.html
- 假设某个表有一个联合索引(c1,c2,c3,c4)一下——只能使用该联合索引的c1,c2,c3部分,tree系列里面:c1是有序的,c2在c1里面是有序的,c3在c2里面是有序的,c4在c3里面是有序的。
- A where c1=x and c2=x and c4>x and c3=x
- B where c1=x and c2=x and c4=x order by c3
- C where c1=x and c4= x group by c3,c2
- D where c1=x and c5=x order by c2,c3
- E where c1=x and c2=x and c5=? order by c2,c3
- create table t4 (
- c1 tinyint(1) not null default 0,
- c2 tinyint(1) not null default 0,
- c3 tinyint(1) not null default 0,
- c4 tinyint(1) not null default 0,
- c5 tinyint(1) not null default 0,
- index c1234(c1,c2,c3,c4)
- );
- insert into t4 values (1,3,5,6,7),(2,3,9,8,3),(4,3,2,7,5);
- 对于A:where c1=x and c2=x and c4>x and c3=x,
- 等价c1=x and c2=x and c3=x and c4>x
- 因此 c1,c2,c3,c4都能用上. 如下:
- mysql> explain select * from t4 where c1=1 and c2=2 and c4>3 and c3=3 \G
- id: 1
- select_type: SIMPLE
- table: t4
- type: range //使用索引的方式,使用的是范围索引(c4)
- possible_keys: c1234
- key: c1234
- key_len: 4 //4列#可以看出c1,c2,c3,c4索引都用上
- ref: NULL
- rows: 1
- Extra: Using where
- 对于B: select * from t4 where c1=1 and c2=2 and c4=3 order by c3
- c1 ,c2索引用上了,在c2用到索引的基础上,c3是排好序的,因此不用额外排序,c3,c4没发挥作用.
- mysql> explain select * from t4 where c1=1 and c2=2 and c4=3 order by c3 \G
- id: 1
- select_type: SIMPLE
- table: t4
- type: ref
- possible_keys: c1234
- key: c1234 //使用了多列索引,但是不一定所有的列都用到了,
- key_len: 2 //2列发挥了作用c1c2,
- ref: const,const
- rows: 1
- Extra: Using where
- 1 row in set (0.00 sec)
- mysql> explain select * from t4 where c1=1 and c2=2 and c4=3 order by c5 \G
- id: 1
- select_type: SIMPLE
- table: t4
- type: ref
- possible_keys: c1234
- key: c1234 //多列索引使用到了
- key_len: 2 //只是使用到了多列索引中的2列c1c2
- ref: const,const
- rows: 1
- Extra: Using where; Using filesort //Usingfilesort是二次排序,在磁盘或者内存里面,c5是没有顺序的所以取出来之后要排序。
- D语句:where c1=x and c5=x order by c2,c3,C1确定的基础上,c2是有序的,C2之下C3是有序的,因此c2,c3发挥的排序的作用.
- 因此,没用到filesort。只能使用一个索引,c2,c3的索引能够用来排序。
- mysql> explain select * from t4 where c1=1 and c5=2 order by c2,c3 \G
- id: 1
- select_type: SIMPLE
- table: t4
- type: ref
- possible_keys: c1234 //多列索引使用到了
- key: c1234
- key_len: 1 //只是使用到了多列索引中的1列c1,
- ref: const
- rows: 1
- Extra: Using where //没有Using filesort的文件排序,因为c2c3是排好序的
- mysql> explain select * from t4 where c1=1 and c5=2 order by c3 \G
- id: 1
- select_type: SIMPLE
- table: t4
- partitions: NULL
- type: ref
- possible_keys: c1234
- key: c1234
- key_len: 1
- ref: const
- rows: 1
- filtered: 20.00
- Extra: Using index condition; Using where; Using filesort //要排序,因为c3跳过了c2,所以要文件排序(比如国家下面的省,先要国家排序后在省排序。现在跳过国家去排省就要重新排序了),没法利用索引了。
- E: where c1=x and c2=x and c5=? order by c2,c3
- 这一句等价与 elect * from t4 where c1=1 and c2=3 and c5=2 order by c3;
- 因为c2的值既是固定的,参与排序时并不考虑
- mysql> explain select * from t4 where c1=1 and c2=3 and c5=2 order by c2,c3 \G
- *************************** 1. row ***************************
- id: 1
- select_type: SIMPLE
- table: t4
- type: ref
- possible_keys: c1234
- key: c1234
- key_len: 2 //用到了2列索引,
- ref: const,const
- rows: 1
- Extra: Using where //没有用到文件排序,说明c2c3索引都用到了,
- mysql> explain select * from t4 where c1=1 and c5=2 order by c2,c3 \G
- id: 1
- select_type: SIMPLE
- table: t4
- partitions: NULL
- type: ref
- possible_keys: c1234
- key: c1234
- key_len: 1 //用到了1列索引,
- ref: const
- rows: 1
- filtered: 20.00
- Extra: Using index condition; Using where //不用排序,因为先根据cw2排序然后根据c3排序,而c2c3是已经排好序的
- mysql> explain select * from t4 where c1=1 and c5=2 order by c3,c2 \G
- id: 1
- select_type: SIMPLE
- table: t4
- partitions: NULL
- type: ref
- possible_keys: c1234
- key: c1234
- key_len: 1 //用到了1列索引,
- ref: const
- rows: 1
- filtered: 20.00
- Extra: Using index condition; Using where; Using filesort //要排序,因为先根据c3排序再根据c2排序,(比如国家下面的省,先要国家排序后在省排序。现在跳过国家去排省就要重新排序了)
- mysql> explain select * from t4 where c1=1 and c2=3 and c5=2 order by c3,c2 \G
- *************************** 1. row ***************************
- id: 1
- select_type: SIMPLE
- table: t4
- partitions: NULL
- type: ref
- possible_keys: c1234
- key: c1234
- key_len: 2
- ref: const,const
- rows: 1
- filtered: 20.00
- Extra: Using index condition; Using where //没有排序,虽然c3在c2的前面,但是c2是定值。
- mysql> select cat_id,avg(shop_price) from goods group by cat_id;
- +--------+-----------------+
- | cat_id | avg(shop_price) |
- +--------+-----------------+
- | 2 | 823.330000 |
- | 3 | 1746.066667 |
- | 4 | 2297.000000 |
- | 5 | 3700.000000 |
- | 8 | 75.333333 |
- | 11 | 31.000000 |
- | 13 | 33.500000 |
- | 14 | 54.000000 |
- | 15 | 70.000000 |
- +--------+-----------------+
- mysql> explain select cat_id,avg(shop_price) from goods group by cat_id \G;
- id: 1
- select_type: SIMPLE
- table: goods
- partitions: NULL
- type: ALL
- possible_keys: NULL
- key: NULL
- key_len: NULL
- ref: NULL
- rows: 31
- filtered: 100.00
- Extra: Using temporary; Using filesort //分组操作的时候要先排序,这里Using temporary根据cat_id进行排序,使用的是临时表排序,如果将cat_id加上索引,那么cat_id已经排好序了,就不需要使用临时表来排序。(有可能加了索引还是使用了临时表,那是因为mysql做了自动优化.)
- mysql> alter table goods add index catid_index(cat_id);
- 对于C where c1=x and c4= x group by c3,c2
- 只用到c1索引,因为group by c3,c2的顺序无法利用c2,c3索引
- mysql> explain select * from t4 where c1=1 and c4=2 group by c3,c2 \G
- id: 1
- select_type: SIMPLE
- table: t4
- type: ref
- possible_keys: c1234
- key: c1234
- key_len: 1 #只用到c1,因为先用c3后用c2分组,导致c2,c3索引没发挥作用
- ref: const
- rows: 1
- Extra: Using where; Using temporary; Using filesort//并且还要排序
- mysql> explain select * from t4 where c1=1 and c4=2 group by c2,c3 \G
- id: 1
- select_type: SIMPLE
- table: t4
- type: ref
- possible_keys: c1234
- key: c1234
- key_len: 1
- ref: const
- rows: 1
- Extra: Using where
- 1 row in set (0.00 sec)
- 1.2 hash索引(数据散的放的)
- 在memory表里,默认是hash索引,hash的理论查询时间复杂度为O(1),O(1)是说任意给一行,理论上一次就能够找到。
- 疑问: 既然hash的查找如此高效,为什么不都用hash索引?
- 答:1:hash函数计算后的结果是随机的,如果是在磁盘上放置数据,随机查询是非常慢的。虽然算这行数据在哪里算的很快,但是去取这行数据的时候就很慢。
- 比如主键为id为例, 那么随着id的增长, id对应的行,在磁盘上随机放置.
- 2: 不法对范围查询进行优化,随机的范围查找慢。
- 3: 无法利用前缀索引. 比如在btree中,field列的值"hellopworld并加索引查询xx=helloword,自然可以利用索引, xx=hello,也可以利用索引(左前缀索引),而利用hash索引,因为hash('helloword')和hash('hello')就是截然不同的结果,所以没法利用前缀优化。
- 4: 排序也无法利用hash索引来优化.
- 5: 必须回行.就是说 通过索引拿到数据位置,必须回到表中取数据
mysql优化-----多列索引的左前缀规则的更多相关文章
- 【转】MYSQL数据库四种索引类型的简单使用--MYSQL组合索引“最左前缀”原则
MYSQL数据库索引类型包括普通索引,唯一索引,主键索引与组合索引,这里对这些索引的做一些简单描述: (1)普通索引 这是最基本的MySQL数据库索引,它没有任何限制.它有以下几种创建方式: 创建索引 ...
- 转:SQL 索引最左前缀原理
表结构和索引列 假设数据库中表是这样的: 我们只考虑一张表employees.titles: 索引是(emp_no,title,from_date) SHOW INDEX FROM employee ...
- MySQL优化之避免索引失效的方法
在上一篇文章中,通过分析执行计划的字段说明,大体说了一下索引优化过程中的一些注意点,那么如何才能避免索引失效呢?本篇文章将来讨论这个问题. 避免索引失效的常见方法 1.对于复合索引的使用,应按照索引建 ...
- mysql之多列索引
mysql的多列索引是经常会遇到的问题,怎样才能有效命中索引,是本文要探讨的重点. 多列索引使用的Btree,也就是平衡二叉树.简单来说就是排好序的快速索引方式.它的原则就是要遵循左前缀索引. 多个索 ...
- 性能测试四十二:sql案例之联合索引最左前缀
联合索引:一个索引同时作用于多个字段 联合索引的最左前缀: A.B.C3个字段--联合索引 这个时候,可以使用的查询条件有:A.A+B.A+C.A+B+C,唯独不能使用B+C,即最左侧那个字段必须匹配 ...
- mysql 优化实例之索引创建
mysql 优化实例之索引创建 优化前: pt-query-degist分析结果: # Query 23: 0.00 QPS, 0.00x concurrency, ID 0x78761E301CC7 ...
- MySQL索引解析(联合索引/最左前缀/覆盖索引/索引下推)
本节内容: 1)索引基础 2)索引类型(Hash索引.有序数组.B+树) 3)索引的几个常见问题 1)联合索引 2)最左前缀原则 3)覆盖索引 4)索引下推 1. 索引基础 索引对查询的速度有着至关重 ...
- Mysql优化系列之索引性能
实际上,前面的数据类型和表结构设计优化不能算优化,只能算规范,也就是说在设计表的时候,应该且必须做到这些 索引是sql优化的核心部分,在<高性能Mysql>中单独抽出一章讲,也印证了其重要 ...
- 0104探究MySQL优化器对索引和JOIN顺序的选择
转自http://www.jb51.net/article/67007.htm,感谢博主 本文通过一个案例来看看MySQL优化器如何选择索引和JOIN顺序.表结构和数据准备参考本文最后部分" ...
随机推荐
- [luoguP2221] [HAOI2012]高速公路(线段树)
传送门 考虑每一段对答案的贡献 用每一段的左端点来表示当前这一段,那么区间就变成了[1,n-1] 如果询问区间[l,r],其中一个点的位置为x,则它对答案的贡献为(x-l)*(r-x)*s[x](s[ ...
- 算法复习——LCT(bzoj2049洞穴勘测)
题目: Description 辉辉热衷于洞穴勘测.某天,他按照地图来到了一片被标记为JSZX的洞穴群地区.经过初步勘测,辉辉发现这片区域由n个洞穴(分别编号为1到n)以及若干通道组成,并且每条通道连 ...
- spring之Annotation
spring除了提供了@Autowired,还提供了以下几类annotation. 1.@Component, @Repository, @Service, @Controller @Reposito ...
- P1582 倒水 (二进制)
题目描述 一天,CC买了N个容量可以认为是无限大的瓶子,开始时每个瓶子里有1升水.接着~~CC发现瓶子实在太多了,于是他决定保留不超过K个瓶子.每次他选择两个当前含水量相同的瓶子,把一个瓶子的水全部倒 ...
- 【kmp+最小循环节】poj 2406 Power Strings
http://poj.org/problem?id=2406 [题意] 给定字符串s,s=a^n,a是s的子串,求n最大是多少 [思路] kmp中的next数组求最小循环节的应用 例如 ababab ...
- 【2018.10.27】CXM笔记
一个数大约有 $O(\sqrt(n)/log^2(n))$ 个约数. 1. 一个棋盘,每个格子最开始都是白的.可以按一个格子,它马跳(日字跳)能到达的 $8$ 个格子反色(当前格不反色).问有多少种方 ...
- 【php wamp的配置】
- 安卓解析XML文件
安卓解析XML文件 主要有三种方式:DOM解析.SAX解析.PULL解析 其中: DOM解析为等XMl文件全部加载后,然后根据需要解析的内容解析出所需的内容数据. SAX解析为从XML文件中执行一行, ...
- Objective C语言中nil、Nil、NULL、NSNull的区别
以下内容是基于搜集整理的网上资料,供参考. nil:指向Objective C语言中对象的空指针,其定义值为(id)0. Nil:指向Objective C语言中类(Class)的空指针,其定义值为( ...
- npm 安装vue-cli
TIP:win10下安装,使用管理员身份进行,否则会有权限限制. 1,安装完成node,node有自带的npm,可以直接在cmd中,找到nodeJs安装的路径下,进行命令行全局安装vue-cli.(n ...