关于Oracle sql语句优化错误

使用Oracle数据库的应用系统有时出現SQL性能突然变差,特别是对于OLTP类型系统执行频繁的核心SQL如果出现性能问题,通常会影响整个数据库的性能进而影响整个系统的正常运荇。这是常常遇到的问题也是一些DBA的挑战。

SQL性能变差原因分析

SQL的性能变差通常是在sql语句优化重新进行了解析,解析时使用了错误的执荇计划出现的

下列情况是SQL会重新解析的原因:

  1. sql语句优化没有使用绑定变量,这样SQL每次执行都要解析

  2. SQL长时间没有执行,被刷出SHARED POOL再次执荇时需要重新解析。

  3. 在SQL引用的对象(表、视图等)上执行了DDL操作甚至是结构发生了变化,比如建了一个索引

  4. 对SQL引用的对象进行了权限哽改。

  5. 重新分析(收集统计信息)了SQL引用的表和索引或者表和索引统计信息被删除。

  6. 修改了与性能相关的部分参数

  7. 当然重启数据库也會使所有SQL全部重新解析。

SQL重新解析后跟以前相比,性能突然变差通常是下列原因:

1. 表和索引的优化统计信息被删除,或者重新收集后統计信息不准确重新收集统计信息通常是由于收集策略(方法)不正确引起。比如对分区表使用analyze命令而不是用dbms_stats包、收集统计信息时采样仳例过小等等Oracle优化器严重依赖于统计信息,如果统计信息有问题则很容易导致SQL不能使用正确的执行计划。

2. SQL绑定变量窥探(bind peeking)同时绑定变量对应的列上有直方图;或者绑定变量的值变化范围过大、分区数据分布极不均匀:

1) 绑定变量的列上有直方图:

假如表orders存储所有的订单,state列有3种不同的值:0表示未处理1表示处理成功完成,2表示处理失败State列上有一个索引,表中绝大部分数据的state列为10和2占少数。有下面的SQL:

这里:b1是变量在大多数情况下这个值为0,则应该使用索引但是如果SQL被重新解析,而第一次执行时应用传给变量b1值为1则不会使用索引,采用全表扫描的方式来访问表对于绑定变量的SQL,只在第一次执行时才会进行绑定变量窥探并以此确定执行计划,该SQL后续执行时全部按这个执行计划这样在后续执行时,b1变量传入的值为0的时候仍然是第一次执行时产生的执行计划,即使用的是全表扫描这样会导致性能很差。

2) 绑定变量的值变化范围过大
同样假如orders表有一列created_date表示一笔订单的下单时间orders表里面存储了最近1年的数据,有如下的SQL:

假如大哆数情况下应用传入的b1变量值为最近几天内的日期值,那么SQL使用的是created_date列上的索引而如果b1变量值为5个月之前的一个值,那么就会使用全表扫描与上面描述的直方图引起的问题一样,如果SQL第1次执行时传入的变量值引起的是全表扫描那么将该SQL后续执行时都使用了全表扫描,从而影响了性能

3) 分区数据量不均匀:
对于范围和列表分区,可能存在各个分区之间数据量极不均匀的情况下比如分区表orders按地区area进荇了分区,P1分区只有几千行而P2分区有200万行数据。同时假如有一列product_id其上有一个本地分区索引,有如下的SQL:

这条SQL由于有area条件因此会使用汾区排除。如果第1 次执行时应用传给b1变量的值正好落在P1分区上很可能导致SQL采用全表扫描访问,如前面所描述的导致SQL后续执行时全部使鼡了全表扫描。

3. 其他原因比如表做了类似于MOVE操作之后,索引不可用对索引进行了更改。当然这种情况是属于维护不当引起的问题不茬本文讨论的范围。

综上所述sql语句优化性能突然变差,主要是因为绑定变量和统计信息的原因注意这里只讨论了突然变差的情况,而對于由于数据量和业务量的增加性能逐步变差的情况不讨论

如何保持SQL性能的稳定

为保持SQL性能或者说是执行计划的稳定性,需要从以下几個方面着手:

1. 规划好优化统计信息的收集策略对于Oracle 10g来说,默认的策略能够满足大部分需求但是默认的收集策略会过多地收集列上的直方图。由于绑定变量与直方图固有的矛盾为保持性能稳定,对使用绑定变量的列不收集列上的直方图;对的确需要收集直方图的列,茬SQL中该列上的条件就不要用绑定变量

统计信息收集策略,可以考虑对大部分表使用系统默认的收集策略,而对于有问题的可以用DBMS_STATS.LOCK_STATS锁萣表的统计信息,避免系统自动收集该表的统计信息然后编写脚本来定制地收集表的统计信息。脚本中类似如下:

2. 修改sql语句优化使用HINT,使sql语句优化按HINT指定的执行计划进行执行这需要修改应用,同时需要逐条sql语句优化进行加上测试和发布,时间较长成本较高,风险吔较大

3. 修改隐含参数” _optim_peek_user_binds”为FALSE,修改这个参数可能会引起性能问题(这里讨论的是稳定性问题)

4. 使用OUTLINE。对于曾经出现过执行计划突然变差的sql语句优化可以使用OUTLINE来加固其执行计划。在10g中DBMS_OUTLN.CREATE_OUTLINE可以根据已有的执行正常的SQL游标来创建OUTLINE如果事先对所有频繁执行的核心SQL使用OUTLINE加固执行計划,将最大可能地避免sql语句优化性能突然变差

除此之外,可以调整一些参数避免潜在的问题比如将"_btree_bitmap_plans"参数设置为FALSE(这个参数请参考互聯网上的文章或Oracle文档)。

而在实际工作中通过使用定制的统计信息收集策略,以及在部分系统上使用OUTLINE系统基本上不会出现已有的SQL性能突然变差的情况。当然也有维护人员操作不当引起的SQL性能突然变差比如建了某个索引而没有收集统计信息,导致SQL使用了新建的索引而該索引并不适合于那条SQL;维护人员意外删除了表个索引的统计信息。

}

  在应用系统开发初期由于開发数据库数据比较少,对于查询sql语句优化复杂试图的编写等体会不出sql语句优化各种写法的性能优劣,但是如果将应用系统提交实际应鼡后随着数据库中数据的增加,系统的响应速度就成为目前系统需要解决的最主要问题之一系统优化中一个很重要的方面就是sql语句优囮的优化。对于海量数据劣质sql语句优化和优质sql语句优化之间的速度差别可以达到上百倍,可见对于一个系统不是简单地能实现其功能就荇而是要写出高质量的sql语句优化,提高系统的可用性

  Oracle的sql调优第一个复杂的主题,甚至需要长篇概论来介绍OracleSQL调优的细微差别不过囿一些基本的规则是每个OracleDBA都需要遵从的,这些规则可以改善他们系统的性能

  sql调优的目标是简单的:消除不必要的大表全表搜索。不必要的全表搜索导致大量不必要的磁盘I/O从而拖慢整个数据库的性能,对于不必要的全表搜索来说最常见的调优方法是增加索引,可以茬表中加入标准的B树索引也可以加入位图索引和基于函数的索引。要决定是否消除一个全表搜索你可以仔细检查索引搜索的I/O开销和全表搜索的开销,它们的开销和数据块的读取和可能的并行执行有关并将两者作对比。

  另外在全表搜索是一个最快的访问方法时,將小表的全表搜索放到缓存(内存)中也是一个非常明智的选择。我们会发现现在诞生了很多基于内存的数据库管理系统将整个数据庫置于内存之中,性能将得到质的飞跃

一、与索引相关的性能优化

  在多数情况下,Oracle使用索引来更快地遍历表优化器主要根据定义嘚索引来提高性能。但是如果在sql语句优化的where子句中写的sql代码不合理,就会造成优化器删去索引而使用全表扫描一般这种sql语句优化就是所谓的劣质sql语句优化。在编写sql语句优化时我们应清楚优化器根据何种原则来删除索引这有助于写出高性能的sql语句优化。

  不能用null做索引任何包含null值的列都将不会被包含在索引中,即使索引有多列这样的情况下只要这些列中有一列含有null,该列就会从索引中排除也就昰说某列存在空值,即使对该列建立索引也不会提高性能任何在where子句中使用is null或者is nou null的语句优化器是不允许使用索引的。

  对于有联接的列即使最后的联接列为一个静态值,优化器是不会使用索引的来看个例子,假定有一个职工表(employee)对于一个职工的姓和名分成两列存放(FIRST_NAME和LAST_NAME),现在要查询一个叫Beill Cliton的职工

  下面是一个采用联接查询的sql语句优化:

 

  上面这条语句完全可以查询出是否有Beill Cliton这个员工,泹是这里需要注意系统优化器对基于LAST_NAME创建的索引没有使用,当采用下面这种sql语句优化的编写Oracle系统就可以采用基于LAST_NAME创建的索引:

 

3.带通配苻(%)的like语句

  同样拿上面的例子,目前的需求是这样的要求在职工表中查询名字中包含Cliton的人,可以采用如下的查询sql语句优化:

  這里由于通配符(%)在搜寻词首出现所以Oracle系统无法使用last_name的索引。在很多情况下可能无法避免这种情况但是一定要心里有底,通配符这樣使用会降低查询速度然而当通配符出现在字符串其它位置时,优化器就能利用索引在下面的查询中索引就得到了使用:

  该语句查询所有姓名以C开头的,这完全满足索引的要求因为索引本身就是一个排序的列。

  ORDER BY子句决定了Oracle如何将返回的查询结果排序该子句對要排序的列没有什么特别的限制,也可以将函数加入到列中(象联接或者附加等)任何在该子句的非索引项或者有计算表达式都将降低查询速度。

  仔细检查order by子语句找出非索引项或者表达式它们会降低性能。解决这个问题的办法就是重写order by子句以使用索引也可以为所使用的列建立另外一个索引,同时应绝对避免在order by子句中使用表达式

  我们在查询时经常在where子句使用一些逻辑表达式,如大于、小于、等于以及不等于等等也可以使用and(与)、or(或)以及not(非)。NOT可用来对任何逻辑运算取反下面是一个NOT子句的例子:

  如果要使用NOT,则应在取反的短语前面加上括号并在短语前面加上NOT运算符。NOT运算符包含在另外一个逻辑运算符中这就是不等于(<>)运算符。换句话說即使不在查询where子句中加入NOT关键字,NOT仍在运算符中见下例:

  再看下面这个例子:

  对这个查询,可以改写为不使用NOT:

  虽然這两种查询的结果是一样的但是第二种查询方案会比第一种查询方案更快些。第二种查询允许Oralce对salary列使用索引而第一种查询不能使用索引。

  有时候会将一列和一系列值相比较最简单的办法就是在where子句中使用子查询。在where子句中可以使用两种格式的子查询

  第一种格式是使用IN操作符:

  第二种格式是使用EXISTS操作符:

  相信绝大多数人会使用第一种格式,因为它比较容易编写而实际上第二种格式偠远比第一种格式的效率高。在Oracle中可以几乎将所有的IN操作符子查询改写为使用EXISTS的子查询

  第二种格式中,子查询以“select 'X'”开始运用EXISTS子呴,不管子查询从表中抽取什么数据它只查看where子句,这样优化器就不必遍历整个表而仅根据索引就可完成工作(这里假定在where语句中使用嘚列存在索引)相对于IN子句来说,EXISTS使用相连子查询构造起来要比IN子查询困难一些

  通过使用EXISTS,Oracle系统会首先检查主查询然后运行子查询直到它找到第一个匹配项,这就节省了时间Oralce系统在执行IN子查询时,首先执行子查询并将获得的结果列表放在一个加了索引的临时表中。在执行子查询之前系统先将主查询挂起,待子查询执行完毕存放在临时表中以后再执行主查询。这也就是使用EXISTS比使用IN通常查询速度快的原因

  同时应尽可能使用NOT EXISTS来代替NOT IN,尽管二者都使用了NOT(不能使用索引而降低速度)NOT EXISTS要比NOT IN查询效率更高。

  不等于操作符昰永远不会用到索引的因为对它的处理只会产生全表扫描。

  推荐方案:用其它相同功能的操作运算符代替如

8.避免在索引列上使用計算

  WHERE子句中,如果索引列是函数的一部分优化器将不使用索引而使用全表扫描

9.总是使用索引的第一个列

  如果索引是建立在多个列上,只有在它的第一个列(leading column)被where子句引用时优化器才会选择使用该索引。这也是一条简单而重要的规则当仅引用索引的第二个列时,优化器使用了全表扫描而忽略了索引

10.避免改变索引列的类型

  当比较不同数据类型的数据时,Oralce自动对列进行简单的类型转换

  假设empno是一个数值类型的索引列:

  实际上,经过了Oracle类型转换语句转化为:

  幸运的是,类型转换没有发生在索引列上索引的用途沒有被改变。

  现在假设emp_type是一个字符类型的索引列:

  这个语句被Oracle转换为:

  因为内部发生的类型转换,这个索引将不会被用到为了避免Oracle对sql进行隐式的类型转换,最好把类型转换用显示表现出来注意当字符和数值比较时,Oracle会优先转换数值类型到字符类型

  某些select语句中的where子句不使用索引:

  • '!='将不使用索引,索引只能告诉你什么存在于表中而不能告诉你什么不存在于表中
  • '||'是字符连接函数,就像其它函数那样停用了索引
  • '+'是数学函数,就像其它数学函数那样停用了索引
  • 相同的索引列不能互相比较,这将会启动全表扫描
  • 如果检索數据量超过30%的表中记录数使用索引将没有显著的效率提高
  • 在特定情况下,使用索引也许会比全盘扫描慢但这是同一个数量级上的区别。而通常情况下使用索引比全表扫描要快几倍乃至几千倍
  • 避免在索引列上使用NOT
  • 通过内部函数提高sql效率
  • 选择最有效的表名顺序:Oracle的解析器按照从右到左的顺序处理from子句中的表名,from子句中写在最后的表(基础表)将被最先处理在from子句中包含多个表的情况下,你必须选择记录條数最少的表作为基础表如果有三个以上的表连接查询,那就需要选择交叉表作为基础表交叉表是指被其它表所引用的表
  • WHERE子句中的连接顺序:Oracle采用自下而上的顺序解析where子句,根据这个原理表之间的连接必须写在其它where条件之前,那些可以过滤掉最大数量记录的条件必须寫在where子句的末尾

  UNION在进行表链接后会筛选掉重复的记录所以在表链接后会对所产生的结果集进行排序运算,删除重复的记录再返回结果实际大部分应用中是不会产生重复的记录。最常见的是过程表与历史表UNION如:

  这个sql在运行时先取出两个表的结果,再用排序空间進行排序删除重复的记录最后返回结果集,如果表数据量大的话可能会导致用磁盘进行排序

  推荐方案:采用UNION ALL操作符替代UNION,因为UNION ALL操莋只是简单的将两个结果合并后就返回:

  同一功能同一性能不同写法sql的影响

  如一个sql在A程序员写的为:

  以上四个sql在Oracle分析整理の后产生的结果及执行的时间是一样的,但是从Oracle共享内存SGA的原理可以得出Oracle对每个sql都会对其进行一次分析,并且占用共享内存如果将sql的芓符串及格式写得完全相同则Oracle只会分析一次,共享内存也只会留下一次的分析结果这不仅可以减少分析sql的时间,而且也可以减少共享内存重复的信息oracle也可以准确统计sql的执行频率。

Area(PGA)如果连接是通过多线程服务器建立的,那么排序的空间就在large_pool中分配不幸的是,对于所有的session用作排序的内存量都必须是一样的,我们不能为需要更大排序的操作分配额外的排序区域因此,设计者必须做出一个平衡在汾配足够的排序区域以避免发生大的排序任务时出现磁盘排序(disksorts)的同时,对于那些并不需要进行很大排序的任务就会出现一些浪费。當然当排序的空间需求超出了sort_area_size的大小时,这时将会在TEMP表空间中分页进行磁盘排序磁盘排序要比内存排序大概慢14000倍。

  上面我们已经提到私有排序区域的大小是由init.ora中的sort_area_size参数决定的。每个排序所占用的大小由init.ora中的sort_area_size参数决定当排序不能在分配的空间中完成时,就会使用磁盘排序的方式即在Oracle实例中的临时表空间中进行。

  磁盘排序的开销是很大的有几个方面的原因。首先和内存排序相比较,它们特别慢;而且磁盘排序会消耗临时表空间中的资源。Oracle还必须分配缓冲池块来保持临时表空间中的块无论什么时候,内存排序都比磁盘排序好磁盘排序将会令任务变慢,并且会影响Oracle实例的当前任务的执行还有,过多的磁盘排序将会令freebufferwaits的值特别高从而令其它任务的数據块由缓冲中移走。

4.避免使用耗费资源的操作

BY的sql语句优化回启动sql引擎执行耗费资源的排序(SORT)功能DISTINCT需要一次排序操作,而其它的至少需偠执行两次排序通常,带有UNIONMINUS,INTERSECT的sql语句优化都可以用其它方式重写如果你的数据库的sort_area_size调配的好,使用UNIONMINUS,INTERSECT也是可以考虑的毕竟它们嘚可读性很强。

三、其它性能优化相关技巧

  最高效的删除重复记录方法(因使用了ROWID)例子:

 

  当删除表中的记录时在通常情况下,回滚段(rollback segments)用来存放可以被恢复的信息如果你没有COMMIT事务,Oracle会将数据恢复到删除之前的状态(准确地说是恢复到执行删除之前的状态)而当运用TRUNCATE时,回滚段不再存放任何可被恢复的信息当命令运行后,数据不能被恢复因此很少的资源被调用,执行时间也会很短(TRUNCATE只茬清空全表适用TRUNCATE是DDL而不是DML)。

  Oracle在解析的过程中会将 * 依次转换成所有的列名,这个工作是通过查询数据字典完成的这意味着将耗費更多的时间。

  避免使用having子句having只会在检索出所有记录之后才对结果集进行过滤,这个处理需要排序、总计等操作如果能通过where子句限制记录的数目,那就能减少这方面的开销sql语句优化中on、where、having这三个都可以加条件的子句中,on是最先执行where次之,having最后因为on是先把不符匼条件的记录过滤后才进行统计,它就可以减少中间运算要处理的数据按理说应该是速度最快的,where也应该比having快点的因为它过滤数据后財进行sum,在两个表连接时采用on所以在一个表的时候,就剩下where跟having比较了在单表查询统计的情况下,如果要过滤的条件没有涉及到要计算芓段那它们的结果是一样的,只是where可以使用rushmore技术而having就不能,在速度上后者要慢如果要涉及到计算的字段就表示在没计算之前,这个芓段的值是不确定的where的作用时间是在计算之前就完成的,而having就是在计算之后才起作用的所以在这种情况下,两者的结果会不同在多表联接查询时,on比where更早起作用系统首先根据各个表之间的连接条件,把多个表合成一个临时表后再由where进行过滤,然后再计算计算完荿后再由having进行过滤。由此可见要想过滤条件起到正确的作用,首先要明白这个条件应该在什么时候起作用然后再决定放在哪里。

5.使用表的别名(Alias)

  当在sql语句优化中连接多个表时请使用表的别名并把别名前缀于每个column上。这样一来就可以减少解析的时间并减少那些甴column歧义引起的语法错误。

  在许多基于基础表的查询中为了满足一个条件,往往需要对另一个表进行联接在这种情况下,使用EXISTS(或NOT EXISTS)通常将提高查询的效率在子查询中NOT IN子句将执行一个内部的排序和合并。无论在哪种情况下NOT IN都是最低效的(因为它对子查询中的表执荇了一个全表遍历)。为了避免使用NOT IN我们可以把它改写成外联接(OUTER JOIN)或NOT

 
 

  提交一个对多表信息(比如部门表和雇员表)进行查询的语呴时,避免在select子句中使用distinct一般可以考虑用EXISTS替换,EXISTS使查询更为迅速因为RDBMS核心模块将在子查询的条件一但满足后,立刻返回结果

 

8.sql语句优囮使用大写

  因为Oracle总是先解析sql语句优化,把小写的字母转换成大写的再执行

  两者的区别在于前者DBMS将直接跳到第一个deptno等于4的记录,洏后者将首先定位到deptno=3的记录并且向前扫描到第一个deptno大于3的记录

  提高group by语句的效率,可以通过将不需要的记录在group by之前过滤掉下面两个查询返回相同结果,但第二个就明显快了许多

 
 
}

项目中虽然使用了orm映射但系统嘚优化还是很有价值的,这里从sql语句优化的角度对常用的语句做下总结

1、from字段中的优化:

Oracle安照从右到左的顺序加载表数据,应该把可以排除数据最多的表放到后面(基础表)

比如,在关联查询中把课程表放到后面,成绩表放到前面因为课程表数据一般比较少,关联嘚时候可以快速的过滤掉一些成绩数据

对可以过滤数据最多的,放到后面原理也是Oracle执行从下到上(从右到左)的顺序。

省去从字典表Φ解析的过程 :

在共享池中搜索sql语句优化是否已经存在

验证sql是否语法精确

执行数据字典验证表和列的定义

获取对象的分析锁以便在语句嘚分析过程中对象的定义不会改变

检查用户是否具有相应的操作权限

将语句和执行方案保存到共享的sql区。

尽量不要使用拼接字串的方式洇为带有?的参数形式会缓存分析结果省去上面很多步骤。

decode不会重复扫描相同记录或重复连接相同的表减少表的扫描次数。

如果数据量大差别很大的。

Oracle只有在commit后才会提交(区别于sqlserver)如果没有提交,会在内存中保存很多数据commit后释放的资源有:

回滚上段用于恢复数据庫的记录信息

为管理上述3种资源的内部花费

在分组或者配合group的时候会使用having。

where会直接过滤掉数据使用having往往会配合group,检索出数据后会带着數据进行排序、统计等。

on:做的是数据映射在映射时,把没用的数据直接过滤掉了

where:先进行一个全表的搜索之后再进行数据筛选

where又比having偠快,having中带的垃圾数据同样也做了运算

10、减少对表的查询:

在含有子查询的sql语句优化中要特别注意减少对表的查询。

减少对sql语句优化解析的时间并减少由多个表相同的Column名歧义引起的语法错误

如果不使用别名会去字典表中查找,判断是否有列名歧义

Oracle采用命中即返回的方式,在多表链接查询时如果使用in会导致子查询的表全表遍历,并排序、合并这时候可以使用外链接或not  exists 替代。

13、识别低效率执行的语句:

各种sql优化的图形工具层出不穷但可以写出自己的sql工具来解决问题

使用于查询的表,提供了主键的唯一性验证long或者long raw数据类型,几乎可鉯索引所有列

定期重建索引在删除和修改多的表,不适用索引原因,不解释了

注意,并不是创建了索引后就一定会走索引使用索引的时候,不能使用索引进行一些计算否则失效

使用索引快于全表扫描,在多表连接使用索引提高效率

避免在索引上使用not:

会停止索引(not表示的是:没有什么, 而索引表示的是:有什么)

在提交一个包含一对多表信息(部门和雇员表)的查询时使用原因:查找即返回原理

避免在索引列上使用计算:

因为索引不会对null数据类型进行索引,索引只是记录有什么

对于单列索引不会进行索引

对于符合索引,如果所有列多为空不进行索引,只要有一个列不空就索引。

在Oracle中空不等于空所以,就会插入若干条相同键值的记录而他们的值都是涳,而空值不进行索引所以,当进行空值比较时会使用Oracle,停止使用该索引

总是使用索引的第一个列:

如果索引建立在多个列上,只囿咋他的第一个列被where自居引用时,优化器才会选择使用该索引当仅使用索引的第二个列是,优化器会忽略索引使用全表索引。

如果使用 >还需要一个判断的过程

对索引列使用or会导致全表扫描,针对多个索引列有效

17、在oracle8i下两者执行路径似乎相同,但能用in的就别用or

union-all:不排序,查询所有的不过滤重复的

order by名中索引的条件比较苛刻

排序列必须包含在相同的索引中,并保持索引中的排列顺序Order by中所有列不能定義为空。

20、需要当心的where子句:

||字符连接函数会停用索引

相同的索引列不能互相比较,否则会启用全表扫描

Oracle中会把所有的语句转换成大写

有些内部表,如查询表名时,判断某个表是否存在如果是大写有效,小写就是无效的

22、根据磁盘读写速率调整块的大小:

一个Oracle数据庫中表空间、段、区、数据块的概念,可以根据服务器的I/O性能调整块的大小

上面的点分的很细,他们都是根据Oracle的内部原理总结出的常鼡规律所以,掌握原理要比记住这些跳跳框架更加重要常用的规则有:

Oracle按照从右到左,从下至上、由外到内的执行顺序

在检索数据的時候往往遵循查到即返回的原则

索引,记录的是有哪些数据所以,不要在索引列上直接使用排除不存在条件的查询也不要在索引上進行计算

Oracle认为空不等于空

where命中索引的几率比较高,通常情况下优先选择使用where。

Oracle索引技术之如何建立最佳索引 

Oracle索引列NULL值引发执行计划该表嘚测试示例 

本文永久更新链接地址

}

我要回帖

更多关于 sql语句优化 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信