Улучшение SQL - PullRequest
       2

Улучшение SQL

0 голосов
/ 08 ноября 2018

Я понял, что приведенный ниже SQL с использованием DISTINCT - плохая вещь для производительности.

Однако, если он не включен, он вернет слишком много строк (из-за отношения «один ко многим» между Instrument и Party таблицами).

Я искал в Интернете и вижу несколько предложений о том, как избавиться от DISTINCT, но я, честно говоря, понятия не имею, какое из них является лучшим решением.

Можете ли вы дать рекомендации по улучшению этого SQL-кода и обеспечению того, чтобы он возвращал только одну строку на инструмент (в отличие от нескольких строк для каждого инструмента)?

Просто к вашему сведению - некоторые вещи, которые я видел в качестве рекомендаций по производительности:

  1. Избавьтесь от оператора IN, который прост и будет сделан

  2. Заменить DISTINCT на GROUP BY, это действительно улучшает производительность?

  3. Возможно, сделайте внешний SELECT, который включает DISTINCT вокруг большого SQL без DISTINCT. Моя мысль заключается в том, что DISTINCT будет выполняться на гораздо меньшем подмножестве, чем строки 1M ++ в таблице INSTRUMENT.

Мой запрос:

select * 
from
(
  SELECT DISTINCT
    I.UOID,
    I.INSTRUMENT_ID,
    I.STATUS,
    I.A_ACTIVITY_ORIG,
    I.A_CURRENCY,
    I.A_OPER_BK_ORG_ORIG,
    I.A_POSITION_ACTIVE,
    I.A_PRODUCT,
    I.A_PRODUCT_TYPE,
    I.A_TERMS_ACTIVE,
    I.CURR_COI,
    I.BOUT_COI,
    I.A_CUST_RELATIONSHP,
    I.DATE_START,
    I.DATE_END,
    I.CLIB_COI,
    I.CLIB_BASE,
    I.BLIB_COI,
    I.BLIB_BASE,
    I.BOUT_BASE,
    I.AVAL_COI,
    I.SEQUENCE_NUM,
    I.AVAL_BASE,
    I.MAXU_COI,
    I.MAXU_BASE,
    I.A_CURRENCY_BASE,I.A_CLIENT_BANK,
    I.A_PRODUCT_CATEGORY,
    I.A_ASSIGNMENT_ACTV,
    I.A_RELATED_ACTIVITY,
    C.CUSTOMER_ID,
    C.SHORT_NAME
  FROM instrument I 
  INNER JOIN PARTY P ON P.A_INSTRUMENT = I.UOID 
  INNER JOIN CUSTOMER C ON P.A_CUSTOMER = C.UOID AND C.CUSTOMER_ID = :customerId
  WHERE (I.STATUS <> 'TMP') 
    AND (I.A_CLIENT_BANK = :clientBank)  
    AND I.A_PRODUCT_CATEGORY <> 'CM'  
    AND I.STATUS NOT IN ( 'CAN','CLO','DEA','LIQ')
)
where rownum <= :maxSize;

1 Ответ

0 голосов
/ 08 ноября 2018

Клиент, которого вы ищете, связан с инструментом одной из сторон. Поскольку клиент также связан с несколькими сторонами, они могут быть связаны с одним и тем же инструментом несколько раз. Вы можете использовать предложение IN или EXISTS, чтобы получить все инструменты, которые происходят в сторонах клиента, но вы также хотите выбрать из таблицы клиентов. Итак, вы хотите присоединиться вместо этого, и это одна из немногих ситуаций, где использование DISTINCT действительно имеет смысл.

Что касается ваших идей:

Избавьтесь от оператора IN, который прост и будет сделан

Я не вижу причин, почему вы бы это сделали. Вы говорите, что хотите заменить IN на несколько OR? Это только делает запрос менее читаемым и делает то же самое внутри.

Заменить DISTINCT на GROUP BY, это действительно улучшает производительность?

Не. Это делает то же самое, но снижает читабельность. GROUP BY для агрегации. Поскольку вы не используете какую-либо функцию агрегирования, используйте DISTINCT. План выполнения должен быть точно таким же.

Возможно, сделайте внешний SELECT, который включает DISTINCT вокруг большого SQL без DISTINCT. Моя мысль заключается в том, что DISTINCT будет выполняться в гораздо меньшем подмножестве, чем строки 1M ++ в таблице INSTRUMENT.

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

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

create index idxc1 on customer( customer_id, uoid );
create index idxp1 on party ( a_customer, a_instrument );
create index idxi1 on instrument ( uoid, a_client_bank, status, a_product_category );

create index idxi2 on instrument ( a_client_bank, status, a_product_category, uoid );
create index idxp2 on party ( a_instrument, a_customer );
create index idxc2 on customer( uoid, customer_id );

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

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