最近我在查询性能方面遇到了一些问题。这里描述的是:poor Hibernate select performance comparing to running directly - how debug? 经过长时间的挣扎,我终于发现了带有选择前缀的查询,如:
SELECT sth.* FROM Something as sth...
慢了300倍,然后以这种方式启动查询:
SELECT * FROM Something as sth..
有人可以帮助我,并回答为什么会这样?关于此的一些外部文件非常有用。
用于测试的表是:
SALES_UNIT 表包含一些基本信息abot销售单位节点,例如名称等。唯一的关联是表SALES_UNIT_TYPE,如ManyToOne。主键是ID和字段VALID_FROM_DTTM,即日期。
SALES_UNIT_RELATION 包含销售单位节点之间的PARENT-CHILD关系。由SALES_UNIT_PARENT_ID,SALES_UNIT_CHILD_ID和VALID_TO_DTTM / VALID_FROM_DTTM组成。与任何表都没有关联。这里的PK是..PARENT_ID,.. CHILD_ID和VALID_FROM_DTTM
我使用的实际查询是:
SELECT s.*
FROM sales_unit s LEFT JOIN sales_unit_relation r
on (s.sales_unit_id = r.sales_unit_child_id)
WHERE r.sales_unit_child_id IS NULL
SELECT *
FROM sales_unit s LEFT JOIN sales_unit_relation r
on (s.sales_unit_id = r.sales_unit_child_id)
WHERE r.sales_unit_child_id IS NULL
相同的查询,两者都使用左连接,唯一的区别是选择。
答案 0 :(得分:4)
当然,它们是两个不同的查询。计划随着选择的不同而变化。即,在某些情况下,它可能是在左连接表上选择完整/快速全索引扫描。而在第一次它可能是一个全表扫描。
为了进一步帮助您,我们能看到这些计划吗?最好在SQL * PLUS中执行此操作
set timing on
set autotrace on traceonly
select s.* from sales_unit s left join sales_unit_relation r on (s.sales_unit_id = r.sales_unit_child_id) where r.sales_unit_child_id is null;
select * from sales_unit s left join sales_unit_relation r on (s.sales_unit_id = r.sales_unit_child_id) where r.sales_unit_child_id is null;
修改强> 的
根据你的解释计划,你会看到每一步的CARDINALITY = 1?当桌子空了的时候你收集了统计数据!看到这个:
SQL> select s.* from sales_unit s left join sales_unit_relation r on (s.sales_unit_id = r.child_sales_unit_id) where r.child_sales_unit_id is null;
no rows selected
Elapsed: 00:00:03.19
Execution Plan
----------------------------------------------------------
Plan hash value: 1064670292
------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 48 | 27 (86)| 00:00:01 |
| 1 | NESTED LOOPS ANTI | | 1 | 48 | 27 (86)| 00:00:01 |
| 2 | TABLE ACCESS FULL| SALES_UNIT | 1 | 35 | 2 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | SALES_REL_IX1 | 1 | 13 | 25 (92)| 00:00:01 |
------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("S"."SALES_UNIT_ID"="R"."CHILD_SALES_UNIT_ID")
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
200314 consistent gets
2220 physical reads
0 redo size
297 bytes sent via SQL*Net to client
339 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
0 rows processed
所以看到它使用200314 IO并花了几秒钟。还要在每一步看到ROWS = 1(即完整扫描)..让我们收集统计数据:
SQL> begin dbms_stats.gather_table_stats(user, 'SALES_UNIT', degree=>8, cascade=>true); end;
2 /
PL/SQL procedure successfully completed.
SQL> begin dbms_stats.gather_table_stats(user, 'SALES_UNIT_RELATION', degree=>8, cascade=>true); end;
2 /
PL/SQL procedure successfully completed.
现在重新运行: SQL> select.s。* from sales_unit s left join sales_unit_relation r on(s.sales_unit_id = r.child_sales_unit_id)其中r.child_sales_unit_id为null;
no rows selected
Elapsed: 00:00:00.84
Execution Plan
----------------------------------------------------------
Plan hash value: 2005864719
-----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 912 | 18240 | | 1659 (3)| 00:00:20 |
|* 1 | HASH JOIN ANTI | | 912 | 18240 | 2656K| 1659 (3)| 00:00:20 |
| 2 | TABLE ACCESS FULL | SALES_UNIT | 100K| 1472K| | 88 (3)| 00:00:02 |
| 3 | INDEX FAST FULL SCAN| SALES_REL_IX1 | 991K| 4841K| | 618 (3)| 00:00:08 |
-----------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("S"."SALES_UNIT_ID"="R"."CHILD_SALES_UNIT_ID")
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
2537 consistent gets
0 physical reads
0 redo size
297 bytes sent via SQL*Net to client
339 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
0 rows processed
SQL>
现在我们只使用2537获取,计划显示正确的ROWS和HASH连接(更符合我们的需求)。我的测试表可能比你的测试表小,这就是时间更接近的原因