SQL通用优化方案:
\1. 使用参数化查询:防止SQL注入,预编译SQL命令提高效率
\2. 去掉不必要的查询和搜索字段:其实在项目的实际应用中,很多查询条件是可有可无的,能从源头上避免的多余功能尽量砍掉,这是最简单粗暴的解决方案。
\3. 选择最有效率的表名顺序: 数据库的解析器按照从右到左的顺序处理FROM子句中的表名,FROM子句中写在最后的表将被最先处理,在FROM子句中包含多个表的情况下,你必须选择记录条数最少的表放在最后,如果有3个以上的表连接查询,那就需要选择那个被其他表所引用的表放在最后。
\4. 不要使用select :不要使用select ,以提高查询效率,减少输出的数据量,提高传输速度(数据库或在解析过程中将""依次转换成所有列名,这意味着消耗更多的时间)
\5. 尽量避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理。
\6. 减少访问数据库的次数:通过存储过程等,把多条语句放在一个存储过程中执行,减少数据库访问次数
\7. 整合简单的、无关联的数据库访问:如果你有几个简单的数据库查询语句,你可以把它们整合到一个查询中(即使它们之间没有关系))
\8. 删除重复记录:删除重复记录,减少数据库文件大小
\9. 使用表的别名(Alias):当在SQL语句中连接多个表时, 请使用表的别名并把别名前缀于每个Column上.这样一来,就可以减少解析的时间并减少那些由Column歧义引起的语法错误.
\10. 使用列的别名:当列的名称很长的时候,使用简短的列的别名可以查询结果更清晰,更简洁。
\11. 用EXISTS替代IN、用NOT EXISTS替代NOT IN:无论在哪种情况下,NOT IN都是最低效的 (因为它对子查询中的表执行了一个全表遍历). 为了避免使用NOT IN ,我们可以把它改写成外连接(Outer Joins)或NOT EXISTS.
\12. 统计相关的查询,影响结果集往往巨大,应避免在业务高峰期执行统计相关的查询,或者仅在从库中执行统计查询。同时建议把数据先保存在内存、缓存中(如redis),再按一定策略写入数据库。
\13. select count() from table;这样不带任何条件的count会引起全表扫描,并且没有任何业务意义,是一定要杜绝的,可以用其他方法代替。
\14. 使用truncate代替delete清空整个数据表:当删除表中的记录时,在通常情况下, 回滚段(rollback segments ) 用来存放可以被恢复的信息. (可以恢复到执行删除命令之前的状态) 而当运用TRUNCATE时, 回滚段不再存放任何可被恢复的信息.当命令运行后,数据不能被恢复.因此很少的资源被调用,执行时间也会很短.
字段类型优化:
\1. 尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连 接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。
\2. 最好不要给数据库留NULL,尽可能的使用 NOT NULL填充数据库.(备注、描述、评论之类的可以设置为 NULL)
where条件语句优化:
\1. WHERE子句中的连接顺序:数据库采用自右而左的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其他WHERE条件之前(左), 那些可以过滤掉最大数量记录的条件必须写在WHERE子句的末尾(右).
\2. 避免在where语句中出现字段的类型转换(字段的类型和传入的参数类型不一致的时候发生的隐式类型转换)
\3. 不要在where条件语句中的"="左边进行函数、算数运算或其他表达式运算,可以通过使用冗余字段来替代函数运算,否则系统无法正确使用索引
\4. where 子句中对字段进行 null 值判断、包含not、!=、<>等操作符,或like的关键词前加%(like ‘%关键词’),都无法使用索引,从而引发全表扫描.
\5. 使用like进行模糊查询时应注意,除非必要,否则不要在关键词前加%,否则必然导致全表查询
索引优化:
\1. 索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有必要。
\2. 用索引提高效率:合理使用索引和复合索引同样能提高效率.但使用索引是有代价的, 索引需要空间来存储,也需要定期维护, 每当有记录在表中增减或索引列被修改时, 索引本身也会被修改. 这意味着每条记录的INSERT , DELETE , UPDATE将为此多付出4 , 5 次的磁盘I/O . 因为索引需要额外的存储空间和处理,那些不必要的索引反而会使查询反应时间变慢.。定期的重构索引是有必要的。
\3. 在使用索引字段作为条件时,如果该索引是联合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用。
\4. 要注意索引的维护,周期性重建索引,重新编译存储过程。
分页语句优化:
\1. 分页查询的优化。页数比较多的情况下,如limit 10000,10 影响的结果集是10010行,查询速度会比较慢。推荐的解决方案是:先只查询主键select id from table where … order by … limit 10000,10(搜索条件和排序请建立索引),再通过主键去获取数据。
\2. 对于多张大数据量(这里几百条就算大了)的表JOIN,要先分页再JOIN,否则逻辑读会很高,性能很差。
事务的优化:
\1. 尽量使用COMMIT:尽可能在程序中使用commit,这样程序的性能得到提高,需求也会因为COMMIT所释放的资源而减少,commit每个数据库引擎都不同,sqlserver默认一条sql语句就是一个事务。
\2. 尽量避免大事务操作,提高系统并发能力。
\3. 只在必要的情况下才使用begin tran:begin tran保证了数据的一致性,可以确保要么几个表都修改成功,要么都不成功,但Begin tran付出的代价是在提交之前,所有SQL语句锁住的资源都不能释放,直到commit掉。Begin tran使用的原则是,在保证数据一致性的前提下,begin tran 套住的SQL语句越少越好!有些情况下可以采用触发器同步数据,不一定要用begin tran。
临时表优化:
\1. 避免频繁创建和删除临时表,以减少系统表资源的消耗。
\2. 使用“临时表”暂存中间结果:将临时结果暂存在临时表,后面的查询就在tempdb中了,这可以避免程序中多次扫描主表,也大大减少了程序执行中“共享锁”阻塞“更新锁”,减少了阻塞,提高了并发性能。同时也能简化sql语句的复杂度。
\3. 在新建临时表时,如果一次性插入数据量很大,那么可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果数据量不大,为了缓和系统表的资源,应先create table,然后insert。
\4. 如果使用到了临时表,在存储过程的最后务必将所有的临时表显式删除,先 truncate table ,然后 drop table ,这样可以避免系统表的较长时间锁定。
\5. 如果临时表的数据量较大,需要建立索引,那么应该将创建临时表和建立索引的过程放在单独一个子存储过程中,这样才能保证系统能够很好的使用到该临时表的索引。
\6. 尽量避免使用distinct、order by、group by、having、join、cumpute,因为这些语句会加重tempdb的负担。
\7. 慎用大的临时表与其他大表的连接查询和修改,减低系统表负担,因为这种操作会在一条语句中多次使用tempdb的系统表。
游标优化:
\1. 尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该考虑改写。
\2. 使用基于游标的方法或临时表方法之前,应先寻找基于集的解决方案来解决问题,基于集的方法通常更有效。
\3. 与临时表一样,游标并不是不可使用。对小型数据集使用 FAST_FORWARD 游标通常要优于其他逐行处理方法,尤其是在必须引用几个表才能获得所需的数据时。
更多优化: 读写分离、主从备份、日志等
面试简单回答:
从三方面:
1.表的字段设计和索引建立
2.分库分表分区
3.主从架构