Есть ли лучший способ поиска по диапазону значений в Oracle, чем тестирование по подзапросу?

StackOverflow https://stackoverflow.com/questions/1085109

  •  23-08-2019
  •  | 
  •  

Вопрос

учитывая эту таблицу:

x   y
--  -
10  a
20  b
30  c

Мне нужен наилучший способ сопоставления значений

[10,20) -> a
[20,30) -> b
[30,inf) -> c

Прямо сейчас я использую запрос типа:

select y from foo
 where x=(select max(x) from foo
           where x<=21);

Есть ли лучший способ сделать это?Существует ли аналитическая функция это могло бы помочь?

Вот мой тестовый пример:

create table foo as
select 10 as x ,'a' as y from dual union
select 20,'b' from dual union
select 30,'c' from dual;

-- returns: a,b,b:
select y from foo where x=(select max(x) from foo where x<=19);
select y from foo where x=(select max(x) from foo where x<=20);
select y from foo where x=(select max(x) from foo where x<=21);
Это было полезно?

Решение

Вы можете переписать свой запрос, чтобы обращаться к таблице foo только один раз, а не дважды, используя агрегатную функцию MAX-KEEP.

Пример:

SQL> var N number
SQL> exec :N := 19

PL/SQL-procedure is geslaagd.

SQL> select max(y) keep (dense_rank last order by x) y
  2    from foo
  3   where x <= :N
  4  /

Y
-
a

1 rij is geselecteerd.

SQL> exec :N := 20

PL/SQL-procedure is geslaagd.

SQL> select max(y) keep (dense_rank last order by x) y
  2    from foo
  3   where x <= :N
  4  /

Y
-
b

1 rij is geselecteerd.

SQL> exec :N := 21

PL/SQL-procedure is geslaagd.

SQL> select max(y) keep (dense_rank last order by x) y
  2    from foo
  3   where x <= :N
  4  /

Y
-
b

1 rij is geselecteerd.

Также a, b, b в результате.Планы запросов:

SQL> set serveroutput off
SQL> select /*+ gather_plan_statistics */
  2         y
  3    from foo
  4   where x = (select max(x) from foo where x<=:N)
  5  /

Y
-
b

1 rij is geselecteerd.

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

PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------
SQL_ID  3kh85qqnb2phy, child number 0
-------------------------------------
select /*+ gather_plan_statistics */        y   from foo  where x =
(select max(x) from foo where x<=:N)

Plan hash value: 763646971

----------------------------------------------------------------------------
| Id  | Operation           | Name | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |      |       |       |     8 (100)|          |
|*  1 |  TABLE ACCESS FULL  | FOO  |     1 |    16 |     4   (0)| 00:00:01 |
|   2 |   SORT AGGREGATE    |      |     1 |    13 |            |          |
|*  3 |    TABLE ACCESS FULL| FOO  |     2 |    26 |     4   (0)| 00:00:01 |
----------------------------------------------------------------------------

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

   1 - filter("X"=)
   3 - filter("X"<=:N)


22 rijen zijn geselecteerd.

SQL> select max(y) keep (dense_rank last order by x) y
  2    from foo
  3   where x <= :N
  4  /

Y
-
b

1 rij is geselecteerd.

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

PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------
SQL_ID  avm2zh62c8cwd, child number 0
-------------------------------------
select max(y) keep (dense_rank last order by x) y   from foo  where x
<= :N

Plan hash value: 3274996510

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |       |       |     4 (100)|          |
|   1 |  SORT AGGREGATE    |      |     1 |    16 |            |          |
|*  2 |   TABLE ACCESS FULL| FOO  |     1 |    16 |     4   (0)| 00:00:01 |
---------------------------------------------------------------------------

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

   2 - filter("X"<=:N)


20 rijen zijn geselecteerd.

Два полных сканирования таблицы в foo против одного для нового запроса.

С уважением, Роб.

Другие советы

select distinct first_value(y) over (order by x desc) from foo where x<=19;
select distinct first_value(y) over (order by x desc) from foo where x<=20;
select distinct first_value(y) over (order by x desc) from foo where x<=21;

Plus:индекс на x, вероятно, будет хорошей идеей.

Вот еще один ответ, полученный через usenet.Пока что этот вариант, по-видимому, имеет наиболее эффективное исполнение.

select max(y) keep (dense_rank last order by x) from foo where x<=21;
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top