Присоединение к таблице с одной строкой занимает слишком много времени

Я пытаюсь прочитать все коды продуктов (столбцы mal_no) и количественные данные (столбцы adet) из таблицы (которая является таблицей «hso» и индексируется mal_no, все таблицы ниже имеют индексы для mal_no), но даже если он имеет только 1 ряд данных, он продолжает работать и никогда не заканчивается.

Запрос без этого соединения (путем добавления только закомментированной части ниже) выполняется немедленно.

Есть ли у вас какие-либо предложения для этого?

Спасибо,

select mt.mal_no,hso.adet siparis,
  mot.birim_no,round((mbs.eldeki_stok_miktar*0.8),0) duzelts,
  mot.oncelik,
  SUM(round((mbs.eldeki_stok_miktar*0.8),0)) OVER(ORDER BY 
    mot.oncelik desc ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) kumule_stok
from mal_birim_ambar_detay@live mbs
  ,mal_tanim@live mt
  ,mss_temin_yeri_oncelik@live mot
  ,web_hso hso
where 1=1
and hso.mal_no=mbs.mal_no
and mbs.mal_no=mt.mal_no
and mbs.birim_no=mot.birim_no
and mt.mal_grup_no=mot.mal_grup_no
and mt.mal_altgrup_no=mot.mal_altgrup_no
--and mt.mal_no in ('1035541001') 
and mbs.eldeki_stok_miktar>0
and mot.oncelik>0
and mbs.ambar_no='01'
order by mot.oncelik desc

person acayipadam    schedule 20.07.2017    source источник
comment
Кажется, что соединения в порядке, не могли бы вы предоставить нам DDL/структуру этих таблиц.   -  person Jayesh Mulwani    schedule 20.07.2017


Ответы (2)


Вы соединяете три таблицы из удаленной базы данных с одной в локальной базе данных. Распределенные запросы, подобные этому, общеизвестно медленны, поскольку данные должны передаваться по сети между двумя базами данных.

Локальная база данных будет отправлять подзапросы в удаленную базу данных; но объединение и фильтрация происходят локально, поэтому существует возможность передачи большого количества избыточных данных из удаленной базы данных. Поэтому вам нужно предоставить оптимизатору достаточно информации, чтобы он мог создавать умные подзапросы.

Например, изолируйте удаленные таблицы во встроенном представлении:

select rmt.mal_no,
      hso.adet siparis,
      rmt.birim_no,
      rmt.duzelts,
      rmt.oncelik,
      rmt.kumule_stok
from web_hso hso
     join 
      ( select mt.mal_no,
              mot.birim_no,
              round((mbs.eldeki_stok_miktar*0.8),0) duzelts,
              mot.oncelik,
              SUM(round((mbs.eldeki_stok_miktar*0.8),0)) 
                OVER(ORDER BY mot.oncelik desc ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) kumule_stok
from mal_birim_ambar_detay@live mbs
     join mal_tanim@live mt
       on mbs.mal_no=mt.mal_no
     join mss_temin_yeri_oncelik@live mot
      on mbs.birim_no=mot.birim_no
      and mt.mal_grup_no=mot.mal_grup_no
      and mt.mal_altgrup_no=mot.mal_altgrup_no
      where mbs.eldeki_stok_miktar>0
      and mot.oncelik>0
      and mbs.ambar_no='01' ) rmt
    on hso.mal_no=rmt.mal_no
    order by rmt.oncelik desc

Очевидно, это только предположение, потому что я не понимаю ни вашу модель данных, ни ваши данные. Вам нужно применить свои знания предметной области здесь, чтобы создать хороший запрос. Одни только встроенные представления могут не обеспечить всю необходимую скорость. Например, если большая часть работы связана с объединением трех удаленных таблиц, и, скорее всего, так оно и есть, то, как предполагает @BriteSponge, вы можете использовать подсказка driving_site может значительно повысить производительность. Итак, используя встроенный вид сверху, код запустится

select  /*+DRIVING_SITE(rmt)*/ 
      rmt.mal_no,
      hso.adet siparis,
      rmt.birim_no,
      rmt.duzelts,
      rmt.oncelik,
      rmt.kumule_stok
from web_hso hso
     join ( ... ) rmt
     on hso.mal_no=rmt.mal_no

Документ Oracle содержит дополнительные указания. Подробнее.

person APC    schedule 20.07.2017
comment
Мне не очень нравятся подсказки, но, похоже, здесь тоже может помочь подсказка DRIVING_SITE. - person BriteSponge; 20.07.2017
comment
@BriteSponge - подсказка DRIVING_SITE обычно считается одной из самых безопасных подсказок. Это хорошее предложение, и я включил его в свой ответ, - person APC; 20.07.2017

Трудно сказать из этого большого количества информации.

Но я бы посоветовал вам выполнить следующие шаги:

  1. Если у вас есть администратор базы данных или соответствующий инструмент, проверьте план выполнения. (Например, TOAD показывает план выполнения для баз данных Oracle.)
  2. Если вы видите «полное сканирование» в плане выполнения во вложенных циклах, это означает, что база данных снова и снова сканирует таблицу.

Для общего подхода вы можете использовать следующие методы:

  1. Среди элементов условия where найдите те, которые сокращают набор в первую очередь.
  2. (Oracle) используйте подсказки индекса и подсказку use_nl, чтобы явно определить базу данных, как она должна идти к таблицам.

И, наконец, из принципа старайтесь избегать больших объединений. Разделяй и властвуй свои данные. Попробуйте написать вложенные циклы и использовать как можно больше индексов при извлечении данных.

person Mehmet Kaplan    schedule 20.07.2017