我想知道这些运算符的区别,主要是它们的性能差异。
我查看了SQL中<>和!=之间的区别,但没有关于性能相关的信息。
然后我在dba-oracle.com找到了这个文章,它暗示从10.2开始,性能可能会有很大不同。
我想知道为什么?!=
是否总是比<>
表现更好?
注意:我们的测试以及生产系统上的性能表明,从<>
改为!=
对查询返回的时间有很大的影响。我来这里是想问为什么会发生这种情况,而不是它们是否相同。我知道语义上它们是相同的,但实际上它们是不同的。
我想知道这些运算符的区别,主要是它们的性能差异。
我查看了SQL中<>和!=之间的区别,但没有关于性能相关的信息。
然后我在dba-oracle.com找到了这个文章,它暗示从10.2开始,性能可能会有很大不同。
我想知道为什么?!=
是否总是比<>
表现更好?
注意:我们的测试以及生产系统上的性能表明,从<>
改为!=
对查询返回的时间有很大的影响。我来这里是想问为什么会发生这种情况,而不是它们是否相同。我知道语义上它们是相同的,但实际上它们是不同的。
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;
为了提高查询性能,表格已被索引。
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);
SYSDATE
作为时间戳,以及通过DBMS_RANDOM(A-Z)和(0-99)随机生成数据来添加1000万行到表中。SELECT COUNT(*) FROM load_test;
COUNT(*)
----------
10000000
1 row selected.
EXEC DBMS_STATS.GATHER_SCHEMA_STATS(ownname => 'LOADTEST', estimate_percent => NULL, cascade => TRUE);
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;
除了不等运算符的语法(不仅限于 <> 和 !=,还包括 ^=),它们完全相同。
首先,为了消除缓存的影响,每个查询都在不收集结果的情况下运行。
接下来,打开计时和自动跟踪以收集查询的实际运行时间和执行计划。
SET TIMING ON
SET AUTOTRACE TRACE
现在,查询将轮流运行。首先是<>。
> 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
Next不等于
> 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
> 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
这三个查询的执行计划相同,时间分别为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
您参考了Burleson网站上的文章。 您有跟进到Oracle-L档案库的链接吗? 您是否阅读了回复Burleson引用的其他电子邮件?
我认为您没有,否则您不会问这个问题。 因为'!='和'<>'之间没有根本区别。 最初的观察几乎肯定是由数据库中的环境条件造成的偶然事件。 阅读Jonathan Lewis和Stephane Faroult的回复以了解更多信息。
“尊重不是程序员需要具备的东西,而是任何人类都应该具备的基本态度”
在一定程度上,当我们在街上遇到陌生人时,当然应该礼貌地对待他们并尊重他们。
但是,如果那个陌生人希望我按特定方式设计我的数据库应用程序以“提高性能”,那么他们应该有令人信服的解释和一些经过严密测试的案例来支持它。 来自某个随机个体的孤立轶事是不够的。
尝试通过explain plan(或autotrace)运行查询,看看会出现什么...按照此说明,“!=”被认为与“<>”相同...Jonathan Lewis
Jonathan Lewis是Oracle社区中备受尊敬的专家。
只是出于好奇...查询优化器是否会为两个查询生成不同的执行计划?问候,克里斯
.
可能是绑定变量窥视在起作用吗?编写“!=”而不是“<>”的确定效果是强制重新解析。如果在第一次执行时:id的值有所不同,并且如果您在claws_doc_id上具有直方图,则可能是原因。如果您告诉我,claws_doc_id是主键,那么我会问您计数的目的是什么,特别是在存在子句的查询与外部查询无关并且将返回相同结果的情况下:id是什么。看起来像是轮询查询。周围的代码必须很有趣。
Stéphane Faroult
.
我非常确定词法解析器会将“!=”转换为“<>”或将“<>”转换为“!=”,但我不确定是否会影响SQL文本是否将匹配存储的轮廓。
.
explain plan是否相同?成本一样吗?
以下回复来自原帖发布者。
乔纳森,谢谢你的回答。我们确实对语句的两个版本进行了解释计划,并且它们完全相同,这就是让人困惑的地方。根据文档,两种不等式形式是相同的(以及“^=”和我无法输入的另一个),因此我无法理解性能上的任何差异。
斯科特·卡南
.
这是一个不可包容的小测试,但至少在10.1.0.2中,它会将其削减为“<>”(请注意每个计划的过滤器行)
.
您是否有任何存储轮廓?存储轮廓与字面匹配,因此如果您对具有“!=”的SQL拥有一个存储的轮廓,并且没有针对具有“<>”或颠倒情况的SQL的存储的轮廓,则存储的轮廓可能使用提示? (尽管这样想想,如果执行存储的轮廓,您的EXPLAIN PLAN应该显示提示吗?)
.
你是否试过超越只解释和自动跟踪,并运行完整的10046级12跟踪,以查看较慢版本花费的时间?这可能会为该主题提供一些启示。此外,请确保验证说明计划在10046跟踪文件(而不是使用EXPLAIN =选项生成的那些)和v $ sqlplan中完全相同。 autotrace和解释存在某些“功能”,可能导致它不能为您提供准确的解释计划。
问候,布兰登
.
这种现象完全可以重现吗?
您是否检查过计划的filter_predicates和access_predicates,而不仅仅是结构。我不希望出现任何差异,但是如果您运气不好,则谓词顺序的更改可能导致CPU使用率发生显着变化。
如果没有差异,请启用rowsource统计信息(alter session set“_rowsource_execution_statistics”= true),然后运行查询,然后从V $ sql_plan中获取执行计划,并连接到v $ sql_plan_statistics,以查看有关last_starts、last_XXX_buffer_gets的数字,最后的磁盘读取,最后的经过时间等,是否给您提供了线索。
如果您使用的是10gR2,则可以使用/*+ gather_plan_statistics */提示,而不是“alter session”。
问候乔纳森·路易斯
此时,主题已死亡,我们没有看到原始发布者的进一步帖子,这让我相信要么原始发布者发现了他们没有真实的假设,要么没有进行进一步的调查。
我还要指出,如果您解释计划或自动跟踪,您将看到比较始终显示为<>
。
这是一些测试代码。如果您喜欢,可以增加循环迭代次数。由于服务器活动的其他活动可能会使一侧或另一侧获得更高的数字,因此您可能会看到其中一个运算符始终优于另一个运算符。
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;
程序员会使用!=
数据库管理员会使用<>
如果存在不同的执行计划,可能是因为每个符号的查询缓存或统计信息存在差异。但我并不认为是这样的。
编辑:
我的意思是,在复杂的数据库中可能会出现一些奇怪的副作用。我对Oracle不够熟悉,但我想这里有一个查询编译缓存,类似于SQL Server 2008 R2。如果一个查询被编译成新查询,那么数据库优化器将根据当前的统计信息计算一个新的执行计划。如果统计信息发生了变化,它将导致一个不同的、可能更糟糕的计划。
<>
运算符。!=
是一些(如果不是全部)数据库管理系统的扩展。 - user330315<>
。在编写 C 或其衍生语言时,我使用 !=
。在编写 Smalltalk 时,我使用 ~=
。在编写 PL/I(我已经近25年没有接触过了)时,我使用 ^=
(实际上应该是一种时髦的 IBM 式“带有垂直下降符号”的字符,而不是插入符号,但你能怎么办呢?)。有很多不同的方式来表示“不相等”——我似乎记得这是 COBOL 中使用的。 :-) - Bob Jarvis - Слава Україні