Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
курс лекций СБД.doc
Скачиваний:
23
Добавлен:
13.11.2019
Размер:
1.94 Mб
Скачать
  1. Взаимодействие sql с приложениями

    1. Встраивание sql-операторов в программный код

При совместном использовании программного кода и SQL-операторов необходимо преодолеть две проблемы. Во-первых, нужно уметь записывать результаты выполнения SQL-операторов в программные переменные. Это можно сделать по-разному. В одних случаях для этого используются объектно-ориентированные программы, в других применяются более простые методы. Например, в SQL Server следующая команда присваивает переменной @rowcount значение, равное количеству строк в таблице Поставщики:

SELECT @rowcount= COUNT(*) FROM Поставщики;

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

SELECT @rowcount:= Имя_П FROM Поставщики;

Если в таблице Поставщики имеется 100 строк, то запрос столбца Имя_П возвратит 100 значений, в то время как переменная @rowcount может принять только одно значение.

Чтобы преодолеть это затруднение, результаты выполнения SQL-операторов обрабатываются как псевдофайлы. SQL-оператор возвращает набор строк. На первую строку помещается курсор и данная строка обрабатывается. Затем курсор перемещается на следующую строку, и так далее, пока не будут обработаны все строки. Типичный псевдокод процесса обработки выглядит так:

Открыть файл SQL (SELECT * FROM Поставщики); Поместить курсор на первую строку; Пока курсор не вышел за пределы таблицы { Присвоить @rowcount значение столбца Имя_П в строке под курсором; …Прочие операторы, использующие это значение @rowcount... Переместить курсор на следующую строку; }; ...Продолжение обработки...

Таким образом, строки, возвращенные SQL -оператором, обрабатываются по одной.

    1. Тип курсора

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

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

В соответствии со стандартом SQL при работе с курсорами можно выделить следующие основные действия:

  • создание или объявление курсора – DECLARE;

  • открытие курсора, т.е. наполнение его данными, которые сохраняются в многоуровневой памяти – OPEN;

  • выборка из курсора и изменение с его помощью строк данных – FETCH;

  • закрытие курсора, после чего он становится недоступным для пользовательских программ – CLOSE;

  • освобождение курсора, т.е. удаление курсора как объекта, поскольку его закрытие необязательно освобождает ассоциированную с ним память – DEALLOCATE.

Рассмотрим в качестве примера команду на создание курсора в стандарте SQL (обычно курсоры определяются с помощью операторов SELECT):

<создание_курсора>::= DECLARE TransCursor [INSENSITIVE][SCROLL] CURSOR FOR SELECT * FROM Поставщики WHERE Статус > 20 [FOR { READ_ONLY | UPDATE [OF имя_столбца[,...n]]}]

В примере определен курсор под названием TransCursor, действующий на наборе строк, указанном в операторе SELECT. Когда прикладная программа открывает курсор и считывает первую строку, о курсоре говорят, что он «указывает на первую строку».

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

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

Оператор запроса SELECT определяет результирующий набор строк курсора.

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

Создание курсора с аргументом FOR UPDATE позволяет выполнять в курсоре изменение данных либо в указанных столбцах, либо, при отсутствии аргумента [OF имя_столбца], во всех столбцах.

В некоторых случаях применение курсора неизбежно. Однако по возможности этого следует избегать и работать со стандартными командами обработки данных: SELECT, UPDATE, INSERT, DELETE. Помимо того, что курсоры не позволяют проводить операции изменения над всем объемом данных, скорость выполнения операций обработки данных посредством курсора заметно ниже, чем у стандартных средств SQL.

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

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

В таблице ХХ перечислены четыре типа курсоров, используемых в среде Windows (в других системах типы курсоров аналогичны). Простейший тип курсора – последовательный (forward only cursor). Он позволяет приложению передвигаться по набору строк только вперед. Изменения, произведенные другими курсорами в данной транзакции, а также другими транзакциями, будут видны только в том случае, если затронутые ими строки находятся впереди курсора.

Остальные три типа курсоров называются двунаправленными курсорами (или прокручиваемыми – scroll able cursors), поскольку приложение может передвигаться по набору записей как вперед, так и назад и переходить к произвольной строке результирующего набора курсора. Если программа способна модифицировать данные, на которые указывает курсор, он называется прокручиваемым и модифицируемым. Говоря о курсорах, не следует забывать об изолированности транзакций. Когда один пользователь модифицирует запись, другой читает ее при помощи собственного курсора, более того, он может модифицировать ту же запись, что делает необходимым соблюдение целостности данных.

Таблица ХХ, Типы курсоров

Тип курсора

Описание

Свойства

Последовательный

Приложение может перебирать набор записей только в одном направлении – вперед.

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

Статический

Приложение видит данные в том состоянии, в каком они были на момент открытия курсора

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

Ключевой

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

Обновления, вызванные любым источником, являются видимыми, вставки из других источников не видны (в наборе записей для них нет ключей). Строки, вставляемые данным курсором, добавляются в конец набора записей. Изменения, вызванные любым источником, являются видимыми. Изменения в порядке строк не видны.

Динамический

Приложение видит любые изменения, вызванные любым источником.

Все вставки, обновления, удаления и изменения в порядке записей являются видимыми. Если выставлен уровень изоляции "незавершенное чтение» (то есть допускается «грязное» чтение), то несохраненные изменения остаются невидимыми. В противном случае видны только сохраненные изменения.

Статический курсор (static cursors) обрабатывает «снимок» отношения, сделанный в момент открытия курсора. Изменения, сделанные таким курсором, являются видимыми для самого курсора; изменения из любых других источников являются невидимыми. Если другие пользователи изменят в исходной таблице включенные в курсор данные, это никак не повлияет на статический курсор. На время открытия курсора сервер устанавливает блокировку на все строки, включенные в его полный результирующий набор. Статический курсор не изменяется после создания и всегда отображает тот набор данных, который существовал на момент его открытия. В статический курсор внести изменения невозможно, поэтому он всегда открывается в режиме "только для чтения".

Ключевые курсоры (keyset cursors) соединяют в себе некоторые свойства статических и динамических курсоров. При открытии такого курсора для каждой строки в наборе записей сохраняется значение первичного ключа. Когда приложение устанавливает курсор на некоторую строку, СУБД по ключу считывает текущее значение этой строки. Если приложение собирается обновить строку, которая была удалена другим курсором этой же транзакции либо другой транзакцией, СУБД создает новую строку со старым значением ключа и помещает в нее обновленные значения. Новые строки, вставленные другими курсорами данной транзакции или другими транзакциями, невидимы для ключевого курсора. Такой тип курсора полезен при реализации прокрутки назад – тогда добавления и удаления рядов не видны, пока информация не обновится, а драйвер выбирает новую версию записи, если в нее были внесены изменения.

Динамический курсор (dynamic cursor) – это полнофункциональный курсор. Все вставки, обновления, удаления и изменения в порядке строк являются видимыми для динамического курсора.

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

Количество потребляемых ресурсов и необходимый объем обработки зависят от типа курсора. В общем случае, чем ниже находится тип курсора в табл. XX, тем выше расходы. Поэтому, чтобы увеличить производительность СУБД, разработчик приложения должен создавать курсоры, имеющие ровно столько возможностей, сколько требуется для выполнения поставленной задачи. Также весьма важно представлять, каким образом курсоры реализуются в конкретной СУБД и где они размещаются – на сервере или на клиенте. Иногда бывает выгоднее иметь динамический курсор на клиенте, чем статический – на сервере. Никакое общее правило сформулировать нельзя, поскольку производительность зависит от способа реализации курсора в СУБД и требований приложения.

Необходимо помнить, что если не указывается уровень изоляции транзакции или тип курсора, СУБД будет использовать уровень или тип, предусмотренный по умолчанию. Заданные по умолчанию параметры могут идеально подходить для вашего приложения, а могут оказаться и совершенно непригодными. Таким образом, хотя эти вопросы можно игнорировать, последствий избежать все равно не удастся. Изучите возможности вашей СУБД и используйте их рационально.