查询优化几个方向
1、尽量避免全文扫描,给相应字段增加索引,应用索引来查询
2、删除不用或者重复的索引
3、查询重写,等价转换(谓词、子查询、连接查询)
4、删除内容重复不必要的语句,精简语句
5、整合重复执行的语句
6、缓存查询结果
5.2、索引缺点
1、索引需要占用一定的存储空间
2、数据插入、更新、删除时会受索引的影响,性能会降低。因为数据变更索引也需要进行更新
3、多个索引,优化器需要耗时则优选择
5.3、索引选择
1、数据量大时采用
2、数据高度重复时,不采用
3、查询取出数据大于20%,将采用全文扫描,不用索引
5.4、索引细究
资料查询:
MySQL中的InnoDB、MyISAM都是B-Tree类型索引
B-Tree包含:PRIMARY KEY, UNIQUE, INDEX, and FULLTEXT
B-Tree类型索引不支持(即字段使用以下符号时,将不采用索引):
>, <, >=, <=, BETWEEN, !=, <>,like ‘%**’
如何激活覆盖索引呢?什么样才是特定场景呢?
索引字段,在select中出现就是了。
复合索引还可能有其他的特殊场景。例如,三列复合索引,仅需要在select、where、group by、order by中,任意一个地方出现一次复合索引最左边列就可以激活使用覆盖索引了。
查看:
EXPLAIN中Extra显示有Using index表示这条语句采用了覆盖索引。
其他索引优化方法:
1、使用索引关键字作为连接的条件
2、复合索引使用
3、索引合并or and,将涉及到的字段合并成复合索引 ???????????
4、where、和group by涉及字段加索引
子查询展开只能展开简单的查询,若子查询含有聚集函数、GROUP BY、DISTINCT,则不能上拉。
select * from t1 (select*from tab where id>10) as t2 where t1.age>10 and t2.age<25;
select*from t1,tab as t2 where t1.age>10 and t2.age<25 and t2.id>10;
具体步骤:
1、from与from合并,修改相应参数
2、where与where合并,用and连接
3、修改相应的谓词(in改=)
7、等价谓词重写:
1、BETWEEEN AND改写为 >= 、<=之类的。实测:十万条数据,重写前后时间,1.45s、0.06s
2、in转换多个or。字段为索引时,两个都能用到索引,or效率相对in好一点
3、name like ‘abc%’改写成name>=’abc’ and name<’abd’;
注意:百万级数据测试,name没有索引之前like比后一种查询快;给字段增加索引后,后面的快一点点,相差不大,因为两种方法在查询的时候都用到了索引。
8、条件化简与优化
3、常量传递。a=b and b=2转换为 a=2 and b=2。尽量不使用变量a=b或a=@var
5、where等号右边尽量不出现表达式计算;where中不要对字段进行表达式计算、函数的使用
6、恒等变换、不等式变换。例:测试百万级数据a>b and b>10变为a>b and a>10 and b>10优化显著
3、可以将筛选条件最为严格的表作为外表(连接顺序最前面,是多层循环体的外循环层),
可以减少不必要的I/O开销,能加快算法执行的速度。
on a.id=b.id与where a.id=b.id的差别,on则表进行连接,where则进行数据对比
注意:前提必须是结果为NULL决绝(即条件限制不要NULL数据行,语意上是内连接)
10、其他查询优化
1、以下将会造成放弃索引查询,采用全文扫描
1.1、where 子句中使用!=或<>操作符 注意:主键支持。非主键不支持
1.2、避免使用or
经测试,并非是使用了or就一定不能使用索引,大多情况下是没用到索引,但还有少数情况是用到的,因此具体情况具体分析。
类似优化:
select * from tab name=’aa’ or name=’bb’;
=>
select * from tab name=’aa’
union all
select * from tab name=’bb’;
实测:
1、十万数据测试,没任何索引的情况下,上面比下面的查询速率快一倍。
2、三十万数据测试,aa与bb都是单独索引情况下,下面的查询速率比or快一点。
1.3、避免使用not in
not in一般不能使用索引;主键字段可以
1.4、where中尽量避免使用对null的判断
1.5、like不能前置百分号 like ‘%.com’
2、将exists代替in
select num from a where num in(select num from b)
select num from a where exists(select 1 from b where num=a.num)
一百万条数据,筛选59417条数据用时6.65s、4.18s。没做其他优化,仅仅只是将exists替换in。
3、字段定义是字符串,查询时没带引号,不会用索引,将会进行全文扫描。
3. 索引字段上进行运算会使索引失效。
尽量避免在WHERE子句中对字段进行函数或表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如: SELECT * FROM T1 WHERE F1/2=100 应改为: SELECT * FROM T1 WHERE F1=100*2
5. 尽量使用数字型字段
一部分开发人员和数据库管理人员喜欢把包含数值信息的字段 设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接回逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了