网上有关SQL优化的方案有很多,但多是杂乱无章。近日闲暇抽空整理了一下,方便大家以后的查阅,若发现其中有什么问题和不全,欢迎大家在下面纠正和补充:
1. 对于SQL语句的性能优化,主要体现在对于查询语句的优化上,要尽量避免全表扫描,首先需要注意的就是在 where 和 order by 涉及的列上添加索引,索引的作用就相当于告诉数据库直接从哪里取数 据就可以了,不用全部查找一遍;
2. 慎用 in 和 not in,使用 in 写出来的SQL的优点是比较容易写及清晰易懂, 但是用 in 的SQL语句执行效率非常低,下面是一个例子:
SELECT d.eid FROM dept d WHERE d.eid IN (SELECT e.eid FROM employee e)
使用 exists 代替 in 是一个不错的选择:
SELECT d.eid FROM dept d WHERE EXISTS (SELECT 1 FROM employee e WHERE e.eid = d.eid)
同理,not in 也用not exists 来替代;
3. 尽量避免在 SQL语句中对字段进行 NULL 值判断,对NULL值的判断会导致引擎放弃使用索引而去做全表扫描,推荐做法为:用其它相同功能的操作运算来代替;例如:
SELECT e.name, e.sex, e.addr FROM employee e WHERE e.eid IS NOT NULL
优化方案为: SELECT e.name, e.sex, e.addr FROM employee e WHERE e.eid > 0
总之,最好不要给数据库留下 NULL 值,使用 NOT NULL 填充数据库;
4. 尽量不要用between .. and ... ,使用 >= 和 <= 来代替:
SELECT d.did, d.dno, d.eid FROM dept d WHERE d.did BETWEEN 1 AND 5
替换为: SELECT d.did, d.dno, d.eid FROM dept d WHERE d.did >= 1 AND d.did <= 5 ;
5. LIKE操作符可以应用通配符查询,里面的通配符组合可能达到几乎是任意的查询,但是如果用得不好会产生性能上的问题,例如使用含有 like '%bc%' 的语句进行查询的时候不会引用索引,而使用
like 'bc%' 可以使用索引,虽然在很多情况下可能无法避免这种情况,但是一定要心中有底,通配符如此使用会降低查询速度。
6. 尽量避免在 where 子句中使用 or 来连接条件,如果一个字段有索引而另外一个字段没有索引,将导致数据库引擎放弃放弃使用索引而进行全表扫描,例如:
SELECT d.dname FROM dept d WHERE d.did = 1 OR d.eid = 1001
可以换成: SELECT d.dname FROM dept d WHERE d.did = 1 UNION SELECT d.dname FROM dept d WHERE d.eid = 10017. 使用 group by 时, 最好先把不用的数据排除掉,缩小查询的范 围,从而提升查询效率。可以先在 where 条件里面排除无关数据,然后再进行 group by 操作。
8. 尽量避免在 where 子句中对字段进行表达式或函数操作,这将导致引擎放弃使用索引而进行全表搜索;
9. 如果在 where 子句中使用参数,也会导致全表扫描。因为SQL只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。然 而,如果在编译时建立 访问计划,变量的值还是未知的,因而无法作为索引选择的输入项。
SELECT d.dname FROM dept d WHERE d.did = @did
解决的办法是强制使用索引:SELECT d.dname FROM dept d WITH(INDEX(索引名)) WHERE d.did = @did
10. 在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序 相一致。
11. 索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而 定。一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有 必要。
12. Update 语句,如果只更改1、2个字段,不要 Update 全部字段,否则频繁调用会引起明显的性能消耗,同时带来大量日志。
13. 对于 UNION 操作符,UNION在进行表链接后会筛选掉重复的记录,所以在表链接后会对所产生的结果集进行排序运算,删除重复的记录再返回结果。而实际大部分应用中是不会产生重复的记录。
SELECT * FROM dept UNION SELECT * FROM emp
这个SQL在运行时先取出两个表的结果,再用排序空间进行排序删除重复的记录,最后返回结果集,如果表数据量大的话可能会导致用磁盘进行排序。推荐做法是在已知没有重复记录的前提下,使用 UNION ALL 操作符替代 UNION,因为 UNION ALL 操作只是简单的将两个结果合并后就返回。14. 不要用 select * from 【表名】 ,用select 【列名】 from 【表名】 ,不要返回用不到的字段。除非不知道表字段时测试用。
15. 程序进行select 时,后面都要commit,这会释放占用的资源。
16. 尽量不要使用游标,因为游标的效率较低,使用游标不仅占用内存,而且还用不可思议的方式锁定表,它们可以使DBA所能做的一切性能优化等于没做。游标里每执行一次fetch就等于执行一次select。游标并不是不可使用,但如果游标操作的数据超过一万行,就应该考虑改写了。
17. 复杂的SQL往往会消耗大量的资源,能用函数解决,就用函数。
18. 尽量避免大事物操作,提高系统的并发能力。