database first! О распространённых ошибках использования...
TRANSCRIPT
О чём и зачем этот доклад
БД — сердце IT-системы
РСУБД и SQL занимают лидирующие позиции.И это надолго
Не использовать полноценно их возможности — глупость*
___________________* Получается глупо, потому что: 1) качество хуже, 2) производительность ниже, 3) потом всё равно придётся исправлять (возможно, уже не вам)
О докладчике• ФУПМ МФТИ / ИСП РАН / «Базы данных»
• MoiKrug (2005), MirTesen (2007), Postila (2013)
• PostgreSQL-консалтинг с 2007 в России, с 2013 в Калифорнии
• #RuPostgres (http://rupostgres.org) — вторая крупнейшая митап-группа в мире
• Postgres-твиттер (3500+ подписчиков): @postgresmen
• ПК конференций HLj, BackendConf, Highload++, PgDay Russia
Проблемы использования SQL & РСУБД
• боязнь и незнание возможностей РСУБД/SQL:• для контроля данных• для манипулирования данными
• архитектурные ошибки, связанные с этими страхами и невежеством
Последствия ошибки №1
1. Отсутствие Primary Key (PK):• дубликаты, грязные данные;• нарушение реляционной модели и вытекающие проблемы (аномалии
данных, неожиданные результаты JOIN и т.д.)• рано или поздно приходится чистить (долго, дорого)
Последствия ошибки №1
1. Отсутствие Primary Key (PK):• дубликаты, грязные данные;• нарушение реляционной модели и вытекающие проблемы (аномалии
данных, неожиданные результаты JOIN и т.д.)• рано или поздно приходится чистить (долго, дорого)
2. Только «суррогатный» PK, но нет Unique Key(s) (UKs):• «скрытые» дубликаты, опять грязные данные и проблемы• опять необходимость чистки (долго, дорого)
Последствия ошибки №1
1. Отсутствие Primary Key (PK):• дубликаты, грязные данные;• нарушение реляционной модели и вытекающие проблемы (аномалии
данных, неожиданные результаты JOIN и т.д.)• рано или поздно приходится чистить (долго, дорого)
2. Только «суррогатный» PK, но нет Unique Key(s) (UKs):• «скрытые» дубликаты, опять грязные данные и проблемы• опять необходимость чистки (долго, дорого)
Числовые PK вида 1, 2, … («суррогатные») — это иллюзия правильного проектирования, легко забыть о потенциальных ключах!
Последствия ошибки №1
1. Отсутствие Primary Key (PK)2. Только суррогатный PK,
но нет Unique Key(s) (UKs)
3. Не используются Foreign Keys (FKs):• orphans (осиротевшие записи) → аномалии, ошибки 404, 500• …и опять: придётся чистить!
Последствия ошибки №1
1. Отсутствие Primary Key (PK)2. Только суррогатный PK, но нет Unique Key(s) (UKs)3. Не используются Foreign Keys (FKs)
4. Не используются NOT NULLs:• неполные данные, бессмысленные записи, аномалии
• опять. придётся. чистить.
Последствия ошибки №1
1. Отсутствие Primary Key (PK)2. Только суррогатный PK, но нет Unique Key(s) (UKs)3. Не используются Foreign Keys (FKs)4. Не используются NOT NULLs
5. Не используются CHECK constraints:• мусор, некорректные данные
• опять. придётся. чистить.
Ещё более фундаментальное — типы данных
0. Типы данных● недостаточно жёсткие ограничения текста (text, varchar(5000) и т.п.)
легко приводят к проблемам отображения (вёрстка и т.п.)
Ещё более фундаментальное — типы данных
0. Типы данных● недостаточно жёсткие ограничения текста (text, varchar(5000) и т.п.)
легко приводят к проблемам вёрстки
● varchar(250) или text превратить в varchar(50) — долго, дорого!
Ещё более фундаментальное — типы данных
0. Типы данных● недостаточно жёсткие ограничения текста (text, varchar(5000) и т.п.)
легко приводят к проблемам вёрстки
● varchar(250) или text превратить в varchar(50) — долго, дорого!
● PK типа integer в больших таблицах — бомба замедленного действия:○ максимум 2147483647 (2.1 млрд)○ перейти на int8 (aka bigint) — долго, дорого!
Ещё более фундаментальное — типы данных
0. Типы данных● недостаточно жёсткие ограничения текста (text, varchar(5000) и т.п.)
легко приводят к проблемам вёрстки
● varchar(250) или text превратить в varchar(50) — долго, дорого!
● PK типа integer в больших таблицах — бомба замедленного действия:○ максимум 2147483647 (2.1 млрд)○ перейти на int8 (aka bigint) — долго, дорого!
● Регистрозависимое поле email (varchar вместо citext и нет lower()):○ аккаунты-дубликаты, жалобы «не могу войти»
А что если проверять данные в приложении?
Data Checks (format, constraints, etc)in App (Ruby or Python or PHP or …)
А что если проверять данные в приложении? Oops
Data Checks (format, constraints, etc)in App (Ruby or Python or PHP or …)
Проверка данных только в приложении — не надо так!
Data Checks (format, constraints, etc)in App (Ruby or Python or PHP or …)
Проверка данных — а как правильно?
App (Ruby or Python or PHP or …)
CHECKSКонтроль данных средствами СУБД:
- чёткая типизация,- все виды ограничений
целостности
Немного о JSON(b) – от неструктурированных данных к слабоструктурированным (semi-structured)
Делаем ключ color обязательным
Немного о JSON(b) – от неструктурированных данных к слабоструктурированным (semi-structured)
Делаем ключ color обязательным
Без ключа color JSON-значение не принимается
Не допускаем ошибку №10. Полноценно используем типы данных
a. citext для регистронезависимых сравненийb. varchar(XX) построжеc. int8 в таблицах, которые вырастут, — сразуd. int2 для экономии, когда знаем, что диапазон значений точно будет малe. timestamptz вместо timestampf. tstzrange, int4range, int8range, numrange + exclusion constraint
A Tour of PostgreSQL Data Types (2013), Tour de (PostgreSQL) Data Types (2017)
1. PK – обязательно
2. Максимально используем UKs (особенно если PK суррогатный — выявляем наш “natural key” и добавляем unique index!)
3. Используем FKs
4. Используем NOT NULLs
5. Используем CHECK constraints
Пример 2.1: инкремент
● Начинающий РНР-программист, задача массовой отправки писем.● Последовательный перебор по возрастанию User ID,
сохранение «указателя» на last User ID в БД.● Ошибки отправки отдельных писем не должны останавливать процесс.
2.1) СУБД сама может сделать инкремент!
Единственная транзакция, очень короткая,UPDATE с RETURNING,до каких-либо действий
Пример 2.2: обновление/удаление группы строк
Задача той самой «чистки» трубочиста. Ruby, опытный СТО.
Пример 2.2: обновление/удаление группы строк
Задача той самой «чистки» трубочиста. Ruby, опытный СТО.
Зачем-то «тянем» IDs на клиент
Пример 2.2: обновление/удаление группы строк
…и генерим длинный список из ID…(а что, если их миллионы?)
Зачем-то «тянем» IDs на клиент
Пример 2.2: обновление/удаление группы строкПолностью
Само удаление с перечислением ID через запятую. Предварительно убрали
из массива все [keep_id]
Пример 2.2: как это делать с CTE
Boilerplate:
Используем типы правильно: int2, timestamp with time zone
Пример 2.2: как это делать с CTE
Boilerplate:
ЗАБЫЛИ!!Natural Key — пара (year, month)
(т.к. «успокоились» на суррогатном PK...)
Пример 2.2: как это делать с CTE
Вставляем данные: У природы нет плохой погоды(особенно с 2000-то года)
Пример 2.2: как это делать с CTE
UK уже не создать, поздно пить «Боржоми»:
Время собирать камни дубликаты. С помощью четырёхэтажного CTE:
Выборка данных
Правка created у тех, что останутся + RETURNING *
Удаление лишних + RETURNING *
Анализ результата (сколько UPDATEd, сколько DELETEd)
Пример 2.2: как это делать с CTE. Action!
Так получаем IDs, которые будем удалять: все IDs группы за вычетом keep_id
Пример 2.2: как это делать с CTE. Action!
Так получаем IDs, которые будем удалять: все IDs группы за вычетом keep_id
… и вот так используем, с UNNEST, чтобы получить список ID для удаления
Пример 2.2: как это делать с CTE. Action!
У UPDATE и DELETE есть RETURNING *
…которые дают нам получить 2 числа — количество затронутых строк
Пример 2.2: O CTE и современном SQL
Внимание: если строк удаляем/обновляем много,может понадобиться поэтапная работа с пачками строк!
(чтобы не блокировать много и надолго; а также давать возможность отработать VACUUM-у)
– нам нужен цикл вызовов извне (что угодно: bash, pyhon, ruby, php, etc)
Пример 2.2: O CTE и современном SQL
О современном SQL
Максим Богук:● «Неклассические приемы оптимизации запросов» (2014)● How to teach an elephant to rock'n'roll (2017)
Markus Winand:● http://use-the-index-luke.com/● http://modern-sql.com/
Внимание: если строк удаляем/обновляем много,может понадобиться поэтапная работа с пачками строк!
(чтобы не блокировать много и надолго; а также давать возможность отработать VACUUM-у)
– нам нужен цикл вызовов извне (что угодно: bash, pyhon, ruby, php, etc)
Пример 2.3: тянем данные на клиент Часто (Machine Learning, Data Science) – вытягивание огромного количества данных на клиент / app server для анализа (R, Python)Имитация:• 1 млн строк• клиент (psql) в Германии• сервер (Postgres 9.6) — в США
SeqScan, получение 1 числа: ~3 сек
SeqScan, получение 10000000 чисел: ~22 сек
MADlib: Machine Learning inside your DBMS- A lot of ML algorithms implemented (more in each release):
- PL/Python- Very easy and quick start to do machine learning with your Postgres data
http://madlib.incubator.apache.org/
MADlib: Machine Learning inside your DBMS
Source: Apache MADlib: Distributed In-Database Machine Learning for Fun and Profit
Details: MADlib Design Document
Data Manipulation Logicin App (Ruby or Python or PHP or …)
Something*
* ElasticSearch, Sphix, Analytics DBMS, etc
Пример 2.4
Пример 2.4
Data Manipulation Logicin App (Ruby or Python or PHP or …)
Something*
* ElasticSearch, Sphix, Analytics DBMS, etc
Пример 2.4
Data Manipulation Logicin App (Ruby or Python or PHP or …)
Something*
* ElasticSearch, Sphix, Analytics DBMS, etc
Пример 2.4
App (Ruby or Python or PHP or …)
Something*
* ElasticSearch, Sphix, Analytics DBMS, etc
DataManipulation
Use:- functions, triggers,- Foreign Data Wrappers (FDW),- Logical Decoding
Database First! Что важно помнить
● Делать вообще всё в СУБД можно, но в некоторых случаях неоправданно○ пример: работа с внешними API с непредсказуемым временем
— оккупация CPU мастера может быть фатальной ошибкой)
Database First! Что важно помнить
● Делать вообще всё в СУБД можно, но в некоторых случаях неоправданно○ пример: работа с внешними API с непредсказуемым временем
— оккупация CPU мастера может быть фатальной ошибкой)
● CTE в PostgreSQL – optimization fence○ планировщик «не знает», какие есть возможности (индексы) у «соседнего этажа»○ это может быть как и проблемой, так и помощью в ускорении запросов
Database First! Что важно помнить● Делать вообще всё в СУБД можно, но в некоторых случаях неоправданно
○ пример: работа с внешними API с непредсказуемым временем — оккупация CPU мастера может быть фатальной ошибкой)
● CTE в PostgreSQL – optimization fence○ планировщик «не знает», какие есть возможности (индексы) у «соседнего этажа»○ это может быть как и проблемой, так и помощью в ускорении запросов
● Иногда всё же очень нужна «внешняя сила»○ пример: дробление UPDATE/DELETE на батчи. Должен кто-то вызывать нас
Database First! Что важно помнить● Делать вообще всё в СУБД можно, но в некоторых случаях неоправданно
○ пример: работа с внешними API с непредсказуемым временем — оккупация CPU мастера может быть фатальной ошибкой)
● CTE в PostgreSQL – optimization fence○ планировщик не знает, какие есть возможности (индексы) у «соседнего этажа»○ это может быть как и проблемой, так и помощью в ускорении запросов
● Иногда всё же очень нужна «внешняя сила»○ пример: дробление UPDATE/DELETE на батчи. Нужны вызовы извне цикле!
● SQL- и PL/pgSQL-код важно правильно «готовить»:○ Code Style, подсветка кода (есть плагин vim для PL/pgSQL)○ версионирование и «миграции» (sqitch, liquibase, etc)○ тестировать (pgtap)○ мониторить (pg_stat_statements.track = all)○ дебажить (простые raise notice; pl/pgsql profiler, debugger)
Database First! Checklist➜ Типы данных
✓ varchar(N) построже✓ int8 для PK больших таблиц✓ int2, где диапазон мал✓ timestamptz вместо timestamp
✓ tstzrange, int4range, etc+ exclusion constraintA Tour of PostgreSQL Data Types (2013),Tour de (PostgreSQL) Data Types (2017)
➜ Манипуляции с данными — прежде всего с помощью средств СУБД!!!✓ если ничего не мешает, ищем/меняем данные средствами СУБД
✓ можно ли «гонять» меньше данных по сети, поручить работу по подготовке данных СУБД?
✓ много ли строк меняются запросом? нужна ли работа частями?
✓ хранимки — не зло, PL/pgSQL — прекрасен, используем; но можно ли обойтись SQL (или SQL-функцией)?
✓ используем современный SQL: CTE, lateral join, работа с массивами, JSONb, агрегация, оконные функции
«Неклассические приемы оптимизации запросов» (2014), How to teach an elephant to rock'n'roll (2017)Cайты: Use-the-Index-Luke.com, Modern-SQL.comTwitter: @postgresmen
➜ Ограничения целостности (constraints):✓ 5 главных: PK, UK, FK, NOT NULL, CHECK;
✓ а какой у таблицы Natural Key? Создаем UK(s);
✓ интервалы/геометрия? + exclusion constraint;
✓ сложные случаи (проверка данных в нескольких таблицах, денормализация, etc) – используем хранимки, триггеры
PostgreSQL Documentation
Thank you!
Twitter: @postgresmen (new Postgres tweets daily!)
http://RuPostgres.org
http://Postgres.chat