Регистр имеет значение или особенности использования UPPER в ORACLE

Большинство языков программирования чувствительны к регистру, это касается и некоторых диалектов SQL. Например, T-SQL в MS SQL не чувствителен к регистру, а PL/SQL в ORACLE чувствителен. В некоторых случаях это может привести к дополнительным трудностям.

Допустим у нас есть перечень ФИО с датами рождений и принадлежащие им номера договоров. По этому перечню нужно выгрузить определённые данные из нескольких таблиц. В исходной базе данных фамилия, имя, отчество могут быть записаны двумя способами: все буквы в верхнем регистре, или большими буквами являются только заглавные.

Импортируем библиотеки и загрузим наш перечень:

import cx_Oracle import pandas as pd data = pd. read_csv(“data.csv”).

Пусть в нем будет три поля: FIO, DR и ND. В ORACLE мы можем использовать следующую конструкцию при использовании оператора in (D_1, D_2, D_3) in (( 'a1', 'b1' ,'c1' ), ( 'a2', 'b2' ,'c2' )), где в левой части названия колонок, а в правой части сгруппированные условия.

В нашем датафрейме поле FIO имеет все буквы в верхнем регистре, будем использовать указанную выше конструкцию вместе с функцией UPPER. Рассмотри для примера 5000 записей.

Sql_txt == ''' select client.c_name FIO ,clp.c_date_pers ,cred.c_num_dog ,cred.c_summa_dog from da_069_000000.z#pr_cred cred inner join da_069_000000.z#client client on client.id = cred.c_client inner join da_069_000000.z#cl_priv clp on client.id = clp.id where (upper(client.c_name) , clp.c_date_pers, cred.c_num_dog) in ({}) '''

Данный скрипт, запустим, через Python.

Создадим список, в которым элементом будет являться другой список из трех элементов [ФИО, Дата рождения, Номер договора] и назовём его union_list

start = dt.datetime.now() #Время начала загрузки df_rez2 = pd.DataFrame() a = 1 start = dt.datetime.now() #Время начала загрузки print('\nНачало выгрузки: ',start) for i in union_list: df = pd.read_sql(sql_txt.format(i), ODS) df_rez2 = df_rez2.append(df) df = None gc.collect() print('\r', a, end='') a += 1 ODS.close() endt = dt.datetime.now() #Время окончания загрузки ddif = endt-start print('\nКонец выгрузки: ',endt) print('\nДлительность: ',ddif)

Начало выгрузки: 11:10:32

Конец выгрузки: 12:03:09

Длительность: 0:52:37

Как мы видим, используя upper в множественном «IN», обработка списка из 5000, при условии, что за одну итерацию, обрабатывается 1000, затраченное время составляет около часа. Это достаточно много. Попробуем сократить это время.

Для этого увеличим наш перечень в два раза, в первой половине ФИО будет написано в верхнем регистре, во второй половине в верхнем регистре будут только первые буквы фамилии, имени и отчества.

Начало выгрузки: 12:06:15

Конец выгрузки: 12:11:19

Длительность: 0:05:04

В этом случае, несмотря на то, что перечень увеличен в два раза, то есть мы имеем 10 итераций, затраченное время составляет пять минут. Причина такого увеличения времени лежит в особенностях использования индекса в PL/SQL.

Стоит отметить, что функция upper замедляет работу, именно во множественном IN, в простом IN, скорость выполнения запроса практически не меняется. Например, если мы захотим запустить наш запрос 5000 записей только по ФИО, результат обработки будет следующий:

Начало выгрузки: 12:47:32

Конец выгрузки: 12:48:06

Длительность: 0:00:34

11
Начать дискуссию