Производительность запросов Oralce Join - PullRequest
0 голосов
/ 14 июля 2020

Я ищу предложения, чтобы узнать, есть ли лучший способ выполнить эту задачу. Моя проблема в том, что есть 2 таблицы (CUSTOMER и REF_DATA). Я просматриваю таблицу CUSTOMER на предмет соответствия шаблонов в таблице REF_DATA.

Структуры таблиц и примеры данных ниже.

-- Table structures
CREATE TABLE CUSTOMER (
CUST_ID         NUMBER(10),
NAME            VARCHAR2(50),
EMAIL           VARCHAR2(50),
CONTACT_DETAILS VARCHAR2(50)
);

CREATE TABLE REF_DATA (
    CITY_NAME VARCHAR2(50)
);

-- Sample data - CUSTOMER
1   A   NA  +1 000 000 000
2   B   NA  abc SYDNEY xyz
3   C   NA  NEW YORK 1234
4   D   NA  DELHI, INDIA, 123456
5   E   NA  123456

-- Sample data - REF_DATA
NEW YORK
SYDNEY
DELHI
ADELAIDE
MELBOURNE

Вариант № 1 Ниже приводится запрос на соединение. Хотя он работает, я считаю, что с точки зрения производительности он плохой. Если таблица CUSTOMER имеет 1 миллион записей, а REF_DATA имеет 20000 строк, набор результатов будет 1 mil x 20000 до применения предиката WHERE.

SELECT 
    contact_details
FROM 
    CUSTOMER cust,
    REF_DATA ref
WHERE
    REGEXP_INSTR(cust.contact_details, ref.city_name) > 0;

Вариант №2 С Вариантом №2, поскольку нет необходимости присоединяться к какой-либо другой таблице, это будет быстрее. Однако он ограничен SQL длиной запроса и количеством шаблонов в таблице REF_DATA.

SELECT 
    contact_details
FROM 
    CUSTOMER cust
WHERE
    REGEXP_LIKE(contact_details, 'NEW YORK|SYDNEY|DELHI|ADELAIDE|MELBOURNE', 'i')

Есть ли способ улучшить это?

Примечания

  1. Столбец CONTACT_DETAILS не имеет определенного индекса.
  2. Версия БД Oracle 11g R2.

1 Ответ

2 голосов
/ 14 июля 2020

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

SELECT cust.contact_details
FROM CUSTOMER cust,
INNER JOIN REF_DATA ref
    ON INSTR(cust.contact_details, ref.city_name) > 0;

Обратите внимание, что я заменил ваше старое школьное неявное соединение явным внутренним соединением. Приведенное выше соединение является предпочтительным способом написания SQL в наши дни (и так было почти тридцать лет).

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

...