如何从以下选择中确定最有效的查询执行计划

问题描述 投票:1回答:2

我有一个疑问,我进行了以下测试,并获得了以下结果

  1. qry-1->费用= 2,consent_gets = 5
  2. qry-2->费用= 3,consent_gets = 5
  3. qry-3->费用= 3,consistent_gets = 3

我如何确定哪个查询是最有效的查询,以及如何查询?

Oracle - 12.2.0.1
query rewrite -> disabled
dynamic sampling -> disabled
create table test_01 as select * from all_object;
create index ix_test_01 on test_01(object_id);
-- gathered stats
-- then ...

qry-1

select * from test_01 where object_id=(select max(object_id) from test_01);

Execution Plan
----------------------------------------------------------
Plan hash value: 753718840

--------------------------------------------------------------------------------------------------
| Id  | Operation                           | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                    |            |     1 |   134 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID BATCHED| TEST_01    |     1 |   134 |     2   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN                  | IX_TEST_01 |     1 |       |     1   (0)| 00:00:01 |
|   3 |    SORT AGGREGATE                   |            |     1 |     5 |            |          |
|   4 |     INDEX FULL SCAN (MIN/MAX)       | IX_TEST_01 |     1 |     5 |     2   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("OBJECT_ID"= (SELECT MAX("OBJECT_ID") FROM "TEST_01" "TEST_01"))


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          5  consistent gets
          0  physical reads
          0  redo size
       2504  bytes sent via SQL*Net to client
        608  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

qry-2

select /*+ first_rows(1) */ * from test_01 order by object_id desc fetch first 1 rows only;

Execution Plan
----------------------------------------------------------
Plan hash value: 905071378

--------------------------------------------------------------------------------------------
| Id  | Operation                     | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |            |     1 |   507 |     3   (0)| 00:00:01 |
|*  1 |  VIEW                         |            |     1 |   507 |     3   (0)| 00:00:01 |
|*  2 |   WINDOW NOSORT STOPKEY       |            |     1 |   134 |     3   (0)| 00:00:01 |
|   3 |    TABLE ACCESS BY INDEX ROWID| TEST_01    | 64489 |  8438K|     3   (0)| 00:00:01 |
|   4 |     INDEX FULL SCAN DESCENDING| IX_TEST_01 |     1 |       |     2   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("from$_subquery$_002"."rowlimit_$$_rownumber"<=1)
   2 - filter(ROW_NUMBER() OVER ( ORDER BY INTERNAL_FUNCTION("TEST_01"."OBJECT_ID")
              DESC )<=1)


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          5  consistent gets
          0  physical reads
          0  redo size
       2504  bytes sent via SQL*Net to client
        608  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

qry-3

SQL> select * from
  2  (
  3  select /*+ first_rows(1) */ * from test_01 order by object_id desc
  4  )
  5  where rownum<=1;


Execution Plan
----------------------------------------------------------
Plan hash value: 1996576387

--------------------------------------------------------------------------------------------
| Id  | Operation                     | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |            |     1 |   481 |     3   (0)| 00:00:01 |
|*  1 |  COUNT STOPKEY                |            |       |       |            |          |
|   2 |   VIEW                        |            |     1 |   481 |     3   (0)| 00:00:01 |
|   3 |    TABLE ACCESS BY INDEX ROWID| TEST_01    | 64489 |  8438K|     3   (0)| 00:00:01 |
|   4 |     INDEX FULL SCAN DESCENDING| IX_TEST_01 |     1 |       |     2   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter(ROWNUM<=1)


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          3  consistent gets 
          0  physical reads
          0  redo size
       2504  bytes sent via SQL*Net to client
        608  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

-我应从上述查询中选择哪一个,为什么?

sql oracle
2个回答
0
投票

qry-1外观最有效,因为子查询的结果是单个id。

qry-2和qry-3构建已排序值的子集(VIEW),然后从已排序集中选择第一行


0
投票

查询3比查询1或查询2快14%。确定哪个查询更好的最佳方法是进行实验。

尽管我同意贾斯汀·凯夫(Justin Cave)的观点,这些性能比较可能毫无意义。通常,转换为基于集合的处理要比优化循环中的微小查询要好。

但是使用不同的方法比较效果很有用。查看执行计划并使用AUTOTRACE是一个很好的开始,但是直接衡量查询的运行时间是衡量性能的最佳方法。

设置

我从您的原始代码开始

create table test_01 as select * from all_objects;
create index ix_test_01 on test_01(object_id);
begin
    dbms_stats.gather_table_stats(user, 'TEST_01');
end;
/

测试是PL / SQL块。 PL / SQL是完美的工具,因为它在服务器上运行,并且不受客户端或网络时间的影响。我使用IDE来测量时间,但是您也可以使用DBMS_UTILITY.GET_TIME在服务器上直接测量它,以得到更准确的结果。

大多数Oracle数据库位于共享服务器上,因此,结果不受其他工作负载的影响很重要。为了避免干扰,我通常会按顺序运行测试用例,然后重复执行,扔掉最高价和最低价,然后取平均值。

PL / SQL测试

--Query 1 (2.74 seconds): 2.718, 2.758, 2.706, 2.754, 2.749.
declare
    type v_test_tab is table of test_01%rowtype;
    v_tests v_test_tab;
begin
    for i in 1 .. 100000 loop
        select * bulk collect into v_tests from test_01 where object_id=(select max(object_id) from test_01);
    end loop;
end;
/

--Query 2 (2.73 seconds): 2.690, 2.741, 2.757, 2.728, 2.721
declare
    type v_test_tab is table of test_01%rowtype;
    v_tests v_test_tab;
begin
    for i in 1 .. 100000 loop
        select /*+ first_rows(1) */ * bulk collect into v_tests from test_01 order by object_id desc fetch first 1 rows only;
    end loop;
end;
/

--Query 3 (2.35 seconds): 2.378, 2.322, 2.306, 2.357, 2.359
declare
    type v_test_tab is table of test_01%rowtype;
    v_tests v_test_tab;
begin
    for i in 1 .. 100000 loop
        select * bulk collect into v_tests from
        (
            select /*+ first_rows(1) */ * from test_01 order by object_id desc
        )
        where rownum<=1;
    end loop;
end;
/
© www.soinside.com 2019 - 2024. All rights reserved.