打破元无知,SQL语句优化的基础策略

什么是元无知?就是不知道自己不知道 … 。接下来,让我们查漏补缺一下吧。


查询慢的影响因素

  • 没有索引或者没有用到索引。
  • I/O吞吐量小,存在瓶颈效应。
  • 内存不足。
  • 络速度慢。
  • 查询出的结果数据量过大。
  • 出现锁或者死锁。
  • 返回不必要的行和列数据,如SELECT * 。
  • 查询语句存在问题,没有优化。

  • SQL语句优化基础策略

    以下SQL优化建议,虽然并不是在所有类型的数据库中都适应,但不影响我们了解可能导致SQL存在问题的原因。

    1. 应尽量避免在 WHERE 子句中使用不等于( != <> 操作符,否则将导致引擎放弃使用索引而进行全表扫描。MySQL只有对以下操作符才使用索引:<、<=、=、>、>=、BETWEEN AND以及某些方式的 LIKE(如,’a%’)。


    2.应尽量避免在 WHERE 子句中对字段进行 NULL 值判断,否则将导致引擎放弃使用索引而进行全表扫描,在创建表时 NULL 是默认值,通常应该使用 NOT NULL,或者使用一个默认值,如 0 作为默认值。


    3.应尽量避免在 WHERE 子句中使用 OR 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描。使用 OR 的字句可以分解成多个查询,并且通过UNION 连接多个查询。他们的速度只同是否使用索引有关,如果查询需要用到联合索引,用 UNION ALL 执行的效率更高。


    4.应尽量避免在 WHERE 子句中使用 IN NOT IN ,否则将导致全表扫描,对于连续的数值,能用 BETWEEN AND 尽量避免使用 IN。一般,用 EXISTS 代替 IN 。若需要使用 IN,在 IN 后面值的列表中,按照值的分布数量降序排列,减少判断的次数。


    5.WHERE 子句中使用 LIKE 时,‘%T%’ 和 ‘%T’ 也将导致全表扫描,可以考虑全文检索,‘T%’ 才会用到索引。


    6.应尽量避免在 WHERE 子句中对 “=” 左边的字段进行函数、算术运算及其他表达式运算,可以将表达式运算移至“=”右边,否则将导致引擎放弃使用索引而进行全表扫描。 如果在 WHERE 子句中使用参数,也会导致全表扫描。因为SQL只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时。它必须在编译时进行选择。然而,如果在编译时建立访问计划,变量的值还是未知的,因而无法作为索引选择的输入项。


    7.在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致。


    8.当索引列有大量数据重复时,SQL查询可能不会去利用索引,并不是所有索引对查询都有效,SQL是根据表中数据来进行查询优化的。如表中有“性别”字段,即使在“性别”字段建立索引也对查询效率起不了作用,尽量不要对数据库中某个含有大量重复的值的字段建立索引。


    9.建立索引可以提高 SELECT 的效率,但索引并不是越多越好。索引同时也降低了 INSERT 及 UPDATE 的效率,因为 INSERT 或 UPDATE 时有可能会重建索引,所以怎样建索引需要慎重考虑,视实际应用情况而定。同时,一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用的字段是否有建立索引的必要。


    10.对于数值字段,尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言,只需要比较一次就够了。

    对于字符型字段,尽量的使用 varchar/nvarchar 代替 char/nchar ,因为首先变长字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。


    11.避免使用 select * from table,用具体的字段列表代替“*”,避免返回用不到的任何字段。


    12.尽可能的使用索引字段作为查询条件,尤其是聚簇索引,必要时可以通过index index_name来强制指定索引,避免对大表查询时进行table scan,必要时考虑新建索引。要注意索引的维护,周期性重建索引,重新编译存储过程。


    13.在新建临时表时,如果一次性插入数据量很大,那么可以使用 SELECT INTO 代替 CREAT TABLE,避免造成产生大量日志 ,以提高速度。如果数据量不大,为了缓和系统表的资源,应先CREAT TABLE,然后INSERT。


    14.如果使用到了临时表,在存储过程的最后务必将所有的临时表显式删除,先 truncate table ,然后 drop table ,这样可以避免系统表的较长时间锁定。


    15.当服务器的内存够多时,配置 线程数量 = 最大连接数 + 5,使其发挥最大的效率。否则使用配置 线程数量 < 最大连接数启用SQL SERVER的线程池来解决,如果还是 线程数量 = 最大连接数+5,可能会严重的损害服务器的性能。


    16.尽量避免向客户端返回大量结果数据,若数据量过大,应该考虑相应需求是否合理。尽量避免大事务操作,提高系统并发能力。


    创建索引的一般规则

  • 表的主键、外键需要建立索引。
  • 频繁与其他表进行连接的表,在连接字段上应该建立索引。
  • 频繁出现在 WHERE 子句及 ORDER BY 中的字段,特别是大表的字段,应该建立索引。
  • 索引应该建在短字段上,对于大的文本字段甚至超长字段,避免建索引。
  • 复合索引的建立需要结合实际应用进行分析,尽量考虑用单字段索引代替。
  • 正确选择复合索引中的主列字段,一般是选择性较好的字段;
  • 复合索引的几个字段是否经常同时以 AND 方式出现在 WHERE 子句中,单字段查询是否极少甚至没有,如果是,则可以建立复合索引,否则考虑单字段索引。
  • 如果复合索引中包含的字段经常单独出现在 WHERE 子句中,则分解为多个单字段索引。
  • 如果复合索引所包含的字段超过3个,需要结合实际应用考虑其必要性,考虑减少复合的字段。
  • 如果既有单字段索引,又有这几个字段上的复合索引,通常可以删除复合索引。
  • 频繁进行数据操作的表,不要建立太多的索引,删除无用的索引。
  • 建立的每个索引都会增加存储开销,索引对于插入、删除、更新操作也会增加处理上的开销。另外,过多的复合索引,在有单字段索引的情况下,一般都是没有存在价值的。相反,还会降低数据增加删除时的性能,特别是对频繁更新的表来说,负面影响非常大。
  • 尽量不要对数据库中某个含有大量重复的值的字段建立索引。

  • 声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

    上一篇 2019年7月25日
    下一篇 2019年7月25日

    相关推荐