Несколько соединений с меньшими затратами

#sql #oracle #join #inner-join

#sql #Oracle #Присоединиться #внутреннее соединение

Вопрос:

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

 SELECT DISTINCT
    st.status_c1
FROM
    schemaname.tablea st
    INNER JOIN (
        SELECT
            lic.SpecId AS applicationid,
            lic.comData AS combusappid,
            lic.ageId,
            lic.licId,
            lic.licid,
            lic.appid,
            com.nybe_bustbl_id AS busid
        FROM
            schemaname.tableb lic
            INNER JOIN tablec com ON lic.comData = com.comData
        WHERE
            lic.ageId = '12'
    ) rt ON
        st.ageId = rt.ageId
    AND
        st.licId = rt.licId
    AND
        st.licid = rt.licid
    AND
        st.appid = rt.appid
WHERE
    status_id = 3;
 

Комментарии:

1. При любой проблеме с производительностью вам следует подумать о том, как бы вы ее выполнили, с какой таблицы вы начнете? Как вы получите доступ к таблице с ее фильтрами? Тогда к какому столу вы присоединитесь? Будете ли вы выполнять поиск для каждой строки из вашего первого запроса или это приведет к выполнению такого количества небольших поисковых запросов, что вы с таким же успехом можете читать из следующей таблицы, используя другие ее фильтры. Теперь, когда вы подумали об этом, проверьте, что думает Oracle, просмотрев план выполнения, а также получите статистику выполнения источника строк, чтобы увидеть, куда пошла вся работа.

Ответ №1:

Ваш текущий запрос создаст дополнительные строки при выполнении JOIN условия для нескольких записей в любой таблице, а затем DISTINCT отфильтрует эти дубликаты. Вы можете попытаться сократить объем работы по фильтрации дубликатов, используя EXISTS :

 SELECT DISTINCT
       st.status_c1
FROM   schemaname.tablea st
WHERE  status_id = 3
AND    EXISTS (
  SELECT 1
  FROM   schemaname.tableb lic
  WHERE  lic.ageId = '12'
  AND    st.ageId = lic.ageId
  AND    st.licId = lic.licId
  AND    st.appid = lic.appid
  AND    EXISTS(
    SELECT 1 FROM tablec com WHERE lic.comData = com.comData
  )
);
 

Ответ №2:

В запросе есть куча избыточности (licid находится в SELECT и ON дважды), и вам не нужно использовать подзапросы для этого. Я думаю, это сработает:

 SELECT DISTINCT st.status_c1

FROM tablea st
  INNER JOIN tableb lic ON st.ageId = lic.ageId
                       AND st.licId = lic.licId
                       AND st.appid = lic.appid
  INNER JOIN tablec com ON lic.comData = com.comData

WHERE status_id = 3
  and lic.ageId = '12'
 

Комментарии:

1. Большое вам спасибо за обновление, но когда я проверяю стоимость, я не вижу никаких изменений в стоимости, и выполняется полное сканирование таблицы для каждой таблицы, есть ли способ снизить стоимость?

Ответ №3:

Как часто вы собираетесь запускать этот запрос, сколько времени это занимает сейчас и каково объяснение. Выполняются ли statistcs для всех таблиц tha. Есть много вещей, о которых мы можем подумать, но для начала, если возможно, не могли бы вы, пожалуйста, дать нам подобную структуру таблицы и объяснить план запроса. Также может быть указатель на таблицу status_c1 tablea help. Как указывалось, попробуйте удалить условие соединения, которое выполняется дважды, И st.licid = rt.licid

 SELECT DISTINCT  st.status_c1
FROM  schemaname.tablea st
    INNER JOIN (
        SELECT
            lic.SpecId AS applicationid, lic.comData AS combusappid, lic.ageId, lic.licId, lic.licid,
            lic.appid, com.nybe_bustbl_id AS busid
        FROM schemaname.tableb lic
            INNER JOIN tablec com ON lic.comData = com.comData
        WHERE lic.ageId = '12'
    ) rt ON st.ageId = rt.ageId AND st.licId = rt.licId AND st.licid = rt.licid AND  st.appid = rt.appid
    WHERE status_id = 3;