IO永远是数据库最容易瓶颈的地方,这是由数据库的职责所决定的,大部分数据库操做中超过90%的时间都是 IO 操做所占用的,减小 IO 次数是 SQL 优化中须要第一优先考虑,固然,也是收效最明显的优化手段。mysql
除了 IO 瓶颈以外,SQL优化中须要考虑的就是 CPU 运算量的优化了。order by, group by,distinct … 都是消耗 CPU 的大户(这些操做基本上都是 CPU 处理内存中的数据比较运算)。当咱们的 IO 优化作到必定阶段以后,下降 CPU 计算也就成为了咱们 SQL 优化的重要目标。sql
明确了优化目标以后,咱们须要肯定达到咱们目标的方法。对于 SQL 语句来讲,达到上述2个目标的方法其实只有一个,那就是改变 SQL 的执行计划,让他尽可能“少走弯路”,尽可能经过各类“捷径”来找到咱们须要的数据,以达到 “减小 IO 次数” 和 “下降 CPU 计算” 的目标。数据库
explain sql;缓存
对于彻底相同的sql,使用已经存在的执行计划,从而跳过解析和生成执行计划的过程。服务器
应用场景:不常常变的表,服务器收到该表的大量相同查询。查询必须是彻底相同的(逐字节相同)才可以被认为是相同的并发
Mysql 判断是否命中缓存的办法很简单,首先会将要缓存的结果放在引用表中,而后使用查询语句,数据库名称,客户端协议的版本等因素算出一个hash值,这个hash值与引用表中的结果相关联。若是在执行查询时,根据一些相关的条件算出的hash值能与引用表中的数据相关联,则表示查询命中。函数
缓存机制失效高并发
额外的消耗优化
区分in和existspa
select * from 表A where id in (select id from 表B)
这句至关于
select * from 表A where exists(select * from 表B where 表B.id=表A.id)
exists:对于表A的每一条数据,都执行select * from 表B where 表B.id=表A.id的存在性判断,若是表B中存在表A当前行相同的id,则exists为真,该行显示,不然不显示。
IN适合于外表大而内表小的状况;EXISTS适合于外表小而内表大的状况。
尽可能用join代替子查询
MySQL须要为内层查询语句的查询结果创建一个临时表。而后外层查询语句在临时表中查询记录。查询完毕后,MySQL须要插销这些临时表。因此在MySQL中可使用链接查询来代替子查询。链接查询不须要创建临时表,其速度比子查询要快。
尽可能少排序
排序操做会消耗较多的 CPU 资源,因此减小排序能够在缓存命中率高等 IO 能力足够的场景下会较大影响 SQL 的响应时间。
减小参与排序的记录条数
非必要不对数据进行排序
尽可能避免select *
尽可能少or
不少时候使用 union all 或者是union(必要的时候)的方式来代替“or”会获得更好的效果。
尽可能用 union all 代替 union
union 和 union all 的差别主要是前者须要将两个(或者多个)结果集合并后再进行惟一性过滤操做,这就会涉及到排序,增长大量的 CPU 运算,加大资源消耗及延迟。因此当咱们能够确认不可能出现重复结果集或者不在意重复结果集的时候,尽可能使用 union all 而不是 union。
尽可能早过滤
在 SQL 编写中一样可使用这一原则来优化一些 Join 的 SQL。好比咱们在多个表进行分页数据查询的时候,咱们最好是可以在一个表上先过滤好数据分好页,而后再用分好页的结果集与另外的表 Join,这样能够尽量多的减小没必要要的 IO 操做,大大节省 IO 操做所消耗的时间。
优先优化高并发的 SQL,而不是执行频率低某些“大”SQL
对于破坏性来讲,高并发的 SQL 老是会比低频率的来得大,由于高并发的 SQL 一旦出现问题,甚至不会给咱们任何喘息的机会就会将系统压跨。而对于一些虽然须要消耗大量 IO 并且响应很慢的 SQL,因为频率低,即便遇到,最多就是让整个系统响应慢一点,但至少可能撑一下子,让咱们有缓冲的机会。
尽可能避免where子句中对字段进行null值的判断
会致使引擎放弃索引,进而进行全表扫描。
尽可能不要给数据库留null值,尽量地使用not null填充数据库。能够为每一个null型的字段设置一个和null对应的实际内容表述。
避免在where中使用!=, >, <操做符
不然引擎放弃使用索引,进行全表扫描
经常使用查询字段建索引
in和not in关键词慎用,容易致使全表扫面
避免在where子句中对字段进行表达式操做或进行函数操做
会致使引擎放弃使用索引
选择最有效率的表名顺序(只在基于规则的优化器中有效)
Oracle的解析器按照从右到左的顺序处理FROM子句中的表名,FROM子句中写在最后的表(基础表 driving table)将被最早处理,在FROM子句中包含多个表的状况下,你必须选择记录条数最少的表做为基础表。若是有3个以上的表链接查询, 那就须要选择交叉表(intersection table)做为基础表, 交叉表是指那个被其余表所引用的表。
WHERE子句中的链接顺序
Oracle采用自下而上的顺序解析WHERE子句,根据这个原理,表之间的链接必须写在其余WHERE条件以前, 那些能够过滤掉最大数量记录的条件必须写在WHERE子句的末尾。