Как заставить «не существовать» быстрее - PullRequest
1 голос
/ 21 октября 2011

У меня проблема. Моя БД - Oracle 9. Вот мой SQL:

SELECT COUNT(distinct A.person_id)
        INTO p_record_count
        FROM A,
             B,
             F,
             T
       WHERE B.position_id = F.position_id **--Normal bussiness association**
         AND T.field2 = A.org_id           **--Normal bussiness association**
         AND F.Organization_Id = A.org_id  **--Normal bussiness association**
         AND A.person_id = F.person_id     **--Normal bussiness association**
         AND F.primary_flag = 'Y'          **--Normal bussiness association**
         and sysdate between F.effective_start_date and
             F.effective_end_date          **--Normal bussiness association**
         AND NOT EXISTS                    --very slow
                (SELECT log.person_id
                FROM cper.ehr_access_log log
               WHERE log.person_id = A.person_id
                 AND log.access_page = 'login.do'
                 AND trunc(log.access_time) BETWEEN
                     to_date(p_startDate, 'yyyy-mm-dd') AND
                     to_date(p_endDate, 'yyyy-mm-dd'))
         AND A.enable_flag = 'Y';            **--Normal bussiness association**

Требование: получить людей, которые не вошли в систему.

Логика: собрать всех людей, которых я могу получить, затем минус людей, которые входят в систему.

У меня есть только таблица с записями для входа.

Таблица cper.ehr_access_log содержит более 10 миллионов записей. Это таблица журнала. Этот SQL занимает около 30 секунд.

В течение 5 с возможно? Спасибо за вашу помощь.

Спасибо ~! Я постараюсь. Хороших выходных ~:)

Ответы [ 4 ]

3 голосов
/ 21 октября 2011

Таблица cper.ehr_access_log содержит более 10 миллионов записей. Это таблица журнала. Этот sql занимает около 30 секунд.В течение 5 с это возможно?

Я бы сказал, что это невозможно без добавления некоторых индексов.Но вы можете попробовать следующие предложения

  • Используйте план запроса для определения горячей точки.Скорее всего, для ehr_access_log потребуется табличное сканирование, и вы, вероятно, сможете использовать этот аргумент, чтобы убедить других в том, что вам нужен индекс.

  • Попробуйте заменить подзапрос внешним соединением, как другие предлагали

  • У вас есть объединения в B и T, но нет предикатов для них.Вы действительно нуждаетесь в них в запросе?

  • Возможно, вы сможете сэкономить время, избегая вызовов trunc (не уверен).В качестве альтернативы, измените p_startDate начало дня и p_endDate до конца дня

2 голосов
/ 21 октября 2011

Часть вашего запроса «не существует» называется коррелированным подзапросом. Как правило, вы можете получить более высокую производительность, если переписать как OUTER join.

Узор

select a from b where not exists (select 1 from c where b.a = c.a)

становится

select a from b left outer join c on b.a = c.a where c.a is null
1 голос
/ 21 октября 2011

Я думаю, что вы можете оптимизировать свой запрос, выбрав только записи DISTINCT log.person_id, это уменьшит количество записей в вашем журнале.

Вы также можете попытаться сделать ИСКЛЮЧЕНИЕ из первой части:

SELECT COUNT(distinct A.person_id)
    INTO p_record_count
    FROM A,
         B,
         F,
         T
   LEFT OUTER JOIN cper.ehr_access_log log
     ON log.person_id = A.person_id
        AND log.access_page = 'login.do'
        AND trunc(log.access_time) BETWEEN
        to_date(p_startDate, 'yyyy-mm-dd') AND
        to_date(p_endDate, 'yyyy-mm-dd')
   WHERE B.position_id = F.position_id **--Normal bussiness association**
     AND T.field2 = A.org_id           **--Normal bussiness association**
     AND F.Organization_Id = A.org_id  **--Normal bussiness association**
     AND A.person_id = F.person_id     **--Normal bussiness association**
     AND F.primary_flag = 'Y'          **--Normal bussiness association**
     and sysdate between F.effective_start_date and
         F.effective_end_date          **--Normal bussiness association**
     AND log.person_id IS null
     AND A.enable_flag = 'Y';            **--Normal bussiness association**
1 голос
/ 21 октября 2011

Для лучшей производительности необходимо ИНДЕКС таблица cper.ehr_access_log

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

...