Oracle <>,!=,^ =运算符

Jun*_*Liu 10 sql database oracle performance query-optimization

我想知道这些运营商的差异,主要是他们的性能差异.

在SQL中查看了<>和!=之间的区别,它没有与性能相关的信息.

然后我在dba-oracle.com上发现了这一点,它表明在10.2以后性能可能会有很大不同.

我想知道为什么?不!=总是有更好的表现,然后<>

注意:我们的测试和实时系统的性能显示,从更改<>!=对查询返回的时间有很大影响.我在这里问为什么会发生这种情况,而不是它们是否相同.我在语义上知道它们,但实际上它们是不同的.

小智 28

我已经测试了Oracle中不等运算符的不同语法的性能.我试图消除对测试的所有外部影响.

我使用的是11.2.0.3数据库.在开始测试之前,没有连接其他会话并重新启动数据库.

使用单个表和主键序列创建了一个模式

CREATE TABLE loadtest.load_test (
  id NUMBER NOT NULL,
  a VARCHAR2(1) NOT NULL,
  n NUMBER(2) NOT NULL,
  t TIMESTAMP NOT NULL
);

CREATE SEQUENCE loadtest.load_test_seq
START WITH 0
MINVALUE 0;
Run Code Online (Sandbox Code Playgroud)

该表已编制索引以提高查询性能.

ALTER TABLE loadtest.load_test
ADD CONSTRAINT pk_load_test
PRIMARY KEY (id)
USING INDEX;

CREATE INDEX loadtest.load_test_i1
ON loadtest.load_test (a, n);
Run Code Online (Sandbox Code Playgroud)

使用序列将1000万行添加到表中,SYSDATE时间戳和随机数据通过DBMS_RANDOM(AZ)和(0-99)添加到其他两个字段.

SELECT COUNT(*) FROM load_test;

COUNT(*)
----------
10000000

1 row selected.
Run Code Online (Sandbox Code Playgroud)

分析了模式以提供良好的统计信息.

EXEC DBMS_STATS.GATHER_SCHEMA_STATS(ownname => 'LOADTEST', estimate_percent => NULL, cascade => TRUE);
Run Code Online (Sandbox Code Playgroud)

三个简单的查询是: -

SELECT a, COUNT(*) FROM load_test WHERE n <> 5 GROUP BY a ORDER BY a;

SELECT a, COUNT(*) FROM load_test WHERE n != 5 GROUP BY a ORDER BY a;

SELECT a, COUNT(*) FROM load_test WHERE n ^= 5 GROUP BY a ORDER BY a;
Run Code Online (Sandbox Code Playgroud)

这些完全相同,除了非等于运算符的语法(不只是<>和!=,还有^ =)

首先运行每个查询而不收集结果以消除缓存的影响.

接下来的计时和自动跟踪以收集查询的实际运行时间和执行计划.

SET TIMING ON

SET AUTOTRACE TRACE
Run Code Online (Sandbox Code Playgroud)

现在查询依次运行.首先是<>

> SELECT a, COUNT(*) FROM load_test WHERE n <> 5 GROUP BY a ORDER BY a;

26 rows selected.

Elapsed: 00:00:02.12

Execution Plan
----------------------------------------------------------
Plan hash value: 2978325580

--------------------------------------------------------------------------------------
| Id  | Operation             | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |              |    26 |   130 |  6626   (9)| 00:01:20 |
|   1 |  SORT GROUP BY        |              |    26 |   130 |  6626   (9)| 00:01:20 |
|*  2 |   INDEX FAST FULL SCAN| LOAD_TEST_I1 |  9898K|    47M|  6132   (2)| 00:01:14 |
--------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter("N"<>5)


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
      22376  consistent gets
      22353  physical reads
          0  redo size
        751  bytes sent via SQL*Net to client
        459  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
         26  rows processed
Run Code Online (Sandbox Code Playgroud)

下一个!=

> SELECT a, COUNT(*) FROM load_test WHERE n != 5 GROUP BY a ORDER BY a;

26 rows selected.

Elapsed: 00:00:02.13

Execution Plan
----------------------------------------------------------
Plan hash value: 2978325580

--------------------------------------------------------------------------------------
| Id  | Operation             | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |              |    26 |   130 |  6626   (9)| 00:01:20 |
|   1 |  SORT GROUP BY        |              |    26 |   130 |  6626   (9)| 00:01:20 |
|*  2 |   INDEX FAST FULL SCAN| LOAD_TEST_I1 |  9898K|    47M|  6132   (2)| 00:01:14 |
--------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter("N"<>5)


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
      22376  consistent gets
      22353  physical reads
          0  redo size
        751  bytes sent via SQL*Net to client
        459  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
         26  rows processed
Run Code Online (Sandbox Code Playgroud)

最后^ =

> SELECT a, COUNT(*) FROM load_test WHERE n ^= 5 GROUP BY a ORDER BY a;

26 rows selected.

Elapsed: 00:00:02.10

Execution Plan
----------------------------------------------------------
Plan hash value: 2978325580

--------------------------------------------------------------------------------------
| Id  | Operation             | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |              |    26 |   130 |  6626   (9)| 00:01:20 |
|   1 |  SORT GROUP BY        |              |    26 |   130 |  6626   (9)| 00:01:20 |
|*  2 |   INDEX FAST FULL SCAN| LOAD_TEST_I1 |  9898K|    47M|  6132   (2)| 00:01:14 |
--------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter("N"<>5)


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
      22376  consistent gets
      22353  physical reads
          0  redo size
        751  bytes sent via SQL*Net to client
        459  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
         26  rows processed
Run Code Online (Sandbox Code Playgroud)

三个查询的执行计划相同,时间分别为2.12,2.13和2.10秒.

应该注意的是,无论在查询中使用哪种语法,执行计划总是显示<>

对于每个操作符语法,测试重复十次.这些是时间: -

<>

2.09
2.13
2.12
2.10
2.07
2.09
2.10
2.13
2.13
2.10

!=

2.09
2.10
2.12
2.10
2.15
2.10
2.12
2.10
2.10
2.12

^=

2.09
2.16
2.10
2.09
2.07
2.16
2.12
2.12
2.09
2.07
Run Code Online (Sandbox Code Playgroud)

虽然有一些百分之几的差异,但它并不重要.三种语法选择中的每一种的结果都是相同的.

语法选择被解析,优化,并在同一时间以相同的努力返回.因此,在该测试中使用一个在另一个上没有可感知的益处.

"啊BC",你说,"在我的测试中,我相信存在真正的差异而你无法证明这一点".

是的,我说,这是完全正确的.您尚未显示测试,查询,数据或结果.所以我对你的结果没什么可说的.我已经证明,在所有其他条件相同的情况下,使用哪种语法并不重要.

"那么为什么我在测试中看到一个更好?"

好问题.有几种可能性: -

  1. 您的测试存在缺陷(您没有消除外部因素 - 其他工作负载,缓存等您没有提供有关我们可以做出明智决定的信息)
  2. 您的查询是一个特例(向我展示查询,我们可以讨论它).
  3. 您的数据是一个特例(也许 - 但是如何 - 我们也没有看到).
  4. 还有其他一些外部影响.

我通过一个记录在案且可重复的过程表明,使用一种语法比另一种语法没有任何好处.我相信<>!=和^ =是同义词.

如果你认为不是很好,那么

a)显示我可以尝试自己的文档示例

b)使用您认为最好的语法.如果我是正确的并且没有区别那就没关系.如果你是正确的,那么很酷,你的工作很少有改进.

"但是Burleson说它更好,我比你更信任他,Faroult,Lewis,Kyte以及所有其他流浪汉."

他说它更好吗?我不这么认为.他没有提供任何明确的例子,测试或结果,但仅与某人说有关!=更好,然后引用他们的一些帖子.

显示不要告诉.


APC*_*APC 19

您可以参考Burleson网站上的文章.您是否关注了Oracle-L存档的链接?你是否阅读了回复Burleson引用电子邮件的其他电子邮件?

我认为你没有,否则你不会问这个问题.因为!= 和之间没有根本的区别<>.最初的观察几乎肯定是由数据库中的环境条件引起的侥幸.阅读Jonathan LewisStephane Faroult的回复以了解更多信息.


"尊重不是程序员需要拥有的东西,它是任何人都应该拥有的基本态度"

在一定程度上.当我们在街上遇到一个陌生人时,我们当然应该礼貌并尊重他们.

但是,如果那个陌生人希望我以特定的方式设计我的数据库应用程序以"提高性能",那么他们应该有一个令人信服的解释和一些防弹测试用例来支持它.一些随机个体的孤立轶事是不够的.

  • @Bob - 从某种意义上说,我不确定他会不会要你.Jonathan Lewis对这个世界如此有用的原因是因为他们所说的东西通常是可测试的和可重复的.你应该检查一下他们说什么,而不是总是"接受他们的话" - 尤其是因为这是一种很好的方法,可以将它固定在你的记忆中;-) (2认同)

Lei*_*fel 12

的作者的文章,虽然一书的作者和一些有用的信息传播者,不具备精度良好的口碑.在这种情况下,该文章仅提及一个人在着名的Oracle邮件列表上的观察.如果您仔细阅读回复,您将看到该帖子的假设受到质疑,但没有推定准确性.以下是一些摘录:

尝试通过解释计划(或自动跟踪)运行您的查询并查看其中的内容...根据此,"!="被认为与"<>"相同... ... Jonathan Lewis

Jonathan Lewis是Oracle社区中备受尊敬的专家.

出于好奇......查询优化器是否为这两个查询生成不同的执行计划?问候,克里斯

.

可能是绑定变量偷看行动?写作!=而不是<>的某些效果是强制重新解析.如果在第一次执行时,id:id的值不同,如果你在claws_doc_id上有直方图,那么这可能是一个原因.如果你告诉我claws_doc_id是主键,那么我会问你计算的目的是什么,特别是当EXISTS子句中的查询与外部查询不相关并且将返回相同的结果时:id是.看起来像一个轮询查询.围绕它的代码必须是有趣的.

StéphaneFouloul

.

我很确定lexical parse会将!=转换为<>或<>转换为!=,但我不确定这是否会影响sql文本是否与存储的大纲相匹配.

.

解释计划看起来一样吗?费用相同?

以下回复来自原始海报.

乔纳森,谢谢你的回答.我们确实对声明的两个版本做了一个解释计划,它们是相同的,这就是令人费解的问题.根据文档,两个不相等的形式是相同的(连同^ =和另一个我无法输入的形式),所以对我来说没有任何意义,为什么性能有任何差异.

斯科特迦南

.

不是一个包罗万象的小测试,但它至少在10.1.0.2中出现,它被削减为"<>"(请注意每个计划的过滤行)

.

你有任何存储大纲吗?存储的轮廓执行精确(文字)匹配,因此如果您有一个存储的大纲,例如,带有"!="的SQL,而没有带有"<>"的SQL(或反之亦然),则存储的大纲可能是使用提示?(虽然,考虑到它,你的EXPLAIN PLAN应该在执行存储大纲时显示提示吗?)

.

您是否尝试过仅仅解释和自动跟踪并运行完整的10046 12级跟踪以查看较慢版本花费时间的位置?这可能会对这个主题有所了解,另外 - 请确保在10046跟踪文件(不是使用EXPLAIN =选项生成的文件)和v $ sqlplan中验证解释计划完全相同.autotrace的一些"功能"和解释可能导致它无法为您提供准确的解释计划.

此致,布兰登

.

这种现象是否完全可以重现?

您是否检查了计划的filter_predicates和access_predicates,或仅检查结构.我不希望有任何区别,但如果您不幸,谓词顺序的更改可能会导致CPU使用率发生重大变化.

如果没有区别,则启用rowsource statistics(alter session set"_rowsource_execution_statistics"= true)并运行查询,然后从V $ sql_plan中获取执行计划并加入v $ sql_plan_statistics以查看是否有关于last_starts的任何数据,last_XXX_buffer_gets,last_disk_reads,last_elapsed_time为您提供时间去处的线索.

如果您使用的是10gR2,则可以使用/*+ gather_plan_statistics*/提示而不是"alter session".

关心乔纳森刘易斯

此时线程已经死亡,我们看不到原始海报中的其他帖子,这让我相信OP发现了他们所做的假设不是真的或者没有进一步调查.

我还要指出,如果您执行解释计划或自动跟踪,您将看到比较始终显示为<>.

这是一些测试代码.如果您愿意,可以增加循环迭代次数.您可能会看到一方或另一方获得更高的数字,具体取决于服务器活动中的其他活动,但是您绝不会看到一个运营商始终比另一方更好.

DROP TABLE t1;
DROP TABLE t2;
CREATE TABLE t1 AS (SELECT level c1 FROM dual CONNECT BY level <=144000);
CREATE TABLE t2 AS (SELECT level c1 FROM dual CONNECT BY level <=144000);

SET SERVEROUTPUT ON FORMAT WRAPPED

DECLARE
   vStart  Date;
   vTotalA Number(10) := 0;
   vTotalB Number(10) := 0;
   vResult Number(10);
BEGIN   
   For vLoop In 1..10 Loop
      vStart := sysdate;
      For vLoop2 In 1..2000 Loop
         SELECT count(*) INTO vResult FROM t1 WHERE t1.c1 = 777 AND EXISTS
            (SELECT 1 FROM t2 WHERE t2.c1 <> 0);
      End Loop;
      vTotalA := vTotalA + ((sysdate - vStart)*24*60*60);

      vStart := sysdate;
      For vLoop2 In 1..2000 Loop
         SELECT count(*) INTO vResult FROM t1 WHERE t1.c1 = 777 AND EXISTS
            (SELECT 1 FROM t2 WHERE t2.c1 != 0);
      End Loop;
      vTotalB := vTotalB + ((sysdate - vStart)*24*60*60);

      DBMS_Output.Put_Line('Total <>: ' || RPAD(vTotalA,8) || '!=: ' || vTotalB);
      vTotalA := 0;
      vTotalB := 0;
   End Loop;

END;
Run Code Online (Sandbox Code Playgroud)

  • 如果没有证据,欢迎你不要相信我.以下是一些可以让我得出结论的事情:http://asktom.oracle.com/pls/asktom/f?p = 100:11:0 ::::P11_QUESTION_ID:47466211228419 http://asktom.oracle.com/pls/apex/f?p = 100:11:0 :::: P11_QUESTION_ID:35336203098853 http://oraclesponge.wordpress.com/2005/04/11/banned-by-burleson/http://jonathanlewis.wordpress .com/2006/12/28/missing-the-point/http://jonathanlewis.wordpress.com/2007/01/02/superfluous-updates/ http://jonathanlewis.wordpress.com/2007/11/10/analyze-statspack8/http://jonathanlewis.wordpress.com/2008/06/08/scientific-method/ (7认同)
  • 咦?再次检查链接.我引用其他五个人,不包括评论中的众多证据. (6认同)
  • http://www.jlcomp.demon.co.uk/untested.html http://kevinclosson.wordpress.com/2007/07/17/oracle-doesnt-scale-without-multiple-log-writer-processes/ http ://www.freelists.org/post/oracle-l/Recent-Email-from-Don-Burleson,1 http://jonathanlewis.wordpress.com/2010/08/26/dmca/ http://jonathanlewis。 wordpress.com/2008/06/10/firefox/ http://www.oaktable.net/content/burleson-buys-bmc http://nlitchfield.blogspot.com/2005_04_01_archive.html (5认同)
  • 你有没有比较解释计划,autotrace结果,10046 12级跟踪输出?您是否向Oracle提交了SR?你能否制作一个类似于我的测试用例,但是不同的结果显示一个不等于另一个的形式的好处? (2认同)