5

这可能是一个新手问题,但仍然......

Oracle的解码和案例大家都熟悉,例如

select
  decode (state,
          0, 'initial',
          1, 'current',
          2, 'finnal',
          state)
from states_table

或者使用 CASE 的相同类型的东西。

现在假设我有一个具有这些相同值的表:

state_num | state_desc
        0 | 'initial'
        1 | 'current'
        2 | 'finnal'

有没有办法可以使用此表作为解码资源来执行相同的查询?请注意,我不想连接该表以访问另一个表中的数据......我只想知道是否有一些东西可以用来做某种decode(myField, usingThisLookupTable, thisValueForDefault).

4

2 回答 2

3

您可以使用子查询而不是连接,即

select nvl(
   (select state_desc 
   from lookup 
   where state_num=state),to_char(state)) 
from states_table;
于 2010-06-23T10:50:47.587 回答
2

不,除了使用连接到第二个表之外,没有其他方法。当然,你可以在你的 select 子句中编写一个标量子查询,或者你可以编写你自己的函数,但那将是低效的做法。

如果您需要表中的数据,则需要从中进行选择。

编辑: 我必须完善我之前关于低效做法的陈述。

在选择列表中使用标量子查询时,您希望强制执行嵌套循环外观计划,其中标量子查询将针对 states_table 的每一行执行。至少我预料到:-)。

但是,Oracle 已经实现了标量子查询缓存,这带来了非常好的优化。它只执行子查询 3 次。有一篇关于标量子查询的优秀文章,您可以在其中看到更多因素在此优化行为中发挥作用:http ://www.oratechinfo.co.uk/scalar_subqueries.html#scalar3

这是我自己的测试,可以在工作中看到这一点。为了模拟您的表格,我使用了以下脚本:

create table states_table (id,state,filler)
as
 select level
      , floor(dbms_random.value(0,3))
      , lpad('*',1000,'*')
   from dual
connect by level <= 100000
/
alter table states_table add primary key (id)
/
create table lookup_table (state_num,state_desc)
as
select 0, 'initial' from dual union all
select 1, 'current' from dual union all
select 2, 'final' from dual
/
alter table lookup_table add primary key (state_num)
/
alter table states_table add foreign key (state) references lookup_table(state_num)
/
exec dbms_stats.gather_table_stats(user,'states_table',cascade=>true)
exec dbms_stats.gather_table_stats(user,'lookup_table',cascade=>true)

然后执行查询,看看真正的执行计划:

SQL> select /*+ gather_plan_statistics */
  2         s.id
  3       , s.state
  4       , l.state_desc
  5    from states_table s
  6         join lookup_table l on s.state = l.state_num
  7  /

        ID      STATE STATE_D
---------- ---------- -------
         1          2 final
...
    100000          0 initial

100000 rows selected.

SQL> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'))
  2  /

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  f6p6ku8g8k95w, child number 0
-------------------------------------
select /*+ gather_plan_statistics */        s.id      , s.state      , l.state_desc   from states_table s        join
lookup_table l on s.state = l.state_num

Plan hash value: 1348290364

---------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation          | Name         | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  |  OMem |  1Mem | Used-Mem |
---------------------------------------------------------------------------------------------------------------------------------
|*  1 |  HASH JOIN         |              |      1 |  99614 |    100K|00:00:00.50 |   20015 |   7478 |  1179K|  1179K|  578K (0)|
|   2 |   TABLE ACCESS FULL| LOOKUP_TABLE |      1 |      3 |      3 |00:00:00.01 |       3 |      0 |       |       |          |
|   3 |   TABLE ACCESS FULL| STATES_TABLE |      1 |  99614 |    100K|00:00:00.30 |   20012 |   7478 |       |       |          |
---------------------------------------------------------------------------------------------------------------------------------

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

   1 - access("S"."STATE"="L"."STATE_NUM")


20 rows selected.

现在对标量子查询变体执行相同的操作:

SQL> select /*+ gather_plan_statistics */
  2         s.id
  3       , s.state
  4       , ( select l.state_desc
  5             from lookup_table l
  6            where l.state_num = s.state
  7         )
  8    from states_table s
  9  /

        ID      STATE (SELECT
---------- ---------- -------
         1          2 final
...
    100000          0 initial

100000 rows selected.

SQL> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'))
  2  /

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  22y3dxukrqysh, child number 0
-------------------------------------
select /*+ gather_plan_statistics */        s.id      , s.state      , ( select l.state_desc
 from lookup_table l           where l.state_num = s.state        )   from states_table s

Plan hash value: 2600781440

---------------------------------------------------------------------------------------------------------------
| Id  | Operation                   | Name         | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  |
---------------------------------------------------------------------------------------------------------------
|   1 |  TABLE ACCESS BY INDEX ROWID| LOOKUP_TABLE |      3 |      1 |      3 |00:00:00.01 |       5 |      0 |
|*  2 |   INDEX UNIQUE SCAN         | SYS_C0040786 |      3 |      1 |      3 |00:00:00.01 |       2 |      0 |
|   3 |  TABLE ACCESS FULL          | STATES_TABLE |      1 |  99614 |    100K|00:00:00.30 |   20012 |   9367 |
---------------------------------------------------------------------------------------------------------------

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

   2 - access("L"."STATE_NUM"=:B1)


20 rows selected.

并查看第 1 步和第 2 步的 Starts 列:只有 3!

这种优化在您的情况下是否总是一件好事,取决于许多因素。可以参考前面提到的文章看一些效果。

在您只有三种状态的情况下,看起来标量子查询变体不会出错。

问候,罗布。

于 2010-06-23T10:46:08.840 回答