通过分析SQL语句的执行计划优化SQL语句

plsql:执行计划中显示时间列(oracle预计的sql执行时间)

cost,size,

card是指计划中这一步所处理的行数;

cost指cbo中这一步所耗费的资源,这个值是相对值;

bytes指cbo中这一步所处理所有记录的字节数,是估算出来的一组值。

 

通过分析SQL 语句的执行计划优化SQL 语句

 

在数据库的日常维护中,调整个别性能较差的SQL 语句是一项极富挑战性的工作。其中的关键在于如何得到SQL 语句的执行计划和如何从SQL 语句的执 行计划中发现问题。总是想将日常经验的点点滴滴总结一下,但是直到最近才下定决心,总共花了3 个周末时间,才将其整理成册,便于自己日常工作。现在将其发 表出来希望能与更多的朋友分享。

  这篇文章主要介绍与SQL 调整有关的内容,内容涉及多个方面:SQL 语句执行的过程、Oracle( 大型网站数据库平台) 优化器,表之间的关联,如何得到SQL 执行计划,如何分析执行计划等内容,从而由浅到深的方式了解SQL 优化的过程,使大家逐步步入SQL 调整之门。

  一: 性能调整综述

  Oracle( 大型网站数据库平台) 数据库是高度可调的数据库产品。本章描述调整的过程和那些人员应与Oracle( 大型网站数据库平台) 服务器的调整有关,以及与调整相关联的操作系统硬件和软件。本章包括以下方面:

  谁来调整系统?

  什么时候调整?

  建立有效调整的目标

  在设计和开发时的调整

  调整产品系统

  监控产品系统

  谁来调整系统:

  为了有效地调整系统,若干类人员必须交换信息并牵涉到系统调整中,例如:

  应用设计人员必须传达应用系统的设计,使得每个人都清楚应用中的数据流动.

  应用开发人员必须传达他们选择的实现策略,使得语句调整的过程中能快速、容易地识别有问题的应用模块和可疑的SQL 语句.

  数据库管理人员必须仔细地监控系统活动并提供它们的资料,使得异常的系统性能可被快速得识别和纠正.

  硬件/ 软件管理人员必须传达系统的硬件、软件配置并提供它们的资料,使得相关人员能有效地设计和管理系统。

  简而言之,与系统涉及的每个人都在调整过程中起某些作用,当上面提及的那些人员传达了系统的特性并提供了它们的资料,调整就能相对的容易和更快一些。

  不幸的是,事实上的结果是:数据库管理员对调整负有全部或主要的责任。

但是,数据库管理员很少有合适的系统方面的资料,而且,在很多情况下,数据库管理员往往是在实施阶段才介入数据库,这就给调整工作带来许多负面的影响,因为在设计阶段的缺陷是不能通过DBA 的调整而得以解决,而设计阶段的缺陷往往对数据库性能造成极大的影响。

  其实,在真正成熟的开发环境下,开发人员作为纯代码编写人员时,对性能的影响最小,此时大部分的工作应由应用设计人员完成,而且数据库管理员往往在前期的需求管理阶段就介入,为设计人员提供必要的技术支持。

  调整并不是数据库管理员的专利,相反大部分应该是设计人员和开发人员的工作,这就需要设计人员和开发人员具体必要的数据库知识,这样才能组成一个高效的团队,然而事实上往往并非如此。

  什么时候作调整?

  多数人认为当用户感觉性能差时才进行调整,这对调整过程中使用某些最有效的调整策略来说往往是太迟了。此时,如果你不愿意重新设计应用的话,你只能通过重新分配内存( 调整SGA) 和调整I/O 的办法或多或少地提高性能。Oracle( 大型网站数据库平台) 提供了许多特性,这些特性只有应用到正确地设计的系统中时才能够很大地提高性能。

  应用设计人员需要在设计阶段设置应用的性能期望值。然后在设计和开发期间,应用设计人员应考虑哪些Oracle( 大型网站数据库平台) 特性可以对系统有好处,并使用这些特性。

  通过良好的系统设计,你就可以在应用的生命周期中消除性能调整的代价和挫折。图1-11-2 说明在应用的生命周期中调整的相对代价和收益,正如你见到的,最有效的调整时间是在设计阶段。在设计期间的调整能以最低的代价给你最大的收益。

  当然,即使在设计很好的系统中,也可能有性能降低。但这些性能降低应该是可控的和可以预见的。

  调整目标

  不管你正在设计或维护系统,你应该建立专门的性能目标,它使你知道何时要作调整。如果你试图胡乱地改动初始化参数或SQl 语句,你可能会浪费调整系统的时间,而且无什么大的收益。调整你的系统的最有效方法如下:

  当设计系统时考虑性能

  调整操作系统的硬件和软件

  识别性能瓶颈

  确定问题的原因

  采取纠正的动作

  当你设计系统时,制定专门的目标;例如,响应时间小于3秒。当应用不能满足此目标时,识别造成变慢的瓶颈(例如,I/O 竞争),确定原因,采取纠正动作。在开发期间,你应测试应用研究,确定在采取应用之前是否满足设计的性能目标。

  当你正在维护生产库系统时,有多种快速有效的方法来识别性能瓶颈。

  不管怎样,调整通常是一系列开销。一旦你已确定了瓶颈,你可能要牺牲一些其它方面的指标来达到所要的结果。例如,如果I/O 有问题,你可能需要 更多内存或磁盘。如果不可能买,你可能要限制系统的并发性,来获取所需的性能。然而,如果你已经明确地定义了性能的目标,那用什么来交换高性能的决策就变 的很容易的,因为你已经确定了哪些方面是最重要的,如过我的目标为高性能,可能牺牲一些空间资源。

  随着应用的越来越庞大,硬件性能的提高,全面的调整应用逐渐变成代价高昂的行为,在这样情况下,要取得最大的投入/ 效率之比,较好的办法是调整 应用的关键部分,使其达到比较高的性能,这样从总体上来说,整个系统的性能也是比较高的。这也就是有名的20/80 原则,调整应用的20%( 关键部分) , 能解决80% 的问题。

  在设计和开发系统时作调整

  良好设计的系统可以防止在应用生命周期中产生性能问题。系统设计人员和应用开发人员必须了解Oracle( 大型网站数据库平台) 的查询处理机制以便写出高效的SQL 语句。 2 章 有效的应用设计 讨论了你的系统中各种可用的配置,以及每种配置更适合哪种类型的应用。 5 章 优化器 讨论了Oracle( 大型网站数据库平台) 的查询优化器,以及如何写语句以获取最快的结果。

  当设计你的系统时,使用下列优化性能的准则:

  消除客户机/服务器应用中不必要的网络传输。-- 使用存储过程。

  使用适合你系统的相应Oracle( 大型网站数据库平台) 服务器选件(例如,并行查询或分布式数据库)。

  除非你的应用有特殊的需要,否则使用缺省的Oracle( 大型网站数据库平台) 锁。

  利用数据库记住应用模块,以便你能以每个模块为基础来追踪性能。

  选择你的数据块的最佳大小。 -- 原则上来说大一些的性能较好。

  分布你的数据,使得一个节点使用的数据本地存贮在该节点中。

  调整产品系统

  本节描述对应用系统快速、容易地找出性能瓶颈,并决定纠正动作的方法。这种方法依赖于对Oracle( 大型网站数据库平台) 服务器体系结构和特性的了解程度。在试图调整你的系统前,你应熟悉Oracle( 大型网站数据库平台) 调整的内容。

  为调整你已有的系统,遵从下列步骤:

  调整操作系统的硬件和软件

  通过查询V $SESSION_WAIT 视图,识别性能的瓶颈,这个动态性能视图列出了造成会话(session)

  等待的事件。

  通过分析V $SESSION_WAIT 中的数据,决定瓶颈的原因。

  纠正存在的问题。

  监控应用系统

  这主要是通过监控Oracle( 大型网站数据库平台) 的动态视图来完成。

  各种有用的动态视图:如v$session_wait, v$session_event 等。

  二:有效的应用设计

  我们通常将最常用的应用分为2 种类型:联机事务处理类型(OLTP) ,决策支持系统(DSS)

  联机事务处理(OLTP)

  该类型的应用是高吞吐量,插入、更新、删除操作比较多的系统,这些系统以不断增长的大容量数据为特征,它们提供给成百用户同时存取,典型的OLTP 系统是订票系统,银行的业务系统,订单系统。OTLP 的主要目标是可用性、速度、并发性和可恢复性。

  当设计这类系统时,必须确保大量的并发用户不能干扰系统的性能。还需要避免使用过量的索引与cluster 表,因为这些结构会使插入和更新操作变慢。

  决策支持(DSS)

  该类型的应用将大量信息进行提取形成报告,协助决策者作出正确的判断。典型的情况是:决策支持系统将OLTP 应用收集的大量数据进行查询。典型的应用为客户行为分析系统( 超市,保险等)

  决策支持的关键目标是速度、精确性和可用性。

  该种类型的设计往往与OLTP 设计的理念背道而驰,一般建议使用数据冗余、大量索引、cluster table 、并行查询等。

  近年来,该类型的应用逐渐与OLAP 、数据仓库紧密的联系在一起,形成的一个新的应用方向。

  三:SQL 语句处理的过程

  在调整之前我们需要了解一些背景知识,只有知道这些背景知识,我们才能更好的去调整sql 语句。

  本节介绍了SQL 语句处理的基本过程,主要包括:

  查询语句处理

  DML 语句处理(insert, update, delete)

  DDL 语句处理(create .. , drop .. , alter .. , )

  事务控制(commit, rollback)

  SQL 语句的执行过程(SQL Statement Execution)

  在某些情况下,Oracle( 大型网站数据库平台) 运行sql 的过程可能与下面列出的各个阶段的顺序有所不同。

  如DEFINE 阶段可能在FETCH 阶段之前,这主要依赖你如何书写代码。

  对许多Oracle( 大型网站数据库平台) 的工具来说,其中某些阶段会自动执行。 绝大多数用户不需要关心各个阶段的细节问题,然而,知道执行的各个阶段还是有必要的,这会帮助你写出更高效的SQL 语句来,而且还可以让你猜测出性能差的 SQL 语句主要是由于哪一个阶段造成的,然后我们针对这个具体的阶段,找出解决的办法。

  DML 语句的处理

  本节给出一个例子来说明在DML 语句处理的各个阶段到底发生了什么事情。

  假设你使用Pro*C 程序来为指定部门的所有职员增加工资。程序已经连到正确的用户,你可以在你的程序中嵌入如下的SQL 语句:

EXEC SQL UPDATE employees
SET salary = 1.10 * salary
WHERE department_id = :var_department_id;

  var_department_id 是程序变量,里面包含部门号,我们要修改该部门的职员的工资。当这个SQL 语句执行时,使用该变量的值。

  每种类型的语句都需要如下阶段:

  第1: Create a Cursor 创建游标

  第2: Parse the Statement 分析语句

  第3: Describe Results of a Query 描述查询的结果集

  第4: Define Output of a Query 定义查询的输出数据

  第5: Bind Any Variables 绑定变量

  第6: Parallelize the Statement 并行执行语句

  第7: Run the Statement 运行语句

  第8: Fetch Rows of a Query 取查询出来的行

  第9: Close the Cursor 关闭游标

  如果使用了并行功能,还会包含下面这个阶段:

  下面具体说一下每一步中都发生了什么事情: .

  第1: 创建游标(Create a Cursor)

  由程序接口调用创建一个游标(cursor )。任何SQL 语句都会创建它,特别在运行DML 语句时,都是自动创建游标的,不需要开发人员干预。 多数应用中,游标的创建是自动的。然而,在预编译程序(pro*c) 中游标的创建,可能是隐含的,也可能显式的创建。在存储过程中也是这样的。

  第2: 分析语句(Parse the Statement)

  在语法分析期间,SQL 语句从用户进程传送到Oracle( 大型网站数据库平台)SQL 语句经语法分析后,SQL 语句本身与分析的信息都被装入到共享SQL 区。在该阶段中,可以解决许多类型的错误。

  语法分析分别执行下列操作:

  翻译SQL 语句,验证它是合法的语句,即书写正确

  实现数据字典的查找,以验证是否符合表和列的定义

  在所要求的对象上获取语法分析锁,使得在语句的语法分析过程中不改变这些对象的定义

  验证为存取所涉及的模式对象所需的权限是否满足

  决定此语句最佳的执行计划

  将它装入共享SQL

  对分布的语句来说,把语句的全部或部分路由到包含所涉及数据的远程节点

  以上任何一步出现错误,都将导致语句报错,中止执行。

  只有在共享池中不存在等价SQL 语句的情况下,才对SQL 语句作语法分析。在这种情况下,数据库内核重新为该语句分配新的共享SQL 区,并对语句进行语法分析。进行语法分析需要耗费较多的资源,所以要尽量避免进行语法分析,这是优化的技巧之一。

  语法分析阶段包含了不管此语句将执行多少次,而只需分析一次的处理要求。Oracle( 大型网站数据库平台) 只 对每个SQL 语句翻译一次,在以后再次执行该语句时,只要该语句还在共享SQL 区中,就可以避免对该语句重新进行语法分析,也就是此时可以直接使用其对应 的执行计划对数据进行存取。这主要是通过绑定变量(bind variable) 实现的,也就是我们常说的共享SQL ,后面会给出共享SQL 的概念。

  虽然语法分析验证了SQL 语句的正确性,但语法分析只能识别在SQL 语句执行之前所能发现的错误( 如书写错误、权限不足等) 。因此,有些错误通 过语法分析是抓不到的。例如,在数据转换中的错误或在数据中的错(如企图在主键中插入重复的值)以及死锁等均是只有在语句执行阶段期间才能遇到和报告的错 误或情况。

  查询语句的处理

  查询与其它类型的SQL 语句不同,因为在成功执行后作为结果将返回数据。其它语句只是简单地返回成功或失败,而查询则能返回一行或许多行数据。查询的结果均采用表格形式,结果行被一次一行或者批量地被检索出来。

从这里我们可以得知批量的fetch 数据可以降低网络开销,所以批量的fetch 也是优化的技巧之一。

  有些问题只与查询处理相关,查询不仅仅指SELECT 语句,同样也包括在其它SQL 语句中的隐含查询。例如,下面的每个语句都需要把查询作为它执行的一部分:

INSERT INTO table SELECT...
UPDATE table SET x = y WHERE...
DELETE FROM table WHERE...
CREATE table AS SELECT...

  具体来说,查询

  要求读一致性

  可能使用回滚段作中间处理

  可能要求SQL 语句处理描述、定义和取数据阶段

  第3: 描述查询结果(Describe Results of a Query)

  描述阶段只有在查询结果的各个列是未知时才需要;例如,当查询由用户交互地输入需要输出的列名。在这种情况要用描述阶段来决定查询结果的特征(数据类型,长度和名字)。

  第4: 定义查询的输出数据(Define Output of a Query)

  在查询的定义阶段,你指定与查询出的列值对应的接收变量的位置、大小和数据类型,这样我们通过接收变量就可以得到查询结果。如果必要的话,Oracle( 大型网站数据库平台) 会自动实现数据类型的转换。这是将接收变量的类型与对应的列类型相比较决定的。

  第5: 绑定变量(Bind Any Variables)

  此时,Oracle( 大型网站数据库平台) 知道了SQL 语句的意思,但仍没有足够的信息用于执行该语句。Oracle( 大型网站数据库平台) 需要得到在语句中列出的所有变量的值。在该例中,Oracle( 大型网站数据库平台) 需要得到对department_id 列进行限定的值。得到这个值的过程就叫绑定变量(binding variables)

  此过程称之为将变量值捆绑进来。程序必须指出可以找到该数值的变量名(该变量被称为捆绑变量,变量名实质上是一个内存地址,相当于指针) 。应用的最终用户可能并没有发觉他们正在指定捆绑变量,因为Oracle( 大型网站数据库平台) 的程序可能只是简单地指示他们输入新的值,其实这一切都在程序中自动做了。

  因为你指定了变量名,在你再次执行之前无须重新捆绑变量。你可以改变绑定变量的值,而Oracle( 大型网站数据库平台) 在每次执行时,仅仅使用内存地址来查找此值。

  如果Oracle( 大型网站数据库平台) 需要实现自动数据类型转换的话(除非它们是隐含的或缺省的),你还必须对每个值指定数据类型和长度。关于这些信息可以参考Oracle( 大型网站数据库平台) 的相关文档,如Oracle( 大型网站数据库平台) Call Interface Programmer's Guide

  第6: 并行执行语句(Parallelize the Statement )

  Oracle( 大型网站数据库平台) 可以在SELECTs, INSERTs, UPDATEs, MERGEs, DELETEs 语句中执行相应并行查询操作,对于某些DDL 操作,如创建索引、用子查询创建表、在分区表上的操作,也可以执行并行操作。并行化可以导致多个服务器进程(Oracle( 大型网站数据库平台) server processes) 为同一个SQL 语句工作,使该SQL 语句可以快速完成,但是会耗费更多的资源,所以除非很有必要,否则不要使用并行查询。

  第7: 执行语句(Run the Statement)

  到了现在这个时候,Oracle( 大型网站数据库平台) 拥有所有需要的信息与资 源,因此可以真正运行SQL 语句了。如果该语句为SELECT 查询或INSERT 语句,则不需要锁定任何行,因为没有数据需要被改变。然而,如果语句为 UPDATEDELETE 语句,则该语句影响的所有行都被锁定,防止该用户提交或回滚之前,别的用户对这些数据进行修改。这保证了数据的一致性。

  对于某些语句,你可以指定执行的次数,这称为批处理(array processing) 。指定执行N 次,则绑定变量与定义变量被定义为大小为N 的数组的开始位置,这种方法可以减少网络开销,也是优化的技巧之一。

  第8: 取出查询的行(Fetch Rows of a Query)

  在fetch 阶段,行数据被取出来,每个后续的存取操作检索结果集中的下一行数据,直到最后一行被取出来。上面提到过,批量的fetch 是优化的技巧之一。

  第9: 关闭游标(Close the Cursor)

  SQL 语句处理的最后一个阶段就是关闭游标

  DDL 语句的处理(DDL Statement Processing)

  DDL 语句的执行不同与DML 语句和查询语句的执行,这是因为DDL 语句执行成功后需要对数据字典数据进行修改。对于DDL 语句,语句的分析阶段实际上包括分析、查找数据字典信息和执行。

  事务管理语句、会话管理语句、系统管理语句只有分析与执行阶段,为了重新执行该语句,会重新分析与执行该语句。

  事务控制(Control of Transactions)

  一般来说,只有使用Oracle( 大型网站数据库平台) 编程接口的应用设计人员才关心操作的类型,并把相关的操作组织在一起,形成一个事务。一般来说,我门必须定义事务,这样在一个逻辑单元中的所有工作可以同时被提交或回滚,保证了数据的一致性。一个事务应该由逻辑单元中的所有必须部分组成,不应该多一个,也不应该少一个。

  在事务开始和结束的这段时间内,所有被引用表中的数据都应该在一致的状态( 或可以被回溯到一致的状态)

  事务应该只包含可以对数据进行一致更改(one consistent change to the data)SQL 语句

  例如,在两个帐号之间的转帐( 这是一个事务或逻辑工作单元) ,应该包含从一个帐号中借钱( 由一个SQL 完成) ,然后将借的钱存入另一个帐号( 由 另一个SQL 完成) 。这2 个操作作为一个逻辑单元,应该同时成功或同时失败。其它不相关的操作,如向一个帐户中存钱,不应该包含在这个转帐事务中。

  在设计应用时,除了需要决定哪种类型的操作组成一个事务外,还需要决定使用BEGIN_DISCRETE_TRANSACTIO 存储过程是否对提高小的、非分布式的事务的性能有作用。

  四:Oracle( 大型网站数据库平台) 的优化器

  优化器有时也被称为查询优化器,这是因为查询是影响数据库性能最主要的部分,不要以为只有SELECT 语句是查询。

实际上,带有任何WHERE 条件的DML(INSERTUPDATEDELETE) 语句中都包 含查询要求,在后面的文章中,当说到查询时,不一定只是指SELECT 语句,也有可能指DML 语句中的查询部分。优化器是所有关系数据库引擎中的最神秘、 最富挑战性的部件之一,从性能的角度看也是最重要的部分,它性能的高低直接关系到数据库性能的好坏。

  我们知道,SQL 语句同其它语言(C 语言) 的语句不一样,它是非过程化(non-procedural) 的语句,即当你要取数据时,不需要告 诉数据库通过何种途径去取数据,如到底是通过索引取数据,还是应该将表中的每行数据都取出来,然后再通过一一比较的方式取数据( 即全表扫描) ,这是由数据 库的优化器决定的,这就是非过程化的含义,也就是说,如何取数据是由优化器决定,而不是应用开发者通过编程决定。在处理SQLSELECT UPDATEINSERTDELETE 语句时,Oracle( 大型网站数据库平台) 必须访问语句所涉及的数据,Oracle( 大型网站数据库平台) 的优化器部分用来决定访问数据的有效路径,使得语句执行所需的I/O 和处理时间最小。

  为了实现一个查询,内核必须为每个查询定制一个查询策略 ,或为取出符合条件的数据生成一个执行计划(execution plan) 。典型的,对于同一个查询,可能有几个执行计划都符合要求,都能得到符合条件的数据。例如,参与连接的表可以有多种不同的连接方法,这取决于连 接条件和优化器采用的连接方法。为了在多个执行计划中选择最优的执行计划,优化器必须使用一些实际的指标来衡量每个执行计划使用的资源(I/0 次数、 CPU) ,这些资源也就是我们所说的代价(cost) 。如果一个执行计划使用的资源多,我们就说使用执行计划的代价大。以执行计划的代价大小作为衡量标 准,优化器选择代价最小的执行计划作为真正执行该查询的执行计划,并抛弃其它的执行计划。

  在Oracle( 大型网站数据库平台) 的发展过程中,一共开发过2 种类型的优化器:基于规则的优化器和基于代价的优化器 。这2 种优化器的不同之处关键在于:取得代价的方法与衡量代价的大小不同。现对每种优化器做一下简单的介绍:

  基于规则的优化器 -- Rule Based (Heuristic) Optimization( 简称RBO)

  在Oracle( 大型网站数据库平台)7 之前,主要是使用基于规则的优化器。Oracle( 大型网站数据库平台) 在 基于规则的优化器中采用启发式的方法(Heuristic Approach) 或规则(Rules) 来生成执行计划。例如,如果一个查询的where 条件(where clause) 包含一个谓词(predicate ,其实就是一个判断条件,如 = , >, < ”等) ,而且该谓词上引用的列上有有效索引,那么优化器将使用索引访问这个表,而不考虑其它因素,如表中数据的多少、表中数据的易变性、索引的 可选择性等。此时数据库中没有关于表与索引数据的统计性描述,如表中有多上行,每行的可选择性等。优化器也不考虑实例参数,如multi block i/o 、可用排序内存的大小等,所以优化器有时就选择了次优化的计划作为真正的执行计划,导致系统性能不高。

  如,对于

select * from emp where deptno = 10;

  这个查询来说,如果是使用基于规则的优化器,而且deptno 列上有有效的索引,则会通过deptno 列上的索引来访问emp 表。在绝大多数情况下,这是比较高效的,但是在一些特殊情况下,使用索引访问也有比较低效的时候,现举例说明:

  1:emp 表比较小,该表的数据只存放在几个数据块中。此时使用全表扫描比使用索引访问emp 表反而要好。因为表比较小,极有可能数据全在内存 中,所以此时做全表扫描是最快的。 而如果使用索引扫描,需要先从索引中找到符合条件记录的rowid ,然后再一一根据这些rowidemp 中将数据取出 来,在这种条件下,效率就会比全表扫描的效率要差一些。

  2:emp 表比较大时,而且deptno = 10 条件能查询出表中大部分的数据如(50%) 。如该表共有4000 万行数据,共放在有500000 个数据块中,每个数据块为8k ,则该表共有约4G ,则 这么多的数据不可能全放在内存中,绝大多数需要放在硬盘上。此时如果该查询通过索引查询,则是你梦魇的开始。

db_file_multiblock_read_count 参数的值200 。如果采用全表扫 描,则需要500000/db_file_multiblock_read_count=500000/200=2500I/O 。但是如果采用索引扫 描,假设deptno 列上的索引都已经cache 到内存中,所以可以将访问索引的开销忽略不计。因为要读出4000x 50% = 2000 万数据,假设在读这2000 万数据时,有99.9% 的命中率,则还是需要20000I/O, 比上面的全表扫描需要的2500 次多多了,所以在这 种情况下,用索引扫描反而性能会差很多。在这样的情况下,用全表扫描的时间是固定的,但是用索引扫描的时间会随着选出数据的增多使查询时间相应的延长。

  上面是枯燥的假设数据,现在以具体的实例给予验证:

  环境: Oracle( 大型网站数据库平台) 817 + linux + 阵列柜,表SWD_BILLDETAIL3200 多万数据;

  表的id 列、cn 列上都有索引

  经查看执行计划,发现执行select count(id) from SWD_BILLDETAIL; 使用全表扫描,执行完用了大约1.50 分钟(4 次执行取平均,每次分别为1.45 1.51 2.00 1.46) 。而执行select count(id) from SWD_BILLDETAIL where cn <'6'; 却用了2 个小时还没有执行完,经分析该语句使用了cn 列上的索引,然后利用查询出的rowid 再从表中查询数据。我为什么不使用 select count(cn) from SWD_BILLDETAIL where cn <'6'; 呢?后面在分析执行路径的索引扫描时时会给出说明。

 

 

放不下 下面的在附件里面

你可能感兴趣的:(oracle,sql,应用服务器,SQL Server,网络应用)