3 кнопки, котоpые потpясли DOS.

Unix Dos Linux Windows Os/2 Qnx Beos Gios Hard Etc Link Форум (тестовый режим) Гостевая Юмор Soft Связь
 
 
 

Etc.: Структуризированный язык запросов (SQL)

Содержание

Глава 5. О предложениях определения данных и оптимизации запросов

5.1. Системный каталог

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

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

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

SELRCT	Tab_name,N_col,N_row,Tab_owner,Comments
FROM	SYSTABLES;

и получить результат, показанный на рис. 5.1,а.

Для получения же некоторых данных о столбцах таблицы Блюда можно дать запрос

SELECT	Col_name, Type, Length, Comments
FROM	SYSCOLUMNS
WHERE	Tab_name = 'Блюда';

и получить результат, показанный на рис. 5.1,б.

а)

Tab_nameN_colN_rowTab_ownerComments
...
SYS_TABLES 11 SYSTEM
SYS_COLUMNS 14 SYSTEM
...
Блюда 6 33 KIRILLOWПеречень блюд, известных шеф-повару
Поставки 4 37 GROMOWДанные о поставляемых продуктах
Вид_блюд 2 5 KIRILLOW Перечень видов блюд
Трапезы 2 3 GROMOW Перечень трапез в пансионате
Состав 3 148 KIRILLOW Состав блюд
Продукты 11 17 KIRILLOW Таблица продуктов
...

б)

Col_nameTypeLengthComments
БЛ INTEGER 4 Код блюда
Блюдо TEXT 16 Название блюда
В TEXT 1 Код вида блюда (З, С, ...)
Основа TEXT 6 Основной продукт в блюде
Выход REAL 4 Масса порции готового блюда
Труд INTEGER 4 Стоимость приготовления блюда (коп)

Рис. 5.1. Результаты запросов по системным таблицам

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

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

^^^

5.2. Создание и уничтожение базовых таблиц

Базовые таблицы описываются в SQL с помощью предложения CREATE TABLE (создать таблицу), синтаксис которого имеет небольшие различия в различных СУБД. Однако все они поддерживают следующую минимальную форму:

CREATE TABLE базовая_таблица (столбец тип_данных [NOT NULL]
				[,столбец тип_данных [NOT NULL]] ...);

где тип_данных должен принадлежать к одному из типов данных, поддерживаемых СУБД (например, одному из типов данных, перечисленных в п.1.2).

Так, описание таблицы Блюда может быть записано в виде

CREATE TABLE Блюда
	(	БЛ	SMALLINT NOT NULL,
		Блюда	CHAR (70) NOT NULL,
		В	CHAR  (1),
		Основа	CHAR (10),
		Выход	FLOAT,
		Труд	SMALLINT );

В результате создается пустая базовая таблица Блюда, а в системный каталог помещается строка, описывающая эту таблицу. Отметим, что в профессиональных СУБД имя таблицы дополняется именем пользователя, который издал предложение CREATE TABLE. Если этот пользователь зарегистрирован в системе под именем Kirillov, то в каталоге будет зарегистрирована таблица Kirillov.Блюда и указанный пользователь может обращаться к ней по имени Kirillov.Блюда или по сокращенному имени Блюда, которое использовалось во всех предшествующих примерах и будет использоваться далее.

Конструкция NOT NULL запрещает использование неопределенного значения, т.е. специального значения, которое вводится для представления "неизвестного значения" или "неприменимого значения". Например, строка поставки таблицы Поставки может содержать неопределенное значение в столбце Цена и (или) К_во (извесно, что поставщик поставляет указанный продукт, но на данный момент неизвестна цена этого продукта и (или) объем поставки).

Существующую базовую таблицу можно в любой момент уничтожить с помощью предложения DROP TABLE (уничтожить таблицу):

DROP TABLE базовая_таблица;

по которому удаляется описание таблицы, ее данные, связанные с ней представления и индексы, построенные для столбцов таблицы (см. п. 5.3).

В SQL существует также предложение ALTER TABLE (изменить таблицу), которое позволяет добавить справа к таблице новый столбец, т.е. модифицировать описание табицы. Так как без него "можно жить", а объем книги ограничен, то мы не будем здесь описывать это предложение.

^^^

5.3. О индексах и производительности

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

Значения столбца Строки, в которых встречается такое значение
Кофе 32 33
Крупа 20 21
Молоко 7 8 12 18 22 24 28 31
Мясо 2 6 9 13 14
Овощи 1 3 17 23 15
Рыба 4 5 10 11
Фрукты 25 26 2729 30
Яйца 16 19

Отметим, что такой индекс уже существовал (в несколько иной форме) в базе данных, хотя это обстоятельство никак не повлияло на текст иллюстрационных предложений SELECT, DELETE, INSERT и UPDATE. SQL намеренно не включает в свои конструкции ссылки на индексы. Решение о том, использовать или не использовать какой-либо индекс при обработке некоторого конкретного запроса принимается не пользователем, а оптимизатором СУБД, который учитывает множество факторов - размер таблиц, тип используемых структур хранения данных, статистическое распределение данных в таблицах и индексах и т.д. Однако чтобы оптимизатор смог использовать индексы, их нужно построить (чтобы выиграть в лотерею нужно, по крайней мере, иметь лотерейный билет).

Естественно, что поиск какого-либо значения путем последовательного перебора неупорядоченных данных будет во много раз медленнее, чем поиск с использованием упорядоченного списка (индекса). Ясно также, что таблицу можно упорядочить лишь по данным одного столбца, тогда как поиск часто приходится осуществлять по данным нескольких столбцов. По нескольким столб-цам производится и соединение таблиц. Поэтому, несмотря на то, что индексы увеличивают объем базы данных, их следует использовать как для отдельных столбцов таблицы, так и для комбинации нескольких ее столбцов (например, для комбинации: Фамилия, Имя, Отчество).

Для построения индекса в SQL существует предложение CREATE INDEX (создать индекс), имеющее формат

CREATE [UNIQUE] INDEX имя_индекса ON базовая_таблица
	(столбец [[ASC] | DESC] [, столбец [[ASC] | DESC]] ...);

где UNIQUE (уникальный) указывает, что никаким двум строкам в индексируемой базовой таблице не позволяется принимать одно и то же значение для индексируемого столбца (или комбинации столбцов) в одно и то же время.

Например, индексы для столбцов БЛ и Основа таблицы Блюда создаются с помощью предложений

CREATE UNIQUE INDEX Блюда_БЛ ON Блюда (БЛ);
CREATE INDEX Блюда_Основа ON Блюда (Основа);

а индекс для первичного ключа (столбцы БЛ и ПР) таблицы Состав - с помощью предложения

CREATE UNIQUE INDEX Состав_БЛ_ПР ON Состав (БЛ, ПР);

В больших (более 1000 строк) таблицах поиск индексированных значений выполняется на порядок быстрее, чем поиск неиндексированных, а в очень больших таблицах - на два-три порядка.

Так может быть, если позволяет память, следует построить индексы для всех столбцов всех таблиц базы данных?

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

DROP INDEX имя_индекса;

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

^^^

5.4. Представления

5.4.1. Создание и уничтожение представлений

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

Синтаксис предложения CREATE VIEW имеет вид

CREATE VIEW имя_представления
	[(столбец[,столбец] ...)]
	AS подзапрос
	[WITH CHECK OPTION];

где подзапрос, следующий за AS и являющийся определением данного представления, не исполняется, а просто сохраняется в каталоге;

необязательная фраза "WITH CHECK OPTION" (с проверкой) указывает, что для операций INSERT и UPDATE над этим пред-ставлением должна осуществляться проверка, обеспечивающая удовлетворение WHERE фразы подзапроса;

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

а) хотя бы один из столбцов подзапроса не имеет имени (создается с помощью выражения, SQL-функции или константы);

б) два или более столбцов подзапроса имеют одно и то же имя;

если же список отсутствует, то представление наследует имена столбцов из подзапроса.

Например, создадим представление Мясные_блюда

CREATE VIEW Мясные_блюда
AS SELECT БЛ, Блюдо, В, Выход
FROM	Блюда
WHERE  Основа = 'Мясо';

которое может рассматриваться пользователем как новая таблица в базе данных.

Уничтожение ненужных представлений выполняется с помощью предложения DROP VIEW (уничтожить представление), имеющего следующий формат:

DROP VIEW представление;

^^^

5.4.2. Операции выборки из представлений

Создав представление Мясные_блюда пользователь может считать, что в базе данных реально существует такая таблица и дать, например, запрос на получение из нее всех данных:

SELECT *
FROM	Мясные_блюда;

результат которого имеет вид

БЛБлюдо В Выход
2 Салат мясной З 200
6 Мясо с гарниром З 250
9 Суп харчо С 500
13 Бастурма Г 300
14 Бефстроганов Г 210

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

CREATE VIEW Горячие_мясные_блюда
	AS SELECT	Блюдо, Продукт, Вес
		FROM	Мясные_блюда, Состав, Продукты
		WHERE	Мясные_блюда.БЛ = Состав.БЛ
		AND	Продукты.ПР = Состав.ПР
		AND	В = 'Г';

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

SELECT	Блюдо, Продукт, Вес
FROM	Горячие_мясные_блюда
WHERE	Блюдо IN
	(	SELECT Блюдо
		FROM	Горячие_мясные_блюда
		WHERE  Продукт = 'Помидоры')

и получить:

Блюдо Продукт Вес
Бастурма Говядина 180
Бастурма Помидоры 100
Бастурма Лук 40
Бастурма Зелень 20
Бастурма Масло 5

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

^^^

5.4.3. Обновление представлений

Рассмотренные в гл.4 операции DELETE, INSERT и UPDATE могут оперировать не только базовыми таблицами, но и представлениями. Однако, если из базовых таблиц можно удалять любые строки, обновлять значения любых их столбцов и вводить в такие таблицы новые строки, то этого нельзя сказать о представлениях, не все из которых являются обновляемыми.

Безусловно обновляемыми являются представления, полученные из единственной базовой таблицы простым исключением некоторых ее строк и (или) столбцов, обычно называемые "представление-подмножество строк и столбцов". Таким является представление Мясные_блюда, полученное из базовой таблицы Блюда исключением из нее столбца Труд и строк, не содержащих значение 'Мясо' в столбце Основа. Работая с ним, можно:

  1. вставить (операция INSERT) новую строку, например, строку (34, 'Шашлык', 'Г', 150), фактически вставляя соответствующую строку (34, 'Шашлык', 'Г', 150, NULL) в лежащую в основе базовую таблицу Блюда;

  2. удалить (операция DELETE) существующую строку из представления, например строку (13, 'Бастурма', 'Г', 300), фактически удаляя соответствующую строку (13, 'Бастурма', 'Г', 300, 5) из таблицы Блюда;

  3. обновить (операция UPDATE) какое-либо поле в существующей строке, например увеличить массу порции Бефстроганова с 210 до 250 граммов, фактически осуществляя то же самое изменение в соответствующем поле таблицы Блюда.

Однако если бы представление Мясные_блюда имело вместо столбца Выход столбец Вых_труд, полученный путем суммирования значений столбцов Выход и Труд таблицы Блюда, то указанные выше операции INSERT и UPDATE были бы отвергнуты системой. Действительно, как распределить вводимое значение столбца Вых_труд (153 или 254) между значениями столбцов Выход и Труд базовой таблицы Блюда? Была бы отвергнута и операция удаления масла из состава бастурмы, если бы ее попытались выполнить путем удаления строки ('Бастурма', 'Масло', 5) в представлении Горячие_мясные_блюда. Встает множество вопросов: надо ли удалять из базовой таблицы Блюда строку, содержащую значение 'Бастурма' в столбце Блюдо?; надо ли удалять из базовой таблицы Продукты строку, содержащую значение 'Масло' в столбце Продукт?; надо ли удалять из базовой таблицы Состав все строки, содержащие значение 5 в столбце Вес?. Последний вопрос возник потому, что при конструировании представления Горячие_мяс-ные_блюда в него не была включена информация о связях между лежащими в его основе базовыми таблицами Блюда, Состав и Продукты, и у системы нет прямых путей для поиска той единственной строки таблицы Состав, которая должна быть удалена.

Таким образом, некоторые представления по своей природе обновляемы, в то время как другие таковыми не являются. Здесь следует обратить внимание на слова "по своей природе". Дело заключается не просто в том, что некоторая СУБД не способна поддерживать определенные обновления, в то время как другие СУБД могут это делать. Никакая СУБД не может непротиворечивым образом поддерживать без дополнительной помощи обновление такого представления как Горячие_мясные_блюда. "Без дополнительной помощи" означает здесь "без помощи какого-либо человека - пользователя".

Как было указано выше, к теоретически обновляемым представ-лениям относятся представления-подмножества строк и столбцов. Однако существуют некоторые представления, которые не являются представлениями-подмножествами строк и столбцов, но также теоретически обновляемы. Хотя известно, что такие есть и можно привести их примеры, но невозможно дать их формального определения. Неверным является такое формальное определение некоторых авторов - "нельзя обновлять соединение". Во-первых, в некоторых соединениях с успехом выполняется операция UPDATE, а, во-вторых, как было показано выше, не обновляемы и некоторые представления, не являющиеся соединениями. Кроме того, не все СУБД поддерживают обновление любых теоретически обновляемых представлений. Поэтому пользователь должен сам оценивать возможность использования операций DELETE, INSERT или UPDATE в созданном им представлении.

^^^

5.4.4. Для чего нужны представления

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

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

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

^^^

Далее >>>

 

© Krio, Xbyte, BooM
2004-2012

id-sign