Чем полезен oracle для пользователей
Перейти к содержимому

Чем полезен oracle для пользователей

  • автор:

Программное обеспечение для обслуживания клиентов в операторском центре

Специалисты по обслуживанию — одна из самых важных команд в вашей компании. Агенты операторского центра обеспечивают поддержку и обслуживание клиентов, осуществляют продажи, проводят опросы и назначают встречи. Они являются лицом компании: отвечают на вопросы о задержках доставок/поставок, решают проблемы с продуктами, планируют встречи, помогают с навигацией по веб-сайту. Их работа — сделать так, чтобы клиенты были довольны полученным опытом.

Долгое время операторские (или контактные) центры занимались только входящими и исходящими телефонными звонками. Сегодня ситуация изменилась. В наши дни большинство операторских центров поддерживают несколько каналов взаимодействия, включая электронную почту, телефон, онлайн-чат и видеочат.

Какие задачи решает ПО для обслуживания клиентов?

ПО для обслуживания клиентов (или ПО для поддержки клиентов) направляет и оптимизирует деятельность компании по обслуживанию клиентов, помогая улучшать клиентский и агентский опыт. Клиенты получают эффективную поддержку, когда они в ней нуждаются. Это улучшает как условия работы сотрудников, так и клиентский опыт (CX). Улучшенная рабочая среда, в свою очередь, помогает компаниям удерживать агентов, повышать коэффициент успешного решения проблем при первом обращении, дополнительно улучшать и персонализировать опыт, а также постоянно совершенствовать работу своих операторских центров.

Как ПО для обслуживания клиентов повышает эффективность решения проблем при первом обращении

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

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

Как ПО для обслуживания клиентов помогает удерживать агентов

В период адаптации новые агенты могут оказаться перегружены изобилием информации, политик и ресурсов. А перегруженный агент не может эффективно обслуживать клиентов. Если агент не знает, что делать, то взаимодействие занимает больше времени, а клиенты остаются недовольными. Чем хуже взаимодействие, тем больше шансов, что клиент уйдет в другую компанию, которая, по его мнению, может предоставить лучшее обслуживание.

Работа в операторских центрах считается изнурительной, что сильно затрудняет привлечение и удержание профессиональных агентов по обслуживанию клиентов. Это становится еще труднее, если у агентов нет инструментов и информации, необходимых для успешной работы. ПО для обслуживания клиентов помогает новым агентам работать успешнее благодаря следующим возможностям.

  • Передача новым агентам самых простых дел. Когда у них появится больше опыта, их можно будет перемещать в другие очереди и поручать им более сложные случаи.
  • Назначение разных агентских рабочих столов в зависимости от уровня опытности. Рабочее место новых сотрудников будет предоставлять им больше помощи.
  • Доступ к наглядным пошаговым сценариям, которые помогут агентам провести клиента по процедуре устранения проблем.
  • Автоматический доступ к контекстной информации, чтобы агентам не приходилось тратить время на ее поиск.
  • Доступ к инструментам, помогающим создавать деревья принятия решений и перемещаться по ним для эффективного выбора приоритетов и решения проблем.

Как ПО для обслуживания клиентов улучшает клиентский опыт

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

Полностью интегрированные многоканальные платформы обслуживания могут предоставлять агентам наглядные отчеты о предыдущих взаимодействиях с клиентом. Этот отчет дает столь необходимый контекст для текущего диалога. Если клиент отправляет текстовое сообщение, а затем звонит по телефону, агент, принимающий вызов, видит, что было получено сообщение, может узнать об ответах на него и вписать текущий разговор в контекст. Агент может продолжить разговор с того места, на котором он был остановлен в переписке. Это делает взаимодействие более персонализированным и позволяет избежать дублирования и избыточности. Больше не возникнет такой ситуации, когда один агент отвечает на электронное письмо, отправленное клиентом в 10:00, а другой агент независимо от первого переписывается с тем же клиентом в чате в 13:00.

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

Единая унифицированная база знаний, которая отображается на всех каналах

Агенты по обслуживанию клиентов могут найти ответы в едином источнике информации. Если агенты, работающие на разных каналах, будут использовать для ответов разные источники, такие ответы вряд ли будут согласованными. А если на всех каналах будет использоваться единая база знаний, агенты смогут отвечать на вопросы клиентов согласованно. И эти ответы могут быть автоматически показаны агентам и легко добавлены в электронные письма, онлайн-чаты или переписку в социальных сетях.

Надежное перенаправление между каналами

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

Последовательное измерение CX

Правильное ПО для обслуживания клиентов постоянно измеряет качество обслуживания во всех каналах. Автоматические опросы для получения обратной связи позволяют клиентам оценить качество только что полученной услуги. Эти аналитические данные можно использовать для непрерывной оптимизации обслуживания.

Доступ к полному профилю клиента

Интегрированное программное решение для обслуживания клиентов дает агентам доступ к полным профилям клиентов. А благодаря интеграции ПО для обслуживания клиентов с CRM- и ERP-системами агенты получают еще более полную картину. Они могут видеть профиль клиента, а также все соответствующие продукты/услуги, включая прошлые покупки, неполученные возвраты, текущие выплаты, проблемы с доставкой, уровни запасов, запросы/заявки на выездное обслуживание и многое другое. Это позволяет применять персональный подход к обслуживанию с самого начала взаимодействия.

Как ПО для обслуживания клиентов помогает получать и обрабатывать отзывы, чтобы понимать потребности клиентов

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

Практически невозможно улучшить клиентский опыт, не зная, что именно нужно вашим клиентам, чего они ожидают и что им не нравится. Также это практически невозможно, если вы не знаете, где и почему что-то пошло правильно или неправильно. Именно поэтому так важно собирать и обобщать отзывы клиентов на каждом этапе и по каждому каналу.

ПО для обслуживания клиентов предоставляет следующие возможности для получения обратной связи от клиентов.

Управление обратной связью по всем каналам

Различные отделы часто собирают отзывы клиентов отдельно друг от друга. Например, отдел маркетинга может использовать опросы на веб-сайте. Операторский центр может собирать аналогичную информацию с помощью интерактивного голосового меню после завершения вызова. Отдел цифрового маркетинга может использовать отдельный инструмент в социальных сетях. Работая параллельно, но не совместно, каждая группа получает ограниченное представление о клиентах. Правильное ПО для обслуживания клиентов помогает собирать отзывы по всем каналам, а интеграция с другими системами, содержащими данные клиентов, дает единый доступ к полным клиентским профилям. Благодаря такому консолидированному представлению разные отделы могут быстро определять, куда им нужно направить свои усилия для улучшения клиентского опыта.

Незамедлительный сбор клиентских отзывов

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

Консолидация обратной связи

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

  • короткие оперативные транзакционные опросы, рассылаемые после завершения взаимодействия с клиентом;
  • опросы широкого профиля, рассылаемые целевым сегментам;
  • виджеты опросов, которые встраивают опросы в сообщества или другие точки взаимодействия с высокой посещаемостью;
  • опросы по веб-ссылкам, которые собирают отзывы посетителей сайта.

Как ПО для обслуживания клиентов поддерживает упреждающее обслуживание клиентов

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

К сожалению, многим операторским центрам сложно обеспечивать такой уровень персонализированных упреждающих взаимодействий, поскольку их базовое ПО не поддерживает необходимый уровень автоматизации. Неспособность своевременно информировать клиентов не только снижает лояльность клиентов, но и увеличивает рабочую нагрузку агентов, потому что клиенты чаще звонят в операторский центр за свежей информацией. Это повышает затраты и снижает удовлетворенность сотрудников и клиентов.

ПО для обслуживания клиентов может переломить эти тенденции благодаря следующим возможностям.

Взаимодействия, инициируемые событиями

ПО для обслуживания клиентов можно настроить таким образом, чтобы оно автоматически отправляло клиентам уведомления при наступлении каких-либо событий. Некоторые программные платформы также предоставляют шаблоны сообщений и механизмы отправки для уведомления клиентов по нескольким каналам — немедленно или по установленному графику.

Рассылка сообщений, связанных с обслуживанием

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

Оптимизация возможностей доставки

Даже если у компаний есть возможность отправлять клиентам уведомления по электронной почте, часто у них нет подходящих инструментов для оптимизации возможностей доставки. Им нужна система управления репутацией с поддержкой интернет-провайдеров, процедур управления претензиями, получения согласий, функций отмены подписки одним нажатием и процессов управления недоставленными электронными письмами и недействительными адресами электронной почты.

Выбор целевой группы и персонализация сообщений

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

Важность ПО для обслуживания клиентов

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

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

Итог: правильное ПО для обслуживания клиентов способствует успешной работе операторского центра, позволяя сохранить и даже увеличить ваш доход.

Познакомьтесь с программными решениями Oracle для обслуживания клиентов

База данных

Сервисы и продукты для баз данных Oracle предлагают заказчикам высокопроизводительные и оптимизированные по стоимости версии Oracle Database, самой передовой в мире конвергентной многомодельной системы управления базами данных, а также резидентные базы данных NoSQL и MySQL. Oracle Autonomous Database, доступная локально через Oracle Cloud@Customer или в Oracle Cloud Infrastructure, позволяет заказчикам упростить среды реляционных баз данных и сократить число нагрузок управления.

Oracle представляет интегрированную векторную базу данных для дополнения генеративного ИИ и существенного повышения производительности труда разработчиков

Новый поиск по сходству векторов с помощью ИИ в Oracle Database 23c позволяет сочетать поиск в семантических и бизнес-данных для быстрого и безопасного предоставления высокоточных ответов.

  • Oracle APEX 23.2 уже в продаже Эта новейшая версия обеспечивает повышенную скорость и эффективность разработки малокодовых приложений корпоративного уровня, подходящих для развертывания на всех платформах.

Oracle Database@Azure уже в продаже Благодаря расширенному партнерству Oracle и Microsoft, покупатели Microsoft Azure теперь могут использовать сервисы СУБД Oracle Database, работающие на платформах OCI в центрах обработки данных Azure.

Oracle называют лидером магического квадранта Gartner в категории «Системы управления облачными базами данных» за 2022 год Компания Oracle была названа лидером магического квадранта Gartner за 2022 год в категории «Системы управления облачными базами данных» и получила наивысшую оценку в 2022 году в номинации «Критически важные возможности облачных систем управления базами данных для сценариев операционного использования».

Компания Oracle названа лидером в исследовании The Forrester Wave™: Cloud Data Warehousesза второй квартал 2023 года В подготовленном Forrester обзоре 15 лучших облачных хранилищ данных отмечается, что «облачное хранилище данных Oracle обладает самыми широкими возможностями в сочетании с мощной стратегией».

Почему стоит выбрать СУБД Oracle Database для работы с данными?

IDC: Oracle Autonomous Database обеспечивает окупаемость инвестиций на 417 %

Исследование независимых аналитиков показывает, что СУБД Oracle Autonomous Database предлагает значительную экономию и 417 % рентабельности инвестиций в течение пяти лет, а окупаемость составляет всего 5 месяцев. Читать отчет IDC (PDF)

Защита от утечки данных
  • IDC: преимущества автономной базы данных Oracle в области безопасности (PDF)
  • Практика — семинар по основам безопасности баз данных
Использование единой базы данных для всех типов данных и рабочих нагрузок
  • Смотреть видео (2:49)
  • Практика — семинар по разработке приложений с использованием JSON, XML, пространственных и графических данных
Развертывание в любом месте
  • Oracle делает облако доступным для вас (PDF)
  • Практика — семинар по контейнерной разработке с Docker в автономной базе данных
  • Варианты облачного развертывания
Упрощение разработки приложений

Упростите разработку и развертывание корпоративных приложений с помощью самой комплексной платформы баз данных, включающей как приложения, так и службы данных. Создавайте приложения SaaS на основе CI/CD, многопользовательской базы данных, Kubernetes, нативных облачных технологий и технологий с минимальным программированием. Узнайте о возможностях

Обеспечение суверенитета данных и горизонтального масштабирования
  • Подробнее об Oracle Sharding
  • Munich Re HealthTech выполняет правила размещения данных с помощью Oracle Sharding
  • Как Oracle создает приложения интернет-масштаба (43:48)

Какая база данных Вам подходит?

Сокращение времени на управление базами данных

С Oracle Autonomous Database процессы работы и защиты СУБД Oracle Database становятся проще, а заказчик получает высочайший уровень производительности, масштабируемости и доступности.

Продукты
  • Autonomous Data Warehouse
  • Автономная обработка транзакций
  • Autonomous JSON Database
  • Oracle APEX Application Development

Работает до 3 раз быстрее, чем любое другое решение

Запуск СУБД Oracle Database на платформе Oracle Exadata, самой быстрой платформе для СУБД, позволяет заказчикам увеличить скорость транзакций, ускорить бизнес-аналитику и упростить управление ИТ. Oracle Exadata доступна в центрах обработки данных заказчиков и в Oracle Cloud Infrastructure, что позволяет заказчикам достигать высочайшего уровня производительности управляемых ими и автономных СУБД Oracle Autonomous Database.

Продукты
  • Autonomous Database
  • Oracle Exadata Database Service
  • Exadata Cloud@Customer
  • Exadata

Лидирующая в отрасли технология СУБД Oracle Database в центрах обработки данных заказчиков

СУБД Oracle Database можно развертывать локально, когда у заказчиков возникают проблемы с размещением данных и сетевой задержкой. Развертывание Cloud@Customer позволяет размещать в ЦОД заказчика новейшие технологии Oracle Cloud, включая Oracle Exadata и Oracle Autonomous Database.

Продукты
  • Exadata Cloud@Customer
  • Autonomous Database on Exadata Cloud@Customer
  • Oracle Exadata X9M
  • СУБД Oracle Database 19c

Координация обновлений баз данных и приложений

Заказчики с приложениями, зависящими от конкретных версий БД Oracle, имеют полный контроль над выполняемыми версиями и при изменении этих версий.

Продукты
  • Oracle Exadata Database Service
  • Oracle Base Database Service

Ускорьте разработку JSON-ориентированных приложений

СУБД Oracle Database полностью поддерживает разработку схематичных приложений с помощью модели данных JSON для повышения производительности разработчиков. Используйте API Oracle Database для MongoDB, чтобы разрабатывать и запускать приложения MongoDB с Oracle Database — локально и в облаке.

Продукты
  • Autonomous JSON Database
  • Автономная обработка транзакций
  • СУБД Oracle Database 19c
  • Oracle NoSQL Database

Самая популярная в мире база данных с открытым кодом в Oracle Cloud

MySQL HeatWave — полностью управляемый сервис баз данных на базе интегрированного акселератора запросов в памяти, HeatWave. Это единственный облачный сервис баз данных, сочетающий транзакции, аналитику и машинное обучение в едином решении MySQL Database, которое предоставляет аналитику в режиме реального времени без сложности, задержки или затрат, связанных с дублированием на ETL. Интерфейс доступен для OCI и AWS.

Продукты

Отклик с минимальной задержкой и гибкое масштабирование

Oracle NoSQL помогает разработчикам повысить производительность за счет использования управляемого облачного сервиса, поддерживающего модели данных документов и ключевых значений.

Продукты

Oracle Cloud Database

Действительно автоматизированное решение для баз данных

Oracle Autonomous Database — это комплексное облачное решение для витрин данных, озер данных, оперативной отчетности и пакетной обработки данных. Oracle использует машинное обучение, чтобы полностью автоматизировать все рутинные задачи по работе с базами данных, обеспечивая высокую производительность, надежность, безопасность и операционную эффективность.

Продукты
  • Autonomous Data Warehouse
  • Autonomous JSON Database
  • Автономная обработка транзакций
  • Oracle APEX Application Development
СУБД Oracle Database

СУБД Oracle Database лидирует на рынке по производительности, масштабируемости, надежности и безопасности — как в локальной среде, так и в облаке.

Продукты
  • СУБД Oracle Database 19c
  • СУБД Oracle Database 21c
Создание, масштабирование и защита баз данных в облаке

Oracle Base Database Service позволяет компаниям создавать полнофункциональные экземпляры СУБД Oracle Database и управлять ими в Oracle Cloud Infrastructure (OCI). ИТ-команды предоставляют базы данных на виртуальных машинах с блочными хранилищами, что обеспечивает экономически эффективные облачные сервисы баз данных с возможностью выбора версий СУБД Oracle Database.

Продукты
Лучшая локальная система СУБД Oracle Database

Oracle Exadata — это комплексное решение, повышающее производительность, масштабируемость, безопасность и доступность корпоративных баз данных Oracle. Oracle Exadata содержит более 60 уникальных функций, таких как перенос Smart Scan SQL, которые разработаны вместе с СУБД Oracle Database. Это позволяет ускорить обработку операций в режиме онлайн, анализ данных и машинное обучение. Oracle Exadata также сокращает капитальные затраты и затраты на управление, позволяя ИТ-отделам консолидировать сотни баз данных в одной системе. Компании могут развертывать Oracle Exadata в локальной среде, в Oracle Cloud Infrastructure или в качестве решения Cloud@Customer, а также использовать Oracle Autonomous Database для упрощения и ускорения цифровых трансформаций.

Продукты
Возможности Oracle Exadata Cloud в центрах обработки данных заказчиков

Решение Oracle Exadata Cloud@Customer объединяет производительность Oracle Exadata с удобством, гибкостью и доступностью управляемого сервиса баз данных в ЦОД заказчика. Это самый простой способ перемещения существующих баз данных Oracle в облако, так как он обеспечивает полную совместимость с существующими системами Oracle Exadata и Oracle Exadata Cloud Service. Oracle Exadata Cloud@Customer также отвечает требованиям заказчиков в отношении суверенитета данных и подключения с малой задержкой к существующим ресурсам центра обработки данных. Это позволяет достичь более высокой консолидации баз данных по сравнению с другими локальными облачными сервисами баз данных.

Продукты
Надежное и максимально простое управление данными

Oracle Exadata — это высокодоступная и высокопроизводительная, а также самая безопасная архитектура для работы с СУБД Oracle Database. Благодаря Oracle Exadata вы можете сократить площадь центра обработки данных и ускорить вывод на рынок критически важных нагрузок.

Продукты
Запускайте сервисы Oracle Database в Microsoft Azure

Oracle Database@Azure позволяет организациям выполнять рабочие нагрузки где угодно, осуществлять модернизацию и внедрять инновации, используя сервисы Oracle и Azure, а также упрощает закупки облачных ресурсов и управление ими. Заказчики могут комбинировать выбранные ими сервисы Azure с Oracle Autonomous Database и Oracle Exadata Database Service, сервисами OCI, глубоко интегрированными с центрами обработки данных Azure и размещенными в них.

Возможности
  • Наивысший уровень производительности, масштабирования и доступности СУБД Oracle Database за счет использования инфраструктуры Oracle Exadata.
  • Оптимальное сочетание цен и возможностей в OCI, включая Oracle Real Application Clusters.
  • Удобство, безопасность и малые задержки единой операционной среды в Azure, в том числе федеративное управление идентификационными данными и доступ для сервисов баз данных с использованием Microsoft Entra ID.
  • Журналы, метрики и события сервиса СУБД Oracle Database доступны непосредственно в Azure для упрощения мониторинга и устранения неполадок.
  • Возможность приобретения через Azure Marketplace с действующими обязательствами Azure и использования существующих лицензий СУБД Oracle Database, а также неограниченных лицензионных соглашений.
Единая база данных MySQL для OLTP и OLAP

MySQL HeatWave — единственный сервис, который позволяет администраторам баз данных и разработчикам приложений выполнять нагрузки OLTP и OLAP непосредственно из базы данных MySQL. Это устраняет необходимость в сложном, трудоемком и дорогостоящем перемещении и интеграции данных с отдельной базой данных аналитики.

Продукты
Высокая доступность, гибкость модели данных, эластичная масштабируемость

Oracle NoSQL Database Cloud Service предоставляет пропускную способность по требованию и выделение ресурсов на основе хранилища, которые поддерживают модели данных «документ», «столбцы» и «ключ-значение», а также гарантирует гибкие транзакции.

Продукты

Гибкие варианты развертывания баз данных в соответствии с Вашей бизнес-стратегией

Oracle Database 19c и 21c

Oracle Exadata

Перенос базы данных в Oracle Cloud

Простое перемещение локальной реляционной базы данных в Oracle Cloud. Oracle предлагает экономичное, полностью автоматизированное, высокодоступное и масштабируемое решение для переноса нагрузок баз данных в облако.

19 СЕНТЯБРЯ 2023 ГОДА

Oracle Database 23c: следующий выпуск с долгосрочной поддержкой

Доминик Джилс, главный менеджер по продуктам, Oracle

Последняя версия самой мощной в мире базы данных Oracle Database 23c стала общедоступной в сервисе Oracle Base Database Service на OCI. Наряду со многими другими усовершенствованиями, выпуск расширяет возможности разработчиков и упрощает использование искусственного интеллекта в базе данных, известной своей непревзойденной поддержкой высокой доступности, производительности и безопасности. Кроме того, в новом выпуске усовершенствован ведущий в отрасли подход Oracle Database к конвергентным базам данных — поддержка JSON, XML, Graph, Spatial, текстовых и реляционных данных для любых рабочих нагрузок, а также возможность выбора разработчиками любого стиля разработки. Откройте для себя новые возможности и получите дополнительные ресурсы, которые помогут вам сориентироваться в этом замечательном новом выпуске.

Рекомендуемые публикации по базам данных

Эталонные архитектуры баз данных

Истории успеха заказчиков СУБД Oracle Database

Решения СУБД Oracle Database поддерживают критически важные для бизнеса приложения заказчиков и обеспечивают безопасность их данных.

История успеха заказчиков, использующих СУБД Oracle Database

Конвергентная база данных Oracle

Oracle Autonomous Data Warehouse помогает госпиталю «Седжон» бороться с заболеваниями сердца

В госпитале «Седжон» используются решения Oracle Autonomous Data Warehouse и Oracle Analytics Cloud, позволяющие принимать более информированные врачебные решения, в том числе когда речь идет о врожденных пороках сердца у детей.

Ресурсы по базам данных

Документация

Доступ к документации базы данных

Справочный центр Oracle предоставляет подробную информацию о наших продуктах и сервисах с помощью целевых решений, руководств по началу работы и инструкций для расширенных сценариев использования.

10 приёмов работы с Oracle

В Сбере есть несколько практик Oracle, которые могут оказаться вам полезны. Думаю, часть вам знакома, но мы используем для загрузки не только ETL-средства, но и хранимые процедуры Oracle. На Oracle PL/SQL реализованы наиболее сложные алгоритмы загрузки данных в хранилища, где требуется «прочувствовать каждый байт».

  • Автоматическое журналирование компиляций
  • Как быть, если хочется сделать вьюшку с параметрами
  • Использование динамической статистики в запросах
  • Как сохранить план запроса при вставке данных через database link
  • Запуск процедур в параллельных сессиях
  • Протягивание остатков
  • Объединение нескольких историй в одну
  • Нормалайзер
  • Визуализация в формате SVG
  • Приложение поиска по метаданным Oracle

Автоматическое журналирование компиляций

На некоторых базах данных Oracle в Сбере стоит триггер на компиляцию, который запоминает, кто, когда и что менял в коде серверных объектов. Тем самым из таблицы журнала компиляций можно установить автора изменений. Также автоматически реализуется система контроля версий. Во всяком случае, если программист забыл сдать изменения в Git, то этот механизм его подстрахует. Опишем пример реализации такой системы автоматического журналирования компиляций. Один из упрощённых вариантов триггера на компиляцию, пишущего в журнал в виде таблицы ddl_changes_log, выглядит так:

create table DDL_CHANGES_LOG ( id INTEGER, change_date DATE, sid VARCHAR2(100), schemaname VARCHAR2(30), machine VARCHAR2(100), program VARCHAR2(100), osuser VARCHAR2(100), obj_owner VARCHAR2(30), obj_type VARCHAR2(30), obj_name VARCHAR2(30), previous_version CLOB, changes_script CLOB ); create or replace trigger trig_audit_ddl_trg before ddl on database declare v_sysdate date; v_valid number; v_previous_obj_owner varchar2(30) := ''; v_previous_obj_type varchar2(30) := ''; v_previous_obj_name varchar2(30) := ''; v_previous_change_date date; v_lob_loc_old clob := ''; v_lob_loc_new clob := ''; v_n number; v_sql_text ora_name_list_t; v_sid varchar2(100) := ''; v_schemaname varchar2(30) := ''; v_machine varchar2(100) := ''; v_program varchar2(100) := ''; v_osuser varchar2(100) := ''; begin v_sysdate := sysdate; -- find whether compiled object already presents and is valid select count(*) into v_valid from sys.dba_objects where owner = ora_dict_obj_owner and object_type = ora_dict_obj_type and object_name = ora_dict_obj_name and status = 'VALID' and owner not in ('SYS', 'SPOT', 'WMSYS', 'XDB', 'SYSTEM') and object_type in ('TRIGGER', 'PROCEDURE', 'FUNCTION', 'PACKAGE', 'PACKAGE BODY', 'VIEW'); -- find information about previous compiled object select max(obj_owner) keep(dense_rank last order by id), max(obj_type) keep(dense_rank last order by id), max(obj_name) keep(dense_rank last order by id), max(change_date) keep(dense_rank last order by id) into v_previous_obj_owner, v_previous_obj_type, v_previous_obj_name, v_previous_change_date from ddl_changes_log; -- if compile valid object or compile invalid package body broken by previous compilation of package then log it if (v_valid = 1 or v_previous_obj_owner = ora_dict_obj_owner and (v_previous_obj_type = 'PACKAGE' and ora_dict_obj_type = 'PACKAGE BODY' or v_previous_obj_type = 'PACKAGE BODY' and ora_dict_obj_type = 'PACKAGE') and v_previous_obj_name = ora_dict_obj_name and v_sysdate - v_previous_change_date 'VIEW' then for z in (select substr(text, 1, length(text) - 1) || chr(13) || chr(10) as text from sys.dba_source where owner = ora_dict_obj_owner and type = ora_dict_obj_type and name = ora_dict_obj_name order by line) loop v_lob_loc_old := v_lob_loc_old || z.text; end loop; else select sys.dbms_metadata_util.long2clob(v.textlength, 'SYS.VIEW$', 'TEXT', v.rowid) into v_lob_loc_old from sys."_CURRENT_EDITION_OBJ" o, sys.view$ v, sys.user$ u where o.obj# = v.obj# and o.owner# = u.user# and u.name = ora_dict_obj_owner and o.name = ora_dict_obj_name; end if; -- store new version of object (after compilation) from v_sql_text in v_lob_loc_new v_n := ora_sql_txt(v_sql_text); for i in 1 .. v_n loop v_lob_loc_new := v_lob_loc_new || replace(v_sql_text(i), chr(10), chr(13) || chr(10)); end loop; -- find information about session that changed this object select max(to_char(sid)), max(schemaname), max(machine), max(program), max(osuser) into v_sid, v_schemaname, v_machine, v_program, v_osuser from v$session where audsid = userenv('sessionid'); -- store changes in ddl_changes_log insert into ddl_changes_log (id, change_date, sid, schemaname, machine, program, osuser, obj_owner, obj_type, obj_name, previous_version, changes_script) values (seq_ddl_changes_log.nextval, v_sysdate, v_sid, v_schemaname, v_machine, v_program, v_osuser, ora_dict_obj_owner, ora_dict_obj_type, ora_dict_obj_name, v_lob_loc_old, v_lob_loc_new); end if; exception when others then null; end;

В этом триггере получают название и новое содержимое компилируемого объекта, дополняют его предыдущим содержимым из словаря данных и записывают в лог изменений.

Как быть, если хочется сделать вьюшку с параметрами

Такое желание может часто посещать разработчика на Oracle. Почему можно сделать процедуру или функцию с параметрами, но не бывает вьюшек с входными параметрами, которые можно использовать при вычислениях? В Oracle есть чем заменить это недостающее, на наш взгляд, понятие.
Рассмотрим пример. Пусть есть таблица с продажами по подразделениям за каждый день.

create table DIVISION_SALES ( division_id INTEGER, dt DATE, sales_amt NUMBER );

Такой запрос сравнивает продажи по подразделениям за два дня. В данном случае, 30.04.2020 и 11.09.2020.

select t1.division_id, t1.dt dt1, t2.dt dt2, t1.sales_amt sales_amt1, t2.sales_amt sales_amt2 from (select dt, division_id, sales_amt from division_sales where dt = to_date('30.04.2020', 'dd.mm.yyyy')) t1, (select dt, division_id, sales_amt from division_sales where dt = to_date('11.09.2020', 'dd.mm.yyyy')) t2 where t1.division_id = t2.division_id;

Вот вьюшка, которую хочется написать для обобщения такого запроса. Хочется передавать даты в качестве параметров. Однако синтаксис не позволяет такое сделать.

create or replace view vw_division_sales_report(in_dt1 date, in_dt2 date) as select t1.division_id, t1.dt dt1, t2.dt dt2, t1.sales_amt sales_amt1, t2.sales_amt sales_amt2 from (select dt, division_id, sales_amt from division_sales where dt = in_dt1) t1, (select dt, division_id, sales_amt from division_sales where dt = in_dt2) t2 where t1.division_id = t2.division_id;

Предлагается такое обходное решение. Создадим тип под строку из этой вьюшки.

create type t_division_sales_report as object ( division_id INTEGER, dt1 DATE, dt2 DATE, sales_amt1 NUMBER, sales_amt2 NUMBER );

И создадим тип под таблицу из таких строк.

create type t_division_sales_report_table as table of t_division_sales_report;

Вместо вьюшки напишем pipelined функцию с входными параметрами-датами.

create or replace function func_division_sales(in_dt1 date, in_dt2 date) return t_division_sales_report_table pipelined as begin for z in (select t1.division_id, t1.dt dt1, t2.dt dt2, t1.sales_amt sales_amt1, t2.sales_amt sales_amt2 from (select dt, division_id, sales_amt from division_sales where dt = in_dt1) t1, (select dt, division_id, sales_amt from division_sales where dt = in_dt2) t2 where t1.division_id = t2.division_id) loop pipe row(t_division_sales_report(z.division_id, z.dt1, z.dt2, z.sales_amt1, z.sales_amt2)); end loop; end;

Обращаться к ней можно так:

select * from table(func_division_sales(to_date('30.04.2020', 'dd.mm.yyyy'), to_date('11.09.2020', 'dd.mm.yyyy')));

Этот запрос и выдаст нам такой же результат, как запрос в начале этой заметки с явным образом подставленными датами.
Pipelined функции могут быть также полезны, если нужно передать параметр внутрь сложного запроса.
Например, рассмотрим сложную вьюшку, в которой поле field1, по которому хочется отфильтровать данные, запрятано где-то глубоко во вьюшке.

create or replace view complex_view as select field1, . from (select field1, . from (select field1, . from deep_table), table1 where . ), table2 where . ;

И запрос из вьюшки с фиксированным значением field1 может иметь плохой план выполнения.

select field1, . from complex_view where field1 = 'myvalue';

Т.е. вместо того, чтобы сначала отфильтровать deep_table по условию field1 = ‘myvalue’, запрос может сначала соединить все таблицы, обработав излишне большой объём данных, а потом уже фильтровать результат по условию field1 = ‘myvalue’. Такой сложности можно избежать, если сделать вместо вьюшки pipelined функцию с параметром, значение которого присваивается полю field1.

Использование динамической статистики в запросах

Бывает, что один и тот же запрос в БД Oracle обрабатывает всякий раз различный объём данных в использующихся в нём таблицах и подзапросах. Как заставить оптимизатор всякий раз понимать, какой из способов соединения таблиц на этот раз лучше и какие индексы использовать? Рассмотрим, например, запрос, который соединяет порцию изменившихся с последней загрузки остатков по счетам со справочником счетов. Порция изменившихся остатков по счетам сильно меняется от загрузки к загрузке, составляя то сотни строк, то миллионы строк. В зависимости от размера этой порции требуется соединять изменившиеся остатки со счетами то способом /*+ use_nl*/, то способом /*+ use_hash*/. Всякий раз повторно собирать статистику неудобно, особенно, если от загрузки к загрузке изменяется количество строк не в соединяемой таблице, а в соединяемом подзапросе. На помощь тут может прийти хинт /*+ dynamic_sampling()*/. Покажем, как он влияет, на примере запроса. Пусть таблица change_balances содержит изменения остатков, а accounts – справочник счетов. Соединяем эти таблицы по полям account_id, имеющимся в каждой из таблиц. В начале эксперимента запишем в эти таблицы побольше строк и не будем менять их содержимое.
Сначала возьмём 10% изменений остатков в таблице change_balances и посмотрим, какой план будет с использованием dynamic_sampling:

SQL> EXPLAIN PLAN 2 SET statement_id = 'test1' 3 INTO plan_table 4 FOR with c as 5 (select /*+ dynamic_sampling(change_balances 2)*/ 6 account_id, balance_amount 7 from change_balances 8 where mod(account_id, 10) = 0) 9 select a.account_id, a.account_number, c.balance_amount 10 from c, accounts a 11 where c.account_id = a.account_id; Explained. SQL> SQL> SELECT * FROM table (DBMS_XPLAN.DISPLAY); Plan hash value: 874320301 ---------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | ---------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 9951K| 493M| | 140K (1)| 00:28:10 | |* 1 | HASH JOIN | | 9951K| 493M| 3240K| 140K (1)| 00:28:10 | |* 2 | TABLE ACCESS FULL| CHANGE_BALANCES | 100K| 2057K| | 7172 (1)| 00:01:27 | | 3 | TABLE ACCESS FULL| ACCOUNTS | 10M| 295M| | 113K (1)| 00:22:37 | ---------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - access("ACCOUNT_ID"="A"."ACCOUNT_ID") 2 - filter(MOD("ACCOUNT_ID",10)=0) Note ----- - dynamic sampling used for this statement (level=2) 20 rows selected.

Итак, видим, что предлагается пройти таблицы change_balances и accounts с помощью full scan и соединить их посредством hash join.
Теперь резко уменьшим выборку из change_balances. Возьмём 0.1% изменений остатков и посмотрим, какой план будет с использованием dynamic_sampling:

SQL> EXPLAIN PLAN 2 SET statement_id = 'test2' 3 INTO plan_table 4 FOR with c as 5 (select /*+ dynamic_sampling(change_balances 2)*/ 6 account_id, balance_amount 7 from change_balances 8 where mod(account_id, 1000) = 0) 9 select a.account_id, a.account_number, c.balance_amount 10 from c, accounts a 11 where c.account_id = a.account_id; Explained. SQL> SQL> SELECT * FROM table (DBMS_XPLAN.DISPLAY); Plan hash value: 2360715730 ------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 73714 | 3743K| 16452 (1)| 00:03:18 | | 1 | NESTED LOOPS | | | | | | | 2 | NESTED LOOPS | | 73714 | 3743K| 16452 (1)| 00:03:18 | |* 3 | TABLE ACCESS FULL | CHANGE_BALANCES | 743 | 15603 | 7172 (1)| 00:01:27 | |* 4 | INDEX RANGE SCAN | IX_ACCOUNTS_ACCOUNT_ID | 104 | | 2 (0)| 00:00:01 | | 5 | TABLE ACCESS BY INDEX ROWID| ACCOUNTS | 99 | 3069 | 106 (0)| 00:00:02 | ------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 3 - filter(MOD("ACCOUNT_ID",1000)=0) 4 - access("ACCOUNT_ID"="A"."ACCOUNT_ID") Note ----- - dynamic sampling used for this statement (level=2) 22 rows selected.

На этот раз к таблице change_balances таблица accounts присоединяется посредством nested loops и используется индекс для чтения строк из accounts.
Если же хинт dynamic_sampling убрать, то во втором случае план останется такой же, как в первом случае, и это не оптимально.
Подробности о хинте dynamic_sampling и возможных значениях его числового аргумента можно найти в документации.

Как сохранить план запроса при вставке данных через database link

Решаем такую задачу. На сервере-источнике данных имеются таблицы, которые нужно соединить и загрузить в хранилище данных. Допустим, на сервере-источнике написана вьюшка, которая содержит в себе всю нужную ETL-логику преобразований. Вьюшка написана оптимально, в ней указаны хинты оптимизатору, подсказывающие, как соединять таблицы и какие индексы использовать. На стороне сервера хранилища данных нужно сделать несложную вещь – вставить данные из вьюшки в целевую таблицу. И тут могут возникнуть сложности. Если вставку в целевую таблицу осуществить командой вида

insert into dwh_table (field1, field2) select field1, field2 from vw_for_dwh_table@xe_link;

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

SQL> EXPLAIN PLAN 2 SET statement_id = 'test' 3 INTO plan_table 4 FOR insert into dwh_table 5 (field1, field2) 6 select field1, field2 from vw_for_dwh_table@xe_link; Explained. SQL> SQL> SELECT * FROM table (DBMS_XPLAN.DISPLAY); Plan hash value: 1788691278 ------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Inst |IN-OUT| ------------------------------------------------------------------------------------------------------------- | 0 | INSERT STATEMENT | | 1 | 2015 | 2 (0)| 00:00:01 | | | | 1 | LOAD TABLE CONVENTIONAL | DWH_TABLE | | | | | | | | 2 | REMOTE | VW_FOR_DWH_TABLE | 1 | 2015 | 2 (0)| 00:00:01 | XE_LI~ | R->S | ------------------------------------------------------------------------------------------------------------- Remote SQL Information (identified by operation id): ---------------------------------------------------- 2 - SELECT /*+ OPAQUE_TRANSFORM */ "FIELD1","FIELD2" FROM "VW_FOR_DWH_TABLE" "VW_FOR_DWH_TABLE" (accessing 'XE_LINK' ) 16 rows selected.

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

declare cursor cr is select field1, field2 from vw_for_dwh_table@xe_link; cr_row cr%rowtype; begin open cr; loop fetch cr into cr_row; insert into dwh_table (field1, field2) values (cr_row.field1, cr_row.field2); exit when cr%notfound; end loop; close cr; end;

Запрос из курсора

select field1, field2 from vw_for_dwh_table@xe_link;

в отличие от вставки

insert into dwh_table (field1, field2) select field1, field2 from vw_for_dwh_table@xe_link;

сохранит план запроса, заложенный во вьюшку на сервере-источнике.

Запуск процедур в параллельных сессиях

Часто стоит задача запустить из некоторой родительской процедуры несколько параллельных расчётов и, дождавшись завершения каждого из них, продолжить выполнение родительской процедуры. Это может быть полезно при параллельных вычислениях, если ресурсы сервера позволяют это. Есть много способов сделать это.
Опишем очень простой вариант реализации такого механизма. Параллельные процедуры будем выполнять в параллельных “одноразовых” джобах, родительская же процедура в цикле будет ожидать завершения всех этих джобов.
Создадим таблицы с метаданными для этого механизма. Для начала сделаем таблицу с группами параллельно запускаемых процедур:

create table PARALLEL_PROC_GROUP_LIST ( group_id INTEGER, group_name VARCHAR2(4000) ); comment on column PARALLEL_PROC_GROUP_LIST.group_id is 'Номер группы параллельно запускаемых процедур'; comment on column PARALLEL_PROC_GROUP_LIST.group_name is 'Название группы параллельно запускаемых процедур';

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

create table PARALLEL_PROC_LIST ( group_id INTEGER, proc_script VARCHAR2(4000), is_active CHAR(1) default 'Y' ); comment on column PARALLEL_PROC_LIST.group_id is 'Номер группы параллельно запускаемых процедур'; comment on column PARALLEL_PROC_LIST.proc_script is 'Pl/sql блок с кодом процедуры'; comment on column PARALLEL_PROC_LIST.is_active is 'Y - active, N - inactive. С помощью этого поля можно временно отключать процедуру из группы';

И сделаем таблицу журнала, где будем собирать лог того, какая процедура когда в каком джобе запускалась:

create table PARALLEL_PROC_LOG ( run_id INTEGER, group_id INTEGER, proc_script VARCHAR2(4000), job_id INTEGER, start_time DATE, end_time DATE ); comment on column PARALLEL_PROC_LOG.run_id is 'Номер запуска процедуры run_in_parallel'; comment on column PARALLEL_PROC_LOG.group_id is 'Номер группы параллельно запускаемых процедур'; comment on column PARALLEL_PROC_LOG.proc_script is 'Pl/sql блок с кодом процедуры'; comment on column PARALLEL_PROC_LOG.job_id is 'Job_id джоба, в котором была запущена эта процедура'; comment on column PARALLEL_PROC_LOG.start_time is 'Время начала работы'; comment on column PARALLEL_PROC_LOG.end_time is 'Время окончания работы'; create sequence Seq_Parallel_Proc_Log;

Теперь приведём код процедуры по запуску параллельных потоков:

create or replace procedure run_in_parallel(in_group_id integer) as -- Процедура по параллельному запуску процедур из таблицы parallel_proc_list. -- Параметр - номер группы из parallel_proc_list v_run_id integer; v_job_id integer; v_job_id_list varchar2(32767); v_job_id_list_ext varchar2(32767); v_running_jobs_count integer; begin select seq_parallel_proc_log.nextval into v_run_id from dual; -- submit jobs with the same parallel_proc_list.in_group_id -- store seperated with ',' JOB_IDs in v_job_id_list v_job_id_list := null; v_job_id_list_ext := null; for z in (select pt.proc_script from parallel_proc_list pt where pt.group_id = in_group_id and pt.is_active = 'Y') loop dbms_job.submit(v_job_id, z.proc_script); insert into parallel_proc_log (run_id, group_id, proc_script, job_id, start_time, end_time) values (v_run_id, in_group_id, z.proc_script, v_job_id, sysdate, null); v_job_id_list := v_job_id_list || ',' || to_char(v_job_id); v_job_id_list_ext := v_job_id_list_ext || ' union all select ' || to_char(v_job_id) || ' job_id from dual'; end loop; commit; v_job_id_list := substr(v_job_id_list, 2); v_job_id_list_ext := substr(v_job_id_list_ext, 12); -- loop while not all jobs finished loop -- set parallel_proc_log.end_time for finished jobs execute immediate 'update parallel_proc_log set end_time = sysdate where job_id in (' || v_job_id_list_ext || ' minus select job from user_jobs where job in (' || v_job_id_list || ') minus select job_id from parallel_proc_log where job_id in (' || v_job_id_list || ') and end_time is not null)'; commit; -- check whether all jobs finished execute immediate 'select count(1) from user_jobs where job in (' || v_job_id_list || ')' into v_running_jobs_count; -- if all jobs finished then exit exit when v_running_jobs_count = 0; -- sleep a little sys.dbms_lock.sleep(0.1); end loop; end;

Проверим, как работает процедура run_in_parallel. Создадим тестовую процедуру, которую будем вызывать в параллельных сессиях.

create or replace procedure sleep(in_seconds integer) as begin sys.Dbms_Lock.Sleep(in_seconds); end;

Заполним название группы и таблицу со cкриптами, которые будут выполняться параллельно.

insert into PARALLEL_PROC_GROUP_LIST(group_id, group_name) values(1, 'Тестовая группа'); insert into PARALLEL_PROC_LIST(group_id, proc_script, is_active) values(1, 'begin sleep(5); end;', 'Y'); insert into PARALLEL_PROC_LIST(group_id, proc_script, is_active) values(1, 'begin sleep(10); end;', 'Y');

Запустим группу параллельных процедур.

begin run_in_parallel(1); end;

По завершении посмотрим лог.

select * from PARALLEL_PROC_LOG;
RUN_ID GROUP_ID PROC_SCRIPT JOB_ID START_TIME END_TIME
1 1 begin sleep(5); end; 1 11.09.2020 15:00:51 11.09.2020 15:00:56
1 1 begin sleep(10); end; 2 11.09.2020 15:00:51 11.09.2020 15:01:01

Видим, что время выполнения экземпляров тестовой процедуры соответствует ожиданиям.

Протягивание остатков

Опишем вариант решения достаточно типовой банковской задачи по “протягиванию остатков”. Допустим, имеется таблица фактов изменения остатков по счетам. Требуется на каждый день календаря указать актуальный остаток по счёту (последний за день). Такая информация часто бывает нужна в хранилищах данных. Если в какой-то день не было движений по счёту, то нужно повторить последний известный остаток. Если объёмы данных и вычислительные мощности сервера позволяют, то можно решить такую задачу с помощью SQL-запроса, даже не прибегая к PL/SQL. Поможет нам в этом функция last_value(* ignore nulls) over(partition by * order by *), которая протянет последний известный остаток на последующие даты, в которых не было изменений.
Создадим таблицу и заполним её тестовыми данными.

create table ACCOUNT_BALANCE ( dt DATE, account_id INTEGER, balance_amt NUMBER, turnover_amt NUMBER ); comment on column ACCOUNT_BALANCE.dt is 'Дата и время остатка по счёту'; comment on column ACCOUNT_BALANCE.account_id is 'Номер счёта'; comment on column ACCOUNT_BALANCE.balance_amt is 'Остаток по счёту'; comment on column ACCOUNT_BALANCE.turnover_amt is 'Оборот по счёту'; insert into account_balance(dt, account_id, balance_amt, turnover_amt) values(to_date('01.01.2020 00:00:00','dd.mm.yyyy hh24.mi.ss'), 1, 23, 23); insert into account_balance(dt, account_id, balance_amt, turnover_amt) values(to_date('05.01.2020 01:00:00','dd.mm.yyyy hh24.mi.ss'), 1, 45, 22); insert into account_balance(dt, account_id, balance_amt, turnover_amt) values(to_date('05.01.2020 20:00:00','dd.mm.yyyy hh24.mi.ss'), 1, 44, -1); insert into account_balance(dt, account_id, balance_amt, turnover_amt) values(to_date('05.01.2020 00:00:00','dd.mm.yyyy hh24.mi.ss'), 2, 67, 67); insert into account_balance(dt, account_id, balance_amt, turnover_amt) values(to_date('05.01.2020 20:00:00','dd.mm.yyyy hh24.mi.ss'), 2, 77, 10); insert into account_balance(dt, account_id, balance_amt, turnover_amt) values(to_date('07.01.2020 00:00:00','dd.mm.yyyy hh24.mi.ss'), 2, 72, -5); 

Нижеприведённый запрос решает нашу задачу. Подзапрос ‘cld’ содержит календарь дат, в подзапросе ‘ab’ группируем остатки за каждый день, в подзапросе ‘a’ запоминаем перечень всех счетов и дату начала истории по каждому счёту, в подзапросе ‘pre’ для каждого счёта составляем календарь дней с начала его истории. Финальный запрос присоединяет к календарю дней активности каждого счёта последние остатки на каждый день и протягивает их на дни, в которых не было изменений.

with cld as (select /*+ materialize*/ to_date('01.01.2020', 'dd.mm.yyyy') + level - 1 dt from dual connect by level = a.min_dt) select pre.dt, pre.account_id, last_value(ab.balance_amt ignore nulls) over(partition by pre.account_id order by pre.dt) balance_amt, nvl(ab.turnover_amt, 0) turnover_amt from pre left join ab on pre.dt = ab.dt and pre.account_id = ab.account_id order by 2, 1; 

Результат запроса соответствует ожиданиям.

DT ACCOUNT_ID BALANCE_AMT TURNOVER_AMT
01.01.2020 1 23 23
02.01.2020 1 23 0
03.01.2020 1 23 0
04.01.2020 1 23 0
05.01.2020 1 44 21
06.01.2020 1 44 0
07.01.2020 1 44 0
08.01.2020 1 44 0
09.01.2020 1 44 0
10.01.2020 1 44 0
05.01.2020 2 77 77
06.01.2020 2 77 0
07.01.2020 2 72 -5
08.01.2020 2 72 0
09.01.2020 2 72 0
10.01.2020 2 72 0

Объединение нескольких историй в одну

При загрузке данных в хранилища часто решается задача, когда нужно выстроить единую историю по сущности, имея отдельные истории атрибутов этой сущности, пришедшие из различных источников. Допустим, имеется некоторая сущность с первичным ключом primary_key_id, о которой известна история (start_dt — end_dt) трёх её различных атрибутов, расположенная в трёх различных таблицах.

create table HIST1 ( primary_key_id INTEGER, start_dt DATE, attribute1 NUMBER ); insert into HIST1(primary_key_id, start_dt, attribute1) values(1, to_date('2014-01-01','yyyy-mm-dd'), 7); insert into HIST1(primary_key_id, start_dt, attribute1) values(1, to_date('2015-01-01','yyyy-mm-dd'), 8); insert into HIST1(primary_key_id, start_dt, attribute1) values(1, to_date('2016-01-01','yyyy-mm-dd'), 9); insert into HIST1(primary_key_id, start_dt, attribute1) values(2, to_date('2014-01-01','yyyy-mm-dd'), 17); insert into HIST1(primary_key_id, start_dt, attribute1) values(2, to_date('2015-01-01','yyyy-mm-dd'), 18); insert into HIST1(primary_key_id, start_dt, attribute1) values(2, to_date('2016-01-01','yyyy-mm-dd'), 19); create table HIST2 ( primary_key_id INTEGER, start_dt DATE, attribute2 NUMBER ); insert into HIST2(primary_key_id, start_dt, attribute2) values(1, to_date('2015-01-01','yyyy-mm-dd'), 4); insert into HIST2(primary_key_id, start_dt, attribute2) values(1, to_date('2016-01-01','yyyy-mm-dd'), 5); insert into HIST2(primary_key_id, start_dt, attribute2) values(1, to_date('2017-01-01','yyyy-mm-dd'), 6); insert into HIST2(primary_key_id, start_dt, attribute2) values(2, to_date('2015-01-01','yyyy-mm-dd'), 14); insert into HIST2(primary_key_id, start_dt, attribute2) values(2, to_date('2016-01-01','yyyy-mm-dd'), 15); insert into HIST2(primary_key_id, start_dt, attribute2) values(2, to_date('2017-01-01','yyyy-mm-dd'), 16); create table HIST3 ( primary_key_id INTEGER, start_dt DATE, attribute3 NUMBER ); insert into HIST3(primary_key_id, start_dt, attribute3) values(1, to_date('2016-01-01','yyyy-mm-dd'), 10); insert into HIST3(primary_key_id, start_dt, attribute3) values(1, to_date('2017-01-01','yyyy-mm-dd'), 20); insert into HIST3(primary_key_id, start_dt, attribute3) values(1, to_date('2018-01-01','yyyy-mm-dd'), 30); insert into HIST3(primary_key_id, start_dt, attribute3) values(2, to_date('2016-01-01','yyyy-mm-dd'), 110); insert into HIST3(primary_key_id, start_dt, attribute3) values(2, to_date('2017-01-01','yyyy-mm-dd'), 120); insert into HIST3(primary_key_id, start_dt, attribute3) values(2, to_date('2018-01-01','yyyy-mm-dd'), 130);

Целью является загрузка единой истории изменения трёх атрибутов в одну таблицу.
Ниже приведён запрос, решающий такую задачу. В нём сначала формируется диагональная таблица q1 с данными из разных источников по разным атрибутам (отсутствующие в источнике атрибуты заполняются null-ами). Затем с помощью функции last_value(* ignore nulls) диагональная таблица схлопывается в единую историю, а последние известные значения атрибутов протягиваются вперёд на те даты, в которые изменений по ним не было:

select primary_key_id, start_dt, nvl(lead(start_dt - 1) over(partition by primary_key_id order by start_dt), to_date('9999-12-31', 'yyyy-mm-dd')) as end_dt, last_value(attribute1 ignore nulls) over(partition by primary_key_id order by start_dt) as attribute1, last_value(attribute2 ignore nulls) over(partition by primary_key_id order by start_dt) as attribute2, last_value(attribute3 ignore nulls) over(partition by primary_key_id order by start_dt) as attribute3 from (select primary_key_id, start_dt, max(attribute1) as attribute1, max(attribute2) as attribute2, max(attribute3) as attribute3 from (select primary_key_id, start_dt, attribute1, cast(null as number) attribute2, cast(null as number) attribute3 from hist1 union all select primary_key_id, start_dt, cast(null as number) attribute1, attribute2, cast(null as number) attribute3 from hist2 union all select primary_key_id, start_dt, cast(null as number) attribute1, cast(null as number) attribute2, attribute3 from hist3) q1 group by primary_key_id, start_dt) q2 order by primary_key_id, start_dt;

Результат получается такой:

PRIMARY_KEY_ID START_DT END_DT ATTRIBUTE1 ATTRIBUTE2 ATTRIBUTE3
1 01.01.2014 31.12.2014 7 NULL NULL
1 01.01.2015 31.12.2015 8 4 NULL
1 01.01.2016 31.12.2016 9 5 10
1 01.01.2017 31.12.2017 9 6 20
1 01.01.2018 31.12.9999 9 6 30
2 01.01.2014 31.12.2014 17 NULL NULL
2 01.01.2015 31.12.2015 18 14 NULL
2 01.01.2016 31.12.2016 19 15 110
2 01.01.2017 31.12.2017 19 16 120
2 01.01.2018 31.12.9999 19 16 130

Нормалайзер

Иногда встаёт задача о нормализации данных, пришедших в формате поля с разделителями. Например, в виде такой таблицы:

create table DENORMALIZED_TABLE ( id INTEGER, val VARCHAR2(4000) ); insert into DENORMALIZED_TABLE(id, val) values(1, 'aaa,cccc,bb'); insert into DENORMALIZED_TABLE(id, val) values(2, 'ddd'); insert into DENORMALIZED_TABLE(id, val) values(3, 'fffff,e');

Такой запрос нормализует данные, расклеив соединённые запятой поля в виде нескольких строк:

select id, regexp_substr(val, '[^,]+', 1, column_value) val, column_value from denormalized_table, table(cast(multiset (select level from dual connect by regexp_instr(val, '[^,]+', 1, level) > 0) as sys.odcinumberlist)) order by id, column_value;

Результат получается такой:

ID VAL COLUMN_VALUE
1 aaa 1
1 cccc 2
1 bb 3
2 ddd 1
3 fffff 1
3 e 2

Визуализация в формате SVG

Часто возникает желание как-то визуализировать числовые показатели, хранящиеся в базе данных. Например, построить графики, гистограммы, диаграммы. В этом могут помочь специализированные средства, например, Oracle BI. Но лицензии на эти средства могут стоить денег, а настройка их может занять больше времени, чем написание “на коленке” SQL-запроса к Oracle, который выдаст готовую картинку. Продемонстрируем на примере, как с помощью запроса быстро нарисовать такую картинку в формате SVG.
Предположим, у нас есть таблица с данными

create table graph_data(dt date, val number, radius number); insert into graph_data(dt, val, radius) values (to_date('01.01.2020','dd.mm.yyyy'), 12, 3); insert into graph_data(dt, val, radius) values (to_date('02.01.2020','dd.mm.yyyy'), 15, 4); insert into graph_data(dt, val, radius) values (to_date('05.01.2020','dd.mm.yyyy'), 17, 5); insert into graph_data(dt, val, radius) values (to_date('06.01.2020','dd.mm.yyyy'), 13, 6); insert into graph_data(dt, val, radius) values (to_date('08.01.2020','dd.mm.yyyy'), 3, 7); insert into graph_data(dt, val, radius) values (to_date('10.01.2020','dd.mm.yyyy'), 20, 8); insert into graph_data(dt, val, radius) values (to_date('11.01.2020','dd.mm.yyyy'), 18, 9);

dt – это дата актуальности,
val – это числовой показатель, динамику которого по времени мы визуализируем,
radius – это ещё один числовой показатель, который будем рисовать в виде кружка с таким радиусом.
Скажем пару слов о формате SVG. Это формат векторной графики, который можно смотреть в современных браузерах и конвертировать в другие графические форматы. В нём, среди прочего, можно рисовать линии, кружки и писать текст:

  2020-01-01

Ниже SQL-запрос к Oracle, который строит график из данных в этой таблице. Здесь подзапрос const содержит различные константные настройки – размеры картинки, количество меток на осях графика, цвета линий и кружочков, размеры шрифта и т.д. В подзапросе gd1 мы приводим данные из таблицы graph_data к координатам x и y на рисунке. Подзапрос gd2 запоминает предыдущие по времени точки, из которых нужно вести линии к новым точкам. Блок ‘header’ – это заголовок картинки с белым фоном. Блок ‘vertical lines’ рисует вертикальные линии. Блок ‘dates under vertical lines’ подписывает даты на оси x. Блок ‘horizontal lines’ рисует горизонтальные линии. Блок ‘values near horizontal lines’ подписывает значения на оси y. Блок ‘circles’ рисует кружочки указанного в таблице graph_data радиуса. Блок ‘graph data’ строит из линий график динамики показателя val из таблицы graph_data. Блок ‘footer’ добавляет замыкающий тэг.

with const as (select 700 viewbox_width, 700 viewbox_height, 30 left_margin, 30 right_margin, 15 top_margin, 25 bottom_margin, max(dt) - min(dt) + 1 num_vertical_lines, 11 num_horizontal_lines, 'rgb(150,255,255)' stroke_vertical_lines, '1px' stroke_width_vertical_lines, 10 font_size_dates, 'rgb(0,150,255)' fill_dates, 23 x_dates_pad, 13 y_dates_pad, 'rgb(150,255,255)' stroke_horizontal_lines, '1px' stroke_width_horizontal_lines, 10 font_size_values, 'rgb(0,150,255)' fill_values, 4 x_values_pad, 2 y_values_pad, 'rgb(255,0,0)' fill_circles, 'rgb(51,102,0)' stroke_graph, '1px' stroke_width_graph, min(dt) min_dt, max(dt) max_dt, max(val) max_val from graph_data), gd1 as (select graph_data.dt, const.left_margin + (const.viewbox_width - const.left_margin - const.right_margin) * (graph_data.dt - const.min_dt) / (const.max_dt - const.min_dt) x, const.viewbox_height - const.bottom_margin - (const.viewbox_height - const.top_margin - const.bottom_margin) * graph_data.val / const.max_val y, graph_data.radius from graph_data, const), gd2 as (select dt, round(nvl(lag(x) over(order by dt), x)) prev_x, round(x) x, round(nvl(lag(y) over(order by dt), y)) prev_y, round(y) y, radius from gd1) /* header */ select '' txt from dual union all select '' from const union all select 'Test graph' from dual union all select 'Test graph' from dual union all select '' from const union all /* vertical lines */ select '' from const connect by level ' || to_char(min_dt + level - 1, 'yyyy-mm-dd') || '' from const connect by level ' from const connect by level ' || to_char(round(max_val / (num_horizontal_lines - 1) * (level - 1), 2)) || '' from const connect by level ' from gd2, const union all /* graph data */ select '' from gd2, const union all /* footer */ select '' from dual;

Результат запроса можно сохранить в файл с расширением *.svg и посмотреть в браузере. При желании можно с помощью какой-либо из утилит конвертировать его в другие графические форматы, размещать на веб-страницах своего приложения и т.д.
Получилась такая картинка:

Приложение поиска по метаданным Oracle

  • Где в коде Oracle зашита константа 61209, представляющая собой номер счёта второго порядка?
  • Где в коде и на каких серверах используется таблица accounts (в т.ч. через database link)?
  • С какого сервера из какой хранимой процедуры или триггера приходит сгенерированная программистом ошибка, например, ORA-20001 “Курс валюты не найден”?
  • Прописан ли планируемый к удалению индекс IX_CLIENTID где-либо явным образом в хинтах оптимизатора в SQL-запросах?
  • Используются ли где-либо (в т.ч. через database link) планируемые к удалению таблица, поле, процедура, функция и т.д.?
  • Где в коде явно зашит чей-то е-мэйл или номер телефона? Такие вещи лучше выносить из серверных объектов в настроечные таблицы.
  • Где в коде на серверах используется зависящий от версии Oracle функционал? Например, функция wm_concat выдаёт различный тип данных на выходе в зависимости от версии Oracle. Это может быть критично и требует внимания при миграции на более новую версию.
  • Где в коде используется какой-либо редкий приём, на который программисту хочется посмотреть, как на образец? Например, поискать в коде Oracle примеры использования функций sys_connect_by_path, regexp_instr или хинта push_subq.

Клиентская часть не сложная. Веб-интерфейс получает введённую пользователем поисковую строку, список серверов для поиска и логин пользователя. Веб-страница передаёт их в хранимую процедуру Oracle на сервере-обработчике. История обращений к поисковику, т.е. кто какой запрос выполнял, на всякий случай журналируется.

Получив поисковый запрос, серверная часть на поисковом сервере Oracle запускает в параллельных джобах несколько процедур, которые по database links на выбранных серверах Oracle сканируют следующие представления словаря данных в поисках искомой строки: dba_col_comments, dba_jobs, dba_mviews, dba_objects, dba_scheduler_jobs, dba_source, dba_tab_cols, dba_tab_comments, dba_views. Каждая из процедур, если что-то обнаружила, записывает найденное в таблицу результатов поиска (с соответствующим ID поискового запроса).

Когда все поисковые процедуры завершили работу, клиентская часть выдаёт пользователю всё, что записалось в таблицу результатов поиска с соответствующим ID поискового запроса.
Но это ещё не всё. Помимо поиска по словарю данных Oracle в описанный механизм прикрутили ещё и поиск по репозиторию Informatica PowerCenter. Informatica PowerCenter является популярным ETL-средством, использующимся в Сбербанке при загрузке различной информации в хранилища данных. Informatica PowerCenter имеет открытую хорошо задокументированную структуру репозитория. По этому репозиторию есть возможность искать информацию так же, как и по словарю данных Oracle. Какие таблицы и поля используются в коде загрузок, разработанном на Informatica PowerCenter? Что можно найти в трансформациях портов и явных SQL-запросах? Вся эта информация имеется в структурах репозитория и может быть найдена. Для знатоков PowerCenter напишу, что наш поисковик сканирует следующие места репозитория в поисках маппингов, сессий или воркфловов, содержащих в себе где-то искомую строку: sql override, mapplet attributes, ports, source definitions in mappings, source definitions, target definitions in mappings, target_definitions, mappings, mapplets, workflows, worklets, sessions, commands, expression ports, session instances, source definition fields, target definition fields, email tasks.

Автор: Михаил Гричик, эксперт профессионального сообщества Сбербанка SberProfi DWH/BigData.

Профессиональное сообщество SberProfi DWH/BigData отвечает за развитие компетенций в таких направлениях, как экосистема Hadoop, Teradata, Oracle DB, GreenPlum, а также BI инструментах Qlik, SAP BO, Tableau и др.

PeopleSoft продолжает внедрять инновации и обеспечивать преимущества

Приложения Oracle PeopleSoft помогают решать самые сложные деловые потребности. PeopleSoft от Oracle — это комплексные отраслевые и бизнес-решения, которые дают возможность компаниям повысить производительность, быстрее достигнуть бизнес-целей и снизить стоимость владения.

Oracle продолжает работать над PeopleSoft

Более чем 30-летняя история лучших в своем классе решений помогает PeopleSoft предлагать современную функциональность новых приложений и постоянно совершенствовать уже имеющиеся решения. Современные интуитивные методы работы пользователей кардинально меняют взаимодействие пользователей с PeopleSoft. Новый пользовательский интерфейс PeopleSoft, удобный для настройки и персонализации, обеспечивает пользователям необходимые сведения в требуемом виде и на любом устройстве.

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

Проведите преобразование с помощью PeopleSoft и Oracle Cloud

Работайте в облаке

Современные решения PeopleSoft лучше всего работает в Oracle Cloud. Экономьте деньги, повышайте производительность и легко реагируйте на новые потребности бизнеса с помощью автоматической, масштабируемой инфраструктуры.

Расширение с помощью возможностей облака

Независимо от того, используете ли вы PeopleSoft в локальной сети или в OCI, вы можете расширить ценность вашей системы PeopleSoft за счет интеграции с дополнительными решениями Oracle Cloud.

Преобразование с помощью облачных приложений

Тысячи клиентов Oracle теперь работают в приложениях Fusion Cloud, включая многих бывших клиентов PeopleSoft.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *