2017-01-28 2 views
0

В упрощенной форме, у нас есть две таблицы - транзакционной таблицы TR и таблицу ITEM:Подключить таблицы без подзапроса?

Таблица ITEM:

+---------+-----------+ 
| ITEM_ID | ITEM_DESC | 
+---------+-----------+ 
| AAA  | parent | 
| AAA111 | child abc | 
| AAA222 | child xyz | 
+---------+-----------+ 

Таблица ТР:

+-------+------------+ 
| TR_ID | TR_ITEM_ID | 
+-------+------------+ 
| 1  | AAA  | 
| 2  | AAA111  | 
| 3  | AAA222  | 
| 4  | AAA333  | 
| 5  | AAA444  | 
+-------+------------+ 

Когда мы объединяем эти две таблицы , если TR_ITEM_ID не существует в таблице поиска (например, для AAA333 или AAA444), такая строка должна быть присоединена к «родительскому» элементу (то есть AAA). Родитель можно просто вывести из первых трех букв идентификатора. Таким образом, желаемый результат должен быть таким:

+-------+------------+---------+-----------+ 
| TR_ID | TR_ITEM_ID | ITEM_ID | ITEM_DESC | 
+-------+------------+---------+-----------+ 
| 1  | AAA  | AAA  | parent | 
| 2  | AAA111  | AAA111 | child abc | 
| 3  | AAA222  | AAA222 | child xyz | 
| 4  | AAA333  | AAA  | parent | 
| 5  | AAA444  | AAA  | parent | 
+-------+------------+---------+-----------+ 

В настоящее время у нас есть представление, которое делает это, но использует подзапросы. например:

select * from (
    select TR.*, 
    (select ITEM.ITEM_ID from ITEM where TR.TR_ITEM_ID = ITEM.ITEM_ID) CHILD_LOOKUP_TYPE, 
    (select ITEM.ITEM_ID from ITEM where substr(TR.TR_ITEM_ID,1,3) = ITEM.ITEM_ID) PARENT_LOOKUP_TYPE 
    from TR 
) f left outer join ITEM on ITEM.ITEM_ID = 
    case 
    when f.CHILD_LOOKUP_TYPE is not null then f.CHILD_LOOKUP_TYPE 
    when f.PARENT_LOOKUP_TYPE is not null then f.PARENT_LOOKUP_TYPE 
    end 
order by TR_ITEM_ID; 

Вопрос заключается в том, что если у нас не было подзапросов, вид будет выполнять величину быстрее (есть и другие объединения в реальном зрения, но в целом наша оценка является то, что он будет работать близко к 10 раз быстрее). Итак, вопрос в том, есть ли способ переписать вышеизложенный вид без подзапросов? Или любое другое предложение сделать соединение более эффективным?

Вот некоторые ограничения, которые мы имеем, в случае, если они будут делать хорошие предложения:

  1. Мы не можем хранить «разрешить» ITEM_ID в транзакционной таблице, потому что мы не можем изменить исторические данные в БД клиентов.
  2. Даже если бы мы могли, таблица поиска время от времени будет меняться (например, они могут добавить элемент AAA333), поэтому «разрешенные» значения станут недействительными.
  3. Мы не можем создать материализованное представление.

Вот некоторые быстрый SQL:

CREATE TABLE ITEM (
    ITEM_ID VARCHAR2(20 BYTE), 
    ITEM_DESC VARCHAR2(20 BYTE) 
); 
Insert into ITEM (ITEM_ID,ITEM_DESC) values ('AAA','parent'); 
Insert into ITEM (ITEM_ID,ITEM_DESC) values ('AAA111','child abc'); 
Insert into ITEM (ITEM_ID,ITEM_DESC) values ('AAA222','child xyz'); 

CREATE TABLE TR (
    TR_ID NUMBER, 
    TR_ITEM_ID VARCHAR2(20 BYTE) 
); 
Insert into TR (TR_ID,TR_ITEM_ID) values (1,'AAA'); 
Insert into TR (TR_ID,TR_ITEM_ID) values (2,'AAA111'); 
Insert into TR (TR_ID,TR_ITEM_ID) values (3,'AAA222'); 
Insert into TR (TR_ID,TR_ITEM_ID) values (4,'AAA333'); 
Insert into TR (TR_ID,TR_ITEM_ID) values (5,'AAA444'); 
+0

Если item_desc отсутствует, можно ли предположить, что он всегда должен быть родителем? –

+0

@vkp item_desc является частью таблицы поиска, которые всегда присутствуют. tr_item_id из таблицы транзакций может отсутствовать, но в этом случае мы заполняем desc «Unknown». но такие случаи могут быть решены с помощью nlv-функции. – ikcodez

ответ

0

Если можно предположить, что отсутствующие ITEM_ID-х item_desc всегда должен быть parent, это будет простой запрос с left join.

select 
tr.tr_id 
,tr.tr_item_id 
,coalesce(i.item_id,substr(tr.tr_item_id,1,3)) as item_id 
,coalesce(i.item_desc,(select item_desc from item where substring(tr.tr_item_id,1,3)=item_id)) as item_desc 
from tr 
left join item i on tr.tr_item_id=i.item_id 
+0

ОК, я понимаю ваш вопрос лучше сейчас :) поэтому, если элемент не находится в таблице поиска, он должен быть сопоставлен с его родителем, поэтому описания для этого элемента должны поступать из таблицы поиска. поэтому «родительская» формулировка была просто примером, она должна принимать все, что находится в таблице поиска. надеюсь, я не делал его более запутанным ... – ikcodez

+0

уверен..и сделал редактирование. –

+0

Да, это работает ... но у него все еще есть подзапрос, хотя и меньше, чем исходный вид. я попытаюсь проверить это на более крупный набор данных (миллион + строк), чтобы узнать, что такое улучшение. – ikcodez

0

Это то, что нужно учитывать. На небольшой выборке, которую вы указали, стоимость оптимизатора составляет 7, а для исходного запроса - 13. Попробуйте это на своем большом наборе данных.

В зависимости от вашей версии Oracle (которую вы всегда должны указывать с вашими вопросами), псевдонимы столбцов в заявлении подзапроса factored (with) могут работать или не работать; если вы находитесь на 11.1 или раньше, их, возможно, придется переместить в факторизованный подзапрос.

Идея состоит в том, чтобы сначала выполнить левое соединение и «сохранить» его (что и делает факторизованный подзапрос). Затем выберите все строки, где item_desc не null; и сделайте дальнейшее соединение только для строк, которые имеют null для item_desc.

Кстати, может item_desc быть null в таблице поиска?Я не предполагал (это было бы необычно в справочной таблице); если он может бытьnull, это может быть легко адаптировано (добавить i.item_id к статье with, и использовать, чтобы определить, какие строки из j переходит в котором ветвь union all).

with j (tr_id, tr_item_id, parent_lookup_type, item_desc) as (
     select t.tr_id, t.tr_item_id, substr(t.tr_item_id, 1, 3), i.item_desc 
     from tr t left outer join item i on t.tr_item_id = i.item_id 
     ) 
select tr_id, tr_item_id, tr_item_id as child_lookup_type, parent_lookup_type, 
     tr_item_id as item_id, item_desc 
    from j 
    where j.item_desc is not null 
union all 
select j.tr_id, j.tr_item_id, null, j.parent_lookup_type, j.parent_lookup_type, 
     i.item_desc 
    from j left outer join item i on j.parent_lookup_type = i.item_id 
    where j.item_desc is null 
; 
+0

Позвольте мне занять некоторое время, чтобы переварить это :), но я запустил это и sql, которые я разместил в вопросе на одном наборе данных, и это работает примерно в 5 раз быстрее! – ikcodez

+0

oh, и да, как и ожидалось, item_desc не может быть нулевым – ikcodez

+0

Я слишком скоро говорил ... с порядком by by он действительно работает примерно в 2 раза быстрее. все же, хорошее улучшение. – ikcodez

Смежные вопросы