Помогите, пожалуйста оптимизировать запрос, сравнивающий текстовые строки.

wisss
Дата: 28.10.2015 22:53:44
Столкнулся со следующей проблемой: есть 2 больших таблицы (больше миллиона строк каждая) в первой таблице (zakaz) условно номера заказов и контрагенты , во второй (tovar) - сведения о товарах . В обеих таблицах есть индексированное поле "номер заказа", так что они без проблем связываются в запросах через left join. Есть необходимость вытащить из этих таблиц записи, в которых название контрагента и описание товара частично совпадают со сведениями, содержащимися в третьей таблице (ono) (около 100 строк). Oracle стоит v10xxx, встроенная функция utm_match_jaro_winkler работать отказалась, так что пришлось написать свою функцию, которая сравнивает 2 текстовых значения и выдаёт процент соответствия от 0 до 100 (zerkalo).
Худо-бедно написал для всего этого нижеприведённый запрос, который, с учётом объёма данных, работает УЖАСНО медленно. Подскажите, пожалуйста, как бы это заставить работать быстрее?

Select 
  zakaz.ID, 
  zakaz.firma, ono.firma, zerkalo(zakaz.firma, ono.firma), 
  tovar.name, ono.name, zerkalo(tovar.name, ono.name)
from zakaz left join tovar on zakaz.ID = tovar.ID, ono
where 
  zerkalo(zakaz.firma, ono.firma)>85,
  zerkalo(tovar.name, ono.name)>85,
  zakaz.date > '01.10.2015',
  zakaz.city = 'Москва' 


Ну где-то так. Реально условий чуть больше и полей тоже, но имхо они тут роли не сыграют. Есть подозрение, что я дурак и сервер обработает этот запрос условно следующим образом:
1. Свяжет таблицы zakaz (1 млн записей) и tovar (10+ млн) итого 10 млн записей;
2. Для каждой записи подставит значения из таблицы ono - 10 млн*100 = млрд. записей причём с расчётом функции zerkalo для каждой;
3. Из этого безобразия начнёт выбирать записи, удовлетворяющие указанным условиям.
4. Начнёт меееедленно выдавать результаты.

Хотелось бы заставить это всё работать быстрее и уменьшить нагрузку на сервер. Хотя бы отсечь сразу дату и город, сократив запрос в сотни раз.

Немного о структуре таблиц: Поля city и date есть и в таблице zakaz и в таблице tovar. Поле ID уникально в таблице zakaz, но повторяется в таблице tovar. Каждому ID, соответствует только одна date и city.
Прав на создание вьюшек нет (мало ли, вдруг помогут), большую таблицу на сервере создать не могу.
mcureenab
Дата: 28.10.2015 23:05:56
Сделайте индекс по Ono и превратите функцию zerkalo в оператор поиска по индексу. Иначе, действительно субд выполнит декартово произведение выборки товаров и контрагентов с таблицей Ono. А потом будет тестировать каждую комбинацию на результат zerkalo.
mcureenab
Дата: 28.10.2015 23:10:53
К стати, почему бы не отфильтровать сначала фирмы по Ono, а потом заказы? Если фирм останется мало, то и заказов нужно будет меньше тестировать. Т.е. покрути план запроса.
wisss
Дата: 28.10.2015 23:16:22
mcureenab, извините, запрос не верный. Меня интересуют и совпадения по фирме и совпадения по товару и ещё пара полей в этих таблицах. То есть любые совпадения с таблицей ONO, просто одни жёсткие, другие просто достаточно похожие.

where 
  zakaz.date > '01.10.2015' or
  zakaz.city = 'Москва' 
  and  (zerkalo(zakaz.firma, ono.firma)>85 or  zerkalo(tovar.name, ono.name)>85 or zerkalo.inn = ono.inn)


так будет вернее.
mcureenab
Дата: 28.10.2015 23:35:22
В общем точи оператор, чтобы хотя бы не все Ono перебирать.
Я только не пойму, тебе сами данные из Ono нужны или это только набор фильтров? Может Ono внутри функции zerkalo смотреть, не надо ее непосредственно двойнить?
mcureenab
Дата: 28.10.2015 23:52:57
Т.е. внутри zerkalo2 имея под рукой все данные Ono можно попытаться быстро определить что соответствий с Ono нет вообще, а если есть, вернуть наилучшее соответствие или таблицу подходящих.

По сути задача опять же сводится к созданию специального индекса и оператора.


Если же проверять по одной записи Ono, то оптимизировать будет сложно.
wisss
Дата: 29.10.2015 00:15:26
mcureenab, не совсем понятно, кто такой "оператор поиска по индексу" и с чем его едят. Гугл завёл в какие-то не понятные дебри.

Таблица оно сформировано как select из zakaz и tovar по определённым критериям. Теперь требуется найти там другие похожие строки.

zakaz
ID date city firma inn прочие поля
123001 01.01.2014 Москва Рога и Копыта 77999999 всякий текст
123002 01.02.2014 Москва ООО "Рога и КопытО" 77999999 всякий текст
123003 01.03.2014 Вязьма Барабашка 77999919 всякий текст
..... ..... ..... .......... .....


tovar
ID date city name количество вес
123001 01.01.2014 Москва Мочалка зелёная в пупырушку 123 435
123001 01.01.2014 Москва Мочалка зелёная в сеточку 384 123
123002 01.02.2014 Москва Киви 1010 1100
123003 01.03.2014 Вязьма Мочалка зелёная в шашечку 529 113
123003 01.03.2014 Вязьма Танк и мочалка зелёная в пупырушку с загагушками 353 867
..... ..... ..... .......... .....


оно
firma name
РОГАч креманка
Копытце танк
Барабашка синий Фил
Бренд Мочалка_з


На выходе мне нужно получить

Критерий совпадения ID zakaz.firma ono.firma %совпадения фирмы tovar.name ono.name %совпадения товара прочие поля
товар 123001 Рога и Копыта Бренд 2 Мочалка зелёная в пупырушку Мочалка_з 99
товар 123001 Рога и Копыта Бренд 2 Мочалка зелёная в сеточку Мочалка_з 99
фирма 123002 ООО "Рога и КопытО" РОГАч 82 Киви креманка 0


Вот какой-то такой бред. Просто я не могу ONO тупо построчно через like вписать в условие, потому что там 100 строк по несколько условий - обязательно собьюсь + нужно периодически обновлять.

Первый столбец мне нужен чтобы понять а по какому из критериев у меня получено совпадение, поля из ОНО нужны чтобы понять а что на самом деле нашлось и подходит ли оно, %совпадения чисто для наглядности, я его могу и в 1 поле запихать.
Отдельно проверять zakaz и tovar можно, но, наверное, бессмысленно. Каждой записи таблицы zakaz соответствует одна или несколько записей tovar, так что они не умножаются.
wisss
Дата: 29.10.2015 00:17:32
wisss, в последней строке последней таблицы совпадение названия фирмы не 82, а >85% иначе не выбралось бы
mcureenab
Дата: 29.10.2015 01:13:49
domain index

Если все к куче like сводится, то сделай генератор запроса. Пусть он из Ono наберет строк и сконструирует предикат. Если ошибешся, то это будет легче заметить и исправить раз и навсегда.
Да ну
Дата: 29.10.2015 02:10:50
wisss,

Для начала - уменьшать число вызовов функции.
Как вариант - вынести условие по date(кстати, кривое) и city в подзапрос (inline view)

И не забыть про DETERMINISTIC у функции