нужна помощь в оптимизации оракула - PullRequest
1 голос
/ 31 марта 2010

Мне нужна помощь в оптимизации следующего запроса. Это займет много времени, чтобы закончить. Это займет почти 213 секунд. из-за некоторых ограничений я не могу добавить индекс и вынужден жить с существующими.

INSERT INTO temp_table_1
( USER_ID, role_id, participant_code, status_id )
WITH A AS
 (SELECT USER_ID user_id,ROLE_ID, STATUS_ID,participant_code
  FROM    USER_ROLE WHERE   participant_code IS NOT NULL), --1
B AS
 (SELECT ROLE_ID
  FROM    CMP_ROLE
  WHERE   GROUP_ID = 3),
C AS (SELECT USER_ID FROM USER) --2

SELECT USER_ID,ROLE_ID,PARTICIPANT_CODE,MAX(STATUS_ID)
FROM A INNER JOIN B USING (ROLE_ID)
       INNER JOIN C USING (USER_ID)
GROUP BY USER_ID,role_id,participant_code ;

--1 = query when ran alone takes 100+ seconds

--2 = query when ran alone takes 19 seconds

DELETE temp_table_1
WHERE ROWID NOT IN
( SELECT a.ROWID
  FROM temp_table_1 a,
  USER_ROLE b
  WHERE a.status_id = b.status_id
  AND   ( b.ACTIVE IN ( 1 ) OR ( b.ACTIVE IN ( 0,3 ) 
  AND SYSDATE BETWEEN b.effective_from_date AND b.effective_to_date ))
);

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

Разве это не может быть сделано таким образом, что нет необходимости удалять? Мы просто получаем необходимые результаты, так как это сэкономит время?

Ответы [ 3 ]

2 голосов
/ 31 марта 2010

Вот запрос, который наивно объединяет два запроса выше, поэтому убедитесь, что вы проверили и сравнили результаты двух методов.

select 
  r.user_id, r.role_id, r.participant_code, max(status_id)
from 
  user_role r, 
  cmp_role c
where 
      r.role_id = c.role_id
  and r.active in (0,1,3)
  and r.participant_code is not null
  and sysdate between r.effective_from_date and r.effective_to_date
  and c.group_id = 3
group by 
  r.user_id, r.role_id, r.participant_code;

Нет необходимости использовать временную таблицу, а затем удалять записи, чтобы получить требуемые результаты. Хотя, возможно, была причина его использования, а может и производительность?

Кроме того, похоже, что запрос и присоединение к таблице USER не нужны, поскольку USER_ID доступен из USER_ROLES. Я опустил его в запросе выше. Надеюсь, это даст вам хорошее начало для его улучшения.

0 голосов
/ 31 марта 2010

Давайте отметим некоторые очевидные вещи.

- 1 = запрос, когда он выполняется в одиночку, занимает более 100 секунд

- 2 = запрос, когда выполняется один, занимает 19 секунд

Полное сканирование таблицы USER не должно занимать 19 секунд. Полное сканирование таблицы USER_ROLE не должно занимать более 100 секунд, даже если в нем десятки миллионов строк. Конечно, если у вас действительно есть двадцать миллионов пользователей, то эти сроки немного менее необоснованны, но все же неприемлемы.

Вам необходимо понять, почему вашей системе требуется так много времени, чтобы выполнить простой поиск. EXPLAIN PLAN будет надеяться, что мы понимаем объединения, но это не решит вашу основную проблему: почему для получения данных USER_ROLE требуется так много времени? Это сложный вид? Есть ли у него сотни миллионов запросов? У вас есть индекс на PARTICIPANT_CODE, который не полезен для этого запроса?

А как насчет других запросов, использующих эти таблицы? Они тоже проблемные? Если это так, вам нужно больше расследовать. Либо система занимает слишком много времени, чтобы что-то сделать, либо она слишком ждала какого-то ресурса. Что вам нужно сделать, это запустить трассировку 10046 для этого запроса и установить, куда идет время. Эта трассировка сообщит о событиях ожидания для вашего сеанса. Это даст вам некоторую приличную информацию для продолжения. Это намного лучше, чем угадывать.

Oracle предоставляет интерфейс ожидания с 9i. Роджер Шраг написал довольно приличное вступление. Прочтите сейчас . (Если вы на 10g или выше, вы также должны прочитать его последующую статью ).

0 голосов
/ 31 марта 2010

Это должно быть семантически эквивалентно набору, оставленному в таблице temp после удаления в существующем коде. Хотя я бы согласился с AR, что таблица User не нужна, если она не содержит меньше user_id, чем user_role. В противном случае это никак не ограничивает набор. Если пользователь содержит больше user_id, чем user_role, это не изменит результирующий набор. User_role является основным драйвером в этом запросе с небольшим ограничением из таблицы cmp_role.

select a.user_id,
       a.role_id,
       a.participant_code,
       a.status_id
  from (select a.user_id,
               a.role_id,
               a.participant_code,
               max(status_id) status_id
          from user_role a,
               (select role_id
                  from cmp_role
                 where group_id = 3
               ) b
         where a.participant_code is not null
           and a.active in (0, 1, 3)
           and sysdate between a.effective_from_date and a.effective_to_date
           and a.role_id = b.role_id
         group by a.user_id,
                  a.role_id,
                  a.participant_code
       ) a
       user c
 where a.user_id = c.user_id;

Если производительность все еще остается низкой, то, возможно, следовало бы посмотреть на индексы некоторых полей, используемых для ограничения данных (user_role.role_id, user_role.participant_code, user_role.active, user_role.effective_from_date, user_role.effective_to_date).

Конечно, для объяснения того, что делает Oracle при выполнении этого запроса на основе ваших данных и структуры, потребуется план или трассировка объяснения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...