mysql怎么切换偏移 mysql怎么切换表( 三 )


4.索引的使用场景
(1)索引检索:检索数据时使用索引 。
(2)索引排序: 如果order by 排序需要的字段上存在索引,则可能使用到索引 。
(3)索引覆盖: 索引拥有的关键字内容 , 覆盖了查询所需要的全部数据,此时,就不需要在数据区获取数据,仅仅在索引区即可 。覆盖就是直接在索引区获取内容,而不需要在数据区获取 。例如: select name from A where name like '小明%';
建立索引索引时,不能仅仅考虑where检索,同时考虑其他的使用场景 。(在所有的where字段上增加索引,就是不合理的)
5.前缀索引
前缀索引是建立索引关键字一种方案 。通常会使用字段的整体作为索引关键字 。有时,即使使用字段前部分数据,也可以去识别某些记录 。就比如一个班级里 , 我要找王xx , 假如姓王的只有1个人,那么就可以建一个关键字为'王'的前缀索引 。语法:Index `index_name` (`index_field`(N))使用index_name前N个字符建立的索引 。
6.索引失效
(1) 应尽量避免在 where 子句中使用 != 或操作符,否则将引擎放弃使用索引而进行全表扫描;
(2) 应尽量避免在 where 子句中使用 or 来连接条件 , 如果一个字段有索引,一个字段没有索引,将导致引擎放弃使用索引而进行全表扫描;
(3) 应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描;
(4)应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描;如select id from t where num/2 = 100;
(5) 应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描;如:select id from t where substring(name,1,3) = ’abc’ ;
(6)应尽量避免在where子句中对字段进行类型转换,这将导致引擎放弃使用索引而进行全表扫描; 如果列类型是字符串,那一定要在条件中将数据使用引号引用起来,如select id from t where id = 1;如果id字段在表设计中是varchar类型,那么即使id列上存的是数字,在查询时也一定要用varchar去匹配,sql应改为select id from t where id = '1';
(7)应尽量避免在where子句中单独引用复合索引里非第一位置的索引;
join 的两种算法:BNL 和 NLJ
NLJ(Nested Loop Join)嵌套循环算法;以如下 SQL 为例:
select * from t1 join t2 on t1.a=t2.a
SQL 执行时内部流程是这样的:
1. 先从 t1(假设这里 t1 被选为驱动表)中取出一行数据 X;
2. 从 X 中取出关联字段 a 值 , 去 t2 中进行查找 , 满足条件的行取出;
3. 重复1、2步骤,直到表 t1 最后一行循环结束 。
这就是一个嵌套循环的过程,如果在被驱动表上查找数据时可以使用索引,总的对比计算次数等于驱动表满足 where 条件的行数 。假设这里 t1、t2都是1万行,则只需要 1万次计算,这里用到的是Index Nested-Loops Join(INLJ,基于索引的嵌套循环联接) 。
如果 t1、t2 的 a 字段都没有索引,还按照上述的嵌套循环流程查找数据呢?每次在被驱动表上查找数据时都是一次全表扫描,要做1万次全表扫描,扫描行数等于 1万+1万*1万 , 这个效率很低,如果表行数更多,扫描行数动辄几百亿,所以优化器肯定不会使用这样的算法,而是选择 BNL 算法;
BNLJ(Block Nested Loop Join)块嵌套循环算法;
1. 把 t1 表(假设这里 t1 被选为驱动表)满足条件的数据全部取出放到线程的 join buffer 中;
2. 每次取 t2 表一行数据,去 joinbuffer 中进行查找,满足条件的行取出 , 直到表 t2 最后一行循环结束 。