Sql 性能问题:select与select之间的差异**

Sql 性能问题:select与select之间的差异**,sql,performance,oracle,hibernate,Sql,Performance,Oracle,Hibernate,最近我在查询的性能上遇到了一些问题。事情是这样描述的: 经过长时间的努力,我终于发现带有select前缀的查询如下: SELECT sth.* FROM Something as sth... 比以这种方式启动查询慢300倍: SELECT * FROM Something as sth.. 谁能帮帮我,回答为什么会这样?关于这方面的一些外部文件将非常有用 用于测试的表格为: 销售单位表格包含销售单位节点的一些基本信息,如名称等。唯一关联的是表格销售单位类型,如manyton

最近我在查询的性能上遇到了一些问题。事情是这样描述的: 经过长时间的努力,我终于发现带有select前缀的查询如下:

    SELECT sth.* FROM Something as sth...
比以这种方式启动查询慢300倍:

    SELECT * FROM Something as sth..
谁能帮帮我,回答为什么会这样?关于这方面的一些外部文件将非常有用

用于测试的表格为:

销售单位表格包含销售单位节点的一些基本信息,如名称等。唯一关联的是表格销售单位类型,如manytone。主键是ID和字段VALID_FROM_DTTM,即日期

销售单元关系包含销售单元节点之间的父子关系。由销售单位父项标识、销售单位子项标识和有效到\u DTTM/有效来自\u DTTM的\u组成。与任何表都没有关联。这里的主键是..父\u ID,…子\u ID和来自\u DTTM的有效\u

我使用的实际查询是:

    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

相同的查询,都使用左连接,唯一的区别是select。

它们当然是两个不同的查询。计划可以随着选择的不同而改变。i、 e.在sth*中,可能是在左侧联接表上选择完全/快速完全索引扫描。而在第一次扫描中,它可能是一个完整的表扫描

为了进一步帮助你,我们能看看计划吗?最好在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;
编辑

根据你的解释计划,你看到每一步都有基数=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,花了几秒钟。另请参见每一步的行数=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>从sales\u unit s left join sales\u unit\u Relationship r on(s.sales\u unit\u id=r.child\u sales\u unit\u id)中选择s.*,其中r.child\u sales\u unit\u id为空

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 gets only,该计划显示了正确的行和哈希连接(更好地满足我们的需要)。我的测试表可能比你的真实表小,这就是为什么计时更接近的原因。当然,它们是两个不同的查询。计划可以随着选择的不同而改变。i、 e.在sth*中,可能是在左侧联接表上选择完全/快速完全索引扫描。而在第一次扫描中,它可能是一个完整的表扫描

为了进一步帮助你,我们能看看计划吗?最好在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;
编辑

根据你的解释计划,你看到每一步都有基数=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,花了几秒钟。另请参见每一步的行数=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>从sales\u unit s left join sales\u unit\u Relationship r on(s.sales\u unit\u id=r.child\u sales\u unit\u id)中选择s.*,其中r.child\u sales\u unit\u id为空

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 gets only,该计划显示了正确的行和哈希连接(更好地满足我们的需要)。我的测试表可能比你的真实表小,这就是为什么计时更接近的原因

这是一个单一的表选择吗?请参考我提供的链接,有描述issue@kamil你应该考虑编辑你的问题,包括完整的SQL。我认为涉及两个表(通过左连接)这一事实可能是这个问题的一个关键组成部分。你是对的,编辑了我的问题。这是一个单表选择吗?请参考我提供的链接,有描述issue@kamil你应该考虑编辑你的问题,包括完整的SQL。我认为涉及两个表(通过左连接)的事实可能是这个问题的一个关键部分。你是对的,编辑了我的问题我在sql plus中遇到了一些实际问题。授予plustrace和plan_表无效,因此我无法运行此语句。我试着从Navicat做“解释”,结果是:希望它能帮助我找到答案。第一个是使用
select s.*
第二个是
select*
干杯。你看到那些计划中的问题了吧?每行的基数=1。这可能意味着您在表为空时收集统计数据。桌子的实际尺寸是多少。我猜要大得多。重新收集他们的数据并重新运行计划。这真的很奇怪。表不是空的,我猜这是Navicat的错误,我将尝试运行到其他地方,而您不必收集统计数据。例如
begin dbms\u stats.gather\u table\u stats(用户,'SALES\u UNIT',度数=>8,cascade=>true);结束(这是一个基本集合..没有直方图)与销售单位关系相同。这不是导航错误,因为它的甲骨文选择了这个计划。由于你设置了错误的统计数据,这是一个糟糕的结果。谢谢你的解释。下面是一个有效的(我想是的)sql语句计划:我在使用sql plus时遇到了一些实际问题。授予plustrace和plan_表无效,因此我无法运行此语句。我试着从Navicat做“解释”,结果是:希望它能帮助我找到答案。第一个是使用
select s.*
第二个是
select*
干杯。你看到那些计划中的问题了吧?每行的基数=1。这可能意味着您在表为空时收集统计数据。桌子的实际尺寸是多少。我猜要大得多。重新收集他们的数据并重新运行计划。这真的很奇怪。表不是空的,我猜这是Navicat的错误,我将尝试运行到其他地方,而您不必收集统计数据。例如
begin dbms\u stats.gather\u table\u stats(用户,'SALES\u UNIT',度数=>8,cascade=>true);结束(这是一个基本集合..没有直方图)与销售单位关系相同。这不是导航错误,因为它的甲骨文选择了这个计划。由于你设置了错误的统计数据,这是一个糟糕的结果。谢谢你的解释。下面是sql语句的有效(我认为是这样)计划: