Базы данныхИнтернетКомпьютерыОперационные системыПрограммированиеСетиСвязьРазное
Поиск по сайту:
Подпишись на рассылку:

Назад в раздел

SQLBase 6

SQLBase 6

А.Брюзгин, Interface Ltd.

Введение

В последнее время технология клиент-сервер стала темой номер один в компьютерном мире. Многие склонны считать это скорее модой, чем объективной тенденцией развития информационных технологий. Однако, нельзя отрицать тот факт, что на сегодняшний день именно в технологии клиент-сервер нашли и находят свое отражение наиболее передовые идеи и решения, которые будут доминировать на рынке в 90-е годы нашего столетия, да и в начале следующего тысячелетия.
Наиболее яркими представителями технологии клиент-сервер являются многопользовательские реляционные СУБД. Они получили широчайшее распространение и завоевали всеобщее признание прежде всего благодаря своей надежности и производительности. В последнее время практически все фирмы-производители СУБД клиент-сервер проделали огромную работу по повышению потребительских свойств своих продуктов - повышению их быстродействия, улучшению пользовательского интерфейса и упрощению процедур поддержки и администрирования.
СУБД клиент-сервер работают в самых различных системах на самых разных компьютерах. Так, СУБД на mainframe управляют базами данных до нескольких терабайт, предоставляя необходимую информацию тысячам пользователей одновременно. В то же время локальные СУБД на компьютерах класса notebook обслуживают отсоединенных пользователей, предоставляя им возможность работать с репликами их корпоративных баз данных практически в любом месте.
Данная статья посвящена одному из ярких представителей сегодняшней технологии клиент-сервер - реляционной СУБД SQLBase фирмы Gupta Corporation. Эта СУБД завоевала широкое признание во всем мире и у нас в России, где за полтора года было продано почти полторы тысячи серверов SQLBase для различных платформ.
SQLBase становится платформой разработки приложений и систем во многих областях, включая банковские и бухгалтерские системы, документооборот, системы поддержки принятия решений, геоинформационные системы и многие другие. При этом растет интерес специалистов в области СУБД, разработчиков конечных приложений, системных администраторов и простых пользователей к техническим возможностям и особенностям SQLBase. Пользуясь предоставленной возможностью автор, Технический директор компании Интерфейс, попробует в данной статье удовлетворить этот интерес.

Общие характеристики

SQLBase - это реляционная многопользовательская СУБД типа клиент-сервер фирмы Gupta Corporation (Menlo Park, USA). Она предназначена для использования в качестве сервера баз данных в локальных вычислительных сетях на базе персональных компьютеров. SQLBase ориентирована прежде всего на сети масштаба малого и среднего предприятия с количеством одновременно обращающихся к СУБД рабочих станций от 20 до 100, а также на подразделения (филиалы, отделения) крупных организаций. В целом СУБД такого класса называют серверами для рабочих групп (Workgroup Server).
SQLBase поддерживает базы данных размером до 4 Гбайт в виде консолидированного файла и до 512 Гбайт в разделенном режиме (partitioned database mode). Сервер SQLBase может работать с базами данных, расположенными на одном компьютере, но позволяет располагать и распределять их на разных физических и логических дисках и других носителях (оптические накопители и CD- ROM).
СУБД фирмы Gupta отличается простотой установки и настройки, малым потреблением системных ресурсов, что позволяет устанавливать и эксплуатировать SQLBase на недорогих компьютерах. Так SQLBase for NetWare может работать под управлением NetWare 3.12 на машине с 8 Мбайт оперативной памяти и при этом эффективно обслуживать 10-15 пользователей.
Режим работы SQLBase, параметры размещения его баз данных, а также описание сетевых протоколов сервера содержатся в конфигурационном файле SQL.INI, который имеет структуру стандартного INI-файла системы Windows. SQL.INI является универсальным файлом конфигурации для всех продуктов Gupta и включает в себя секции описывающие поведение различных серверов и клиентов Gupta.

Платформы

SQLBase разрабатывалась специально для применения на персональных компьютерах с процессорами фирмы Intel. В настоящее время эта СУБД выпускается для следующих сетевых операционных систем: Novell NetWare 3.x и 4.x, Windows 95 и NT, OS/2 2.x. Существует также локальная версия для платформы Windows 3.x. При работе в Windows 95, Windows NT и OS/2 SQLBase поддерживает как традиционную технологию клиент-сервер, так и новую технологию клиент-клиент, позволяющую создавать сложные системы серверов баз данных с распределением данных и задач между компьютерами даже в одноранговой сети. В ОС NetWare SQLBase является классическим сервером баз данных, таким же как Oracle или Sybase.

Протоколы

SQLBase осуществляет поддержку практически всех распространенных сетевых протоколов, включая IPX/SPX для NetWare, NetBIOS, NetBEUI, Named Pipes и TCP/IP (Windows Sockets) для Windows NT и OS/2. Для Windows 95 и Windows NT фирма Gupta разработала новый 32- разрядный протокол обмена данными Anonimous Pipes для эффективной работы с локальным сервером SQLBase в этих средах. Кроме этого, SQLBase поддерживает технологию SNMP, что позволяет эффективно управлять сервером баз данных в сложных распределенных сетях под управлением Novell NetWare. Новая версия SQLBase, которая находится сейчас в стадии Бета- тестирования и будет выпущена в продажу в конце января, будет включать поддержку протокола TCP/IP для NetWare.
SQLBase поддерживает стандартный интерфейс связи с базами данных в среде Windows ODBC. Драйвер ODBC входит в комплект каждого сервера SQLBase.

Объекты

SQLBase содержит набор стандартных объектов и структур, общих для большинства реляционных СУБД. Данные SQLBase хранит в виде таблиц, состоящих из колонок и строк. SQLBase поддерживает виртуальные таблицы (views) и рассматривает их как отдельные объекты базы данных. Для поддержания уникальности данных в колонках таблиц, а также для ускорения доступа к данным используются индексы. База данных SQLBase включает также пользователей и их привилегии. В качестве расширения стандартного набора объектов SQLBase содержит триггеры, хранимые команды и хранимые процедуры. В начальной редакции SQLBase 6 эта СУБД включала также и события или таймеры базы данных, однако этот тип объектов не вошел в окончательную версию продукта. Поддержка событий в SQLBase намечена на середину года.
Типы данных, поддерживаемые SQLBase, приведены на рис. 1. Следует отметить, что тип данных CHAR в SQLBase не отличается от VARCHAR (в обоих случаях СУБД не хранит пустые места в колонках) и поддерживается, в основном, для совместимости с DB2.
SQLBase поддерживает стандарт SQL-89 с многочисленными расширениями.
Кроме поддержки выполнения стандартных SQL запросов SQLBase содержит большое количество встроенных функций (более 60). Они включают агрегатные функции, функции преобразования форматов данных, выбора и логического ветвления, обработки строковых, числовых и временных данных, а также различные математические и финансовые функции.
Рис. 1. Типы данных SQLBase Тип Данных Описание Размерность Примечание
CHAR (или VARCHAR) Строковый тип до 254 байт Имеет вид CHAR(3). Пустые места не хранятся
LONG VARCHAR Строковый тип неограниченный размер Для этого типа не поддерживаются предложения WHERE, ORDER BY и многие функции СУБД.
NUMBER Числовой тип до 15 цифр Суперсет всех числовых типов SQLBase
DECIMAL Числовой тип с фиксированной точкой до 15 цифр Имеет вид DECIMAL (размер, десятичных знаков). SQLBase не поддерживает тип CURRENCY. Используйте для этого DECIMAL(15,2)
INTEGER Числовой целый тип до 10 цифр
SMALLINT Числовой целый тип до 5 цифр
DOUBLE PRECISION Числовой тип до 15 цифр Для чисел с плавающей точкой
FLOAT Числовой тип до 15 цифр Отличается от DOUBLE PRECISION указанием количества значащих цифр
DATETIME (или TIMESTAMP) Дата/Время Точность временной компоненты - до 1 мксек
DATE Дата
TIME Время Точность до 1 сек
В SQLBase существуют пользователи трех уровней: CONNECT, RESOURCE и DBA. Особенности уровня доступа к данным и другие привилегии каждой категории пользователей приведены на рис. 2.
Рис. 2. Типы пользователей SQLBase Тип Пользователя Описание
SYSADM Создает пользователей и устанавливает их пароли и права доступа
DBA Выдает, изменяет и отнимает права доступа к объекту БД для любого пользователя
RESOURCE Создает и удаляет объекты БД. Выдает, изменяет и отнимает права доступа к этим объектам для других пользователей
CONNECT Имеет доступ к объектам, но не может их создавать
Всю информацию о базе данных сервер хранит в системном каталоге базы. При этом поддерживаются два системных каталога: один полный, который содержит всю информацию об объектах и состоянии базы данных SQLBase, и универсальный, который совместим по структуре с системными каталогами большинства других СУБД. Поддержка универсального системного каталога позволяет управлять базами данных SQLBase из программ и средств администрирования СУБД других фирм. Краткое описание таблиц системного каталога приведено на рис. 3.
Рис. 3. Таблицы системного каталога SQLBase Таблица Описание
SYSCOLAUTH Права обновления колонок
SYSCOLUMNS Колонки базы данных
SYSCOMMANDS Хранимые команды и хранимые процедуры
SYSEVENTS Системные события таймера (в текущей версии не используются)
SYSEXECUTEAUTH Права выполнения хранимых процедур
SYSFKCONSTRAINTS Внешние ключи (foreign keys)
SYSINDEXES Индексы
SYSKEYS Колонки индексов
SYSPARTTRANS Незавершенные распределенные транзакции
SYSPKCONSTRAINTS Первичные ключи (primary keys)
SYSROWIDLISTS Сохраненные множества результатов (result sets)
SYSSYNONYMS Синонимы объектов базы данных
SYSTABAUTH Права доступа к таблицам
SYSTABCONSTRAINTS Ограничения ссылочной целостности
SYSTABLES Таблицы и views
SYSTRGCOLS Колонки триггеров
SYSTRIGGERS Триггеры
SYSUSERAUTH Пользователи БД и их пароли
SYSVIEWS Описание views в виде SQL запросов

Курсоры

Контакт клиента с сервером SQLBase является постоянным. Сеанс контакта с базой данных инициируется клиентом с помощью команды CONNECT и прекращается командой DISCONNECT. Во время сеанса клиент выпускает одну или несколько транзакций к базе данных. SQLBase относится СУБД транзакционного типа, основанного на концепции курсоров (cursor) в отличие от технологии процессов базы данных (db-process).
Курсор в SQLBase имеет много самых разных значений. Прежде всего, курсор - это идентификатор контакта пользователя с базой данных (или административного контакта с сервером SQLBase). Далее, с курсором связаны скомпилированные запросы на языке SQL, извлеченные из базы данных и подготовленные к выполнению хранимые команды и процедуры, а также полученные в результате выполнения запросов, команд и процедур множества результатов (result sets). Наконец, курсор также определяет положение (строку) в текущем result set'е, обрабатываемым клиентским приложением.

В SQLBase, так же как и в Oracle, не существует специальной команды, определяющей начало транзакции подобно BEGIN WORK или BEGIN TRANSACTION. Транзакция автоматически начинается с первого запроса к базе данных, последовавшего за окончанием предыдущей транзакции. Для указания окончания транзакции служат команды, приведенные на рис. 4.
Рис. 4. Команды окончания транзакции SQLBase Команда Описание
ROLLBACK Неудачное окончание транзакции. Изменения не записываются в базу данных. Блокировки, связанные с данной транзакцией сбрасываются.
COMMIT Удачное окончание транзакции. Изменения записываются в базу данных. Блокировки, связанные с данной транзакцией сбрасываются.
SAVEPOINT Удачное окончание части длительной транзакции. Частичные изменения записываются в базу данных. Эта команда используется во время длительных транзакций (например, ввода большого количества данных) для фиксации прохождения некоторого этапа. Если при дальнейшей обработке транзакции произойдет ее откат (ROLLBACK), все изменения, сделанные до последней команды SAVEPOINT, останутся в базе данных.
SQLBase поддерживает именованные и распределенные транзакции. Именованные транзакции позволяют объединять несколько курсоров от одного клиента в процесс, изолированный от других процессов в той же базе данных. Это позволяет организовать работу клиента с базой одновременно в нескольких режимах. Например, клиент может выделить в своем приложении 2 именованные транзакции "Проводка" и "Баланс". При этом ошибка выполнения запроса по одному из курсоров транзакции "Проводка" приведет к откату только этой транзакции и не окажет никакого действия на курсоры транзакции "Баланс".
Описание распределенных курсоров приведено ниже в разделе "Распределенные базы данных".
Существует также разделение курсоров по объекту контакта.
Курсоры базы данных используются для выполнения запросов к базе данных (предложений SELECT, INSERT, UPDATE, DELETE), а также выполнения команд конфигурирования базы данных (CREATE, ALTER, DROP, GRANT, REVOKE и т.д.).
Курсоры сервера применяются для операций, непосредственно связанных с функционированием сервера SQLBase. К ним относятся процедуры архивирования и восстановления (BACKUP и RESTORE), команды создания, активизации и удаления баз данных (CREATE DATABASE, DROP DATABASE, INSTALL DATABASE, DEINSTALL DATABASE), а также команды, изменяющие параметры и режимы работы SQLBase в целом.
Для создания курсора каждого типа (подключения к серверу и базе данных соответственно) требуется указать имя пользователя и пароль, который может быть разным для базы данных и сервера SQLBase.

Программный интерфейс

Основным программным интерфейсом SQLBase является SQL API - библиотека функций на языке C, реализующая все возможности управления СУБД. Помимо базового интерфейса SQL API существует большое количество программ и библиотек, реализующих собственные интерфейсы к SQLBase. Среди них нужно прежде всего отметить SQLBase++ (библиотеку классов в стандарте MFC), Borland Delphi и целый ряд языков и систем 4 поколения, включающих SQLWindows (Gupta), PowerBuilder (Powersoft), Crystal Reports и Crystal Info.

Поддержка многопользовательского режима

"Оптимистическая" и "Пессимистическая" модели блокировок Блокировки Уровни изоляции Особенности сервера

Обработка SQL запросов

Структура сервера Индексы

Оптимизация и выбор плана выполнения запроса

Оптимизация выполнения SQL запросов и модули поддержки подобной оптимизации (оптимизаторы или optimizers) играют крайне важную роль в реляционных СУБД. SQL запросы определяют какие данные необходимо передать пользователю, но не говорят РСУБД о том, как этот запрос обработать эффективно. Обычно существует большое количество возможностей выполнения запроса. Оптимизаторы серверов баз данных отвечают за выбор наилучшей стратегии выполнения. Поэтому скорость выполнения запросов в ведущей степени зависит от качества оптимизатора данной РСУБД.
Результатом работы оптимизатора SQLBase является план выполнения запроса (execution plan). Говоря упрощенно, execution plan - это последовательность шагов, которая указывает программе серверу SQLBase, как выполнить запрос. В плане каждый шаг может быть однотабличным (single table) или двухтабличным (two table). Все шаги производят результирующие таблицы (result tables). Результирующая таблица не обязательно должна иметь материальное воплощение в виде физического объекта. Для любого шага плана результирующая таблица может быть пользовательской (user-defined), временной (temporary) или концептуальной (conceptual).
Однотабличный шаг плана
Однотабличный шаг плана выполнения запроса определяет исходную таблицу, метод доступа к данным, используемый для извлечения строк таблицы, и имя результирующей таблицы (чаще всего, концептуальной). В настоящее время SQLBase поддерживает следующие методы доступа к данным:
Последовательное сканирование (Sequential Scan) - Это наиболее простой из всех методов доступа. В этом считывается методе каждая страница данных, принадлежащая исходной таблице. (Следует отметить, что все страницы базы данных для данной таблицы связаны между собой, поэтому не требуется сканирование всего файла базы данных). Доступ по индексу (Index Access) - Существуют два способа использования индекса. При первом, значение индекса известно, и индекс может быть использован для позиционирования на индексной странице БД и последующего извлечения данных непосредственно из индексной страницы. При втором способе индексные страницы сканируются в возрастающем или убывающем порядке для поиска положения индекса. Если запрос включает колонки таблицы, не входящие в индекс, потребуются дополнительные операции для считывания информации из страниц данных таблицы. Хэшированный доступ (Hash Access) - В этом методе ключевое значение используется для прямого извлечения информации из страницы данных, которая содержит строки, удовлетворяющие значению ключа. Метод преобразования ключа в адрес страницы, на которой он находится, носит название "хэширование". Хэшированный доступ может быть использован только в том случае, если для ключа создан хэшированный индекс и предикатом является равенство "=". Двухтабличный шаг плана
Двухтабличный шаг плана выполнения запроса определяет все исходные таблицы, метод доступа к данным, используемый для извлечения строк из этих таблиц, метод объединения строк данных и имя результирующей таблицы. Одна из исходных таблиц называется внешней, а другая - внутренней. SQLBase поддерживает следующие методы объединения данных:
Вложенный цикл (Nested loop) и его вариации Слияние индексов (Index merge) Гибридное хэшированное объединение (Hybrid hashed join) Пример схемы выполнения
В качестве примера рассмотрим базу данных типа поставщик-товар-поставка. База содержит 3 таблицы: S для поставщика, P для товара и SP - для поставок. Таблица S имеет уникальный первичный ключ S#. Таблица P имеет уникальный первичный ключ P#. Таблица SP имеет уникальный первичный ключ на колонках S#P#. Дополнительно, эта таблица содержит индексы для колонок City, Color и Weight. Схема базы приведена на рис.5.
Рис. 5. Схема демонстрационной базы данных Таблицы Колонки Индексы
S S#, SName, Status, City SXS#(S#), SXCITY(City)
P P#, PName, Color, Weight, City PXP#(P#), PXCOLOR(Color), PXWEIGHT(Weight)
SP S#, P#, QTY SPXS#P#(S#, P#)
Запрос 1: Select * from P where color = 'Red' and weight =19;
План выполнения Номер шага Внешняя таблица Внешний индекс Внутренняя таблица Внутренний индекс Результирующая таблица Метод объединения
1 PPXWEIGHT RESULT
Для выполнения данного запроса у оптимизатора есть три варианта: 1) последовательное сканирование, 2) индексный доступ с помощью индекса PXCOLOR и 3) индексный доступ с помощью индекса PXWEIGHT. В данном случае, оптимизатор выбрал индекс PXWEIGHT. Поэтому программа сервера будет использовать ключ weight (значение 19) для извлечения всех строк, которые удовлетворяют условию "weight =19" и отфильтровывать те из них которые не удовлетворяют второму условию (color = 'Red'). Оптимизатор предпочел индекс PXWEIGHT индексу PXCOLOR, поскольку он посчитал, что в таблице существует меньше строк, удовлетворяющих критерию выбора по ключу weight. Иными словами, индекс PXCOLOR является более "плохим" и потребует больше операций ввода/вывода и команд процессора для выполнения запроса. Результат запроса представляется в виде концептуальной таблицы RESULT.
Стоимостная модель оптимизации
Оптимизатор SQLBase использует так называемый стоимостной метод (cost-based technique) для определения наилучшего плана выполнения запроса, в отличие от методов, основанных на анализе синтаксиса (syntax-based) запроса или жестко установленных правилах выбора (rule-based). Оптимизатор оценивает стоимость или затраты на работу процессора и операции ввода/вывода для различных методов доступа к данным и операций над ними. Стоимость процессора оценивается в миллисекундах. Стоимость ввода/вывода, которая представляет собой количество операций ввода/вывода в секунду, также преобразуется в миллисекунды. Такой подход позволяет проводить сравнение нагрузки на процессор и подсистему ввода/вывода. Производительность методов доступа к данным и операций объединения зависит от размера и распределения данных. Информация о данных представлена в виде статистики таблиц и индексов. Запрос разбивается на ряд небольших индивидуальных шагов. Наименьший шаг - это доступ к данным одной таблицы, который выбирается из всех возможным методов доступа. При этом исследуются все возможности выбора данных из таблицы, а также методы объединения между любыми двумя таблицами или таблицей и промежуточным результатом. Оптимизатор выбирает наиболее простой и эффективный план выполнения.
В реальной обстановке оптимизатор SQLBase выбирает план выполнения запроса на основе вычисления затрат на выполнение целого ряда операций, которые помимо простого использования процессора и подсистемы ввода/вывода включают следующие факторы:
Операции сравнения
Перемещение данных Повторный доступ к той же таблице Методы объединения данных Использование буферов ввода/вывода Распределение предикатов Учет всех вышеприведенных факторов делает реальные формулы оптимизатора весьма сложными и не позволяет привести их в рамках данной статьи.

Управление оптимизатором SQLBase

Оптимизатор SQLBase выбирает план выполнения запроса на основе информации, которая хранится в самой базе данных. При этом он, естественно, не обращается к данным непосредственно (например, не производит анализ распределения данных по колонкам заданной таблицы), поскольку в этом случае выбор плана выполнения занимал бы гораздо больше времени, чем собственно выполнение запроса. Вместо этого оптимизатор использует статистику, хранящуюся в таблицах базы данных. Эта статистика создается сервером SQLBase сразу после создания объектов базы данных или в результате выполнения команды UPDATE STATISTICS.
В новой версии SQLBase 6 пользователю предоставлена возможность изменять эту статистику и, таким образом, воздействовать на оптимизатор и реальное выполнение SQL запросов.
Изменение статистики возможно с помощью новой команды UPDATE STATISTICS. Полное описание синтаксиса этой команды приведено в документации по SQLBase. Вкратце же синтаксис команды UPDATE STATISTICS выглядит следующим образом:
Для модификации табличной статистики
UPDATE STATISTICS ON TABLE имя-таблицы
SET колонка-статистики = ...., ;

Например,
UPDATE STATISTICS ON TABLE ORDER
SET ROWCOUNT = 10000, PAGECOUNT=100;
(количество строк в таблице равно 10000, а количество страниц - 100)
Для модификации индексной статистики
UPDATE STATISTICS ON INDEX имя-индекса
SET колонка-статистики = ...., ;
Например,
UPDATE STATISTICS ON INDEX ORDER_IX1
SET HEIGHT = 2, CLUSTERCOUNT = 10000, LEAFCOUNT = 10000/150, DISTINCTCOUNT(order_num) = 5000 ;
Управление статистикой базы данных
Управление статистикой базы данных в SQLBase служит следующим целям:
Предоставить средства изучения поведения приложений в процессе разработки, когда вы не имеете доступа к реальной (продажной) базе данных.
Помочь разработчику и администратору смоделировать реальную базу данных используя малое количество фактических данных.
Следует отметить, что существующий метод воздействия на выполнение SQL запросов с помощью команды UPDATE STATISTICS является очень сложным и весьма нелинейным. В новой версии SQLBase планируется появление специального модуля "Управление планом выполнения", которая даст возможность специалистам и пользователям воздействовать на способы выполнения запросов к базе данных непосредственным образом.

Дополнительные возможности

Хранимые процедуры

Хранимые процедуры (stored procedures) представляют собой приложения, которые хранятся в базе данных. Обычно, в среде клиент-сервер конечные приложения располагаются на клиентской машине и там же выполняются. Любой доступ к базе данных из конечного приложения использует контакт с сервером по компьютерной сети. Когда же приложение располагается внутри базы данных, оно называется хранимой процедурой. Хранимые процедуры выполняются непосредственно на компьютере сервера базы данных.
SQLBase использует хранимые процедуры, написанные на языке инструмента разработки конечных приложений SQLWindows Application Language (SAL).
Использование хранимых процедур преследует следующие цели:
Повышение производительности - Так как прикладная программа перенесена на сервер, она не требует затрат на передачу информации по сети при обращении к базе данных. Кроме того, сервер обычно бывает более мощным компьютером, чем клиентские машины. Следовательно, те же операции выполняются на сервере быстрее. Простота использования - Обычно, технология клиент-сервер подразумевает большое количество клиентов, подключенным к одному серверу. Использование хранимых процедур позволяет хранить приложение на одном компьютере, а не на каждом клиенте в отдельности. Если приложение в базе данных модифицируется, оно становится сразу доступно всем клиентам в наиболее обновленном виде. Усиление защиты данных - Пользователь может получить возможность доступа к данным только через использование заранее запрограммированных процедур и не иметь прямой возможности изменять данные. Следовательно, набор операций, которые могут быть осуществлены пользователем, легко контролируются с помощью управления доступом к небольшому числу хранимых процедур. Ускорение процесса освоения - Хранимые процедуры SQLBase пишутся на языке SAL. Этот язык хорошо знаком разработчикам приложений на продуктах Gupta. Кроме того, разработчики могут создавать и отлаживать прототипы хранимых процедур в среде SQLWindows и затем переносить их в базу данных с помощью программы SQLConsole. В SQLBase имеется возможность хранения двух типов процедур.
Хранимые команды - это SQL запрос, который хранится на сервере в скомпилированном виде (то есть вместе со своим планом выполнения). Выполнение хранимых команд производиться гораздо быстрее, чем обычных SQL запросов, поскольку целый ряд шагов, необходимых для выполнения запроса, производится в момент записи хранимой команды в базу данных. В то же время хранимые команды имеют ограниченную функциональность в рамках синтаксиса языка SQL. Хранимые процедуры - это приложения, объединяющие SQL запросы и процедурную логику (операторы присваивания, логического ветвления и т.д.). Хранимые процедуры позволяют хранить на сервере сложные приложения, выполняющие большой объем работы без передачи данных по сети и взаимодействия с клиентом. Создание хранимых процедур
Хранимые процедуры и хранимые команды SQLBase создаются с помощью команды STORE языка SQL или при помощи функции sqlsto() SQL/API.
Тело хранимой процедуры состоит из следующих элементов или разделов:
Имя процедуры. Является идентификатором процедуры и используется при извлечении (retrieve) процедуры из базы данных перед ее выполнением. Переменные. SQLBase поддерживает 5 типов данных в качестве переменных хранимых процедур. Все они идентичны типам данных SQLWindows с теми же именами. а Number - Числовой тип данных а Boolean - Логический тип данных с допустимыми значениями TRUE/FALSE а String - Строковый тип данных а Date/Time - Этот тип может быть использован для данных типа Дата, Время или Дата/Время а Sql Handle - используется в качестве курсоров для доступа к базе данных Секция описания переменных хранимой процедуры состоит из двух блоков: блока параметров (Parameters) и блока локальных переменных (Local Variables).
Блок параметров содержит переменные, которые передают информацию в хранимую процедуру или возвращают информацию из нее в вызывающее процедуру приложение. Блок параметров эквивалентен списку bind-переменных в SQL запросе. Хранимые процедуры SQLBase могут содержать параметры двух типов: для ввода и для вывода. Параметры вывода обозначаются ключевым словом RECEIVE перед описанием типа переменной. Эти параметры эквивалентны списку into-переменных в запросах SELECT.
Блок локальных переменных содержит описания переменных, которые используются только внутри данной хранимой процедуры и не могут быть определены извне.
Процедурная логика. Этот раздел начинается с ключевого слова ACTIONS. Он содержит всю логику и выполняемые инструкции процедуры. Весь код этого раздела пишется на языке SAL. Хранимые процедуры SQLBase поддерживают некоторое подмножество полного языка SAL. Например, в текущей версии SQLBase реализована поддержка только тех функций SAL, которые начинаются с префикса Sql ( SqlPrepare()). Поддержка остальных функций (начинающихся с префикса Sal) будет реализована в последующих версиях продукта. Раздел процедурной логики может также состоять из следующих необязательных секций:
ON PROCEDURE STARTUP - Эта секция используется для процедур инициализации, таких как установление контакта с базой данных, компиляция запросов и т.д. Она выполняется только во время первого выполнения хранимой процедуры.
ON PROCEDURE EXECUTE - Данная секция выполняется всякий раз, когда хранимая процедура выполняется командой EXECUTE. Во время первого выполнения эта секция выполняется после секции ON PROCEDURE STARTUP. Во время всех последующих команд EXECUTE выполняется только эта секция.
ON PROCEDURE FETCH - Эта секция выполняется всякий раз, когда процедуре передается команда FETCH в случае использования процедуры в качестве result set (не забудьте, что хранимые процедуры ведут себя подобно запросам SELECT). При этом строки из множества результатов возвращаются из процедуры посредством переменных типа RECEIVE.
ON PROCEDURE CLOSE - Данная секция выполняется в тот момент, когда для курсора, связанного с хранимой процедурой, происходит компиляция нового запроса или этот курсор отсоединяется от базы данных. Она используется для выполнения операций завершения, таких как выпуск транзакции COMMIT, отсоединение от базы данных и т.д.
Если процедура не содержит описанных выше секций, по умолчанию предполагается, что она состоит из одной секции ON PROCEDURE EXECUTE.
Хранимая процедура может быть определена как статическая или динамическая с помощью ключевых слов STATIC/DYNAMIC после имени процедуры. По умолчанию, хранимые процедуры SQLBase являются динамическими. Если процедура определяется как статическая, все SQL запросы в ней должны быть предварительно скомпилированы и записаны в базу данных в виде хранимых команд. Поэтому в статических процедурах все SQL запросы должны быть представлены в виде строковых констант и не могут содержать переменных. Кроме того, в статических процедурах не допускается использование команд типа CREATE, ALTER, DROP. Статические процедуры обладают гораздо более высокой производительностью по сравнению с динамическими, поскольку не требуют компиляции своих запросов во время выполнения.
Доступ пользователей к хранимым процедурам
Для того, чтобы выполнить хранимую процедуру, пользователь должен обладать определенными привилегиями. Он может иметь право выполнить процедуру либо с привилегиями автора (execute with creator privilege), либо со своими привилегиями (execute with grantee privilege). Если пользователь выполняет процедуру с правами автора, он получает все его права по отношению к объектам базы данных на время выполнения процедуры. При втором способе выполнения изменения прав пользователя не происходит. Использование возможности расширения (изменения) прав пользователя на время выполнения хранимой процедуры позволяет повысить защищенность данных и канализировать доступ к ним через отработанные и проверенные процедуры.
Получение кодов ошибок из хранимых процедур
Процедура указывает на нормальное завершение возвращая нулевое значение в вызвавшее ее приложение.
Если процедура возвращает ненулевое значение, оно рассматривается как ошибка. Такое возвращаемое значение ищется в файле ERROR.SQL, для того, чтобы выдать пользователю соответствующее сообщение. Пользователь может поместить в ERROR.SQL свои собственные коды и описания ошибок и использовать их для возвращения информации из хранимых процедур.
Пример хранимой процедуры
Ниже приведен пример хранимой процедуры SQLBase, иллюстрирующей некоторые моменты, описанные в данной статье. Эта процедура обновляет баланс по счету AccountNum в соответствии с выплаченной суммой nAmount и возвращает новое значение баланса в переменной nNewBalance. Если при этой операции происходит овердрафт, процедура устанавливает флаг bOverDrawn.
(Примечание: при написании хранимых процедур, также как и в коде на языке SQL, индентация различных блоков кода имеет критическое значение. В программу SQLConsole входит редактор хранимых процедур, который поддерживает нужные уровни индентации.)
Procedure Withdraw Parameters Number: nAccount Number: nAmount Receive Number: nNewBalance Receive Boolean: nOverDrawn Local Variables Sql Handle: hSelect Sql Handle: hUpdate String: sSelect String: sUpdate Number: nStatus Actions On Procedure Startup Set sSelect = 'Select Balance from Checking where AccountNum=:nAccount' || 'into :nNewBalance' Set sUpdate = 'Update Checking Set Balance = Balance - :nAmount' || 'where AccountNum = :nAccount' Call SqlConnect( hSelect ) Call SqlPrepare( hSelect, sSelect ) Call SqlConnect( hUpdate ) Call SqlPrepare( hUpdate, sUpdate ) On Procedure Execute Call SqlExecute( hSelect ) Call SqlFetchNext (hSelect, nStatus ) Set nNewBalance = nNewBalance - nAmount If ( nNewBalance < 0 ) Set bOverDrawn = TRUE Else Set bOverDrawn = FALSE Call SqlExecute( hSelect ) On Procedure Close Call SqlDisconnect( hSelect ) Call SqlDisconnect( hUpdate )

Триггеры

Триггеры - это определяемые пользователем действия, которые выполняются, когда над таблице, к которой прикреплен триггер, выполняются операции INSERT, UPDATE или DELETE. В SQLBase действия триггера являются хранимыми процедурами. Иными словами, пользователь создает хранимые процедуры, которые описывают действия, совершаемые триггерами.
В SQLBase триггеры используются для решения трех основных задач:
Усиление ссылочной целостности - Триггеры могут быть использованы для реализации ограничений ссылочной целостности, выходящие за пределы стандартных ограничений SQLBase. Например, пользователь может захотеть реализовать правило. каскадного изменения данных (update cascade rule). Он может это сделать, создав триггер, который будет обновлять дочернюю таблицу (таблицы) при каждом изменении колонки в родительской таблице. Проверка данных - Триггеры могут выполнять разнообразную проверку данных. Значения колонок могут передаваться в триггерные процедуры в качестве параметров, где над ними могут производиться самые разнообразные операции. В текущей версии SQLBase реализован механизм, который позволяет производить ввод данных в таблицы непосредственно из триггера, без передачи информации извне. Например, пользователь может создать триггер, который будет получать из приложения данные для ввода в строку таблицы, создавать уникальный ключ для этой строки внутри своей процедуры и передавать в базу данных полную строку с ключом. Помимо генерации ключей, триггеры SQLBase могут выполнять и другие подобные операции. Регистрация изменения данных - Создатель таблицы или администратор базы данных может пожелать иметь информацию о времени каждого изменения данных в таблице, а также о том, какой пользователь эти изменения производил. Для этого он создает триггер, в который поступает системное время операции UPDATE и имя пользователя. Процедура триггера затем вводит эту информацию в специальную таблицу регистрации изменений. Использование триггеров подобного типа позволяет организовать системы регистрации изменений не зависящие от действий пользователя и поэтому наиболее надежные при попытках выполнения несанкционированных операций. Поскольку триггер запускается автоматически при изменении содержимого таблицы, любой пользователь, обладающий привилегиями по отношению к этой таблице, может запустить триггер. Следует отметить, что триггер всегда запускается с привилегиями автора, а не пользователя, т.е. на время выполнения триггера пользователь получает привилегии автора процедуры, вызываемой триггером.
Триггер может быть определен для выполнения либо перед операцией insert/update/delete (before триггер), либо после нее (after триггер). Типичный пример использования before триггеров - проверка данных. After триггеры полезны в тех случаях, когда хранимая процедура триггера содержит код, анализирующий содержимое таблицы, на которой определен триггер, и этот код должен включать результаты последней операции insert/update/delete.
Операции insert/update/delete, которые содержат предложения WHERE или суб-запросы (sub- selects), модифицируют более одной строки таблицы. Триггеры SQLBase могут быть сконфигурированы таким образом, чтобы запускаться только один раз за всю операцию или каждый раз при изменении отдельной строки.
Update триггеры могут быть определены таким образом, чтобы запускаться только при изменении отдельных колонок таблицы (селективные update триггеры) или реагировать на любое изменение данных в таблице.
При передаче данных в процедуры триггеров можно использовать следующие типы данных в качестве параметров процедур:
Значения колонок таблицы - Поскольку триггер определяется на конкретной таблице базы данных, он "знает" о ее строении: количестве, именах и типах колонок и т.д. Поэтому значения колонок таблицы могут передаваться в процедуру непосредственно по своим именам. Константы Псевдоконстанты - В процедуру можно передавать некоторые ключевые слова SQLBase, такие как USER, SYSTIME и другие. Если в процессе выполнения операции UPDATE содержимое колонки изменяется, имеется возможность передать в процедуру триггера как старое, так и новое значение колонки. Для этого служит предложение REFERENCING в определении триггера. Если предложение REFERENCING не используется, по умолчанию значение колонки является старым для before update триггеров и новым для after update триггеров. Поскольку для insert триггеров старых значений не существует, значение колонки по умолчанию является новым. Аналогично, значение колонки для delete триггера является старым.
Ограничения триггеров
При использовании триггеров существует целый ряд ограничений: Все триггеры должны иметь уникальные имена. Нельзя иметь два идентичных триггера. Другими словами, не может быть двух before insert триггеров на одной таблице. Если update триггер определен на конкретной колонке или группе колонок, на данной таблице нельзя определить update триггер на всю таблицу. На таблице можно определить не более двух insert, двух delete и четырех update триггеров одновременно. Допускается не более восьми уровней рекурсии триггеров. Рекурсия триггеров возникает в тех случаях, когда операция insert/update/delete внутри процедуры триггера запускает другой триггер. Предложение REFERENCING допускается только для update триггеров. Кроме того, это предложение возможно только для триггеров, запускающихся для каждой изменяемой строки отдельно, поскольку в противном случае значения колонок становятся неопределенными. Хранимая процедура триггера должна быть статической. Пример триггера
Ниже приведен пример триггера, который реагирует на обновление колонки в таблице. Предположим, мы имеем таблицу T1, содержащую целочисленную колонку C1 и таблицу T2 с колонками (OldC1 int, NewC1 int, Updater char(10)). В триггер передаются старое и новое значение колонки C1 и имя пользователя. Триггер затем вводит эту информацию в таблицу T2. (Отметим возможность определения хранимой процедуры триггера непосредственно в теле триггера с помощью оператора INLINE.)
create trigger tg1 before update of c1 on t1 referencing old as o new as n (execute inline (o.c1, n.c1, user) procedure p1 static parameters number: old number: new string: updater actions call sqlimmediate( 'insert into t2 values (:old, :new, :updater)' ) for each row;

Внешние функции хранимых процедур

Хранимые процедуры позволяют объединить большое количество операций над базой данных непосредственно с базой данных. Это обеспечивает возможности расширения функциональности наряду с большой гибкостью. Дополнительно, хранимые процедуры имеют следующие преимущества:
Перенос процедурной логики в базу данных для распределенной использования многими приложениями. Улучшение производительности путем объединения большого количества запросов к базе данных в один вызов сервера. Хранимые процедуры также предоставляют мощный процедурный язык с конструкциями, хорошо знакомыми разработчикам.
В случае SQLBase процедурным языком является SAL. Однако, как указывалось выше, язык хранимых процедур SQLBase все еще является подмножеством полного языка SAL, имеющегося в SQLWindows. Кроме того, многие пользователи SQLBase хотели бы иметь возможность создавать собственные процедуры, не будучи привязанными к какому-либо конкретному языку.
Естественно, одним из способов расширения функциональности хранимых процедур SQLBase является расширение используемого подмножества языка SAL. Такой путь, однако, не дает возможности пользователям гибко добавлять компоненты и собственные функции для реализации дополнительной функциональности существующих систем. Поэтому процесс придания хранимым процедурам SQLBase большей "открытости" проводится по двум направлениям:
Создание мощного и расширяемого механизма, позволяющего пользователям самим расширять функциональность хранимых процедур на основе концепции plag & play с применением стандартных компонентов или пользовательских программ. Возможность выбора пользователем любого языка программирования для реализации процедурной логики. Первым шагом на этом пути является поддержка в SQLBase нового типа объектов базы данных, называемого внешней функцией (External Function).
Внешняя функция - это любая пользовательская функция, которая располагается в отдельной библиотеке (Dynamic Link Library или DLL для платформы Windows) и может быть динамически вызвана для выполнения из другой задачи. Функция может быть написана на любом языке, допускающем создание DLL. Единственным ограничением является требование использования в качестве параметров типов переменных, поддерживаемых SQLBase, и следование требованиям программного интерфейса.
После того, как внешняя функция и интерфейс к ней описываются в базе данных, эта функция может быть вызвана из хранимой процедуры точно так же, как вызывается любая другая функция SAL. Вызов внешней функции можно представить в виде следующей диаграммы.
Пользователи могут создавать или приобретать библиотеки полезных функций, которые выполняют специфические задачи, например, производят трансформации данных, чтобы отмасштабировать на другие единицы измерения. Определяемые пользователям функции могут быть как очень простыми, так и очень сложными и выполняться в различных режимах в зависимости от типа задачи, которую они решают.
Применение внешних функций дает пользователям SQLBase следующие преимущества:
Этот механизм помогает пользователям управлять расширением функциональности SQLBase. Вместо использования встроенных функций, которые не всегда могут удовлетворять существующим требованиям, пользователи могут создавать свои собственные наборы функций. Появляется возможность динамического подключения пользовательского кода к SQLBase не дожидаясь, например, новой версии продукта. Кроме этого, для использования и смены внешних функций не нужно перекомпоновывать приложение или останавливать и перезапускать сервер базы данных. Реализуется простая и понятная для использования парадигма. Возможность вызывать внешние функции из процедурного языка является естественным механизмом создания модульных процедур. Наконец, внешние функции не увеличивают ресурсопотребление SQLBase и не сказываются на его производительности для других клиентов, позволяя при этом иметь доступ к практически неограниченному множеству функций. Внешняя функция является новым объектом схемы базы данных SQLBase. Она создается с помощью команды CREATE EXTERNAL FUNCTION. Имя функции, ее физическое положение и интерфейс (параметры и их типы данных, возвращаемые данные и пр.) передаются в этой команде. Данная информация хранится в системном каталоге в специальных таблицах. Ниже приведен пример описания внешней функции.
CREATE EXTERNAL FUNCTION MyFunc PARAMETERS (Number: INT) RETURNS (BOOLEAN: WORD) DESCRIPTION 'Sample External Function Declaration' LIBRARY MYLIB.DLL EXPORT ORDINAL 2 EXECUTE IN SAME THREAD Типы данных для параметров функции и возвращаемого значения состоят из двух частей. Сначала описывается "внутренний формат", соответствующий стандартным типам данных SAL. Могут быть использованы все типы данных SAL, которые поддерживаются хранимыми процедурами (см. выше). "Внешний формат", который следует за внутренним, описывает один из стандартных форматов C, который служит для передачи данных во внешнюю функцию.
Предложение EXECUTE IN описывает как SQLBase будет загружать динамическую библиотеку и в каком контексте с точки зрения сервера базы данных будет выполняться внешняя функция. Это, в свою очередь, определяет тип операций, которые могут осуществляться внутри внешнего кода.
Можно предложить много различных путей использования механизма внешних функций. Ниже приведен ряд примерных сценариев.
Набор пользовательских функций трансформации и трансляции данных, которые могут быть использованы при извлечении строк из результата запроса, а также при вставке и изменении строк. Функция такого типа может принимать значение одной (или нескольких) колонки и возвращать трансформированные данные на основе действующих в организации правил (business rules) для отображения в приложении. Следующая категория функций может быть названа "Предупреждения и уведомления". Их суть состоит в том, что при наступлении определенного состояния базы данных могут запускаться триггеры. Эти триггеры выполняют хранимые процедуры. Может оказаться полезным уведомлять некоторых пользователей или приложения о наступлении определенного состояния базы данных. Одним из примеров такого типа функций может быть функция, направляющая по электронной почте сообщение определенным пользователям о том, что данные в созданных ими таблицах были изменены другими пользователями. С помощью этих же функций можно в принципе реализовать механизм "теплой связи", когда пользователь будет получать уведомления от сервера всякий раз, когда будут изменены данные его result set. Еще одной иллюстрацией возможностей технологии внешних функций может являться пример удаленного доступа для запуска хранимых процедур. Например, приложение может вызвать хранимую процедуру на локальном сервере SQLBase, чтобы получить доступ к некоторым данным. Однако, хранимая процедура может содержать логику, распознающую ситуацию когда требуемые данные на сервере отсутствуют или являются устарелыми. В таком случае использование внешней функции поможет установить контакт к удаленной базе данных и извлечь нужные данные. Эти данные затем могут быть занесены в локальную базу данных и возвращены приложению. Другим классом внешних функций могут быть генераторы отчетов в режиме off-line. При этом вместо запуска приложения отчетов с клиентской машины весь модуль (или набор функций) может быть создан в виде динамической библиотеки, которая вызывается из хранимой процедуры как внешняя функция. Код этой функции может осуществлять контакт с базой данных и извлекать нужные для генерации отчета данные. Основным преимуществом такого подхода является повышение производительности, поскольку весь код будет выполняться на сервере без передачи данных и команд по сети. Многие ведущие производители СУБД включают поддержку вызова внешних функций из серверов баз данных. Некоторые из них поддерживают только вызовы внешних функций с помощью расширений процедурных языков ( в качестве примеров можно привести Microsoft SQLServer для NT и Sybase). Другие допускают вызов функций также из SQL запросов. К таким система относятся Oracle 7 и Rdb. В последующих версиях SQLBase. фирма Gupta планирует реализовать несколько механизмов вызова внешних функций, включая их использование в выражениях SQL запросов (сейчас в этих целях используются встроенные функции SQLBase).

Распределенные базы данных

Репликация

Защита данных и поддержка работы

Возможность аудирования, новое свойство SQLBase 6, позволяет регистрировать информацию о том, что происходит на сервере баз данных. Это дает возможность администраторам и пользователям SQLBase осуществлять следующие дополнительные функции:
Мониторинг активности сервера баз данных - Регистрация разнообразной информации на регулярной основе. Дополнительные возможности защиты данных - Предыдущие версии SQLBase осуществляли защиту данных на уровне имени и пароля пользователя, однако не регистрировали попытки нарушить систему защиты. Аудирование позволяет регистрировать такие случаи как попытки доступа к базе данных с неправильным именем или паролем. Кроме того, есть возможность регистрировать попытки нарушения пользователем его привилегий по отношению к объектам базы данных, например, попытки считать информацию из закрытых для него таблиц. Отладка приложений - Можно использовать аудирование для отладки конечных приложений путем просмотра того, какие действия приложение осуществляет по отношению к базе данных и серверу. Повышение производительности базы данных - Аудирование базы данных позволяет получить информацию обо всех SQL запросах и транзакциях. Это свойство можно использовать непосредственно на рабочем месте пользователя для решения проблем типа "Я нажимаю вот эту кнопку и потом жду 20 минут выполнения запроса". Поскольку аудирование предоставляет временную информацию о выполнении запросов, его можно использовать для анализа причин снижения производительности конечных приложений. Существует два класса аудирования: глобальный аудит и аудирование производительности. В свою очередь, каждый из классов состоит из нескольких категорий описание этих категорий приведено на рис. 6. Класс Категория ОписаниеGlobal Performance
Rejected logons Регистрирует неудавщиеся попытки контакта с базой данных. Используется для идентификации пользователей, которые пытаются получить доступ к закрытым базам данных.
Security violations Регистрирует пользователей, пытающихся получить доступ к данным не имея соответствующих привилегий.
Valid logons/logoffs Регистрирует все удавшиеся события соединения и отсоединения. Используется для регистрации сеансов работы пользователей с системой.
Valid connects/disconnects Регистрирует все команды CONNECT и DISCONNECT.
Database create, drop, install and deinstalls Регистрирует выполнение операций CREATE DATABASE, DROP DATABASE, INSTALL DATABASE и DEINSTALL DATABASE.
Recovery operations Регистрирует все операции ROLLBACK.
Backup and restore operations Регистрирует все операции BACKUP и RESTORE.
Database deadlocks and timeouts Записывает информацию о всех событиях deadlock и timeout. Очень важная категория, которая может быть использована для разрешения проблем блокировок.
Table access information Регистрирует информацию о том, кто реализует доступ к таблицам базы данных.
Table update information Регистрирует информацию о том, кто выполняет операции insert/update/delete по отношению к таблицам базы данных.
Connects and disconnects Регистрирует время выполнения каждой операции connect/disconnect.
SQL command compilation, execution, storage and retrieval Эта категория регистрирует информацию о времени компиляции и выполнения запроса, записи и извлечения хранимой команды или процедуры.
End of transaction Регистрирует длительность каждой транзакции. Может использоваться для выявления долго идущих транзакций, которые могут являться источниками deadlock и timeout.
Информация аудирования записывается в файл аудита. Файл аудита является плоским текстовым файлом. Его содержимое можно просматривать из программы SQLConsole или в любом текстовом редакторе.
Хотя SQLBase позволяет иметь до 32 активных файлов аудита одновременно, следует помнить, что аудирование оказывает влияние на производительность сервера.
Информация, записываемая в файл аудита, зависит от класса аудирования и выбранных категорий. Пользователи также могут определять собственные сообщения для записи в файл аудита.
Процесс аудирования базы данных инициируется на уровне сервера. Это значит, что для запуска процесса аудирования необходимо иметь соединение с сервером. Аудирование можно начать несколькими различными способами. Наиболее удобным является использование программы SQLConsole. Окно Audit Manager этой программы позволяет просто и удобно сконфигурировать аудирование, запустить и остановить его, а также просмотреть любой активный файл аудита из имеющихся на сервере.
Можно также запустить процесс аудирования новой командой на языке SQL START AUDIT. Так как эта команда, подобно всем другим SQL запросам, может быть скомпилирована и выполнена, START AUDIT можно выполнить из приложений SQLWindows с помощью функций SqlPrepare, SqlExecute или SqlPrepareAndExecute.
После запуска процесса аудирования он остается активным до получения специальной команды STOP AUDIT. SQLBase записывает строку в конфигурационный файл сервера, и эта строка остается там все время, в течение которого аудирование является активным. Таким образом, если сервер SQLBase сбрасывается и запускается снова, все активные файлы аудита остаются активными.


  • Главная
  • Новости
  • Новинки
  • Скрипты
  • Форум
  • Ссылки
  • О сайте




  • Emanual.ru – это сайт, посвящённый всем значимым событиям в IT-индустрии: новейшие разработки, уникальные методы и горячие новости! Тонны информации, полезной как для обычных пользователей, так и для самых продвинутых программистов! Интересные обсуждения на актуальные темы и огромная аудитория, которая может быть интересна широкому кругу рекламодателей. У нас вы узнаете всё о компьютерах, базах данных, операционных системах, сетях, инфраструктурах, связях и программированию на популярных языках!
     Copyright © 2001-2024
    Реклама на сайте