Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/74.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 通过使用具有内联提示的命名子查询替换子查询进行优化_Sql_Oracle_Oracle11g_Subquery_Query Optimization - Fatal编程技术网

Sql 通过使用具有内联提示的命名子查询替换子查询进行优化

Sql 通过使用具有内联提示的命名子查询替换子查询进行优化,sql,oracle,oracle11g,subquery,query-optimization,Sql,Oracle,Oracle11g,Subquery,Query Optimization,让我们有这两张桌子: create table table_x( x_id varchar2(100) primary key ); create table table_y( x_id varchar2(100) references table_x(x_id), stream varchar2(10), val_a number, val_b number ); create index table_y_idx on table_y (x_id, stream);

让我们有这两张桌子:

create table table_x(
  x_id varchar2(100) primary key
);

create table table_y(
  x_id varchar2(100) references table_x(x_id),
  stream varchar2(10),
  val_a number,
  val_b number
);

create index table_y_idx on table_y (x_id, stream);
假设每个表中有数百万行,
table_y
每个
x_id
包含0到10行

以下示例中的查询按filter
substr(x_id,2,1)=“B”
返回200行

需要优化查询:

QUERY 1

select
    x.x_id,
    y.val_a,
    y.val_b
  from table_x x

  left join (select
                 x_id,
                 max(val_a)  KEEP (DENSE_RANK FIRST ORDER BY stream) as val_a,
                 max(val_b)  KEEP (DENSE_RANK FIRST ORDER BY stream) as val_b
               from table_y
              group by x_id
   ) y on x.x_id = y.x_id

 where substr(x.x_id, 2, 1) = 'B'; -- intentionally not use the primary key filter

------
PLAN 1
----------------------------------------------------------------------------------
| Id  | Operation              | Name    | Rows    | Bytes    | Cost  | Time     |
----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT       |         |   10000 |  2400000 | 22698 | 00:04:33 |
| * 1 |   HASH JOIN OUTER      |         |   10000 |  2400000 | 22698 | 00:04:33 |
| * 2 |    TABLE ACCESS FULL   | TABLE_X |   10000 |   120000 |   669 | 00:00:09 |
|   3 |    VIEW                |         |   10692 |  2437776 | 22029 | 00:04:25 |
|   4 |     SORT GROUP BY      |         |   10692 |   245916 | 22029 | 00:04:25 |
|   5 |      TABLE ACCESS FULL | TABLE_Y | 1069200 | 24591600 | 19359 | 00:03:53 |
----------------------------------------------------------------------------------
* 1 - access("X"."X_ID"="Y"."X_ID"(+))
* 2 - filter(SUBSTR("X"."X_ID", 2, 1)='B')
有一种重要的优化方法,因此
query2
返回行的速度比
query1
快2-3倍。
INLINE
提示非常重要,因为没有它,第二个提示的执行速度与第一个提示一样慢

QUERY 2

with
  table_y_total as (
    select --+ INLINE
        x_id,
        max(val_a)  KEEP (DENSE_RANK FIRST ORDER BY stream) as val_a,
        max(val_b)  KEEP (DENSE_RANK FIRST ORDER BY stream) as val_b
      from table_y
     group by x_id
)
select
    x.x_id,
    (select val_a from table_y_total y where y.x_id = x.x_id) as val_a,
    (select val_b from table_y_total y where y.x_id = x.x_id) as val_b
  from table_x x
 where substr(x.x_id, 2, 1) = 'B';

------
PLAN 2
-----------------------------------------------------------------------------------------
| Id  | Operation                      | Name        | Rows  | Bytes  | Cost | Time     |
-----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |             | 10000 | 120000 |  669 | 00:00:09 |
|   1 |   SORT GROUP BY NOSORT         |             |     1 |     19 |  103 | 00:00:02 |
|   2 |    TABLE ACCESS BY INDEX ROWID | TABLE_Y     |   100 |   1900 |  103 | 00:00:02 |
| * 3 |     INDEX RANGE SCAN           | TABLE_Y_IDX |   100 |        |    3 | 00:00:01 |
|   4 |   SORT GROUP BY NOSORT         |             |     1 |     20 |  103 | 00:00:02 |
|   5 |    TABLE ACCESS BY INDEX ROWID | TABLE_Y     |   100 |   2000 |  103 | 00:00:02 |
| * 6 |     INDEX RANGE SCAN           | TABLE_Y_IDX |   100 |        |    3 | 00:00:01 |
| * 7 |   TABLE ACCESS FULL            | TABLE_X     | 10000 | 120000 |  669 | 00:00:09 |
----------------------------------------------------------------------------------------- 
* 3 - access("X_ID"=:B1)
* 6 - access("X_ID"=:B1)
* 7 - filter(SUBSTR("X"."X_ID", 2, 1)='B')
由于第一个查询使用较少的代码重复,我宁愿保留它

是否有提示或其他技巧可以同时满足以下条件

  • 保留第一个查询代码(
    query1
  • 强制优化器使用第二个计划(
    计划2

    • 也许您的代码过于简化了,但这不是您想要的吗:

      select y.x_id,
             max(y.val_a) KEEP (DENSE_RANK FIRST ORDER BY stream) as val_a,
             max(y.val_b) KEEP (DENSE_RANK FIRST ORDER BY stream) as val_b
      from table_y y
      where substr(y.x_id, 2, 1) = 'B'
      group by x_id;
      
      我不认为表x的连接是不必要的,因为您已经提出了这个问题。

      使用索引提示

        select /*+index(index_name)*/ from table
      

      由于对
      表_x
      的完全扫描是计划中最便宜的部分,因此有一种方法可以在加入
      表_y
      之前对其进行过滤。尽管优化器决定在默认情况下对
      表y
      使用完全扫描,但使用
      索引(y)
      进行提示有助于将时间减少到
      查询2
      的110%

      with
        table_x_filtered as (
          select x_id
            from table_x
           where substr(x_id, 2, 1) = 'B'
        )
      select /*+ index(y table_y_idx) */
          x.x_id,
          max(val_a)  KEEP (DENSE_RANK FIRST ORDER BY stream) as val_a,
          max(val_b)  KEEP (DENSE_RANK FIRST ORDER BY stream) as val_b
        from table_x_filtered x 
        left join table_y y on y.x_id = x.x_id
       group by x.x_id;
      

      我刚发现我打错了。该查询应该使用
      左外部联接
      。对于这个错误,我很抱歉,我将编辑我的帖子。请在你的答案中添加解释*