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",你说,"在我的测试中,我相信存在真正的差异而你无法证明这一点".
是的,我说,这是完全正确的.您尚未显示测试,查询,数据或结果.所以我对你的结果没什么可说的.我已经证明,在所有其他条件相同的情况下,使用哪种语法并不重要.
"那么为什么我在测试中看到一个更好?"
好问题.有几种可能性: -
我通过一个记录在案且可重复的过程表明,使用一种语法比另一种语法没有任何好处.我相信<>!=和^ =是同义词.
如果你认为不是很好,那么
a)显示我可以尝试自己的文档示例
和
b)使用您认为最好的语法.如果我是正确的并且没有区别那就没关系.如果你是正确的,那么很酷,你的工作很少有改进.
"但是Burleson说它更好,我比你更信任他,Faroult,Lewis,Kyte以及所有其他流浪汉."
他说它更好吗?我不这么认为.他没有提供任何明确的例子,测试或结果,但仅与某人说有关!=更好,然后引用他们的一些帖子.
显示不要告诉.
APC*_*APC 19
您可以参考Burleson网站上的文章.您是否关注了Oracle-L存档的链接?你是否阅读了回复Burleson引用电子邮件的其他电子邮件?
我认为你没有,否则你不会问这个问题.因为!= 和之间没有根本的区别<>.最初的观察几乎肯定是由数据库中的环境条件引起的侥幸.阅读Jonathan Lewis和Stephane Faroult的回复以了解更多信息.
"尊重不是程序员需要拥有的东西,它是任何人都应该拥有的基本态度"
在一定程度上.当我们在街上遇到一个陌生人时,我们当然应该礼貌并尊重他们.
但是,如果那个陌生人希望我以特定的方式设计我的数据库应用程序以"提高性能",那么他们应该有一个令人信服的解释和一些防弹测试用例来支持它.一些随机个体的孤立轶事是不够的.
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)