Skip to content

Instantly share code, notes, and snippets.

@theaspect
Last active December 12, 2021 20:06
Show Gist options
  • Save theaspect/c26d7eb641979a3facb20f6c1e1c4ac7 to your computer and use it in GitHub Desktop.
Save theaspect/c26d7eb641979a3facb20f6c1e1c4ac7 to your computer and use it in GitHub Desktop.
race and deadlock
-- Транзакция - связанный набор операций
--
-- Atomicity Атомарность, выполняется либо целиком, либо целиком откатывается/отменяется
-- Вася Петя
-- 20 10
-- 20-10
-- СБОЙ СИСТЕМЫ
-- 10+10
-- Consistency Консистентность, после завершения транзакции система должна оказаться в непротиворечивом состоянии
-- Граф A <-> B
-- NodeID (not null), ParentId (not null, FK NodeId)
-- BEGIN
-- A Null (Запрещено ключами)
-- B A
-- UPDATE table SET ParentID = B where NodeID = A
-- COMMIT
-- Isolated Изолированность - Транзации происходящие одновременно с текущей не должны влиять
-- Durable Надежность – Как только произошел коммит, никакой сбой произошедший после коммита не должен на него повлиять
-- Atomicity транзакция выполняется либо полностью либо откатывается целиком
-- Consistency если база данных находится в консистентном состоянии (все инварианты выполнены),
-- то после транзакции база останется в консистентном состоянии
-- внутри транзакции консистентность может нарушаться
-- Isolation эффекты одних транзакций не должны влиять на другие транзакции
-- Durability эффекты от завершенной транзакции должны быть устойчивыми
-- Transaction последовательность операций либо выполняется либо отклонояется
-- Инварианты:
-- Суммарный баланс не должен меняться
-- Баланс >= 0
drop table if exists account;
create table account(client varchar(100) primary key, balance int);
insert into account values
('vasya', 100),
('petya', 200);
select * from account;
-- do check in application petya's balance >= 100
-- BEGIN;
update account set balance = balance - 100 where client = 'petya';
update account set balance = balance + 100 where client = 'vasya';
-- COMMIT;
-- ROLLBACK;
select * from account;
-- Race Condition (Lost Update)
-- Connect1 Connect2
-- read petya read petya
-- check petya balance check petya balance
-- petya -100
-- write 100
-- petya -200
-- write 0
BEGIN;
select * from account;
UPDATE account set balance = balance + 10 where client = 'petya';
select * from account;
ROLLBACK;
-- Одновременно во втором коннекте НАЧАЛО
BEGIN;
select * from account;
UPDATE account set balance = balance + 20 where client = 'petya';
select * from account;
COMMIT;
-- Одновременно во втором коннекте КОНЕЦ
-- Option 1 прервать
-- Option 2 перезапустить
-- Deadlock
select * from account;
BEGIN;
UPDATE account set balance = balance + 10 where client = 'petya';
select * from account;
UPDATE account set balance = balance - 10 where client = 'vasya';
select * from account;
COMMIT;
-- Одновременно во втором коннекте НАЧАЛО
select * from account;
BEGIN;
UPDATE account set balance = balance - 10 where client = 'vasya';
select * from account;
UPDATE account set balance = balance + 10 where client = 'petya';
COMMIT;
-- Одновременно во втором коннекте КОНЕЦ
-- Lock, Unlock, Read, Write
-- p == petya
-- v == vasya
-- T1 T2
-- lock(p)
-- lock(v)
-- read(p)
-- read(v)
-- write(p)
-- write(v)
-- lock(v) <- Ждём T2
-- lock(p) <- Ждём Т1
-- обнаружена блокировка
-- rollback T2:
-- unlock(v)
-- блокировка v успешна
-- read(v)
-- write(v)
-- commit:
-- unlock(v)
-- unlock(p)
-- Список Блокировок
-- T1: p
-- T2: v
-- Граф ожидания
-- T1 <-> T2 (цикл в графе)
-- Процесс поиска блокировок периодически строит граф и ищет в нём циклы
-- Read-Write lock
-- R W
-- R + -
-- W - -
-- CAP-theorem consistency/availability/partition-tolerance
-- BASE - Basically Available, Soft state, Eventually Consistent
-- stale/fair
use se;
show schemas;
show tables;
# Cycle
drop table if exists graph;
create table graph(
id INT primary key,
parent_id INT not null,
FOREIGN KEY (parent_id) references graph(id)
);
select * from graph;
# 1, 2
# 2, 1
insert into graph values (1, 2);
insert into graph values (2, 1);
insert into graph values
(1, 2),
(2, 1);
insert into graph values (1, NULL);
insert into graph values (2, 1);
UPDATE graph set parent_id = 2 where id = 1;
insert into graph values (1, 1);
insert into graph values (2, 1);
UPDATE graph set parent_id = 2 where id = 1;
select * from graph;
-- mysql not support deferred checks
set foreign_key_checks = 0;
BEGIN;
insert into graph values (1, 2);
insert into graph values (2, 1);
COMMIT;
set foreign_key_checks = 1;
-- copy from console 2
# use se;
# SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
# BEGIN;
# select * from t;
# ROLLBACK;
#
# SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
# BEGIN;
# UPDATE t set b = b + 1 WHERE a = 1;
# COMMIT;
#
# SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
# BEGIN;
# insert into t values (3, 3);
# select * from t;
# COMMIT;
#
# SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
# BEGIN;
# insert into t values (4, 4);
# select * from t;
# COMMIT;
show schemas;
create schema if not exists se;
use se;
drop table if exists t;
create table t (a int primary key, b int);
insert into t values (1, 1), (2, 2);
select * from t;
-- READ UNCOMMITTED
-- READ COMMITTED
-- REPEATABLE READ
-- SERIALIZABLE
-- Isolation Level Dirty Read Nonrepeatable Read Phantom Read Serialization Anomaly
-- Read uncommitted Allowed, but not in PG Possible Possible Possible
-- Read committed Not possible Possible Possible Possible
-- Repeatable read Not possible Not possible Allowed, but not in PG Possible
-- Serializable Not possible Not possible Not possible Not possible
-- Lost Update (невозможен)
-- T1 T2
-- BEING
-- b = b + 1 where a = 1 BEGIN
-- b = b + 2 where a = 1
-- COMMIT
-- COMMIT
-- Первый пользователь попытался купить билет
-- Второй пользователь в этот момент увидел что билет куплен
-- У первого пользователя не хватило денег и он отказался
-- Dirty Read
-- T1 T2
-- b = b + 1 where a = 1
-- select b
-- rollback
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
BEGIN;
UPDATE t set b = b + 1 WHERE a = 1;
select * from t;
ROLLBACK;
show processlist;
kill connection 19;
kill query 19;
-- Non repeatable read
-- T1 T2
-- select b
-- b = b + 1 where a = 1
-- select b
-- rollback
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
BEGIN;
select * from t;
-- update in t2
select * from t;
ROLLBACK;
-- Phantom read
-- T1 T2
-- select b
-- insert b (3, 3)
-- select b
-- rollback
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
BEGIN;
-- select * from t;
-- insert in t2
-- select * from t;
-- mysql does not allow phantom reads, but allow phantom writes
select * from t;
-- insert in t2
update t set b = 10 where a = 3;
select * from t;
COMMIT;
-- Самая строгая изоляция
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN;
select * from t;
update t set b = 3 where a = 3;
select * from t;
COMMIT;
-- Нормальные формы
-- Дублирование
-- Аномалии DML
-- Неконсистентность
-- 1НФ
-- Нет повторений
-- Все значения скалярны
drop table if exists cars;
create table cars (brand varchar(100), model varchar(100));
insert into cars values ('BMW', 'X5, X7'), ('NISSAN', 'GT-R'), ('NISSAN', 'GT-R');
select * from cars;
drop table if exists cars;
create table cars (brand varchar(100), model varchar(100), primary key (brand, model));
insert into cars values
('BMW', 'X5'),
('BMW', 'X7'),
# ('NISSAN', 'GT-R'),
('NISSAN', 'GT-R');
select * from cars;
-- 2НФ
-- 1НФ +
-- Каждый неключевой атрибут неприводимо зависит от каждого потенциального кллюча
-- (схемы с простыми ключами всегда во 2НФ)
-- Аномалии:
-- Избыточность
-- Нельзя создать склад без деталей
-- Удаление детали приводит к потере склада
drop table if exists store;
create table store (
store varchar(100),
detail varchar(100),
count int,
address varchar(100),
primary key (store, detail));
insert into store values
('main', 'monitor', 10, 'bakinsky 15'),
('main', 'laptop', 10, 'bakinsky 15'),
('aux', 'mouse', 1, 'kuznetsky 18');
select * from store;
-- Разбиваем составной ключ
drop table if exists stores;
create table stores (
store varchar(100) primary key,
address varchar(100));
insert into stores values
('main', 'bakinsky 15'),
('aux', 'kuznetsky 18');
drop table if exists details;
create table details(
store varchar(100),
detail varchar(100),
count int,
primary key (store, detail),
foreign key (store) references stores(store)
);
insert into details values
('main', 'monitor', 10),
('main', 'laptop', 10),
('aux', 'mouse', 1);
select * from stores;
select * from details;
select * from stores s join details d on s.store = d.store;
-- 3НФ
-- 2НФ +
-- Ни один неключевой отрибут не находится в зависимости от потенциального ключа
-- (Есть транзитивные зависимости между атрибутами)
drop table if exists employee;
create table employee (name varchar(100) primary key, department varchar(100), phone varchar(100));
insert into employee values
('vasya@example.com', 'development', '101'),
('petya@example.com', 'development', '101'),
('kolya@example.com', 'qa', '103');
select * from employee;
-- НФБК 3+НФ Бойс Кодд
-- Более строгая 3НФ
-- Каждая нетривиальная неприводимая слева функциональная зависимость
-- имеет в качестве своего детерминанта некоторый потенциальный ключ
-- (Нет зависимостей внутри ключа)
drop table if exists supplier;
create table supplier(
code int,
supplier varchar(100),
detail varchar(100),
count int,
primary key (code, supplier, detail));
insert into supplier values
(1, 'gl', 'internet', 100),
(1, 'gl', 'tv', 10),
(2, 'papa', 'pizza', 5);
select * from supplier;
-- 4НФ
-- НФБК +
-- Все нетривиальные многозначные зависимости фактически являются функциональными зависимостями от потенциальных ключей
-- Аномалии:
-- При добавлении пиццы или района необходимо добавить все районы/пиццы/рестораны
-- При удалении теряется информация от районах/пиццах
drop table if exists pizza;
create table pizza (
restraunt varchar(100),
pizza varchar(100),
district varchar(100),
primary key (restraunt, pizza, district));
insert into pizza values
('sovetsky', 'pepperoni', 'central'),
('sovetsky', 'margarita', 'central'),
('raduga', 'margarita', 'kirovsky'),
('raduga', 'margarita', 'rudnichny');
select * from pizza;
-- Пиццы
-- Рестораны
-- delivery, rest_district Ресторан -> Районы доставки
-- assort Ресторан -> Пиццы
-- order (delivery_id, assort_id, 10)
-- 5НФ
-- 4НФ +
-- Отсутствуют сложные соединения между атррибутами
-- Аномалии:
-- Продавец имеет право торговать только с определенными фирамами
-- данное отношение не может исключать ситуации когода отношение нарушается
drop table if exists seller;
create table seller (
seller varchar(100),
supplier varchar(100),
product varchar(100),
primary key (seller, supplier, product));
insert into seller values
('ya', 'bosch', 'refrigerator'),
('ya', 'bosch', 'cooker'),
('ya', 'lg', 'vacuum'),
('promenad', 'bosch', 'washing machine'),
('promenad', 'lg', 'vacuum');
select * from seller;
-- Необхоимо разбить на три отношения
-- ДКНФ
-- Каждое наложенное ограничение является логическим следствием ограничений доменов и
-- ограничений ключей наложенных на данную переменную отношения
-- По-сути задание перечня допустимых значений для каждого типа
-- 6НФ
-- 5НФ +
-- Переменная отношения находится в 6НФ тогда и только тогда когда удовлетворяет всем нетривиальными зависимостям соединения
-- Декомпозиция 6НФ невозможна без потерь
-- Применяется во временных рядах
--
-- id клиента
-- Интервал дат
-- Улица |
-- Город |
-- Штат | - Каждое из полей может изменяться независимоб что приводит к дублированию данных
-- Индекс |
-- Телефон |
-- Можно разбить на отдельные отношения, но из-за того что интервалы могут не пересекаться сложно джойнить
-- circular inclusion constraint требует при наличии хотя бы одной строки из (улицы, города, штата, индекса)
-- все остальные тоже должны существовать. Это требование невозможно выполнить в современных БД,
-- поэтому ограничения выносятся в слой приложения
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment