add homework 6.4: tasks 1-3

This commit is contained in:
2022-06-02 10:54:44 +07:00
parent 7870726c8c
commit c7a639e42c
5 changed files with 325 additions and 1 deletions

View File

@@ -27,3 +27,4 @@
* [6.1. Типы и структура СУБД](/src/homework/06-database/6.1)
* [6.2. SQL](/src/homework/06-database/6.2)
* [6.3. MySQL](/src/homework/06-database/6.3)
* [6.4. PostgreSQL](/src/homework/06-database/6.4)

View File

@@ -46,7 +46,7 @@ docker-compose exec postgres sh
createdb --username=admin some_db
```
Далее создадим пользователей. Для начала подключимся к БД с помощью утилиты psql:
Далее создадим пользователей. Для начала подключимся к БД с помощью утилиты `psql`:
```shell
docker-compose exec postgres psql --username=admin --dbname=test_db
```

View File

@@ -0,0 +1,19 @@
---
version: '3.8'
services:
postgres:
image: postgres:13.5-alpine
environment:
POSTGRES_USER: admin
POSTGRES_PASSWORD: 123
POSTGRES_DB: test_database
PGDATA: /var/lib/postgresql/data/pgdata
ports:
- "25432:5432"
volumes:
- netology_pgdata:/var/lib/postgresql/data/pgdata
- ./dump:/opt/dump
volumes:
netology_pgdata:

View File

@@ -0,0 +1,99 @@
--
-- PostgreSQL database dump
--
-- Dumped from database version 13.0 (Debian 13.0-1.pgdg100+1)
-- Dumped by pg_dump version 13.0 (Debian 13.0-1.pgdg100+1)
SET statement_timeout = 0;
SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SELECT pg_catalog.set_config('search_path', '', false);
SET check_function_bodies = false;
SET xmloption = content;
SET client_min_messages = warning;
SET row_security = off;
SET default_tablespace = '';
SET default_table_access_method = heap;
--
-- Name: orders; Type: TABLE; Schema: public; Owner: postgres
--
CREATE TABLE public.orders (
id integer NOT NULL,
title character varying(80) NOT NULL,
price integer DEFAULT 0
);
ALTER TABLE public.orders OWNER TO postgres;
--
-- Name: orders_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
--
CREATE SEQUENCE public.orders_id_seq
AS integer
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER TABLE public.orders_id_seq OWNER TO postgres;
--
-- Name: orders_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
--
ALTER SEQUENCE public.orders_id_seq OWNED BY public.orders.id;
--
-- Name: orders id; Type: DEFAULT; Schema: public; Owner: postgres
--
ALTER TABLE ONLY public.orders ALTER COLUMN id SET DEFAULT nextval('public.orders_id_seq'::regclass);
--
-- Data for Name: orders; Type: TABLE DATA; Schema: public; Owner: postgres
--
COPY public.orders (id, title, price) FROM stdin;
1 War and peace 100
2 My little database 500
3 Adventure psql time 300
4 Server gravity falls 300
5 Log gossips 123
6 WAL never lies 900
7 Me and my bash-pet 499
8 Dbiezdmin 501
\.
--
-- Name: orders_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
--
SELECT pg_catalog.setval('public.orders_id_seq', 8, true);
--
-- Name: orders orders_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
--
ALTER TABLE ONLY public.orders
ADD CONSTRAINT orders_pkey PRIMARY KEY (id);
--
-- PostgreSQL database dump complete
--

View File

@@ -0,0 +1,205 @@
Выполнение [домашнего задания](https://github.com/netology-code/virt-homeworks/blob/master/06-db-04-postgresql/README.md)
по теме "6.4. PostgreSQL".
## Q/A
### Задача 1
> Используя docker поднимите инстанс PostgreSQL (версию 13). Данные БД сохраните в volume.
>
> Подключитесь к БД PostgreSQL используя `psql`.
>
> Воспользуйтесь командой `\?` для вывода подсказки по имеющимся в `psql` управляющим командам.
>
> **Найдите и приведите** управляющие команды для:
> - вывода списка БД
> - подключения к БД
> - вывода списка таблиц
> - вывода описания содержимого таблиц
> - выхода из psql
Запуск postgresql в docker-контейнере производится с использованием конфигурации [docker-compose.yml](./docker-compose.yml).
Для подключения к БД с использованием `psql` нужно выполнить следующую команду:
```shell
docker-compose exec postgres psql --username=admin --dbname=test_db
```
Команды работы с БД:
```shell
# вывод списка БД
\l
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges
-----------+-------+----------+------------+------------+-------------------
postgres | admin | UTF8 | en_US.utf8 | en_US.utf8 |
template0 | admin | UTF8 | en_US.utf8 | en_US.utf8 | =c/admin +
| | | | | admin=CTc/admin
template1 | admin | UTF8 | en_US.utf8 | en_US.utf8 | =c/admin +
| | | | | admin=CTc/admin
test_db | admin | UTF8 | en_US.utf8 | en_US.utf8 |
# подключение к БД
\c postgres
You are now connected to database "postgres" as user "admin".
# вывод списка таблиц
\dt
List of relations
Schema | Name | Type | Owner
--------+---------+-------+-------
public | clients | table | admin
public | orders | table | admin
# вывод описания содержимого таблиц
\d orders
Table "public.orders"
Column | Type | Collation | Nullable | Default
--------+------------------------+-----------+----------+------------------------------------
id | integer | | not null | nextval('orders_id_seq'::regclass)
name | character varying(255) | | |
price | integer | | |
Indexes:
"orders_pkey" PRIMARY KEY, btree (id)
Referenced by:
TABLE "clients" CONSTRAINT "client_order_fk" FOREIGN KEY (order_id) REFERENCES orders(id) ON DELETE CASCADE
# выход из psql
\q
```
### Задача 2
> Используя `psql` создайте БД `test_database`.
>
> Изучите [бэкап БД](./dump/test_dump.sql).
>
> Восстановите бэкап БД в `test_database`.
>
> Перейдите в управляющую консоль `psql` внутри контейнера.
>
> Подключитесь к восстановленной БД и проведите операцию ANALYZE для сбора статистики по таблице.
>
> Используя таблицу [pg_stats](https://postgrespro.ru/docs/postgresql/13/view-pg-stats), найдите столбец таблицы `orders`
> с наибольшим средним значением размера элементов в байтах.
>
> **Приведите в ответе** команду, которую вы использовали для вычисления и полученный результат.
Для восстановления дампа нужно выполнить следующую последовательность команд:
```shell
docker-compose exec postgres sh
cd /opt/dump/
psql -Uadmin -dtest_database < test_dump.sql
psql -Uadmin -dtest_database
\dt
List of relations
Schema | Name | Type | Owner
--------+--------+-------+-------
public | orders | table | admin
(1 row)
```
Для сбора статистики по таблице, нужно выполнить следующий запрос:
```sql
analyze verbose orders;
-- INFO: analyzing "public.orders"
-- INFO: "orders": scanned 1 of 1 pages, containing 8 live rows and 0 dead rows; 8 rows in sample, 8 estimated total rows
-- ANALYZE
```
Вывод информации по таблице:
```sql
select tablename, attname, avg_width from pg_stats where tablename like 'orders';
-- tablename | attname | avg_width
-- -----------+---------+-----------
-- orders | id | 4
-- orders | title | 16
-- orders | price | 4
-- (3 rows)
```
Таким образом, наибольшее среднее значение размера элементов у столбца `title` с размером 16 байт.
### Задача 3
> Архитектор и администратор БД выяснили, что ваша таблица orders разрослась до невиданных размеров и
> поиск по ней занимает долгое время. Вам, как успешному выпускнику курсов DevOps в нетологии предложили
> провести разбиение таблицы на 2 (шардировать на orders_1 - price>499 и orders_2 - price<=499).
>
> Предложите SQL-транзакцию для проведения данной операции.
>
> Можно ли было изначально исключить "ручное" разбиение при проектировании таблицы orders?
Для партицирования существующей таблицы (шардирование таблицы в рамках текущего инстанса БД)
необходимо использовать функционал наследования и создать две таблицы, которые наследуют базовую.
```sql
create table orders_1 (
constraint pk_orders_1 primary key (id),
constraint ck_orders_1 check ( price > 499)
) inherits (orders);
create table orders_2 (
constraint pk_orders_2 primary key (id),
constraint ck_orders_2 check ( price <= 499)
) inherits (orders);
```
При этом, запись в основную таблицу не переведёт данные в дочерние таблицы. Для этого необходимо написать триггер,
который будет все новые данные записывать в дочерние таблицы:
```sql
CREATE OR REPLACE FUNCTION insert_new_order()
RETURNS TRIGGER AS $$
begin
if (NEW.price > 499) then
insert into orders_1 values (NEW.*);
else
insert into orders_2 values (NEW.*);
end if;
return null;
end;
$$
LANGUAGE plpgsql;
create trigger insert_new_orders_trigger
before insert on orders
for each row execute function insert_new_order();
```
Теперь новые данные, которые будут записываться в таблицу `orders` будут физически попадать в одну из таблиц `orders_1` или `orders_2`,
но при этом при запросе к родительской таблице эти данные будут видны.
На этапе проектирования структуры БД необходимо выделять таблицы, которые будут иметь очень большой размер.
В этом случае можно использовать нативный функционал партицирования, который может быть активирован только при создании таблицы.
Таким образом, создание таблицы `orders` в самом начале создания схемы выглядело бы следующим образом:
```sql
CREATE TABLE orders (
id serial4 NOT NULL,
title varchar(80) NOT NULL,
price int4 NULL DEFAULT 0,
CONSTRAINT orders_pkey PRIMARY KEY (id)
) PARTITION BY RANGE (price);
CREATE TABLE orders_1 PARTITION OF orders
FOR VALUES FROM (500) TO (maxvalue);
CREATE TABLE orders_2 PARTITION OF orders
FOR VALUES FROM (minvalue) to (500);
```
### Задача 4
> Используя утилиту `pg_dump` создайте бекап БД `test_database`.
>
> Как бы вы доработали бэкап-файл, чтобы добавить уникальность значения столбца `title` для таблиц `test_database`?
// todo