Welcome 微信登录

首页 / 数据库 / MySQL / Oracle 有表连接的connect by 的优化

说明
有1个有表连接,还有connect by 的SQL,整了好几天才优化成功,感觉像游戏中打死了只大boss一样。现将这个过程整理一下。
优化前:
 SELECT r.OUT_VER_BEGIN_IDdataIDFROM DMS_DATA_RELA r, DMS_OBJ oWHERE r.DELETE_FLAG = "0"AND r.RELA_TYPE_CODE = "parent"AND r.OUT_OBJ_CODE = o.OBJ_CODEAND o.DELETE_FLAG = "0"AND o.OPEN_STATE = "1"AND r.IN_OBJ_CODE != "o_in"START WITH r.IN_DATA_ID in(SELECT d.OUT_DATA_IDFROM DMS_DATA_RELA dwhere d.OUT_VER_BEGIN_ID = :1and d.last_curent_flag = "1")CONNECT BY r.IN_VER_BEGIN_ID = PRIOR r.OUT_VER_BEGIN_ID 
优化后:
我把这个SQL先做了connect by 循环,然后再与另1个表做了连接,效果超好,我从李华值 《海量数据库解决方案》3.2.5 找到相关例子,并有这样的说明 : ”如果查询条件中的列位于同一表中时,并没有必要优先执行表连接“select dataIDfrom(SELECT r.OUT_VER_BEGIN_ID dataID, r.out_obj_codeFROM DMS_DATA_RELA rWHERE r.DELETE_FLAG = "0"AND r.RELA_TYPE_CODE = "parent"AND r.IN_OBJ_CODE != "o_in"STARTWITH r.IN_DATA_ID in(SELECT d.OUT_DATA_IDFROM DMS_DATA_RELA dwhere d.OUT_VER_BEGIN_ID=:1and d.last_curent_flag= "1")CONNECT BY r.IN_VER_BEGIN_ID = PRIOR r.OUT_VER_BEGIN_ID) e,DMS_OBJ owheree.OUT_OBJ_CODE = o.OBJ_CODEANDo.DELETE_FLAG = "0"ANDo.OPEN_STATE = "1" 
优化过程:
曾中途一筹莫展时,到刘大的论坛求助过,下面是地址。http://t.askmaclean.com/thread-3381-1-1.html下面过程是基于以上的整理。有基本信息和试过的方法
基本信息
基本环境
操作系统:windows server 2008 r2 enterprise

SQL> select * from V$version;
BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise EditionRelease 10.2.0.4.0 - 64bi
PL/SQL Release 10.2.0.4.0 - Production
CORE 10.2.0.4.0 Production
TNS for 64-bit Windows: Version 10.2.0.4.0- Production
NLSRTL Version 10.2.0.4.0 - Production



开发中的库,在做测试时,发现有1SQL比较消耗资源,我想把他优化一下。

SQL如下:
SELECT r.OUT_VER_BEGIN_ID dataID
FROM DMS_DATA_RELA r, DMS_OBJ o
WHERE r.DELETE_FLAG = "0"
AND r.RELA_TYPE_CODE ="parent"
AND r.OUT_OBJ_CODE =o.OBJ_CODE
AND o.DELETE_FLAG = "0"
AND o.OPEN_STATE = "1"
AND r.IN_OBJ_CODE != "o_in"
START WITH r.IN_DATA_ID in
(SELECT d.OUT_DATA_ID
FROM DMS_DATA_RELA d
where d.OUT_VER_BEGIN_ID = :1
and d.last_curent_flag = "1")
CONNECT BY r.IN_VER_BEGIN_ID = PRIORr.OUT_VER_BEGIN_ID

执行计划: (来自awrsqrpt)

0 SELECT STATEMENT 8045 (100)
1 FILTER
2 CONNECT BY WITHFILTERING
3 FILTER
4 COUNT
5 HASH JOIN 717K 111M 8045 (1)00:01:37
6 TABLE ACCESSFULL DMS_OBJ 41 656 3 (0)00:00:01
7 TABLE ACCESSFULL DMS_DATA_RELA 717K 100M 8037 (1)00:01:37
8 TABLE ACCESS BY INDEX ROWIDDMS_DATA_RELA 1 91 4 (0) 00:00:01
9 INDEX RANGE SCAN OUT_VER_BEGIN_ID_INDEX 1 3 (0) 00:00:01
10 HASH JOIN
11 CONNECT BY PUMP
12 COUNT
13 HASH JOIN 717K 111M 8045 (1)00:01:37
14 TABLE ACCESSFULL DMS_OBJ 41 656 3 (0)00:00:01
15 TABLE ACCESSFULL DMS_DATA_RELA 717K 100M 8037 (1)00:01:37

随便找个变量单独执行这条SQL试了下,大概能执行6秒。

表上记录数
SQL> select count(*) from dms_data_rela;
COUNT(*)
----------
858470

SQL> select count(*) from dms_obj;
COUNT(*)
----------
41


表上索引:(索引较多,如果不影响此条SQL的查询性能,先不考虑这些索引合不合理,因为有些非技术因素)

SQL> selectindex_name,column_name,table_name from dba_ind_columns where table_name="DMS_DATA_RELA" order by index_name;
INDEX_NAME COLUMN_NAME TABLE_NAME
-------------------------------------------------- ------------------------------
CREATE_TIME_INDEX SYS_NC00031$ DMS_DATA_RELA
DELETE_FLAG_INDEX DELETE_FLAG DMS_DATA_RELA
IN_DATA_ID_INDEX IN_DATA_ID DMS_DATA_RELA
IN_DATA_NAME_INDEX IN_DATA_NAME DMS_DATA_RELA
IN_DATA_SOURCE_CODE_INDEX IN_DATA_SOURCE_CODE DMS_DATA_RELA
IN_DATA_SOURCE_ID_INDEX IN_DATA_SOURCE_ID DMS_DATA_RELA
IN_OBJ_CODE_INDEX IN_OBJ_CODE DMS_DATA_RELA
IN_VER_BEGIN_ID_INDEX IN_VER_BEGIN_ID DMS_DATA_RELA
LAST_CURENT_FLAG_INDEX LAST_CURENT_FLAG DMS_DATA_RELA
OUT_DATA_ID_INDEX OUT_DATA_ID DMS_DATA_RELA
OUT_DATA_NAME_INDEX OUT_DATA_NAME DMS_DATA_RELA
OUT_DATA_SOURCE_ID_INDEX OUT_DATA_SOURCE_ID DMS_DATA_RELA
OUT_OBJ_CODE_INDEX OUT_OBJ_CODE DMS_DATA_RELA
OUT_VER_BEGIN_ID_INDEX OUT_VER_BEGIN_ID DMS_DATA_RELA
PK_DMS_DATA_RELA RELA_ID DMS_DATA_RELA
RELA_TYPE_CODE_INDEX RELA_TYPE_CODE DMS_DATA_RELA



SQL> selectindex_name,column_name,table_name from dba_ind_columns where table_name="DMS_OBJ" order by index_name;
INDEX_NAME COLUMN_NAME TABLE_NAME
-------------------------------------------------- ------------------------------
PK_DMS_OBJ OBJ_ID DMS_OBJ

上面SQL走全表,我找了一些资料说是在IN_VER_BEGIN_ID 列上有索引的话,会走索引,但是实际有索引,还是全表,加hint也还是全表。
另外表也收集过统计信息了。 
表上的列:

SQL> desc DMS_DATA_RELA
Name Type Nullable Default Comments
------------------------------ ------------- -------- ------- --------
RELA_ID CHAR(32)
IN_DATA_ID VARCHAR2(200) Y
IN_DATA_NAME VARCHAR2(200) Y
IN_DATA_SOURCE_ID VARCHAR2(200) Y
IN_DATA_SOURCE_CODE VARCHAR2(200) Y
IN_OBJ_CODE VARCHAR2(200) Y
IN_VER_BEGIN_ID VARCHAR2(200) Y
IN_VER_BEGIN_DATA_SOURCE_ID VARCHAR2(200) Y
IN_VER_BEGIN_DATA_SOURCE_CODE VARCHAR2(64) Y
IN_VER_BEGIN_DATA_OBJ_CODE VARCHAR2(64) Y
OUT_DATA_ID VARCHAR2(200) Y
OUT_DATA_NAME VARCHAR2(200) Y
OUT_DATA_SOURCE_ID VARCHAR2(200) Y
OUT_DATA_SOURCE_CODE VARCHAR2(200) Y
OUT_OBJ_CODE VARCHAR2(200) Y
OUT_VER_BEGIN_ID VARCHAR2(200) Y
OUT_VER_BEGIN_DATA_SOURCE_ID VARCHAR2(200) Y
OUT_VER_BEGIN_DATA_SOURCE_CODE VARCHAR2(64) Y
OUT_VER_BEGIN_DATA_OBJ_CODE VARCHAR2(64) Y
RELA_TYPE_CODE VARCHAR2(200) Y
MIDDLE_OBJ_CODE VARCHAR2(64) Y
LAST_CURENT_FLAG CHAR(1) Y
CREATE_USER_NAME VARCHAR2(200) Y
CREATE_USER_REAL_NAME VARCHAR2(200) Y
CREATE_TIME TIMESTAMP(6) Y
UPDATE_USER_NAME VARCHAR2(200) Y
UPDATE_USER_REAL_NAME VARCHAR2(200) Y
UPDATE_TIME TIMESTAMP(6) Y
DELETE_FLAG CHAR(1) Y
ORDER_NUM NUMBER(10) Y
另外也有人提到清理索引后,效果会好。 首先,索引有些非技术原因不让清理。另外我弄了1个新环境,没有过多索引,试过不同的列上建不同的索引,效果也是一样的。单就此条SQL来说,过多的索引应该影响不大。

有人问索引状态,也一并附上:
SQL> select table_name, index_name,index_type,statusfrom user_indexes where table_name="DMS_DATA_RELA";
TABLE_NAME INDEX_NAME INDEX_TYPE STATUS
------------------------------------------------------------ --------------------------- --------
DMS_DATA_RELA OUT_VER_BEGIN_ID_INDEX NORMAL VALID
DMS_DATA_RELA IN_DATA_ID_INDEX NORMAL VALID
DMS_DATA_RELA IN_DATA_NAME_INDEX NORMAL VALID
DMS_DATA_RELA IN_DATA_SOURCE_CODE_INDEX NORMAL VALID
DMS_DATA_RELA IN_DATA_SOURCE_ID_INDEX NORMAL VALID
DMS_DATA_RELA IN_OBJ_CODE_INDEX NORMAL VALID
DMS_DATA_RELA IN_VER_BEGIN_ID_INDEX NORMAL VALID
DMS_DATA_RELA OUT_DATA_NAME_INDEX NORMAL VALID
DMS_DATA_RELA OUT_DATA_SOURCE_ID_INDEX NORMAL VALID
DMS_DATA_RELA OUT_OBJ_CODE_INDEX NORMAL VALID
DMS_DATA_RELA RELA_TYPE_CODE_INDEX NORMAL VALID
DMS_DATA_RELA DELETE_FLAG_INDEX NORMAL VALID
DMS_DATA_RELA LAST_CURENT_FLAG_INDEX NORMAL VALID
DMS_DATA_RELA CREATE_TIME_INDEX FUNCTION-BASED NORMAL VALID
DMS_DATA_RELA OUT_DATA_ID_INDEX NORMAL VALID
DMS_DATA_RELA PK_DMS_DATA_RELA NORMAL VALID
16 rows selected
我试过物化视图
 CREATE MATERIALIZED VIEW mv_dms_ddr
REFRESH force
ON demand
WITH ROWID enable query rewrite AS
SELECT r.OUT_VER_BEGIN_ID, r.IN_DATA_ID,r.IN_VER_BEGIN_ID
FROM DMS_DATA_RELA r, DMS_OBJ o
WHERE r.DELETE_FLAG = "0"
AND r.RELA_TYPE_CODE = "parent"
AND r.IN_OBJ_CODE != "o_in"
AND r.OUT_OBJ_CODE =o.OBJ_CODE
AND o.DELETE_FLAG = "0"
AND o.OPEN_STATE = "1"
改写SQL
SELECT OUT_VER_BEGIN_ID dataID
FROM mv_dms_ddr
START WITH IN_DATA_ID in
(SELECT d.OUT_DATA_ID
FROM DMS_DATA_RELA d
where d.OUT_VER_BEGIN_ID = :1
and d.last_curent_flag = "1")
CONNECT BY PRIOR OUT_VER_BEGIN_ID =IN_VER_BEGIN_ID
(没用fast更新),带入变量试了,第1次慢,后面快,执行时间大概是3秒多了。有提升,但不是很理想,而且表更新也频繁,刷新方式没做on commit。(我猜测在数据库变动频繁的情况下,是不是这个查询还是会慢,这个想法还没验证)

管理 
试过Nested Loop
有人提到nested loop,我前面测过了,效果不怎么好,现在再把nl的执行计划附上。执行计划是代入变量测的。  代入变量值,不加nl的hint set autot traceonly SELECTr.OUT_VER_BEGIN_ID dataIDFROM DMS_DATA_RELA r, DMS_OBJ oWHERE r.DELETE_FLAG = "0"AND r.RELA_TYPE_CODE = "parent"AND r.OUT_OBJ_CODE = o.OBJ_CODEAND o.DELETE_FLAG = "0"AND o.OPEN_STATE = "1"AND r.IN_OBJ_CODE != "o_in"START WITH r.IN_DATA_ID in(SELECT d.OUT_DATA_IDFROM DMS_DATA_RELA dwhere d.OUT_VER_BEGIN_ID = "20130131036703_syspro_o_wbs"and d.last_curent_flag = "1")CONNECT BY r.IN_VER_BEGIN_ID = PRIORr.OUT_VER_BEGIN_ID 已用时间: 00: 00: 06.45 执行计划----------------------------------------------------------Plan hash value: 3423681500 ----------------------------------------------------------------------------------------------------| Id | Operation |Name | Rows | Bytes | Cost (%CPU)| Time |----------------------------------------------------------------------------------------------------| 0| SELECT STATEMENT | | 637K| 92M| 6643 (1)| 00:01:20 ||* 1| FILTER | | | | | ||* 2| CONNECT BY WITH FILTERING | | | | | ||* 3| FILTER | | | | | || 4| COUNT | | | | | ||* 5| HASH JOIN | | 637K| 92M| 6643 (1)| 00:01:20 || 6| TABLE ACCESS FULL | DMS_OBJ | 63 | 945 | 3 (0)| 00:00:01 || 7| TABLE ACCESS FULL | DMS_DATA_RELA | 637K| 83M| 6636 (1)| 00:01:20 ||* 8| TABLE ACCESS BY INDEX ROWID|DMS_DATA_RELA | 1 | 82 | 4 (0)| 00:00:01 ||* 9| INDEX RANGE SCAN | OUT_DATA_ID_INDEX | 1 | | 3 (0)| 00:00:01 ||* 10 | HASH JOIN | | | | | || 11| CONNECT BY PUMP | | | | | || 12| COUNT | | | | | ||* 13 | HASH JOIN | | 637K| 92M| 6643 (1)| 00:01:20 || 14| TABLE ACCESS FULL | DMS_OBJ | 63 | 945 | 3 (0)| 00:00:01 || 15| TABLE ACCESS FULL | DMS_DATA_RELA | 637K| 83M| 6636 (1)| 00:01:20 || 16| COUNT | | | | | ||* 17 | HASH JOIN | | 637K| 92M| 6643 (1)| 00:01:20 || 18| TABLE ACCESS FULL | DMS_OBJ | 63 | 945 | 3 (0)| 00:00:01 || 19| TABLE ACCESS FULL | DMS_DATA_RELA | 637K| 83M| 6636 (1)| 00:01:20 ||* 20 | TABLE ACCESS BY INDEX ROWID | DMS_DATA_RELA | 1 | 82 | 4 (0)| 00:00:01 ||* 21 | INDEX RANGE SCAN |OUT_DATA_ID_INDEX | 1 | | 3 (0)| 00:00:01 |---------------------------------------------------------------------------------------------------- Predicate Information (identified byoperation id):--------------------------------------------------- 1- filter("R"."DELETE_FLAG"="0" AND"R"."RELA_TYPE_CODE"="parent" AND"O"."DELETE_FLAG"="0" AND"O"."OPEN_STATE"="1" AND"R"."IN_OBJ_CODE"<>"o_in")2- filter( EXISTS (SELECT 0 FROM "DMS_DATA_RELA" "D" WHERE"D"."OUT_DATA_ID"=:B1 AND"D"."OUT_VER_BEGIN_ID"="20130131036703_syspro_o_wbs"AND "D"."LAST_CURENT_FLAG"="1"))3- filter( EXISTS (SELECT 0 FROM "DMS_DATA_RELA" "D" WHERE"D"."OUT_DATA_ID"=:B1 AND"D"."OUT_VER_BEGIN_ID"="20130131036703_syspro_o_wbs"AND "D"."LAST_CURENT_FLAG"="1"))5-access("R"."OUT_OBJ_CODE"="O"."OBJ_CODE")8-filter("D"."OUT_VER_BEGIN_ID"="20130131036703_syspro_o_wbs"AND"D"."LAST_CURENT_FLAG"="1")9- access("D"."OUT_DATA_ID"=:B1)10- access("R"."IN_VER_BEGIN_ID"=NULL)13-access("R"."OUT_OBJ_CODE"="O"."OBJ_CODE")17-access("R"."OUT_OBJ_CODE"="O"."OBJ_CODE")20-filter("D"."OUT_VER_BEGIN_ID"="20130131036703_syspro_o_wbs"AND"D"."LAST_CURENT_FLAG"="1")21- access("D"."OUT_DATA_ID"=:B1)  统计信息----------------------------------------------------------1 recursive calls0 db block gets2103709 consistent gets0 physical reads0 redo size596 bytes sent via SQL*Net toclient350 bytes received via SQL*Netfrom client2 SQL*Net roundtrips to/fromclient4 sorts (memory)0 sorts (disk)5 rows processed更多详情见请继续阅读下一页的精彩内容: http://www.linuxidc.com/Linux/2013-12/93455p2.htm
  • 1
  • 2
  • 下一页
Oracle 10g RAC重建ASM以及相关报错解决解决Oracle 10201 RAC安装中libpthread.so.0问题相关资讯      Oracle优化  Oracle Connect By 
  • Oracle 查询技巧与优化  (今 09:02)
  • Oracle数据库性能优化之内存磁盘  (09/19/2015 15:42:44)
  • Oracle热点表优化总结  (02/25/2015 09:39:32)
  • Oracle多表查询优化  (11/24/2015 12:02:59)
  • Oracle优化实战(绑定变量)  (06/16/2015 20:01:38)
  • Oracle 多表查询优化  (02/24/2015 20:46:48)
本文评论 查看全部评论 (0)
表情: 姓名: 字数