索引优化原则
- 全值匹配
- 最佳左前缀法则: 如果索引了多列,要遵守最左前缀法则。指的是查询从索引的最左前列开始并且不跳过索引中的列。
- 不在索引列上做任何操作(计算、函数、(自动or手动)类型转换),会导致索引失效而转向全表扫描
- 存储引擎不能使用索引中范围条件右边的列
- 尽量使用覆盖索引(只访问索引的查询(索引列包含查询列)),减少select *语句
- mysql在使用不等于(!=或者<>)的时候无法使用索引会导致全表扫描
- is null,is not null 也无法使用索引
- like以通配符开头(’$abc…’)mysql索引失效会变成全表扫描操作
- 字符串不加单引号索引失效
- 少用or,用它连接时很多情况下索引会失效
- 小表驱动大表
通俗理解口诀:
全值匹配我最爱,最左前缀要遵守;
带头大哥不能死,中间兄弟不能断;
索引列上少计算,范围之后全失效;
LIKE百分写最右,覆盖索引不写星;
不等空值还有or,索引失效要少用。
问题一:解决like’%字符串%'索引不被使用的方法?
优化%字符串是不可能的了,所以使用覆盖索引,查询字段必须是建立覆盖索引字段。
注意:当覆盖索引指向的字段是varchar(380)及380以上的字段时,覆盖索引会失效!
问题二:in和exsits的区别
原则:小表驱动大表,即小的数据集驱动大的数据集
in:当B表的数据集必须小于A表的数据集时,in优于exists
select * from A where id in (select id from B)#等价于: for select id from B for select * from A where A.id = B.id
exists:当A表的数据集小于B表的数据集时,exists优于in
将主查询A的数据,放到子查询B中做条件验证,根据验证结果(true或false)来决定主查询的数据是否保留
select * from A where exists (select 1 from B where B.id = A.id) #等价于 for select * from A for select * from B where B.id = A.id#A表与B表的ID字段应建立索引
注意:
1、EXISTS (subquery)只返回TRUE或FALSE,因此子查询中的SELECT * 也可以是SELECT 1或select X,官方说法是实际执行时会忽略SELECT清单,因此没有区别
2、EXISTS子查询的实际执行过程可能经过了优化而不是我们理解上的逐条对比
3、EXISTS子查询往往也可以用JOIN来代替,何种最优需要具体问题具体分析
问题三:count(1),count(*)和count(field)区别
注意:在MySQL中,查询研究得出这个和MySQL中用什么引擎有关,比如InnoDB和MyISAM在处理这count(*)、count(1)、count(field)都有不同的方式,还有就是和版本都有关系,不同的版本会对查询进行优化处理等等。
- count(*)对行的数目进行计算,包含NULL count(column)对特定的列的值具有的行数进行计算,不包含NULL值。
- count()还有一种使用方式,count(1)这个用法和count(*)的结果是一样的。
- 任何情况下select count(*)from tablename是最优选择;
- 尽量减少select count(*) from tablename where COL =‘value’这种查询;
- 杜绝select count(COL) from tablename where COL2 =‘value’的出现。
- 如果表没有主键,那么count(1)比count(*)快。
- 如果有主键,那么count(主键,联合主键)比count(*)快。
- 如果表只有一个字段,count(*)最快。
- count(1)跟count(主键)一样,只扫描主键。count(*)跟count(非主键)一样,扫描整个表。明显前者更快一些。
- 若含有where语句,则会优先where中条件索引。
explain