From c7a639e42caecc66d6d45106544be1eec58447ac Mon Sep 17 00:00:00 2001 From: dannc Date: Thu, 2 Jun 2022 10:54:44 +0700 Subject: [PATCH] add homework 6.4: tasks 1-3 --- readme.md | 1 + src/homework/06-database/6.2/readme.md | 2 +- .../06-database/6.4/docker-compose.yml | 19 ++ .../06-database/6.4/dump/test_dump.sql | 99 +++++++++ src/homework/06-database/6.4/readme.md | 205 ++++++++++++++++++ 5 files changed, 325 insertions(+), 1 deletion(-) create mode 100644 src/homework/06-database/6.4/docker-compose.yml create mode 100644 src/homework/06-database/6.4/dump/test_dump.sql create mode 100644 src/homework/06-database/6.4/readme.md diff --git a/readme.md b/readme.md index 221d754..4b5fa54 100644 --- a/readme.md +++ b/readme.md @@ -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) diff --git a/src/homework/06-database/6.2/readme.md b/src/homework/06-database/6.2/readme.md index b9f7808..ead0924 100644 --- a/src/homework/06-database/6.2/readme.md +++ b/src/homework/06-database/6.2/readme.md @@ -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 ``` diff --git a/src/homework/06-database/6.4/docker-compose.yml b/src/homework/06-database/6.4/docker-compose.yml new file mode 100644 index 0000000..575af45 --- /dev/null +++ b/src/homework/06-database/6.4/docker-compose.yml @@ -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: diff --git a/src/homework/06-database/6.4/dump/test_dump.sql b/src/homework/06-database/6.4/dump/test_dump.sql new file mode 100644 index 0000000..0ebc284 --- /dev/null +++ b/src/homework/06-database/6.4/dump/test_dump.sql @@ -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 +-- + diff --git a/src/homework/06-database/6.4/readme.md b/src/homework/06-database/6.4/readme.md new file mode 100644 index 0000000..7365ffe --- /dev/null +++ b/src/homework/06-database/6.4/readme.md @@ -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 \ No newline at end of file