Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
SlideShare a Scribd company logo
Database First!
О распространённых ошибках
использования РСУБД
Николай Самохвалов
@postgresmen
ru@postgresql.org
О чём и зачем этот доклад
БД — сердце 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
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
Проверка данных — а как правильно?
App (Ruby or Python or PHP or …)
CHECKS
Контроль данных
средствами СУБД:
- чёткая типизация,
- все виды ограничений
целостности
Немного о JSON(b) – от неструктурированных данных
к слабоструктурированным (semi-structured)
Немного о JSON(b) – от неструктурированных данных
к слабоструктурированным (semi-structured)
Делаем ключ color обязательным
Немного о JSON(b) – от неструктурированных данных
к слабоструктурированным (semi-structured)
Делаем ключ color обязательным
Без ключа color JSON-значение не принимается
Откуда взялось недоверие к СУБД?
Database First! О распространённых ошибках использования РСУБД
Роль MySQL в росте страхов и невежества
Роль MySQL в росте страхов и невежества
Роль MySQL в росте страхов и невежества
Роль MySQL и MariaDB в росте страхов и невежества
Не допускаем ошибку №1
0. Полноценно используем типы данных
a. citext для регистронезависимых сравнений
b. varchar(XX) построже
c. int8 в таблицах, которые вырастут, — сразу
d. int2 для экономии, когда знаем, что диапазон значений точно будет мал
e. timestamptz вместо timestamp
f. 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:
неиспользование возможностей SQL
для манипуляции данными
Пример 2.1: инкремент
● Начинающий РНР-программист, задача массовой отправки писем.
● Последовательный перебор по возрастанию User ID,
сохранение «указателя» на last User ID в БД.
● Ошибки отправки отдельных писем не должны останавливать процесс.
Пример 2.1: инкремент
Что получим, если потоков несколько?
3 потока, каждый
«отправил» по 100 писем
2.1) Что не так? Транзакция 1
Транзакция 2, использует
значение из первой
2.1) СУБД сама может сделать инкремент!
Единственная транзакция,
очень короткая,
UPDATE с RETURNING,
до каких-либо действий
2.1) СУБД сама может сделать инкремент!
3 потока, каждый
«отправил» по 100 писем
Пример 2.2: обновление/удаление группы строк
Задача той самой «чистки» трубочиста. Ruby, опытный СТО.
Пример 2.2: обновление/удаление группы строк
Задача той самой «чистки» трубочиста. Ruby, опытный СТО.
Зачем-то «тянем» IDs на клиент
Пример 2.2: обновление/удаление группы строк
…и генерим длинный список из ID…
(а что, если их миллионы?)
Зачем-то «тянем» IDs на клиент
Пример 2.2: обновление/удаление группы строк
Полностью IDs, которые оставим
Пример 2.2: обновление/удаление группы строк
Полностью
А это мы хотим «забрать с собой»
Пример 2.2: обновление/удаление группы строк
Полностью
А это мы хотим «забрать с собой»
… и забираем
Пример 2.2: обновление/удаление группы строк
Полностью
Само удаление с перечислением ID
через запятую. Предварительно убрали
из массива все [keep_id]
Пример 2.2: более правильное решение — CTE
Используем CTE (Common Table Expressions):
Пример 2.2: как это делать с CTE
Boilerplate:
Пример 2.2: как это делать с CTE
Boilerplate:
Не забыли: PK, NOT NULL
Пример 2.2: как это делать с CTE
Boilerplate:
Используем типы
правильно: int2,
timestamp with time zone
Пример 2.2: как это делать с CTE
Boilerplate:
ЗАБЫЛИ!!
Natural Key — пара (year, month)
(т.к. «успокоились» на суррогатном PK...)
Пример 2.2: как это делать с CTE
Вставляем данные:
Пример 2.2: как это делать с CTE
Вставляем данные: У природы нет плохой
погоды
(особенно с 2000-то года)
Пример 2.2: как это делать с CTE
Вставляем данные:
Но на самом деле есть.
Май 2017, ураган.
Пример 2.2: как это делать с CTE
Вставляем данные:
Ooops! INSERT вместо
UPDATE...
Пример 2.2: как это делать с CTE
Получили грязные данные, дубликаты:
Пример 2.2: как это делать с CTE
Получили грязные данные, дубликаты:
Пример 2.2: как это делать с CTE
UK уже не создать, поздно пить «Боржоми»:
Время собирать камни дубликаты. С помощью четырёхэтажного CTE:
Выборка данных
Правка created у тех, что
останутся + RETURNING *
Удаление лишних + RETURNING *
Анализ результата (сколько
UPDATEd, сколько DELETEd)
Пример 2.2: как это делать с CTE. Action!
Пример 2.2: как это делать с CTE. Action!
IDs, которые оставим
Пример 2.2: как это делать с CTE. Action!
А это мы хотим «забрать с собой»
Пример 2.2: как это делать с CTE. Action!
А это мы хотим «забрать с собой»
… и забираем
Пример 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: как это делать с CTE. Action!
У UPDATE и DELETE есть RETURNING *
…которые дают нам получить 2 числа
— количество затронутых строк
Пример 2.2: как это делать с CTE. Action!
Результат:
Пример 2.2: как это делать с CTE. Action!
Результат:
Пример 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 Logic
in App (Ruby or Python or PHP or …)
Something*
* ElasticSearch, Sphix, Analytics DBMS, etc
Пример 2.4
Пример 2.4
Data Manipulation Logic
in App (Ruby or Python or PHP or …)
Something*
* ElasticSearch, Sphix, Analytics DBMS, etc
Пример 2.4
Data Manipulation Logic
in 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
Data
Manipulation
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 constraint
A 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.com
Twitter: @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!)
ru@postgresql.org
http://RuPostgres.org
http://Postgres.chat

More Related Content

Database First! О распространённых ошибках использования РСУБД

  • 1. Database First! О распространённых ошибках использования РСУБД Николай Самохвалов @postgresmen ru@postgresql.org
  • 2. О чём и зачем этот доклад БД — сердце IT-системы РСУБД и SQL занимают лидирующие позиции. И это надолго Не использовать полноценно их возможности — глупость* ___________________ * Получается глупо, потому что: 1) качество хуже, 2) производительность ниже, 3) потом всё равно придётся исправлять (возможно, уже не вам)
  • 3. О докладчике • ФУПМ МФТИ / ИСП РАН / «Базы данных» • MoiKrug (2005), MirTesen (2007), Postila (2013) • PostgreSQL-консалтинг с 2007 в России, с 2013 в Калифорнии • #RuPostgres (http://rupostgres.org) — вторая крупнейшая митап-группа в мире • Postgres-твиттер (3500+ подписчиков): @postgresmen • ПК конференций HLj, BackendConf, Highload++, PgDay Russia
  • 4. Проблемы использования SQL & РСУБД • боязнь и незнание возможностей РСУБД/SQL: • для контроля данных • для манипулирования данными • архитектурные ошибки, связанные с этими страхами и невежеством
  • 6. Последствия ошибки №1 1. Отсутствие Primary Key (PK): • дубликаты, грязные данные; • нарушение реляционной модели и вытекающие проблемы (аномалии данных, неожиданные результаты JOIN и т.д.) • рано или поздно приходится чистить (долго, дорого)
  • 7. Последствия ошибки №1 1. Отсутствие Primary Key (PK): • дубликаты, грязные данные; • нарушение реляционной модели и вытекающие проблемы (аномалии данных, неожиданные результаты JOIN и т.д.) • рано или поздно приходится чистить (долго, дорого) 2. Только «суррогатный» PK, но нет Unique Key(s) (UKs): • «скрытые» дубликаты, опять грязные данные и проблемы • опять необходимость чистки (долго, дорого)
  • 8. Последствия ошибки №1 1. Отсутствие Primary Key (PK): • дубликаты, грязные данные; • нарушение реляционной модели и вытекающие проблемы (аномалии данных, неожиданные результаты JOIN и т.д.) • рано или поздно приходится чистить (долго, дорого) 2. Только «суррогатный» PK, но нет Unique Key(s) (UKs): • «скрытые» дубликаты, опять грязные данные и проблемы • опять необходимость чистки (долго, дорого) Числовые PK вида 1, 2, … («суррогатные») — это иллюзия правильного проектирования, легко забыть о потенциальных ключах!
  • 9. Последствия ошибки №1 1. Отсутствие Primary Key (PK) 2. Только суррогатный PK, но нет Unique Key(s) (UKs) 3. Не используются Foreign Keys (FKs): • orphans (осиротевшие записи) → аномалии, ошибки 404, 500 • …и опять: придётся чистить!
  • 10. Последствия ошибки №1 1. Отсутствие Primary Key (PK) 2. Только суррогатный PK, но нет Unique Key(s) (UKs) 3. Не используются Foreign Keys (FKs) 4. Не используются NOT NULLs: • неполные данные, бессмысленные записи, аномалии • опять. придётся. чистить.
  • 11. Последствия ошибки №1 1. Отсутствие Primary Key (PK) 2. Только суррогатный PK, но нет Unique Key(s) (UKs) 3. Не используются Foreign Keys (FKs) 4. Не используются NOT NULLs 5. Не используются CHECK constraints: • мусор, некорректные данные • опять. придётся. чистить.
  • 12. Ещё более фундаментальное — типы данных 0. Типы данных ● недостаточно жёсткие ограничения текста (text, varchar(5000) и т.п.) легко приводят к проблемам отображения (вёрстка и т.п.)
  • 13. Ещё более фундаментальное — типы данных 0. Типы данных ● недостаточно жёсткие ограничения текста (text, varchar(5000) и т.п.) легко приводят к проблемам вёрстки ● varchar(250) или text превратить в varchar(50) — долго, дорого!
  • 14. Ещё более фундаментальное — типы данных 0. Типы данных ● недостаточно жёсткие ограничения текста (text, varchar(5000) и т.п.) легко приводят к проблемам вёрстки ● varchar(250) или text превратить в varchar(50) — долго, дорого! ● PK типа integer в больших таблицах — бомба замедленного действия: ○ максимум 2147483647 (2.1 млрд) ○ перейти на int8 (aka bigint) — долго, дорого!
  • 15. Ещё более фундаментальное — типы данных 0. Типы данных ● недостаточно жёсткие ограничения текста (text, varchar(5000) и т.п.) легко приводят к проблемам вёрстки ● varchar(250) или text превратить в varchar(50) — долго, дорого! ● PK типа integer в больших таблицах — бомба замедленного действия: ○ максимум 2147483647 (2.1 млрд) ○ перейти на int8 (aka bigint) — долго, дорого! ● Регистрозависимое поле email (varchar вместо citext и нет lower()): ○ аккаунты-дубликаты, жалобы «не могу войти»
  • 16. А что если проверять данные в приложении? Data Checks (format, constraints, etc) in App (Ruby or Python or PHP or …)
  • 17. А что если проверять данные в приложении? Oops Data Checks (format, constraints, etc) in App (Ruby or Python or PHP or …)
  • 18. Проверка данных только в приложении — не надо так! Data Checks (format, constraints, etc) in App (Ruby or Python or PHP or …)
  • 19. Проверка данных — а как правильно? App (Ruby or Python or PHP or …) CHECKS
  • 20. Проверка данных — а как правильно? App (Ruby or Python or PHP or …) CHECKS Контроль данных средствами СУБД: - чёткая типизация, - все виды ограничений целостности
  • 21. Немного о JSON(b) – от неструктурированных данных к слабоструктурированным (semi-structured)
  • 22. Немного о JSON(b) – от неструктурированных данных к слабоструктурированным (semi-structured) Делаем ключ color обязательным
  • 23. Немного о JSON(b) – от неструктурированных данных к слабоструктурированным (semi-structured) Делаем ключ color обязательным Без ключа color JSON-значение не принимается
  • 26. Роль MySQL в росте страхов и невежества
  • 27. Роль MySQL в росте страхов и невежества
  • 28. Роль MySQL в росте страхов и невежества
  • 29. Роль MySQL и MariaDB в росте страхов и невежества
  • 30. Не допускаем ошибку №1 0. Полноценно используем типы данных a. citext для регистронезависимых сравнений b. varchar(XX) построже c. int8 в таблицах, которые вырастут, — сразу d. int2 для экономии, когда знаем, что диапазон значений точно будет мал e. timestamptz вместо timestamp f. 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
  • 31. Ошибка №2: неиспользование возможностей SQL для манипуляции данными
  • 32. Пример 2.1: инкремент ● Начинающий РНР-программист, задача массовой отправки писем. ● Последовательный перебор по возрастанию User ID, сохранение «указателя» на last User ID в БД. ● Ошибки отправки отдельных писем не должны останавливать процесс.
  • 33. Пример 2.1: инкремент Что получим, если потоков несколько? 3 потока, каждый «отправил» по 100 писем
  • 34. 2.1) Что не так? Транзакция 1 Транзакция 2, использует значение из первой
  • 35. 2.1) СУБД сама может сделать инкремент! Единственная транзакция, очень короткая, UPDATE с RETURNING, до каких-либо действий
  • 36. 2.1) СУБД сама может сделать инкремент! 3 потока, каждый «отправил» по 100 писем
  • 37. Пример 2.2: обновление/удаление группы строк Задача той самой «чистки» трубочиста. Ruby, опытный СТО.
  • 38. Пример 2.2: обновление/удаление группы строк Задача той самой «чистки» трубочиста. Ruby, опытный СТО. Зачем-то «тянем» IDs на клиент
  • 39. Пример 2.2: обновление/удаление группы строк …и генерим длинный список из ID… (а что, если их миллионы?) Зачем-то «тянем» IDs на клиент
  • 40. Пример 2.2: обновление/удаление группы строк Полностью IDs, которые оставим
  • 41. Пример 2.2: обновление/удаление группы строк Полностью А это мы хотим «забрать с собой»
  • 42. Пример 2.2: обновление/удаление группы строк Полностью А это мы хотим «забрать с собой» … и забираем
  • 43. Пример 2.2: обновление/удаление группы строк Полностью Само удаление с перечислением ID через запятую. Предварительно убрали из массива все [keep_id]
  • 44. Пример 2.2: более правильное решение — CTE Используем CTE (Common Table Expressions):
  • 45. Пример 2.2: как это делать с CTE Boilerplate:
  • 46. Пример 2.2: как это делать с CTE Boilerplate: Не забыли: PK, NOT NULL
  • 47. Пример 2.2: как это делать с CTE Boilerplate: Используем типы правильно: int2, timestamp with time zone
  • 48. Пример 2.2: как это делать с CTE Boilerplate: ЗАБЫЛИ!! Natural Key — пара (year, month) (т.к. «успокоились» на суррогатном PK...)
  • 49. Пример 2.2: как это делать с CTE Вставляем данные:
  • 50. Пример 2.2: как это делать с CTE Вставляем данные: У природы нет плохой погоды (особенно с 2000-то года)
  • 51. Пример 2.2: как это делать с CTE Вставляем данные: Но на самом деле есть. Май 2017, ураган.
  • 52. Пример 2.2: как это делать с CTE Вставляем данные: Ooops! INSERT вместо UPDATE...
  • 53. Пример 2.2: как это делать с CTE Получили грязные данные, дубликаты:
  • 54. Пример 2.2: как это делать с CTE Получили грязные данные, дубликаты:
  • 55. Пример 2.2: как это делать с CTE UK уже не создать, поздно пить «Боржоми»: Время собирать камни дубликаты. С помощью четырёхэтажного CTE: Выборка данных Правка created у тех, что останутся + RETURNING * Удаление лишних + RETURNING * Анализ результата (сколько UPDATEd, сколько DELETEd)
  • 56. Пример 2.2: как это делать с CTE. Action!
  • 57. Пример 2.2: как это делать с CTE. Action! IDs, которые оставим
  • 58. Пример 2.2: как это делать с CTE. Action! А это мы хотим «забрать с собой»
  • 59. Пример 2.2: как это делать с CTE. Action! А это мы хотим «забрать с собой» … и забираем
  • 60. Пример 2.2: как это делать с CTE. Action! Так получаем IDs, которые будем удалять: все IDs группы за вычетом keep_id
  • 61. Пример 2.2: как это делать с CTE. Action! Так получаем IDs, которые будем удалять: все IDs группы за вычетом keep_id … и вот так используем, с UNNEST, чтобы получить список ID для удаления
  • 62. Пример 2.2: как это делать с CTE. Action! У UPDATE и DELETE есть RETURNING *
  • 63. Пример 2.2: как это делать с CTE. Action! У UPDATE и DELETE есть RETURNING * …которые дают нам получить 2 числа — количество затронутых строк
  • 64. Пример 2.2: как это делать с CTE. Action! Результат:
  • 65. Пример 2.2: как это делать с CTE. Action! Результат:
  • 66. Пример 2.2: O CTE и современном SQL Внимание: если строк удаляем/обновляем много, может понадобиться поэтапная работа с пачками строк! (чтобы не блокировать много и надолго; а также давать возможность отработать VACUUM-у) – нам нужен цикл вызовов извне (что угодно: bash, pyhon, ruby, php, etc)
  • 67. Пример 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)
  • 68. Пример 2.3: тянем данные на клиент  Часто (Machine Learning, Data Science) – вытягивание огромного количества данных на клиент / app server для анализа (R, Python) Имитация: • 1 млн строк • клиент (psql) в Германии • сервер (Postgres 9.6) — в США SeqScan, получение 1 числа: ~3 сек SeqScan, получение 10000000 чисел: ~22 сек
  • 69. 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/
  • 70. MADlib: Machine Learning inside your DBMS Source: Apache MADlib: Distributed In-Database Machine Learning for Fun and Profit Details: MADlib Design Document
  • 71. Data Manipulation Logic in App (Ruby or Python or PHP or …) Something* * ElasticSearch, Sphix, Analytics DBMS, etc Пример 2.4
  • 72. Пример 2.4 Data Manipulation Logic in App (Ruby or Python or PHP or …) Something* * ElasticSearch, Sphix, Analytics DBMS, etc
  • 73. Пример 2.4 Data Manipulation Logic in App (Ruby or Python or PHP or …) Something* * ElasticSearch, Sphix, Analytics DBMS, etc
  • 74. Пример 2.4 App (Ruby or Python or PHP or …) Something* * ElasticSearch, Sphix, Analytics DBMS, etc Data Manipulation Use: - functions, triggers, - Foreign Data Wrappers (FDW), - Logical Decoding
  • 75. Database First! Что важно помнить ● Делать вообще всё в СУБД можно, но в некоторых случаях неоправданно ○ пример: работа с внешними API с непредсказуемым временем — оккупация CPU мастера может быть фатальной ошибкой)
  • 76. Database First! Что важно помнить ● Делать вообще всё в СУБД можно, но в некоторых случаях неоправданно ○ пример: работа с внешними API с непредсказуемым временем — оккупация CPU мастера может быть фатальной ошибкой) ● CTE в PostgreSQL – optimization fence ○ планировщик «не знает», какие есть возможности (индексы) у «соседнего этажа» ○ это может быть как и проблемой, так и помощью в ускорении запросов
  • 77. Database First! Что важно помнить ● Делать вообще всё в СУБД можно, но в некоторых случаях неоправданно ○ пример: работа с внешними API с непредсказуемым временем — оккупация CPU мастера может быть фатальной ошибкой) ● CTE в PostgreSQL – optimization fence ○ планировщик «не знает», какие есть возможности (индексы) у «соседнего этажа» ○ это может быть как и проблемой, так и помощью в ускорении запросов ● Иногда всё же очень нужна «внешняя сила» ○ пример: дробление UPDATE/DELETE на батчи. Должен кто-то вызывать нас
  • 78. 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)
  • 79. Database First! Checklist ➜ Типы данных ✓ varchar(N) построже ✓ int8 для PK больших таблиц ✓ int2, где диапазон мал ✓ timestamptz вместо timestamp ✓ tstzrange, int4range, etc + exclusion constraint A 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.com Twitter: @postgresmen ➜ Ограничения целостности (constraints): ✓ 5 главных: PK, UK, FK, NOT NULL, CHECK; ✓ а какой у таблицы Natural Key? Создаем UK(s); ✓ интервалы/геометрия? + exclusion constraint; ✓ сложные случаи (проверка данных в нескольких таблицах, денормализация, etc) – используем хранимки, триггеры PostgreSQL Documentation
  • 80. Thank you! Twitter: @postgresmen (new Postgres tweets daily!) ru@postgresql.org http://RuPostgres.org http://Postgres.chat