前台的应用程序要在数据库服务器上起作用,最终靠的都是应用程序中的一条条SQL语句。据不完全统计,SQL语句消耗了数据库服务器80%左右的资源。所以,如何提高SQL语句的执行效率,是在数据库查询优化中必须要考虑的一个问题。
但是,在实际工作中,许多程序员有个误区,他们认为数据库查询优化不是他们的事情,而应该是数据库管理系统的任务,这是很多程序员的一个错误认识。他们错误地认为,他们所开发的应用程序的性能,跟他们所编写的SQL语句关系不大。一个好的查询语句往往可以使得应用程序的性能提高数十倍,而且,随着记录量的增加,这个效果还会以几何级数上升。
另外,SQL语句是独立于程序设计逻辑的,也就是说,无论你的业务逻辑是怎么设计的,最后分解成SQL语句,就是那么几个语法,所以,相对于应用程序源代码的优化,SQL查询语句的优化在时间与风险上,都要低许多。
对于SQL语句的优化,Oracle数据库与SQL Server数据库有类似的地方,也有一些差异。下面笔者就这两者的差异与共同点做一个综合介绍。
1、 通过索引来提高SQL语句的执行效率。
一般来说,对于一些经常需要查询的表,如产品信息表,我们可以通过建立外键来提高查询效率。但是,也不是说每个字段都要指定为外键。对于一些没有指定外键的字段,我们可以为其建立索引,来提高数据表的查询效率。
一般情况,在以下几种情况下,我们可以为表建立索引来提高SQL语句的执行效率。
一是对于一些经常需要查询的表,我们出于某种考虑,没有设置外键,而是通过设置索引来提高对于表的查询效率。在数据库表中,外键的设置往往受到一些限制;而相对于外键来说,索引的限制则要小得多。所以,在一些不使用外键的情况下,我们可以采用索引来提高对于表的查询效率。
二是在需要频繁进行排序或者分组的表上,建立索引,可以极大地提高查询效率。如ERP系统在设计的时候,可能需要频繁地查询采购订单明细,而且,这份报表是需要根据采购订单的号码进行排序。如此的话,在数据库设计的时候,就可以把采购订单的号码设置为索引,在每次运行采购订单明细作业的时候,前台ERP程序的性能就会高许多。而有时候,可能需要按供应商来统计当天的进货金额,此时,最好能够在进货明细表中,给供应商字段添加索引,这对于提高当天进货汇总表作业的运行效率,会有非常大的帮助。总之,在分组查询或者排序查询的表上,设置索引对于提高应用程序的整体性能,具有不可忽视的作用。
三是如果待排序的列有多个,则需要在这些列上建立复合索引。如前台应用程序在生成当天的进货明细表时,需要按供应商、采购订单号、产品编号进行排序。此时,也就是说,在生成进货明细表这份报表时,要按这三个字段进行排序。遇到这种情况时,对这些字段建立复合索引,提高查询效率,是一个不错的选择。
以上这些SQL语句优化,Oracle数据库与SQL Server数据库都可以实现。虽然具体的实现语句可能稍有区别,但都是换汤不换药,没有本质区别。
2、 把索引与数据文件存放在不同的磁盘中。
当索引或者数据库文件比较庞大时,把他们放在同一个磁盘中会加大输入输出等竞争,从而抵消了索引的作用。为了解决过多的索引导致输入输出效率降低的问题,在数据库设计的时候,最好把索引跟用户的表空间建立在不同的磁盘中。如把数据库的表空间建立在一块硬盘中,而把索引建立在另外一块硬盘中。如此的话,就可以明显地降低输入输出竞争。也就是说,这样设计,随着索引的增加,不会导致输入输出效率的低下。
不过,根据笔者的了解,索引与数据文件存放在不同的磁盘中,现在好像只有Oracle 数据库可以做到,而微软的SQL Server数据库则无法实现这一点。
这也许根他们的定位不同。甲骨文的数据库系统是针对大型的数据库应用而设计,所以,对于查询的效率要求更加高。
3、 合理利用群集索引来提高SQL语句的执行效率。
在一些特殊情况下,我们需要用到群集索引。如在ERP系统中,采购部门经常需要按月来查询采购订单明细。如需要查询2008年8月份的采购订单明细,而且这份报表需要按照供应商、采购订单号码、产品品号、交货期等进行排序,有时候还需要对供应商进行汇总。这一份简单的报表,用到了范围查询、多个字段记录排序、记录汇总等技术。此时,若能够建立群集索引的话,对于提高这份报表的查询效率,具有非常明显的效果,特别是在数据记录比较多的情况下,效果特别明显。
所谓的群集索引与非群集索引的区别,主要是在于数据存放记录上的差异。若我们采用群集索引的话,在存放记录的时候,会按群集索引指定的规则存放。如对于采购订单中的供应商ID字段采用群集索引,则在存放记录的时候,会把相同的供应商存放在一起。如此的话,在查询的时候,效率就会高得多。而若没有采用群集索引的话,则记录保存时就是按记录保存的先后顺序来进行记录的存储。
在建立群集索引的时候,Oracle 数据库有一个,就是必须在数据库表建立的时候,数据还没导入之前就建立群集索引。也就是说,若数据库表中有记录的话,则无法建立群集索引,这一点我们需要引起注意。
同时,若给某个表中的字段建立了群集索引,在记录保存时,为了能够按照群集索引所指定的规则存储数据,需要对数据表中的记录进行一些调整,以符合原有的规则,如此的话,就会让数据库进行一些额外的动作,从而影响数据库的性能。如在建立某个供应商的采购记录时,为了把相同供应商的记录保存在一起(如我们把供应商ID设置为群集索引),就需要调整原有的记录存储结构。虽然在保存的时候,牺牲一点效率,但是,这对于后续数据查询,效率就会高许多。所以,对于群集索引的话,要让其取得比较高的效果,有一个应用前提,就是这个表中的数据要是经常查询的。如在ERP系统中,有一个库存历史交易报表,这个查询就会经常用到,而且,在查询的过程中,都需要用到范围查询、排序、汇总等功能。所以,用在库存历史交易等数据库表中,则效果会好得多。
若利用一句话来区分群集索引与非群集索引的区别,那就是群集索引“更新慢,查询难快”。
在实际应用中,如果利用SQL Server设计数据库系统的过程中,很少用到群集索引技术(根据笔者的了解)。而在Oracle数据库系统中,则应用的相对比较广泛一点。
不过,两个数据库在群集索引上都有一个共同点,就是要利用索引的话,必须在数据表建立的时候,就要设置群集索引。当数据库中有记录的话,是不能建立群集索引的。
说起区别,具体的实现语法有点差异,但是没有什么本质的区别。另外,对于甲骨文的数据库来说,可以把群集索引跟数据库文件存放在不同的磁盘中,从而提高输入输出效率。但是,微软的SQL Server数据库则不行。
4、 使用Oracle数据库自带的优化器优化SQL语句。
在Oracle数据库中,自带了一个SQL语句的优化工具,Oracle语句优化器。利用这个工具,可以提高SQL语句的执行效率。
一方面,Oracle数据库语句优化器是跟行锁管理工具一起使用的,两者往往需要配合使用,才能够起到意想不到的作用。另一方面,对于“扶不起的阿斗”,Oracle语句优化器也无能为力。也就是说,对于一些实在写得很糟糕的SQL语句,语句优化器对其也没有丝毫办法;只有对一些本来就比较合理的SQL语句,语句优化器与行锁管理工具,才能够在这个基础之上,再找到一些可以改善的地方,然后提出可行的改善意见。
具体来说,语句优化器,一方面确定SQL语句的最小代价执行计划,同时,确定数据的访问路径,如是否采用索引或者表扫描;采用合理的表连接方式以及顺序;判断索引不可使用时是否需要进行排序等等。综合以上因素,然后给我们提出一个改善的建议。
在实际工作中,语句优化器可以给我们找出一个SQL语句优化过程中的盲点。而这个工具是微软SQL Server数据库所缺乏的,或者跟甲骨文的数据库比起来,有差距的地方。