sql语句中使⽤函数会耗费性能吗_挽救数据库性能的30条黄⾦
法则
1. 优化查询,应尽量避免全表扫描,应该在⽤于检索数据和排序数据的字段上建⽴索引,如where⼦句⽤于搜索,order by⼦句⽤于排序,所以在这两个⼦句涉及到的字段上需要建⽴索引。
2. 应该在where⼦句中使⽤否定的操作符,如不等于(!=或<>)、否则数据库引擎将放弃使⽤索引⽽进⾏全表扫描。
3. 在尽量避免在where⼦句中使⽤或(or)作为连接条件,否则数据库引擎将放弃使⽤索引⽽进⾏全表扫描。
如下⾯的SQL语句可能会带来性能问题
select id,name,age from persons
where name = 'Bill' or age > 30
由于这条SQL语句使⽤了or,所以数据库引擎会进⾏全表扫描,为了避免全表扫描,可以将这条SQL语句改成下⾯的形式。
select id,name,age from persons where name = 'Bill'
union all
select id,name,age from persons where num = 20
4. 应该尽量避免在where⼦句中使⽤null进⾏判断,否则数据库引擎将放弃使⽤索引⽽进⾏全表扫描。
先看下⾯的SQL语句:
select id,name,age from persons where age is null
为了避免使⽤null,可以设置age字段的默认值为0,这样就可以通过下⾯的SQL语句达到同样的结果。
select id,name,age from persons where age = 0
5. 尽量不⽤使⽤like检索数据,因为也会导致数据库引擎将放弃使⽤索引⽽进⾏全表扫描。
例如,下⾯的SQL语句执⾏的效率会⾮常低:
select id,name,age from persons where name like '%John%'
如果真想进⾏模糊查询,可以使⽤全⽂检索。
6. 在where⼦句中应尽量避免在字段中使⽤表达式(包括函数运算、算数运算等),否则据库引擎将放弃使⽤索引⽽进⾏全表扫描。
例如,下⾯的SQL语句执⾏的性能⽐较差
select id,name,age from persons age / 2 > 12
应该利⽤表达式变换,改成下⾯的形式:
select id,name,age from persons age > 2 * 12
或者⼲脆改成下⾯的形式:
select id,name,age from persons age > 24
7. 应尽量避免使⽤in和not in,否则也会导致全表扫描。
如并不推荐下⾯的写法:
select id, name,age from persons where age in (22,23,24)
如果数值是连续的,应该使⽤between,⽽不要⽤in,如果数值是不连续的,可以分成多个SQL,⽤union all连接查询结果。
select id,name,age from persons where age between 22 and 24
select id,name,age from persons where age = 22
union all
select id,name,age from persons where age = 26
union all
select id,name,age from persons where age = 30
8. 应该尽量避免在where⼦句中使⽤参数,否则也将导致全表扫描。这是因为参数需要在SQL运⾏时才进⾏替换,⽽SQL优化(使⽤索引属于优化的⼀部分)是在编译时进⾏的。所以数据库引擎在检索到参数时,由于参数的具体指是未知的,所以也就⽆法优化了,当然也就⽆法使⽤索引了。
不使⽤索引的SQL语句:
select id,name,age from persons where name = @name
为了使⽤索引,可以改成下⾯强制使⽤索引的⽅式:
select id,name,age from persons with(index(name_index)) where name = @name
insert语句字段顺序其中name_index是建⽴在name字段上的索引名。
9. 尽量不要执⾏⼀些没意义的查询,如条件完全为false的查询:
select id,name,age into persons1 from persons where age < 0
这样的代码会返回⼀个空结果集,⽽且会⼤量消耗系统资源,如果真的想建⼀个空表,应该直接⽤create table语句。
10. 如果使⽤的索引是符合索引,只有使⽤该符合索引的第1个字段作为条件时才能保证数据库引擎使⽤该符合索引,否则该符合索引不会被使⽤。并且应该尽可能让字段顺序与索引顺序⼀致。例如,name_index是first_name和last_name字段的符合索引,使⽤下⾯的SQL语句会使⽤该索引。
select id,first_name,last_name from persons where first_name = 'Bill'
11. 如果⾮要在SQL语句中使⽤in,那么使⽤exists代替in是⼀个好主意:
select id,num from t where num in (select num from h)
应该⽤下⾯的SQL语句代替:
select id,num form t where exists(select 0 from h where num = t.num)
12. 索引并不是在任何时候都有效,如果索引列有⼤量重复的数据,那么数据库引擎可能不会去利⽤索引。例如,sex字段的值只有两种可能:male和female,可能这两个值各占⼀半,这样在sex字段上建⽴索引就没有任何意义。
13. 能使⽤数值型字段就使⽤数值型字段。因为⽐较数值型字段的效率要远⽐字符型字段的效率⾼,这是因为⽐较字符型的值,要⼀个字母⼀个字母地⽐较,⽽数值型的值,只是⽐较⼀个数。所以如果只包含数值信息的值,应该尽量使⽤数值类型的字段。例如,age、salary 等。
14. 应尽量避免使⽤固定长度的字段,如char、nchar。使⽤可变长度的字段是⼀个⾮常好的选择。因为可变长度字段占⽤的空间是按需分配的,所以占⽤空间⽐较少。对于查询来说,毫⽆疑问,当然是占⽤空间⼩的字段的查询效率更⾼了。
15. 尽量按需返回字段和记录,例如:
select id,name,age from persons where age > 20
尽量如要使⽤“*”返回所有不需要的字段,也不需要⼀下就查询出所有的记录,如下⾯的SQL语句在数据量很⼤时查询效率是⾮常低的。
select * from persons
16. 索引有利有弊,增加索引,可以提⾼select的执⾏效率,但付出的代价是在进⾏insert和update操作时,可能会降低效率。因为进⾏insert和update操作时通常需要重建索引。所以在⼀个表中并不是索引越多越好。我的建议如下:
(1)如果⼀个表⼤多数时进⾏的是select操作,那么索引多⼀些⼤多数时候确实可以提升性能,但这有⼀个前提,就是不能频繁进⾏insert和update操作。
(2)⼀个表中的索引数不能太多,最好不要超过6个,否则就好考虑优化⼀下数据库了。
17. 应尽可能的避免更新 clustered 索引数据列,因为 clustered 索引数据列的顺序就是表记录的物理存储顺序,⼀旦该列值改变将导致整个表记录的顺序的调整,会耗费相当⼤的资源。若应⽤系统需要频繁更新 clustered 索引数据列,那么需要考虑是否应将该索引建为clustered 索引。
18. 应尽量避免向客户端返回⼤理数据,如果数据量过⼤,应该改变⼀下需求,或采⽤分页返回的⽅式,如使⽤MySQL中的limit⼦句现在返回的数据。
19. 尽量避免使⽤游标,因为游标的效率较差,如果游标操作的数据超过1万⾏,那么就应该采⽤其他⽅案。
20. 使⽤基于游标的⽅法或临时表⽅法之前,应先寻基于数据集的解决⽅案来解决问题,基于数据集的⽅法通常更有效。
21. 如果使⽤到了临时表,在存储过程的最后务必将所有的临时表显式删除,先⽤ truncate table清除表中的数据 ,然后 ⽤drop table彻底删除物理表 ,这样可以避免系统表的较长时间锁定。
22. 避免频繁创建和删除临时表,以减少系统表资源的消耗。
23. 在新建临时表时,如果⼀次性插⼊的数据量很⼤,那么可以使⽤ select into 代替 create table,避免造成⼤量 log ,以提⾼执⾏效率;如果数据量不⼤,为了缓和系统表的资源,应先create table,然后使⽤insert插⼊数据。
24. 在所有的存储过程和触发器的开始处设置 SET NOCOUNT ON ,在结束时设置 SET NOCOUNT OFF 。⽆需在执⾏存储过程和触发器的每个语句后向客户端发送 DONE_IN_PROC 消息。
25. 尽量避免⼤事务操作,提⾼系统并发能⼒。
26. 应尽量⼀次性插⼊多条数据,例如,使⽤下⾯的SQL语句性能会很低:
insert into persons(id,name,age) values('Bill',24)
insert into persons(id,name,age) values('Mike',26)
insert into persons(id,name,age) values('John',20)
为了提升性能,可以⼀次性插⼊这3条记录。
insert into persons(id,name,age) values('Bill',24),('Mike',26),('John',20)
27. 如果不得不使⽤like进⾏模糊查询时,不要在关键字前⾯加%。
反例:
select id,name,age from persons where name like '%abc%'
如果在关键字前⾯加%,那么查询是肯定要⾛全表查询的。
正例:
select id,name,age from persons where name like 'abc%'
28. 尽量⽤union all代替union
union和union all的差异主要是前者需要将两个(或者多个)结果集合并后再进⾏唯⼀性过滤操作,这就会涉及到排序,增加⼤量的cpu运算,加⼤资源消耗及延迟。所以当我们可以确认不可能出现重复结果集或者不在乎重复结果集的时候,尽量使⽤union all⽽不是union。
29.尽量使⽤等值连接
等值连接就是inner join,也称为内联进,⽽left join和right join是外连接。
先看下⾯的SQL语句
select a.id,a.name,b.id,b.name from a left join b on a.id = b.id
select a.id,a.name,b.id,b.name from a right join b on a.id = b.id
select a.id,a.name,b.id,b.name from a inner join b on a.id = b.id
上⾯的3条SQL语句,前两条分别使⽤了左连接和右连接,⽽最后⼀条使⽤了内连接,经过实际运⾏,使⽤内连接的SQL语句的执⾏效率明显优于左连接和右连接。所以在能满⾜需求的前提下,应该尽可能使⽤内连接(等值连接)。
30. 尽量⽤外连接来替换⼦查询
反例
select id,name from a where exists (select id from b where id>=10 and
a.product_id=
b.product_id)
在上⾯的SQL语句中,数据库引擎会先对外表a执⾏全表查询,然后根据product_id逐个执⾏⼦查询,如果外层表(a表)中的数据⾮常多,查询性能会⾮常糟糕。所以应该将SQL语句改成下⾯的形式:
select id,name from a inner join b on A.product_id=b.product_id where b.id>=10
作者: 银河使者
原⽂:挽救数据库性能的30条黄⾦法则 - 银河使者 - 博客园
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论