开发人员如何对sql优化

  说到sql优化,很多人都会觉得这个是DBA做的事,和他无关。也觉得数据库里面的各种命令,参数复杂难懂,不愿意去了解。其实不然,sql语句其实和我们写程序一样,如何高效,如何少用内存,如何速度最快,都

是有理可循,并不一定要拿着一本几十厘米的书啃来啃去。

    开发人员对于sql优化,从两个方面来考虑,一是数据表结构与sql语句的写法。二是程序的控制。

  (一)sql本身的优化。

  我们经常强调着优化,强调执行速度。我们开发人员用来提高速度的主要方法是建立索引。所以,如何建立合适的索引,如何恰当的使用索引是非常重要的。我自己常用的数据库是oracle数据库,我相信其它数据库也

类似,下面就以在oracle上的使用作分析。

  oracle索引的结构为B树,如果对B树有点了解,应该知道通过这种树形结构查询起来是非常快的,时间维数和树的高度相关。索引种类可能有很多种,但我们使用到的主要有两类:unique和normal,这两种索引在执

行效率上差不多,主要区别是unique带有唯一性验证。索引结构方面,使用较多的有单列索引,联合索引。对于单列索引,主要是为了针对对于某列的查询较频繁,而且响应时间要求较高。下面我以几个表为例:

  表A: id     nvchar(10)                    表B :  id      nvchar(10)

     date  number(10)                           name nvchar(20)

            time number(10)                            type   nvchar(5)

     data1 nvchar(5)                                          。

              。                                                       。

                    。                                                       。

                    。     

 上面的两个表,表A为数据表(此处认为id+date+time是唯一的),数据量大概在几千万以上,表B 为静态信息表,id与A表的id对应。下面主要通过各种需求来分析sql语句的执行。

  (1),需要经常统计A表某个id的数量,或者统计总数。

   因为表数据较大,对于统计数量这种,肯定不能用全表扫描,消耗太大。全表扫描需要逐一比较每条数据,io消耗大。此处最合理的是在id上建一个单列索引,时间维度应该在毫秒级。

   语句可以这样写: select count(id) from A where id = ...

  (2) 在往上点,如果查询条件经常包括id,data,time这三个。那么可以考虑建一个联合索引,把三个字段包括在内。但这个索引的先后顺序是很重要的,首先要看使用频繁率,比如:使用频繁上id > date > time,那

么,优先考虑结构为(id,date,time),其次,看那个字段过滤的记录比例。比如某个id能过滤掉百分之九十九的书,其他的都没这么高,那么优先考虑将id作为第一索引位置。为了体现索引的效率,联合索引不要太长,

不然容易影响效率,而且索引的维护方面代价也较高。

  索引建立后,怎样写sql语句也很关键,比如

  ##要查询条件包括id,date,time三个的结果

    语句自然是 select * from A where id = #id and date = #date and time = #time

    习惯上是条件顺序为索引结构顺序,原先很多认为这个顺序不对执行效率不一样,不过我测试新版本的oracle,查看执行计划是一样的,所以我认为现在这个顺序影响不大。

  ##如果条件包括id,time。

    查询条件没全在索引中,而且中间还差了一个date,为了执行时候能走索引,我么通常会把条件date带上,范围为全部,比如date范围在2000-2500之间,那么sql语句我么可以这样写

    select * from A whee id = #id and date >=2000 and date <=2500 and time = #time.

    同理如果id不在条件内,那么一定要把id条件补上去,联合索引如果没有第一项,是不会走的。

   (3) 上面都是单表查询,如果碰到多表联合查询咋办,特别是数据量那么大,如果去做笛卡尔乘积来匹配,都不敢去想那个数量。oracle数据库对于表连接方面,肯定是有优化的,不会直接傻傻的连起来然后再去查

找,首先会对各个表根据条件查询出来结果,然后用结果来匹配,这样总数量就要少很多,所以,表连接尽量在条件中把每个表的结果数控制到最小。

  ##要查询A中条件包括id,date,time,而且该id对应B表中的数据的type为#type的结果。

    语句通常这样写,select * from A a,B b where a.id = b.id and id = #id and date = #date and time = #time and type = #type.

    这个语句如果A表通过id,date,time过滤后的数据量不大,那么该语句执行的效率还是可以的。

    但是如果A过滤后数据量大,而B本事数据也不小,那么效率就会很低,我么知道最好的方式,是通过索引查询单表。我有一个项目,里面B表中type字段和id有关联,id = type + 某些字符。

如果是这种情况,那么多表就可以转化为单表的查询了,语句如下:

    select * from A where id = #id and id like '#type%' and date = #date and time = #time

这样又转化为了单表索引过程,效率比上面要高很多(对于like 条件,通配符只能放后面才能走索引)

  (4) 强制走索引,很多时候,oracle有自己的一个预估计划,比如,结果集大于一定比率,那么它不会走索引,转而全表扫描,其实这时候,走索引还是要快很多。那么我么可以在sql语句中强制走索引,

  语句如下:

  select /*+ index(a,A_pk)*/ * from A a where  id = #id and date = #date and time = #time   (A_pk为A表索引名称)

  这样会有意想不到效果,让执行计划按照你的想法来。

 sql语句的索引优化主要是要通过索引能筛选和过滤掉更多的记录。在这也分享一下全表扫描时候的一个小技巧,多进程处理:如 select /*+ parallel(8)*/  * from A where 。。。。,能显著提高速度,8是制定进

程数,当然这个不是越大越好,和服务器的cpu核心有关。

(二)程序控制

  很多时候,我么想要的结果不一定完全靠数据库和sql语句来达到。通过程序能查询结果与项目需要结果的使用效率提高。通过一下几个情景来分析一下。

  (1),我们要根据某些条件查询结果,由于结果数较多,我么必须对查询结果分页。其实分页,我们很多时候只是看前几页或者第一页,所以,我么可以通过一些策略来使得前面记录查询很快。  

 比如,要查A表,date条件在2000到3000之间的一个数据统计,这个之间数据量有几十万条,如果我么在语句中先查出这么多记录,做一个统计,然后再取前面多少条数据,那一个查询结果会是很慢的,我么可以这

样,比如第一页的范围肯定在2000-2010之间,那么我们就可以缩小范围,

  如 select * from (select *,rownum num from A where date >=2000 and date<=2010 ) where num <= #pageRecord

  这样查询范围就很小,速度会快很多,不一样的策略,结果一样,效果打不通。

  (2) 如果查询结果不只是要看第一页,上面的策略不行。如果此时我么想通过date,time来查找,date指日期,time指每天的时间,我么要查输入范围内,对date,time做分组的一个统计,同样,如果范围很

大,结果集很多,那么查询时候,需要扫描,索引的记录数就很多。对于查询页面,这个是不能忍受的,超过几秒估计就会有人要摔键盘。如果 date和time是一直连续的(即记录中日期是一天连着一天,time是包括

全天的各分钟),那么对于每一页的记录,我们能预估它的范围,比如以date范围在20150101-20150201,time以分钟统计,每页查询15条记录,那么这个范围为,date = 20150101,time在零分钟到一点一十这

个范围内,那么查询第一页,我么只需要查询该范围的数据。同样第二页,第三页都一样,这样查询效率就上来了,语句如下:

    select * from A where date = 20150101 and time>=0 and time <=110,扫描范围缩小了不知多少倍。

  以上是我作为一个开放人员对于sql优化,效率方面的一个理解,我觉得开发人员不依靠DBA,照样实现高效的功能。

  

原文地址:https://www.cnblogs.com/2015zzh/p/5014145.html