只有增加DISTINCT关键字,Oracle 必然需要对后面的所有字段进行排序。以前也经常发现由于开发人员对SQL不是很理解,在SELECT列表的20多个字段前面添加了DISTINCT,造成查询基本上不可能执行完成,甚至产生ORA-7445错误。所以一直向开发人员强调DISTINCT给性能带来的影响。
没想到开发人员在测试一条大的SQL的时候,告诉我如果加上了DISTINCT,则查询大概需要4分钟左右可以执行完,如果不加DISTINCT,则查询执行了10多分钟,仍然得不到结果。
首先想到的是可能DISTINCT是在子查询中,由于加上了DISTINCT,将第一步结果集缩小了,导致查询性能提高,结果一看SQL,发现DISTINCT居然是在查询的最外层。
由于原始SQL太长,而且牵扯的表太多,很难说清楚,这里模拟了一个例子,这个例子由于数据量和SQL的复杂程度限制,无法看出二者执行时间上的明显差别。这里从两种情况的逻辑读对比来说明问题。
首先建立模拟环境:
SQL> CREATE TABLE T1 AS SELECT * FROM DBA_OBJECTS 2 WHERE OWNER = 'SYS' 3 AND OBJECT_TYPE NOT LIKE '%BODY' 4 AND OBJECT_TYPE NOT LIKE 'Java %';
Table created.
SQL> CREATE TABLE T2 AS SELECT * FROM DBA_SEGMENTS WHERE OWNER = 'SYS';
Table created.
SQL> CREATE TABLE T3 AS SELECT * FROM DBA_INDEXES WHERE OWNER = 'SYS';
Table created.
SQL> ALTER TABLE T1 ADD CONSTRAINT PK_T1 PRIMARY KEY (OBJECT_NAME);
Table altered.
SQL> CREATE INDEX IND_T2_SEGNAME ON T2(SEGMENT_NAME);
Index created.
SQL> CREATE INDEX IND_T3_TABNAME ON T3(TABLE_NAME);
Index created.
SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS(USER, 'T1', METHOD_OPT => 'FOR ALL INDEXED COLUMNS SIZE 100', CASCADE => TRUE)
PL/SQL procedure sUC cessfully completed.
SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS(USER, 'T2', METHOD_OPT => 'FOR ALL INDEXED COLUMNS SIZE 100', CASCADE => TRUE)
PL/SQL procedure successfully completed.
SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS(USER, 'T3', METHOD_OPT => 'FOR ALL INDEXED COLUMNS SIZE 100', CASCADE => TRUE)
PL/SQL procedure successfully completed.
仍然沿用上面两篇文章例子中的结构,看看原始SQL和增加DISTINCT后的差别:
SQL> SET AUTOT TRACE SQL> SELECT T1.OBJECT_NAME, T1.OBJECT_TYPE, T2.TABLESPACE_NAME 2 FROM T1, T2 3 WHERE T1.OBJECT_NAME = T2.SEGMENT_NAME 4 AND T1.OBJECT_NAME IN 5 ( 6 SELECT INDEX_NAME FROM T3 7 WHERE T3.TABLESPACE_NAME = T2.TABLESPACE_NAME 8 );
311 rows selected.
Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE (Cost=12 Card=668 Bytes=62124)
复制本页网址和标题,发送给你QQ/Msn的好友一起分享
上一篇:另一个角度谈谈DIV+CSS
下一篇:针对Google进行网站优化