Интеграция языков программирования с базами данных: в чем состоит проблема?

Автор работы: Пользователь скрыл имя, 23 Сентября 2011 в 22:30, статья

Описание

Проблема «потери соответствия» (impedance mismatch) между языками программирования и системами баз данных обсуждается в сообществе баз данных на протяжении всей моей профессиональной жизни. Попытки решения этой проблемы породили направления языков программирования баз данных, объектно-ориентированных и, отчасти, объектно-реляционных баз данных.

Работа состоит из  1 файл

Интеграция языков программирования с базами данных.doc

— 201.50 Кб (Скачать документ)

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

4. Статическая типизация  (T*)

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

Критерий статической  типизации отличается от критериев отображения данных и интерпретации null-значений. Это связано с тем, что статическая типизация не является свойством данных; это свойство системы, управляющей данными, и способ интерпретации ею программ или запросов. Таким образом, статическая типизация является мета-аспектом, применимым к другим критериям. Например, отображение данных может производиться во время выполнения, а может статически проверяться. В нашей оценке статическая типизация является дополнительным измерением оценки по другим критериям, а не отдельным критерием.

5. Стили интерфейсов

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

void printInfo(String prefix) {

for (Employee e in db.allEmployees() )

    if ( e.name.startsWith(prefix) && e.salary > e.manager.salary ) {

      print( e.name );

      print( e.salary );

      print( e.department.name );

    }

}

Рис. 2. Печать информации о  служащих

5.1 Ортогональная персистентность  (S1)

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

Программы, манипулирующие персистентными данными, выглядят подобно  обычным программам. В предположении, что db является корнем персистентности, содержащим коллекцию служащих, в примере на рис. 2 находятся все служащие, фамилии которых начинаются с заданного префикса, и зарплата которых превышает зарплату их менеджера. Затем печатаются фамилия служащего, его заработная плата и название отдела.

К числу примеров систем с ортогональной персистентностью относятся PJama [7], Thor [31] и OPJ [33]. В системах с чистой ортогональной персистентностью часто реализуется собственный менеджер хранения, а не используется существующая технология баз данных. Ортогональность полезнее представлять не как бинарное свойство, а в виде спектра. При таком представлении ортогональность является показателем уровня единообразия при работе с персистентными и не персистентными данными. Это представление является разумным также и по той причине, что некоторые операции, в частности, те, которые связаны с транзакциями, осмысленны только для персистентных данных, так что требуется некоторая степень неортогональности [11].

В большинстве  объектно-ориентированных баз данных (ООБД) реализуется некоторый уровень  ортогональной персистентности, хотя часто допускается персистентность  только тех значений, которые являются объектами [16]. ООБД редко бывают чисто ортогональными, поскольку для пересистентных данных обеспечиваются специальные операции для их запросов. Некоторый уровень ортогональности обеспечивают и средства объектно-реляционного отображения. В число примеров входят TopLink, JDO, EJB и Hibernate [20263734].

5.2 Явное выполнение  запросов (S2)

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

string empQuery = “SELECT e.name, e.salary, d.name as deptName”

    + “FROM (Employee e INNER JOIN Department d ON d.ID = e.department)”

    + “INNER JOIN Employee m ON m.ID = e.manager”

    + “WHERE e.name LIKE ? AND e.salary > m.salary”

 

Connection conn = DriverManager.getConnection(...);

PreparedStatement stmt = con.prepareStatement(empQuery);

stmt.setString(1, prefix + “%”);

ResultSet rs = stmt.executeQuery(empQuery);

while ( rs.next() ) {

    print( rs.getString(“name”) );

    print( rs.getDecimal(“salary”) );

    print( rs.getString(“deptName”) );

}

Рис. 3. Явное выполнение запроса с использованием JDBC

Встраиваемые  запросы. Явные запросы могут встраиваться в язык программирования или обрабатываться препроцессором [27]. К числу примеров относится SQLJ [8]. Встраиваемый SQL обеспечивает статически типизированный подход к явному выполнению запросов. Как обсуждается в разд. 7, одним из существенных недостатков встраивания является отсутствие поддержки динамических запросов. Другой проблемой является то, что изменение синтаксиса языка программирования обычно приводит к нарушению работы средств рефакторинга, интегрированных сред разработки (Integrated Development Environment, IDE) и CASE-средств.

Интерфейсы  уровня вызова. Доминирующим механизмом явного выполнения запросов являетсяинтерфейс уровня вызовов (call level interface, CLI) [28], обеспечивающий языку программирования доступ к серверу баз данных на основе стандартизованного API [2824]. Ключевой характеристикой CLI является возможность выполнения запросов и команд базы данных, представленных в виде строк или других структур данных времени выполнения [26]. На рис. 3 показано, как запрос с рис. 2 может быть выполнен с использованием JDBC [24].

В большинстве  систем с ортогональной персистентностью явные запросы не поддерживаются. В некоторых, хотя и не во всех объектно-ориентированных базах данных поддержка явных запросов имеется. В большинстве средств объектно-реляционного отображения явные запросы поддерживаются в качестве дополнения к ортогональной персистентности. Иногда явные запросы добавляются для решения проблем производительности; например, в EJB 1.0 поддержка запросов отсутствовала, а в EJB 2.0 – появилась. В других системах, таких как TopLink, JDO и Hibernate, имеются сложные языки запросов. Запросы могут представляться не только символьными строками, но и структурами данных времени выполнения. В Hibernate допускается представление запросов в виде критериальных объектов. Имена полей в этих системах по-прежнему представляются в виде строк символов.

Интерфейсам уровня вызовов свойственен ряд существенных проблем. Синтаксис и типы программ баз данных не проверяются статически, так что ошибки не выявляются до времени выполнения. Для конструирования  и повторного использования запросов во время выполнения требуются сложные и чреватые ошибками манипуляции. Результаты запросов представляются как динамически типизируемые объекты, доступ к которым производится по именам строк. В некоторых ситуациях для встраиваемых запросов возможна проверка типов. Гулд, Су и Деванбу [23] применяют статический анализ для проверки программ, использующих интерфейсы уровня вызовов. Их анализ в настоящее время не покрывает параметры запросов и типы результатов и может приводить к неверным результатам при раздельной компиляции компонентов. Основным достоинством подхода является его применимость к существующим программам.

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

6. Оптимизация

Для приложений, работающих с большими объемами данных, важно оптимизировать доступ к данным. Адекватная стратегия выполнения запроса  часто может оказаться на несколько  порядков быстрее прямолинейной  стратегии [41].

В примерах этого  раздела представлены распространенные оптимизации запросов, но с точки  зрения языка программирования. Для  обеспечения более глубокого  анализа решений мы разделяем  понятияпоиска и навигации. Это приблизительно соответствует разделам WHERE и SELECT в языке SQL: поиск относится к выбору подмножества интересующих пользователя объектов, а навигация используется для обработки результатов поиска. Это различие является важным, поскольку во многих решениях одно из этих понятий поддерживается лучше другого.

6.1 Оптимизация поиска

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

Явные индексы (P1). Распространенным методом является изменение порядка подопераций, таких как итерирование и проверка условия. Так, оптимизатор запросов может использовать индекс для вычисления множества идентификаторов записей, удовлетворяющих условию, а затем найти соответствующие данные путем поиска этих идентификаторов во втором индексе. Этот аспект плана иллюстрируется на рис. 4, где эта оптимизация применяется к исходному Java-коду.

Проверка префикса реализуется путем поиска по индексу: метод match возвращает итератор над множеством элементов индекса, соответствующих первому условию. Затем для нахождения данных о служащих используется эффективный индекс, отображающий идентификаторы записей в значения записей. Если большинство фамилий не начинается с заданного префикса, этот метод будет гораздо эффективнее линейного поиска. Явное программирование с использованием индексов поддерживается в Exodus [13] и Ontos [40].

void printInfo(String prefix) {

    for (IndexItem l in employeeNameIndex.match(“S”)) {

      Employee e = employeeID_Index.lookup(l.ID);

      if (e.salary > managerID_Index.lookup(e.managerID).salary) {

          print( e.name );

          print( e.salary );

          Department d = departmentID_Index.lookup(e.deptID);

          print( d.name );

      }

    }

}

Рис. 4. Оптимизированная выдача на печать информации о служащих

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

Информация о работе Интеграция языков программирования с базами данных: в чем состоит проблема?