Задание 2.
Предположим, что студент группы ИВТ-42 Полиграф Шариков во время зимней сессии пересдал экзамен по дисциплине «Операционные системы» на оценку 5 и пересдал экзамен по дисциплине «Базы данных» на 5. Одновременно с проставлением баллов за его успехами следила методист кафедры. Для работы с несколькими транзакциями запустите два командных окна (запросника). В первом вводите команды за преподавателя, проставляющего оценки, а во втором за методиста, просматривающего результаты.
Работа с транзакциями
В рамках транзакции измените значение оценки студента по Операционным системам и проверьте значение в первом и втором окне. Зафиксируйте изменения и вновь проверьте значения. Аналогично внесите новую оценку по Базам данных и проверьте изменения.
Преподаватель |
Методист |
BEGIN; Изменяет оценку Добавляет оценку COMMIT |
Смотрит результат до фиксации изменений преподавателем Смотрит результат после фиксации изменений преподавателем |
Отмена изменений транзакций
Удалите добавленное значение и верните исправленную оценку в прежнее состояние. Повторите аналогичные действия, только по окончании внесения изменений преподавателем откатите их с помощью команды ROLLBACK. Какое значение увидела методист?
Моделирование аномалий при выполнении транзакций
Повторите эксперименты в п. 1.2.1, используя различные уровни изоляции.
Преподаватель |
Методист |
BEGIN ISOLATION LEVEL … Изменяет оценку Добавляет оценку COMMIT |
BEGIN ISOLATION LEVEL … Смотрит результат до фиксации изменений преподавателем Смотрит результат после фиксации изменений преподавателем
|
Внесите в таблицу в какой момент были получены ошибочные значения из-за аномалий.
Уровень изоляции |
До фиксации |
После фиксации |
Read uncommited |
|
|
Read committed |
|
|
Repeatable read |
|
|
Serializable |
|
|
Как вы считаете, какой уровень изоляции необходимо использовать на практике и почему?
Задание 3.
Проанализируйте учебную базу данных и проиндексируйте одно из полей любой таблицы. Объясните свой выбор.
Контрольные вопросы
За счет чего индексы ускоряют выборку данных?
Существуют ли случаи, когда использование индексов замедляет выборку данных?
Какая структура данных хранит в себе индексные записи?
Для чего предназначены транзакции?
В чем отличие между неповторяющимся и фантомным чтением?
1)
CREATE TABLE attendance (
attendance_id SERIAL PRIMARY KEY, -- Уникальный идентификатор записи
generated_code VARCHAR(64), -- Сгенерированный код для посещения
person_id INTEGER, -- Идентификатор студента
enter_time TIMESTAMP, -- Время входа
exit_time TIMESTAMP, -- Время выхода
FOREIGN KEY (person_id) REFERENCES student_ids (student_id) -- Внешний ключ, ссылающийся на таблицу студентов
);
2)
DO
$$
DECLARE
enter_time TIMESTAMP(0); -- Время входа
exit_time TIMESTAMP(0); -- Время выхода
person_id INTEGER; -- Идентификатор студента
enter_id VARCHAR(64); -- Сгенерированный код для посещения
BEGIN
FOR i IN 1..1000000 LOOP -- Генерация 1 миллиона записей
-- Генерация случайной даты в пределах 2025 года
enter_time := to_timestamp(
random() * (
extract(epoch from '2025-12-31'::date) -
extract(epoch from '2025-01-01'::date)
) + extract(epoch from '2025-01-01'::date)
);
-- Генерация случайного времени, не более 10 часов (36000 секунд)
exit_time := enter_time + (floor(random() * 36000 + 1) * '1 SECOND'::interval);
-- Получаем случайного студента из таблицы студентов
person_id := (
SELECT student_id FROM students
ORDER BY random()
LIMIT 1
);
-- Генерация уникального кода для посещения
enter_id := md5(random()::text);
-- Вставка данных в таблицу attendance
INSERT INTO attendance(generated_code, person_id, enter_time, exit_time)
VALUES (enter_id, person_id, enter_time, exit_time);
END LOOP;
END
$$;
3)
-- Удаляем индекс, если он существует
DROP INDEX IF EXISTS idx_generated_code;
-- Выполнение анализа производительности при вставке данных
EXPLAIN ANALYZE
INSERT INTO attendance (generated_code, person_id, enter_time, exit_time)
VALUES ('ABC123', 1, '2024-12-03 10:00:00', '2024-12-03 11:00:00');-------- 4 шаг
EXPLAIN ANALYZE SELECT * FROM attendance
EXPLAIN ANALYZE SELECT * FROM attendance WHERE person_id = 1;
CREATE INDEX idx_person_id ON attendance (person_id);
EXPLAIN ANALYZE SELECT * FROM attendance
EXPLAIN ANALYZE SELECT * FROM attendance WHERE person_id = 1;
-- Удаляем индекс, если он существует
DROP INDEX IF EXISTS idx_generated_code;
-- Выполнение анализа производительности при вставке данных
EXPLAIN ANALYZE
INSERT INTO attendance (generated_code, person_id, enter_time, exit_time)
VALUES ('ABC123', 1, '2024-12-03 10:00:00', '2024-12-03 11:00:00');
INSERT INTO students (student_id, last_name, first_name, patronymic, students_group_number, birthday)
VALUES (1, 'Ерёмин', 'Даниил', 'Валерьевич', 'ИВТ-43', '2003-10-13');
INSERT INTO student_ids (student_id)
VALUES (1);
-- Повторный анализ производительности после добавления данных
EXPLAIN ANALYZE
INSERT INTO attendance (generated_code, person_id, enter_time, exit_time)
VALUES ('XYZ789', 1, '2024-12-03 12:00:00', '2024-12-03 13:00:00');
CREATE INDEX idx_generated_code ON attendance (generated_code);
EXPLAIN ANALYZE
INSERT INTO attendance (generated_code, person_id, enter_time, exit_time)
VALUES ('LMN456', 1, '2024-12-03 14:00:00', '2024-12-03 15:00:00');
EXPLAIN ANALYZE
SELECT * FROM attendance ORDER BY generated_code;
5)
EXPLAIN ANALYZE SELECT * FROM attendance
WHERE generated_code LIKE '%a'
ORDER BY generated_code;
6)
ALTER TABLE grades
ADD COLUMN student_name VARCHAR(255);
UPDATE grades
SET student_name = (
SELECT CONCAT(s.first_name, ' ', s.last_name)
FROM students s
WHERE s.student_id = grades.student_id
);
ALTER TABLE grades
ADD COLUMN students_group_number VARCHAR(255);
UPDATE grades
SET students_group_number = (
SELECT s.students_group_number
FROM students s
WHERE s.student_id = grades.student_id
);
SELECT * FROM public.grades
ORDER BY grade_id DESC LIMIT 20
INSERT INTO grades (grade_id, student_id, professor_id, grade, student_name, students_group_number, subject)
VALUES
(7089, 1, 1, 3, ’Полиграф Шариков’, 'ИВТ-42', 'Операционные системы'),
(7090, 1, 1, 3, ’Полиграф Шариков’, 'ИВТ-42', 'Базы данных');
ALTER TABLE grades
ADD COLUMN subject VARCHAR(255);
UPDATE grades
SET subject = (
SELECT f.field_name
FROM fields f
WHERE f.field_name = grades.subject
);
Преподаватель
BEGIN;
UPDATE grades
SET grade = 5
WHERE student_name = ‘Полиграф Шариков’ AND subject = 'Операционные системы';
UPDATE grades
SET grade = 5
WHERE student_name = ‘Полиграф Шариков’ AND subject = 'Базы данных';
------
SELECT * FROM grades
WHERE student_name = ‘Полиграф Шариков’;
-----
COMMIT;
------
SELECT * FROM grades
WHERE student_name = ‘Полиграф Шариков’;
------C ROLLBACK
BEGIN;
UPDATE grades
SET grade = 3
WHERE student_name = ‘Полиграф Шариков’ AND subject = 'Операционные системы';
UPDATE grades
SET grade = 3
WHERE student_name = ‘Полиграф Шариков’ AND subject = 'Базы данных';
COMMIT;
---------------
BEGIN;
UPDATE grades
SET grade = 5
WHERE student_name = ‘Полиграф Шариков’ AND subject = 'Операционные системы';
UPDATE grades
SET grade = 5
WHERE student_name = ‘Полиграф Шариков’ AND subject = 'Базы данных';
SELECT * FROM grades
WHERE student_name = ‘Полиграф Шариков’;
-----------------
SELECT * FROM grades
WHERE student_name = ‘Полиграф Шариков’;
ROLLBACK;
SELECT * FROM grades
WHERE student_name = ‘Полиграф Шариков’;
-----Аномалия -----
------
BEGIN;
UPDATE grades
SET grade = 5
WHERE student_name = ‘Полиграф Шариков’ AND subject = 'Операционные системы';
UPDATE grades
SET grade = 5
WHERE student_name = ‘Полиграф Шариков’ AND subject = 'Базы данных';
SELECT * FROM grades
WHERE student_name = ‘Полиграф Шариков’;
-----------------
SELECT * FROM grades
WHERE student_name = ‘Полиграф Шариков’;
--------------
COMMIT;
-----------------
SELECT * FROM grades
WHERE student_name = ‘Полиграф Шариков’;
-----------
BEGIN;
UPDATE grades
SET grade = 3
WHERE student_name = ‘Полиграф Шариков’ AND subject = 'Операционные системы';
UPDATE grades
SET grade = 3
WHERE student_name = ‘Полиграф Шариков’ AND subject = 'Базы данных';
COMMIT;
-----Аномалия Read committed
----------------
BEGIN;
UPDATE grades
SET grade = 5
WHERE student_name = ‘Полиграф Шариков’ AND subject = 'Операционные системы';
UPDATE grades
SET grade = 5
WHERE student_name = ‘Полиграф Шариков’ AND subject = 'Базы данных';
SELECT * FROM grades
WHERE student_name = ‘Полиграф Шариков’;
-----------------
SELECT * FROM grades
WHERE student_name = ‘Полиграф Шариков’;
-----------------
COMMIT;
SELECT * FROM grades
WHERE student_name = ‘Полиграф Шариков’;
BEGIN;
UPDATE grades
SET grade = 3
WHERE student_name = ‘Полиграф Шариков’ AND subject = 'Операционные системы';
UPDATE grades
SET grade = 3
WHERE student_name = ‘Полиграф Шариков’ AND subject = 'Базы данных';
COMMIT;
-----Аномалия Repeatable read
---------------
BEGIN;
UPDATE grades
SET grade = 5
WHERE student_name = ‘Полиграф Шариков’ AND subject = 'Операционные системы';
UPDATE grades
SET grade = 5
WHERE student_name = ‘Полиграф Шариков’ AND subject = 'Базы данных';
SELECT * FROM grades
WHERE student_name = ‘Полиграф Шариков’;
SELECT * FROM grades
WHERE student_name = ‘Полиграф Шариков’;
COMMIT;
SELECT * FROM grades
WHERE student_name = ‘Полиграф Шариков’;
-----------SELECT * FROM grades
WHERE student_name = ‘Полиграф Шариков’;
BEGIN;
UPDATE grades
SET grade = 3
WHERE student_name = ‘Полиграф Шариков’ AND subject = 'Операционные системы';
UPDATE grades
SET grade = 3
WHERE student_name = ‘Полиграф Шариков’ AND subject = 'Базы данных';
COMMIT;
-----Аномалия Serializable
BEGIN;
UPDATE grades
SET grade = 5
WHERE student_name = ‘Полиграф Шариков’ AND subject = 'Операционные системы';
UPDATE grades
SET grade = 5
WHERE student_name = ‘Полиграф Шариков’ AND subject = 'Базы данных';
SELECT * FROM grades
WHERE student_name = ‘Полиграф Шариков’;
SELECT * FROM grades
WHERE student_name = ‘Полиграф Шариков’;
COMMIT;
SELECT * FROM grades
WHERE student_name = ‘Полиграф Шариков’;
BEGIN;
UPDATE grades
SET grade = 3
WHERE student_name = ‘Полиграф Шариков’ AND subject = 'Операционные системы';
UPDATE grades
SET grade = 3
WHERE student_name = ‘Полиграф Шариков’ AND subject = 'Базы данных';
COMMIT;
Вкратце:
Создал таблицу attendance согласно примеру из методических материалов.
Заполнил таблицу данными, следуя примеру из методички.
При попытке вставить данные в таблицу с person_id = 1 возникла ошибка, указывающая на отсутствие такого id в связанных таблицах. Для исправления добавил себя в таблицы students и student_ids с id = 1 как пример. После внесения изменений команды начали выполняться корректно.
|
Время до индексирования Tb |
Время после индексирования Ta |
Ta/ Tb |
SELECT |
Planning Time: 0.225 ms Execution Time: 1626.683 ms |
Planning Time: 0.164 ms Execution Time: 1055.04 ms |
Planning Time 0.64 Execution Time 0.65 |
INSERT |
Planning Time: 0.214 ms Execution Time: 0.543 ms |
Planning Time: 0.067 ms Execution Time: 0.586 ms |
Planning Time 0.33 Execution Time 0.94 |
|
|
|
|
SELECT Planning Time 1.59
Execution Time 1.55
INSERT Planning Time 3.26
Execution Time 1.08
По результатам можно сделать вывод, что индексирование ускоряет работу с базами данных в области поиска но незначительно ускоряет при добавлении данных
4)
|
Время до индексирования Tb |
Время после индексирования Ta |
Ta/ Tb |
SELECT |
Planning Time: 0.379 ms Execution Time: 177.351 ms |
Planning Time: 0.517 ms Execution Time: 135.950 ms |
Planning Time 1.43 Execution Time 0.772 |
SELECT+WHERE |
Planning Time: 0.519 ms Execution Time: 103.511 ms |
Planning Time: 0.171 ms Execution Time: 0.332 ms |
Planning Time 0.341 Execution Time 3.26e-3 |
SELECT Planning Time 1.42
Execution Time 1.31
INSERT Planning Time 2.93
Execution Time 307.23
По результатам видно, что время запроса с условием после добавления индекса в сотни раз меньше, чем время аналогичного запроса до индексирования
После выполнения запроса к таблице были получены следующие результаты:
Время планирования: 42.136 мс
Время выполнения: 188.660 мс
Индекс в данном запросе не использовался, поскольку поиск с шаблоном, начинающимся с символа %, требует полного сканирования таблицы. Это связано с тем, что индекс не может эффективно сузить диапазон значений, если они начинаются с переменной части строки.
Обновил таблицу grades, добавив фамилию и имя студента, его группу и название предмета. Открыл два окна: одно для преподавателя, другое — для методиста. 6.1) Для преподавателя обновил оценки студента и вывел информацию о нем (оценки изменились на 5). 6.2) Для методиста вывел информацию по тому же студенту (оценки остались прежними — 3). 6.3) Для преподавателя выполнил команду COMMIT;. 6.4) Для методиста повторил запрос и увидел обновленные оценки (5). 6.5) Для преподавателя откатил внесенные изменения с помощью команды ROLLBACK; (выводил информацию по студенту до и после отката — до ROLLBACK оценки изменились, а после отката остались прежними). 6.6) Для методиста повторил запрос и увидел, что оценки остались неизменными (3).
Уровень изоляции |
До фиксации |
После фиксации |
Read uncommited |
ПР5 МЕТ3 |
ПР5 МЕТ5 |
Read committed |
ПР5 МЕТ3 |
ПР5 МЕТ5 |
Repeatable read |
- |
- |
Serializable |
- |
- |
