在多数情况下,Oracle使用索引来更快地遍历表,优化器主要根据定义的索引来提高性能。但是,如果在SQL语句的where子句中写的SQL代码不合理,就会造成优化器删去索引而使用全表扫描,一般就这种SQL语句就是所谓的劣质SQL语句。在编写SQL语句时我们应清楚优化器根据何种原则来删除索引,这有助于写出高性能的SQL语句。
在下列情况下,Mysql不会使用已有的索引:
- 如果 mysql 估计使用索引比全表扫描更慢,则不使用索引。例如:如果 key_part 1均匀分布在 1 和 100 之间,下列查询中使用索引就不是很好:
SELECT * FROM table_name where key_part1 > 1 and key_part1 < 90 - 如果使用 heap 表并且 where 条件中不用=索引列,其他 > 、 < 、 >= 、 <= 均不使 用索引(MyISAM和innodb表使用索引);
- 使用or分割的条件,如果or前的条件中的列有索引,后面的列中没有索引,那么涉及到的索引都不会使用。
- 如果创建复合索引,如果条件中使用的列不是索引列的第一部分;(不是前缀索引)
- 如果 like 是以%开始;
- 对 where 后边条件为字符串的一定要加引号,字符串如果为数字 mysql 会自动转 为字符串,但是不使用索引。
操作符优化
IN、 NOT IN操作符
- 分析:ORACLE试图将其转换成多个表的连接,如果转换不成功则先执行IN里面的子查询,再查询外层的表记录,如果转换成功则直接采用多个表的连接方式查询。由此可见用IN的SQL至少多了一个转换的过程。一般的SQL都可以转换成功,但对于含有分组统计等方面的SQL就不能转换了。
- 替代方案:用EXISTS、NOT EXISTS 方案代替
IS NULL 或IS NOT NULL操作
判断字段是否为空一般是不会应用索引的,因为索引是不索引空值的。不能用null作索引,任何包含null值的列都将不会被包含在索引中。即使索引有多列这样的情况下,只要这些列中有一列含有null,该列就会从索引中排除。也就是说如果某列存在空值,即使对该列建索引也不会提高性能。任何在where子句中使用is null或is not null的语句优化器是不允许使用索引的。
替代方案1: 用其它相同功能的操作运算代替,如:a is not null 改为 a>0 或a>’’等
- 替代方案2:不允许字段为空,而用一个缺省值代替空值,如申请中状态字段不允许为空,缺省为申请。
> 、!=、< 操作符
分析:大于或小于操作符一般情况下是不用调整的,因为它有索引就会采用索引查找,但有的情况下可以对它进行优化,如一个表有100万记录,一个数值型字段A,30万记录的A=0,30万记录的A=1,39万记录的A=2,1万记录的A=3。那么执行A>2与A>=3的效果就有很大的区别了,因为A>2时ORACLE会先找出为2的记录索引再进行比较,而A>=3时ORACLE则直接找到=3的记录索引。
替代方案:在有些情况下实验>=及<=
LIKE操作符
分析:LIKE操作符可以应用通配符查询,里面的通配符组合可能达到几乎是任意的查询,但是如果用得不好则会产生性能上的问题,如LIKE ‘%5400%’ 这种查询不会引用索引,而LIKE ‘X5400%’则会引用范围索引。
替代方案:尽可能使用’字符%’的形式
UNION操作符
分析:UNION在进行表链接后会筛选掉重复的记录,所以在表链接后会对所产生的结果集进行排序运算,删除重复的记录再返回结果。实际大部分应用中是不会产生重复的记录。
替代方案: 采用UNION ALL操作符替代UNION,因为UNION ALL操作只是简单的将两个结果合并后就返回。
Order by 语句
分析:ORDER BY语句决定了Oracle如何将返回的查询结果排序。任何在Order by语句的非索引项或者有计算表达式都将降低查询速度。ORDER BY 子句只在两种严格的条件下使用索引:ORDER BY中所有的列必须包含在相同的索引中并保持在索引中的排列顺序、ORDER BY中所有的列必须定义为非空.
替代方案:写order by语句使用索引,也可以为所使用的列建立另外一个索引,同时应绝对避免在order by子句中使用表达式。或者用where代替order by。
OR 语句
分析: 应尽量避免在 where 子句中使用 or 来连接条件, 否则将导致引擎放弃使用索引而进行全表扫描。
替代方案: 可以 使用UNION合并查询:select id from t where num=10 or num=20 替换为 select id from t where num=10 union all select id from t where num=20
COUNT语句
对于有些场景,因为数据库对 count() 计数操作做了一些特别的优化。count() 优于count(1)和count(primary_key)
替代方案:count(*) 代替count(1)和 count(primary_key)
SQL书写方式优化
SELECT使用具体字段
分析:在select语句中,返回的列越少使用性能越高。
替代方案:尽可能select a from 表名代替select * from 表名。
WHERE后面条件顺序的影响
- 分析:
WHERE子句后面的条件顺序对大数据量表的查询会产生直接的影响。如:
select * from a where dy_dj = ‘1KV以下’ and xh_bz=1
select * from a where xh_bz=1 and dy_dj = ‘1KV以下’
以上两个SQL中dy_dj(电压等级)及xh_bz(销户标志)两个字段都没进行索引,所以执行的时候都是全表扫描,第一条SQL的dy_dj = ‘1KV以下’条件在记录集内比率为99%,而xh_bz=1的比率只为0.5%,在进行第一条SQL的时候99%条记录都进行dy_dj及xh_bz的比较,而在进行第二条SQL的时候0.5%条记录都进行dy_dj及xh_bz的比较,以此可以得出第二条SQL的CPU占用率明显比第一条低。