Как повысить производительность SQL-запросов, где предложения, ищущие составные значения - PullRequest
1 голос
/ 21 июня 2019

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

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

Пример 1: работает быстро

Select * From
(
    With Exmp1 AS 
    (
    Select ID, RCD From Table1 a where EFFDT = (Select Max(b.EFFDT) 
    FROM Table1 b 
    Where a.ID = b.ID and a.RCD = b.RCD) and status = 'A'
    )

    Select USERNAME, RCD
    From MainTable MT Inner Join Exmp1 E1 ON MT.ID = E1.ID 

)
Where USERNAME = 'test1'

Пример 2: работает медленно

Select * From
(
    With Exmp1 AS 
    (
    Select ID, RCD From Table1 a where EFFDT = (Select Max(b.EFFDT) 
    FROM Table1 b 
    Where a.ID = b.ID and a.RCD = b.RCD) and status = 'A'
    )

    Select USERNAME || '@domain.com', RCD
    From MainTable MT Inner Join Exmp1 E1 ON MT.ID = E1.ID 

)
Where USERNAME = 'test1@domain.com'

Если вам интересно, почему у меня весь запрос заключен в выборку, приложение, которое использует этот запрос, ожидает, что запрос начинается с «Выбрать». Я уже пытался переписать его без предложения «with», но получил те же результаты.

Select USERNAME || '@domain.com', RCD
From MainTable MT Inner Join 
(Select ID, RCD 
 From Table1 a 
 Where EFFDT = (Select Max(b.EFFDT) FROM Table1 b Where a.ID = b.ID and a.RCD = b.RCD) and status = 'A'
) E1 ON MT.ID = E1.ID 
Where USERNAME|| '@domain.com' = 'test1@domain.com'

============ Отредактировано для дополнительной информации:

Таблица1 имеет четыре столбца: ID, RCD, EFFDT, STATUS. Важно, чтобы я получал только самые последние записи (EFFDT) и записи со значением состояния «A».

Основная таблица имеет два столбца: ID, ИМЯ ПОЛЬЗОВАТЕЛЯ. Я не могу изменить эту таблицу или создать дополнительные таблицы, представления базы данных. Я должен использовать эти данные в том виде, в каком они существуют сегодня, и взаимодействовать только в форме запросов SQL.

Желаемый результат - USERNAME@domain.com и RCD для данного USERNAME@domain.com.

.

Помните, что это только конкретный пример, и общая помощь по этому вопросу приветствуется.

1 Ответ

2 голосов
/ 21 июня 2019

Когда вы объединяете строку, вы запрещаете оптимизатору SQL использовать существующий индекс в MainTable (USERNAME).Это заставляет двигатель следовать по другому [более медленному] пути;вероятно, Куча [TABLE] SCAN.Так просто.

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

Select USERNAME || '@domain.com', RCD From
(
    With Exmp1 AS 
    (
    Select ID, RCD From Table1 a where EFFDT = (Select Max(b.EFFDT) 
    FROM Table1 b 
    Where a.ID = b.ID and a.RCD = b.RCD) and status = 'A'
    )

    Select USERNAME, RCD
    From MainTable MT Inner Join Exmp1 E1 ON MT.ID = E1.ID 

)
Where USERNAME = 'test1'

РЕДАКТИРОВАТЬ :

Продвигая идею на один шаг вперед, вы можете перефразировать весь запрос и выяснить, какие оптимизации легко увидеть, как только запрос будетупрощенно:

  • Дело в том, что столбец MT.USERNAME, вероятно, гораздо более избирателен, чем a.STATUS, поэтому сначала следует выполнить фильтрацию по нему.
  • Затем, чтобы создать коррелированный подзапросбыстро, вы, вероятно, хотите использовать «индекс покрытия», поэтому я предлагаю добавить ix2, как показано ниже.

Например:

Select
  MT.USERNAME || '@domain.com', a.RCD 
From MainTable MT
join Table1 a on a.ID = MT.ID
where MT.USERNAME = 'test1'
  and a.status = 'A'
  and a.EFFDT = (
    Select Max(b.EFFDT) FROM Table1 b Where a.ID = b.ID and a.RCD = b.RCD
  )

Теперь, вЧтобы этот запрос был очень быстрым, вам понадобятся следующие индексы.Кажется, у вас уже есть первый:

create index ix1 on MainTable (USERNAME); -- You already have this one
create index ix2 on Table1 (ID, RCD, EFFDT);

ВТОРОЕ РЕДАКТИРОВАНИЕ : Если вы действительно хотите выполнять поиск по полному имени пользователя, вы можете добавить индекс для выражения.Возьмите «Пример 2» и измените условие WHERE, как показано ниже:

Select * From
(
    With Exmp1 AS 
    (
    Select ID, RCD From Table1 a where EFFDT = (Select Max(b.EFFDT) 
    FROM Table1 b 
    Where a.ID = b.ID and a.RCD = b.RCD) and status = 'A'
    )

    Select USERNAME || '@domain.com', RCD
    From MainTable MT Inner Join Exmp1 E1 ON MT.ID = E1.ID 

)
Where USERNAME || '@domain.com' = 'test1@domain.com' -- changed here

Затем добавьте следующий индекс:

create index ix3 on MainTable (USERNAME || '@domain.com');

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

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