Почему между этими двумя запросами такая большая разница? - PullRequest
2 голосов
/ 09 октября 2019

У меня была задача получить определенные учетные записи и транзакции на основе нескольких правил. Стоит отметить, что счета и транзакции находятся в разных таблицах, и мой запрос возвращает в основном счета - пропорции составляют около 70 счетов на 1 транзакцию . Я хотел получить их в одном запросе для удобства - это этап в более крупном процессе.

Исходный запрос:

SELECT DISTINCT 
    CASE 
        WHEN (a.transaction_type IN ('500', '501', '502', '920') AND a.transaction_date >= '#DATE#' AND to_char(a.transaction_date,'HH24') >= 16) THEN 'Transaction time'
        WHEN b.closing_date >= '#DATE#' THEN 'Closing time'
        WHEN b.opening_date >= '#DATE#'    THEN 'Opening time'  
        WHEN (b.type = 'X' AND b.active = 'NO') THEN 'Frozen account'   
    END AS "comment"
    ,b.branch 
    ,b.basic 
    ,b.lmt 
FROM 
    VDS.transactions a
    JOIN VDS.accounts b ON a.acct_no = b.acct_no
WHERE
    (a.transaction_type IN ('500', '501', '502', '920')
    AND a.transaction_date  >= '#DATE#'
    AND to_char(a.transaction_date,'HH24') >= 16)
    OR
    (b.closing_date >= '#DATE#'
    OR b.opening_date >= '#DATE#'   
    OR (b.type = 'X' AND b.active = 'NO'))

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

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

Вариант с подзапросом:

SELECT 
    'Transaction time' AS "comment"
    ,b.branch 
    ,b.basic 
    ,b.lmt 
FROM 
    VDS.transactions a
    JOIN VDS.accounts b ON a.acct_no = b.acct_no
WHERE
    a.transaction_type IN ('500', '501', '502', '920')
    AND a.transaction_date  >= '#DATE#'
    AND to_char(a.transaction_date,'HH24') >= 16

UNION

SELECT 
    CASE 
        WHEN closing_date >= '#DATE#' THEN 'Closing time'
        WHEN opening_date >= '#DATE#'    THEN 'Opening time'    
        WHEN (type = 'X' AND active = 'NO') THEN 'Frozen account'   
    END AS "comment"
    ,branch 
    ,basic 
    ,lmt 
FROM 
    VDS.accounts 
WHERE
    closing_date >= '#DATE#'
    OR opening_date >= '#DATE#' 
    OR (type = 'X' AND active = 'NO'))

И вот - время выполнения было сокращено до 3-5 с, а запрос нетбольше заблокированная база данных . Он также дал немного больше результатов, что странно, но не проблема.

Итак, мой последний вопрос: может ли кто-нибудь объяснить мне , что, возможно, происходило в кишечнике базы данных, что он с радостью принял вариант с подзапросом, в то время как получал ошибочный с исходным? Я могулучше понять производительность с помощью подзапроса, но я не знаю, почему запрос иногда работает, а иногда зависает целиком.

Ответы [ 2 ]

2 голосов
/ 09 октября 2019

На самом деле, это имеет смысл ... Давайте посмотрим на предложение WHERE вашего первого запроса

WHERE
    (a.transaction_type IN ('500', '501', '502', '920')
    AND a.transaction_date  >= '#DATE#'
    AND to_char(a.transaction_date,'HH24') >= 16)
    OR
    (b.closing_date >= '#DATE#'
    OR b.opening_date >= '#DATE#'   
    OR (b.type = 'X' AND b.active = 'NO'))

Первая часть проста ... транзакции, которые> = заданная дата и определенного типа транзакции,Нет проблем.

СЕЙЧАС, вы добавляете ИЛИ к ЛЮБОМУ из других критериев проверки таблицы ваших счетов "B" для открытых, закрытых или замороженных счетов.

Из-за (транзакций) ИЛИ(счета), вы открыли запрос до ВСЕХ СДЕЛОК (из-за ИЛИ), когда сравниваете последнее предложение «ИЛИ» для условия замораживания, которое не заботится о дате / времени.

Странзакция произойдет с учетной записью, чтобы открыть или закрыть учетную запись, вы ЗНАЕТЕ, что учетная запись будет иметь продолжение деятельности. Если предпринята попытка совершить транзакцию против замороженного аккаунта, это тоже будет учтено.

Вот как я бы скорректировал ваше положение where ...

WHERE
        a.transaction_date  >= '#DATE#'
    AND to_char(a.transaction_date,'HH24') >= 16)
    AND 
        (  a.transaction_type IN ('500', '501', '502', '920')
             OR
           (   b.closing_date >= '#DATE#'
            OR b.opening_date >= '#DATE#'   
            OR (b.type = 'X' AND b.active = 'NO')
        )

Так что вы только когда-либос учетом транзакции в течение ожидаемого периода даты ... и только тех, которые имеют тип транзакции ИЛИ (открытая, закрытая, замороженная)

1 голос
/ 09 октября 2019

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

Во второй форме запросазапрос транзакции запрос может использовать индексы transaction_type и transaction_date, если они есть (что, вероятно, с учетом домена), и транзакции, которые не совпадают, могут быть полностью пропущены.

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

Вы говорите, что запрос возвращает больше учетных записей, чем транзакций. Это может быть так, но я подозреваю, что в общей сложности транзакций намного больше, чем аккаунтов? А поскольку первая форма запроса, вероятно, должна сканировать таблицу транзакций, не имеет значения, совпадают они или нет, важно, насколько велика таблица.

...