Множественная и навигационная обработка данных СУБД, менеджеры записей

Способы обработки данных СУБД для программиста - множественная и навигационнаяКак уже отмечалось в блогах на этом портале, в отличие от иерархической и сетевой моделей реляционная относится не к графовым, а к теоретико-множественным. Это означает, что все операции происходят не с единичными экземплярами записей и ссылками, а со множествами записей в соответствии с выбранными критериями и ограничениями. В частности, понятие «текущая запись» в реляционной модели отсутствует[1], и программисту надо отходить от традиционной последовательной обработки данных, перестраивая мозги на работу со множествами.

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

-- установить цену для всех товаров с идентификатором 7615
-- в заказе № 123-45
UPDATE order_items
SET price = 10.55
WHERE id_product = 7615 AND
	id_order IN (SELECT id FROM orders WHERE number = '123-
45')

 

И при последовательной обработке:

SELECT orders // текущая область данных - "заказы"
SET ORDER TO id // упорядочиваем по индексу id
SEEK '123-45' // находим первую запись по значению
IF FOUND() THEN // если нашли
	SET @id_order = current.id
	SELECT order_itmes // переходим в область данных "элементы заказов"
	SET ORDER TO id_order
	SEEK @id_order
	BEGIN TRANSACTION
	WHILE current.id_order = @id_order
	DO
		IF current.id_product = 4615 THEN
			current.price = 10.55
		ENDIF
		NEXT
	END
	COMMIT TRANSACTION
ENDIF

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

Основное отличие декларативного языка в том, что программист описывает его в терминах «что делать», а «как делать» — решает исполняющая код система. В противоположность декларативному, императивный язык позволяет программисту определять непосредственно «как делать». У обоих подходов есть свои преимущества и недостатки, проявляющиеся в разных случаях применения технологии. В случае СУБД декларативный язык является несомненным преимуществом, по многим причинам. Приведу некоторые:

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

 
SET @id_client = 4587 // идентификатор клиента
SET @id_prod = 493 // идентификатор товара
SET @orders_count = 0
SELECT orders
SET ORDER TO id_client
SEEK @id_client
IF FOUND()THEN
	WHILE current.id_client = @id_client
	DO
		SET @id_order = current.id
		SELECT order_items // проверяем товар в позициях заказа
		SET ORDER TO id_order
		SEEK @id_order
		IF FOUND() THEN
			WHILE current.id_order = @id_order
			DO
				IF current.id_prod = @id_prod THEN
					@orders_count = @orders_count + 1
					BREAK
				ENDIF
			END
		ENDIF
		SELECT orders // возвращаемся к циклу по заказам
		NEXT
	END
ENDIF
PRINT @orders_count

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

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

А если наоборот? Тогда оптимальная по времени обработка должна идти со стороны позиций заказа.

 

SET @id_client = 4587 // идентификатор клиента
SET @id_prod = 493 // идентификатор товара
SET @orders_count = 0
SELECT order_items
SET ORDER TO id_prod
SEEK @id_prod
IF FOUND() THEN
	WHILE current.id_prod = @id_prod
	DO
		SET @id_order = current.id_order
		SELECT orders // проверяем клиента сделавшего заказ
		SET ORDER TO id
		SEEK @id_order
		IF FOUND() THEN
			IF current.id_client = @id_client THEN
				@orders_count = @orders_count + 1
				BREAK
			ENDIF
		ENDIF
		SELECT order_items // возвращаемся к циклу по позициям заказам
		NEXT
	END
ENDIF
PRINT @orders_count

Декларативный подход решает данную проблему. 

SELECT count(*)
FROM orders o
     INNER JOIN order_items oi ON o.id = oi.id_order
WHERE o.id_client = 4587 AND oi.id_prod = 493

 

Интерпретирующая запрос подсистема СУБД, так называемый оптимизатор, учтёт статистическую информацию о распределении (плотности) значений идентификаторов клиентов и товаров соответственно в колонках id_client и id_prod или их индексах, после чего будет выбран оптимальный вариант выполнения этого запроса.

Разница в размере кода и, особенно, в его универсальности значительна. Но чем приходится платить?

Прежде всего, программисту в общих чертах надо понимать, как работает реляционная СУБД внутри. Если в нашем примере в базе данных отсутствуют индексы по колонкам   orders.id_client, order_items.id_order и order_items.id_prod, то в общем случае планом выполнения будет прямое сканирование таблиц. Но даже если

индексы построены, следует оценить их избирательность, чтобы удалить бесполезные.

А что произойдёт, если во время расчёта другой пользователь добавит или удалит строки? К такого рода вопросам мы обратимся в главе, посвящённой изоляции транзакций.

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

Основное отличие менеджеров записей от полноценных СУБД — отсутствие общей схемы базы данных. Менеджеры записей могут быть даже транзакционными, как Btrieve, но по своей логике они гораздо ближе к системам на основе плоских файлов, чем к СУБД, реализующим одну из перечисленных моделей данных.

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

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

 


[1]Многие реляционные СУБД поддерживают в своих процедурных расширениях так называемые курсоры, позволяющие перемещаться по выбранному множеству записей.

Вас заинтересует / Intresting for you:

Инструментальная диалоговая си...
Инструментальная диалоговая си... 1562 просмотров Ирина Светлова Sun, 24 Mar 2019, 06:01:30
Что такое базы данных? Назначе...
Что такое базы данных? Назначе... 12916 просмотров Ирина Светлова Mon, 28 Oct 2019, 05:41:34
База данных - определение
База данных - определение 47412 просмотров Antoniy Wed, 01 Jul 2020, 07:43:24
База данных как объект правово...
База данных как объект правово... 1571 просмотров Денис Wed, 27 Mar 2019, 03:16:24
Печать
Войдите чтобы комментировать

ildergun аватар
ildergun ответил в теме #9185 5 года 7 мес. назад
Хорошая статья для начинающих программистов. Хорошо пояснили существующую проблематику навигации и обработки данных в СУБД / менеджерах записей.