Роль разработчика (1). Базы данных.
Разработка бизнес приложений Лекция 5
Почему начинаем с БД
• БД есть практически во всех бизнес приложениях и не только (in process db)
• С проектирования БД проще всего начать проектирование корпоративного приложения (хотя это, быть может, и не лучший способ)– Альтернативный путь (DDD) – существенно
более сложен и рискован (требует большей квалификации)
Что такое БД и зачем они нужны
• Коллекция структурированных данных– большого их количества
• Цель БД – упростить операции с данными:– хранение данных– доступ к данным
Задачи решаемые БД
• Как организовать данные (логическая схема хранения)
• Как хранить данные (физическая схема хранения)• Как считывать данные (быстро!!)• Атомарность операций с данными• Согласованность (консистентность) данных• Изоляция пар-льных операций над данными• Надежность хранения данных в случае сбоев• Контроль доступа к данным
Правильное восприятие
• БД это черный ящик и набор некоторых правил, при соблюдении которых, он хорошо решает вышеуказанные проблемы
• Какие правила нужно знать– Как организовывать данные (лог. структура)– Как их запрашивать– Основы физ. устройства (индексы, для пр-сти)– Что такое транзакции, блокировки и как они
работают
Основные типы БД
• On-line transaction processing (OLTP)– Многочисленные изменения небольших кусков
данных, быстрые и относительно многочисленные update / insert
• On-line analytical data processing– «Тяжелые запросы» агрегированных
объединенных данных, не обязательно актуальных, редкие, но массовые insert / update
NoSQL движение
• Основная проблема scalability– Традиционные БД в силу архитектуры очень
плохо горизонтально масштабируются• Добавляем уменьшенные требования
(noACID) и другие проблемы (ООП) получаем массу решений– Google, Facebook, Amazon…– http://nosql-database.org/
БАЗЫ ДАННЫХ OLTP
Логическая организация данных
• Ученые много думали, спорили и решили:• Таблица (набор колонок и ограничений на них)– Колонка (тип данных + размер)
• Ограничения (в т.ч. на уникальность)
– Колонка• Первичный ключ
– Колонка • Внешний ключ (ссылка на первичный ключ
устанавливающее обязательное отношение между таблицами / строками)
Нормализация (искл. дублирования)
• Почему? Потому что научно обоснованно
СтудентОценкаГруппа
СтудентОценка
ГруппаId
Id группыНазвание
группы
СтудентОценкаIdГруппаId
Id оценкиПоложительная / отрицательная
ERD Диаграммы
• Рисуют заранее что бы не мучаться в процессе• Ключевое – сущность. То, с чем система работает.
– Чем управляет– Оперирует как объектом, понятием– У чего есть идентификатор
• 1-* : FK NOT NULL• 0..1 - *: FK NULL• *..* -> Таблица связка
SQL: язык запросов к лог. модели
• Декларативный язык описания того, чего хочется от БД
• Стандарт (SQL 92 / 99)– Однако, как обычно, каждый реализовал по
своему• В зависимости от БД разные наборы доп.
конструкций (функции, процедуры, циклы, переменные и пр.). T/SQL, PL/SQL
Все что нужно знать об SQL*
SELECT [DISTINCT] [TOP (выражение)] <список колонок> (выражений / подзапросов) [ FROM { <таблицы / подзапросы> } [ ,...n ] ] [ WHERE <условия, в т.ч. с подзапросами>] [ GROUP BY <{колонка / выражение }> [ ,...n ]] [ HAVING <условия для аггрегатов> ] [ ORDER BY { колонка / выражение } [ ,...n ] ]
* фраза приведена исключительно в рекламных целях
Простой select
SELECT *FROM PrizesWHERE SystemName = @p0
Сложный selectSELECT [t0].[Id], [t0].[UserName], [t0].[Password], [t0].[TempPassword], [t0].[TempPasswordEmail], [t0].[TempPasswordMobilePhone], [t0].[UserType], [t0].[Email], [t0].[IsEmailConfirmed], [t0].[EmailToBeConfirmed], [t0].[MobilePhone], [t0].[IsMobilePhoneConfirmed], [t0].[MobilePhoneToBeConfirmed], [t0].[MobilePhoneConfirmationCode], [t0].[IsBlocked], [t0].[IsDeleted], [t0].[RowVersion], [t0].[LastName], [t0].[FirstName], [t0].[MiddleName], [t0].[Sex], [t0].[BirthDate], [t0].[HomePhone], [t0].[HasAgreedToAdvertisement], [t0].[MobileRegionId], [t0].[OperatorId], [t0].[CityId], [t0].[PostAddressId], [t0].[DoesRequireMobileInfoUpdate], [t0].[RequestToDeleteDateTime], [t0].[RequestToDeleteChannel], [t16].[test], [t16].[Id] AS [Id2], [t16].[PostIndex], [t16].[RegionId], [t16].[RayonId], [t16].[CityId] AS [CityId2], [t16].[StreetId], [t16].[House], [t16].[IsEstate], [t16].[Building], [t16].[Stroenie], [t16].[Flat], [t16].[IsOffice], [t16].[Comments], [t16].[IsCorrect], [t16].[RowVersion] AS [RowVersion2], [t16].[Id2] AS [Id3], [t16].[TypeId], [t16].[Name], [t16].[DisplayName], [t16].[OrderNum], [t16].[UtcOffset], [t16].[FederalRegionId], [t16].[Id3] AS [Id4], [t16].[FullName], [t16].[ShortName], [t16].[DisplayName2], [t16].[OrderNum2], [t16].[test2], [t16].[Id4] AS [Id5], [t16].[RegionId2], [t16].[TypeId2], [t16].[Name2], [t16].[ContainsRegionCapitol], [t16].[IsVerified], [t16].[Id22] AS [Id6], [t16].[FullName2], [t16].[ShortName2], [t16].[DisplayName3], [t16].[OrderNum3], [t16].[Id5] AS [Id7], [t16].[RegionId3], [t16].[RayonId2], [t16].[TypeId3], [t16].[Name3], [t16].[Status], [t16].[OrderNum4], [t16].[UtcOffset2], [t16].[IsVerified2], [t16].[StreetRequired], [t16].[Id6] AS [Id8], [t16].[TypeId4], [t16].[Name4], [t16].[DisplayName4], [t16].[OrderNum5], [t16].[UtcOffset3], [t16].[FederalRegionId2], [t16].[Id7] AS [Id9], [t16].[FullName3], [t16].[ShortName3], [t16].[DisplayName5], [t16].[OrderNum6], [t16].[test3], [t16].[Id8] AS [Id10], [t16].[RegionId4], [t16].[TypeId5], [t16].[Name5], [t16].[ContainsRegionCapitol2], [t16].[IsVerified3], [t16].[Id23] AS [Id11], [t16].[FullName4], [t16].[ShortName4], [t16].[DisplayName6], [t16].[OrderNum7], [t16].[test4], [t16].[Id9] AS [Id12], [t16].[CityId2] AS [CityId3], [t16].[TypeId6], [t16].[Name6], [t16].[IsVerified4], [t16].[Id24] AS [Id13], [t16].[FullName5], [t16].[ShortName5], [t16].[DisplayName7], [t16].[OrderNum8]FROM [dbo].[Users] AS [t0]LEFT OUTER JOIN ( SELECT 1 AS [test], [t1].[Id], [t1].[PostIndex], [t1].[RegionId], [t1].[RayonId], [t1].[CityId], [t1].[StreetId], [t1].[House], [t1].[IsEstate], [t1].[Building], [t1].[Stroenie], [t1].[Flat], [t1].[IsOffice], [t1].[Comments], [t1].[IsCorrect], [t1].[RowVersion], [t2].[Id] AS [Id2], [t2].[TypeId], [t2].[Name], [t2].[DisplayName], [t2].[OrderNum], [t2].[UtcOffset], [t2].[FederalRegionId], [t3].[Id] AS [Id3], [t3].[FullName], [t3].[ShortName], [t3].[DisplayName] AS [DisplayName2], [t3].[OrderNum] AS [OrderNum2], [t6].[test] AS [test2], [t6].[Id] AS [Id4], [t6].[RegionId] AS [RegionId2], [t6].[TypeId] AS [TypeId2], [t6].[Name] AS [Name2], [t6].[ContainsRegionCapitol], [t6].[IsVerified], [t6].[Id2] AS [Id22], [t6].[FullName] AS [FullName2], [t6].[ShortName] AS [ShortName2], [t6].[DisplayName] AS [DisplayName3], [t6].[OrderNum] AS [OrderNum3], [t7].[Id] AS [Id5], [t7].[RegionId] AS [RegionId3], [t7].[RayonId] AS [RayonId2], [t7].[TypeId] AS [TypeId3], [t7].[Name] AS [Name3], [t7].[Status], [t7].[OrderNum] AS [OrderNum4], [t7].[UtcOffset] AS [UtcOffset2], [t7].[IsVerified] AS [IsVerified2], [t7].[StreetRequired], [t8].[Id] AS [Id6], [t8].[TypeId] AS [TypeId4], [t8].[Name] AS [Name4], [t8].[DisplayName] AS [DisplayName4], [t8].[OrderNum] AS [OrderNum5], [t8].[UtcOffset] AS [UtcOffset3], [t8].[FederalRegionId] AS [FederalRegionId2], [t9].[Id] AS [Id7], [t9].[FullName] AS [FullName3], [t9].[ShortName] AS [ShortName3], [t9].[DisplayName] AS [DisplayName5], [t9].[OrderNum] AS [OrderNum6], [t12].[test] AS [test3], [t12].[Id] AS [Id8], [t12].[RegionId] AS [RegionId4], [t12].[TypeId] AS [TypeId5], [t12].[Name] AS [Name5], [t12].[ContainsRegionCapitol] AS [ContainsRegionCapitol2], [t12].[IsVerified] AS [IsVerified3], [t12].[Id2] AS [Id23], [t12].[FullName] AS [FullName4], [t12].[ShortName] AS [ShortName4], [t12].[DisplayName] AS [DisplayName6], [t12].[OrderNum] AS [OrderNum7], [t15].[test] AS [test4], [t15].[Id] AS [Id9], [t15].[CityId] AS [CityId2], [t15].[TypeId] AS [TypeId6], [t15].[Name] AS [Name6], [t15].[IsVerified] AS [IsVerified4], [t15].[Id2] AS [Id24], [t15].[FullName] AS [FullName5], [t15].[ShortName] AS [ShortName5], [t15].[DisplayName] AS [DisplayName7], [t15].[OrderNum] AS [OrderNum8] FROM [dbo].[PostAddresses] AS [t1] INNER JOIN ([dbo].[Regions] AS [t2] INNER JOIN [dbo].[ObjectTypes] AS [t3] ON [t3].[Id] = [t2].[TypeId]) ON [t2].[Id] = [t1].[RegionId] LEFT OUTER JOIN ( SELECT 1 AS [test], [t4].[Id], [t4].[RegionId], [t4].[TypeId], [t4].[Name], [t4].[ContainsRegionCapitol], [t4].[IsVerified], [t5].[Id] AS [Id2], [t5].[FullName], [t5].[ShortName], [t5].[DisplayName], [t5].[OrderNum] FROM [dbo].[Rayons] AS [t4] INNER JOIN [dbo].[ObjectTypes] AS [t5] ON [t5].[Id] = [t4].[TypeId] ) AS [t6] ON [t6].[Id] = [t1].[RayonId] INNER JOIN ([dbo].[Cities] AS [t7] INNER JOIN ([dbo].[Regions] AS [t8] INNER JOIN [dbo].[ObjectTypes] AS [t9] ON [t9].[Id] = [t8].[TypeId]) ON [t8].[Id] = [t7].[RegionId] LEFT OUTER JOIN ( SELECT 1 AS [test], [t10].[Id], [t10].[RegionId], [t10].[TypeId], [t10].[Name], [t10].[ContainsRegionCapitol], [t10].[IsVerified], [t11].[Id] AS [Id2], [t11].[FullName], [t11].[ShortName], [t11].[DisplayName], [t11].[OrderNum] FROM [dbo].[Rayons] AS [t10] INNER JOIN [dbo].[ObjectTypes] AS [t11] ON [t11].[Id] = [t10].[TypeId] ) AS [t12] ON [t12].[Id] = [t7].[RayonId]) ON [t7].[Id] = [t1].[CityId] LEFT OUTER JOIN ( SELECT 1 AS [test], [t13].[Id], [t13].[CityId], [t13].[TypeId], [t13].[Name], [t13].[IsVerified], [t14].[Id] AS [Id2], [t14].[FullName], [t14].[ShortName], [t14].[DisplayName], [t14].[OrderNum] FROM [dbo].[Streets] AS [t13] INNER JOIN [dbo].[ObjectTypes] AS [t14] ON [t14].[Id] = [t13].[TypeId] ) AS [t15] ON [t15].[Id] = [t1].[StreetId] ) AS [t16] ON [t16].[Id] = [t0].[PostAddressId]WHERE ([t0].[Email] = @p0) AND (NOT ([t0].[IsDeleted] = 1))
Физическая схема хранения
• Таблица – представляем как плоский фаил• Кластерный индекс– Физически сортирует таблицу (соотв. один)– Используется как ссылка на запись в других
индексах (и FK)• Для ускорения запросов (поисков) – обычные
индексы– Чаще всего: b-деревья, но могут быть и другие– Ключ (колонка или неск.) и «включенные колонки»
Простой практический совет
• Используйте суррогатные, возрастающие (IDENTITY) первичные ключи и кластерные индексы– Гарантированно уникальны (!)– Единообразно и просто в понимании– Экономят размер (особенно на др. индексах)– Увеличивают производительность в большинстве
случаев• http
://sqlskills.com/BLOGS/KIMBERLY/category/Clustering-Key.aspx
Оптимизация запросов
• Перезапись SQL (реляционная алгебра)– Раскрыть подзапросы– Переставить и раскрыть логические операторы– …
• Выбор методов выполнения (на осн. эвристик, или статистических оценок)– Алгоритмы доступа: scan / seek и откуда– Алгоритмы сортировки / join’а (nested loops, merge, hash)
• Все это – план запроса– Планы - кэшируются
Например
• Разные варианты стратегий join’а– Nested loops– Merge– Hash
• Зачем нужны включенные в индекс колонки
План запроса
• Позволяет видеть решения оптимизатораSELECT COUNT(*)FROM PrizesWon as pwINNER JOIN Prizes AS prizes ON prizes.Id = pw.PrizeIdWHERE (pw.OrderId IS NOT NULL) AND (pw.PrizeType = 'Payment') AND (pw.UserId = 544496) AND (prizes.ActionName = 'NCP 2011 Baltika23')
12
3
4
5
6
1
2
3
4
56
Транзакции
BEGIN TRANSACTIONSql-1 Sql-2 . . . Sql-n COMMINT or ROLLBACK TRANSACTION
Требования к транзакциям (ACID)
• Atomic (атомарность): все или ничего • Durable (надежность): если коммит, то навсегда • Consistency (консистентность): соблюдаются
ограничения логической схемы– Все три надежно и прозрачно обеспечиваются
реализацией БД• Isolation (изоляция): дает правильные
результаты при любых параллельных транзакциях
Параллелизм: два подхода
• Пессимистический параллелизм – Обеспечивается блокировками
запрашиваемого ресура (остальные ждут)• Оптимистический параллелизм– Обеспечивается версиями (или проверкой всех
полей), т.е. через обнаружение конфликтов
Пессимистическая модель
Оптимистическая модель
Уровни изоляций и проблемыСотрудник Отдел Зарплата
Иван Обувной 10К
Александр Обувной 15К
Олеся Игрушек 12К
Ира Игрушек 8К
Вася Обувной 14К
T1: всем в обувном поднять ЗП на 10%T2: Переместить Олесю и Иру в обувной
• Результат д.б. аналогичный последовательному выполнению операций (в любом порядке)
Решение
• Разделяем на маленькие кусочки (в БД чаще всего строки) и блокируем на время транзакции всё что мы трогаем. Держим блокировки до конца транзакции
• Для оптимизации можно использовать R/W блокировки
По этому поводу можно встретить термин двухфазное блокирование – если не хотите писать БД – не вдавайтесь в детали.
Проблемы
• Гранулярность накладываемых блокировок– Select avg(зарплата)– Эскалации
• Что делать если не получается получить лок– Ждать (таймаут)
• Дедлоки.T1:lock(a), T2:lock(b), T1:locl(b), T2:lock(a)– Проверять и выбирать жертву или таймаут– Повтор выполнения (возможен голод)– Блокировать только все сразу, вперед или в одном
порядке (нереально)
Еще проблемыСотрудник Отдел Зарплата
Иван Обувной 10К
Александр Обувной 15К
Олеся Игрушек 12К
Ира Игрушек 8К
Вася Обувной 14К
T1: всем в обувном поднять ЗП на 10%T2: Переместить Олесю и Иру в обувной
• Даже если блокировать все строки, новые записи могут попасть под условие (во время scan)– Range locks (Index) / TABLE locks. И то и то – очень грустно
(WHERE IS NULL, верхушка индекса)
Пессимистическое решение
• Не мешать OLTP с OLAP• Ждать• Подбирать уровни изоляции и допускать
ошибки– Read uncommitted (без блокировок, только
атомарность)– Read committed (R временно, W до конца)– Repeatable read (W, R до конца на строки)– Serializable (W, R до конца + Range locks)
Оптимистическое решение (2)
• Изоляция на основе версий (оптимистический параллелизм)
• Легко гарантирует согласованное чтение• Проблемы с записью (при конфликте – откат
транзакции)• Исследования показали что кроме крайних
случаев менее эффективно чем блокировки, хотя как опция – поддерживается в современных БД
Восстановление и резервирование
• Full / incremental backup• Журнал транзакций• Целостность данных на физическом уровне• Различные стратегии mirror / репликации
для дублирования в realtime / построения схем master / slave
Распространенные БД
• MySQL – OS, простая, популярная, куплена oracle
• PostgreSql– OS, более взрослая и сложная
• Oracle– Enterprise АД, очень дорого и мощно
• MS SQL Server– Серьезный продукт с человеческим лицом
MS SQL Server (Demo)
• Enterprise Studio– Intellisense– План запроса
• Books online• SQL Server profiler• Tuning advisor
Общие советы разработчикам
• До последнего полагайтесь на базу данных в– Производительности выборок– Сохранении консистентности данных– Оптимизации запросов– Блокировках и обеспечении параллелизма– Резервном копировании
• Почему? Потому что их писали очень умные люди очень много лет– Отказ от БД – только после измерения реальной
производительности (тест / прототип)
Ресурсы
• SQL Server books online– http://
msdn.microsoft.com/en-us/library/ms130214.aspx
– http://www.microsoft.com/sqlserver/en/us/editions/express.aspx
• Wikipedia• Произвольная книга по нужной вам СУБД• http://softwarestencils.com/ (visio stencils)
Темы для докладов
• AOP• Kanban / Lean• SCRUM: Team / ScrumMaster – подробнее
про процесс (DS, Retro, SprintPlan, Demo…)• Portfolio management, BMG (Alex Ostervald),
Scrum of Scrum• NoSql БД
Лабы• Открытые данные
– http://www.apps4russia.ru/, http://apps4russia.reformal.ru/, http://data.worldbank.org/
• Готовое:– http://minenergo.gov.ru/activity/statistic/,http
://www.fms.gov.ru/about/ofstat/, http://www.federalspace.ru/main.php?id=10, http://ivan.begtin.name/2011/10/02/gosuslugijson/
• Повышенный балл:– Или наличие БД– Или наличие веб интерфейса– Индивидуальное задание (для тех, у кого уже есть что показать)
• Стажировка (Тестер / Разработчик)– MS: C#, MS MVC, MS SQL Server