Я так понял, после прочтения книжки по постгрес Алексей открыл для себя что-то новое и интересное и решил поделиться этим с остальными) спасибо большое!
@@АндрейСветлоков-з2ш ну не надо басней, 49.5% контента для людей уровнем выше джунов это конференции, ещё 49.5% это видосы с неподражаемым индийским акцентом по скидке за 480 рублей и 1% это видосы вроде этого
Алексей! Доброго времени. Внедрю пожелание лайфхака. Следующее видео делайте в соседней комнате. Мы-же тоже дзырим ваши замечательные апартаменты. Пыточную из прошлых видео изучили, теперь понятно место откуда вещали прошлые видосы. Похоже что дальняя коричневая дверь стоит на вентиляции микроклимата. Фигасе. Спасибо за идею. За окна понятно, но двери - это свежо!😂 Отличный контент. Ну сказать что-нибудь надо, вот и сказал. Вот...
Если phone_num PK, то чел. уже не сможет его поменять. PK -- это не только UNIQUE NOT NULL, но ещё и read-only. Всё же не нужно юзать phone_num в качестве PK. Это сущность/запись клиент-человек. Даже здравый смысл подсказывает нам, что нельзя его отождествлять/идентифицировать/привязывать к номеру телефона.
Главный недостаток естественного ключа заключается в том что как только на запись с таким ключом появляется ссылка из другой таблицы, то менять этот ключ придётся как в самой таблице, так и во всех таблицах где на запись есть ссылки. Причём делать это придётся в одной транзакции с отложеной проверкой целостности. А ошибиться пользователь может очень легко и ошибочно вбитый номер телефона или паспорта который оказался ключом может вылиться в ряд неприятностей. Поэтому если у вас на таблицу есть ссылки, то очень хорошо подумайте прежде чем делать в этой таблице естественный ключ.
Вцелом согласен, но тут стоит ещё заметить, что номер телефона, номер паспорта, мыло, номер аськи - это всё примеры неудачного естественного ключа, как раз потому, что они могут меняться. Примеры более удачных ключей - это налоговые номера (ИНН, TIN, NIF и др.) и номера социального стразования (СНИЛС, SSN и др.), так как они назначаются один раз и на всю жизнь.
@@vryaboshapko в таких ключах есть ещё одна проблема. Это опечатки, а ключ уникальный. И вот оператор вводит, например СНИЛС или номер серию паспорта, если это составной естественный ключ. И делает там опечатку в одной цифре. А в другую организацию приходит человек именно с таким номером, например паспорта. И в той организации ввести его данные не могут и разобраться без помощи разработчиков тоже не могут, потому что опечатку сделала другая организация. В итоге в базе данные не правильные и ввести правильные нельзя. В общем использовать естественные ключи можно, но как по мне с таким количеством нюансов - ну его...
@@ВладимирБарков-п6ц для этого в СНИЛС и ИНН зашита проверка целостности. Грубо говоря, если хитро сложить первые цифры, получится последняя (точные алгоритмы публичны и легко гуглятся). Такая же, кстати, есть для номеров баноковских карт, но это не относится к теме естественных ключей). Плюс есть публичные базы данных, по которым можно провалидировать, например, что номер соответствует ФИО или дате рождения. А номер паспорта точно нельзя использовать как естественный ключ (даже как часть составного) по той же причине, что и номер телефона: он меняется. Это уникальный номер документа, а не человека.
Частный случай префиксных ключей - это номера паспортов и других подобных документов. Они содержат серию и номер. Серия назначена по территориальному принципу, а номер - это просто счётчик. То есть, каждому актору, имеющему право генерировать первичный ключ, присваиватеся свой префикс, а он внутри себя следит за простым счётчиком. Причём, счётчик персистится с помощью write ahead log: каждый новый паспорт заносится в журнал, и ему присваивается номер на единичку больше от предыдущего занесённого. Ничто не ново под Луной, как говорится)
Классный первичный ключ - сотовый телефон Только у пользователя может быть несколько телефонов, ну и телефон можно потерять. На мой взгляд - Естественные ключи использовать крайне ненадежно. Вы должны быть уверены, что естественный ключ уникален в рамках проекта, концов которой не видно. (Подразумевается что вы работаете в проекте, а не пришлый наемник для решения одной задачи) Префиксы в начале - это реинкарнация Венгерской нотации от MS 😃
Один телефон может быть главным, остальные будут сохранены дополнительно (если нужно их сохранять). Тут больший вопрос по смене телефона, если он PK, то надо будет менять потенциально много записей в разных таблицах, что может быть тяжело. Поэтому пример с телефоном может быть не лучший, да, но мне важнее было показать суть.
Доступный и подробный разбор вариантов первичных ключей, спасибо за информацию! Наверное нет смысла спорить о применении в первичных ключах int или даже smallint, потому что если такая надобность будет, то разработчик это увидит и применит. А кто-то посчитает что необходимости применения 2-х или 4-х байтового числового первичного ключа не случается никогда.
Я знаю примерно три случая, когда можно использовать small int в качестве первичного ключа, и во всех трёх случаях есть решение в виде естественного аналога: это списки валют, стран и языков. На все три есть ISO с буквенными кодами, и такие коды будут сильно удобнее, потому что их после минимальной тренировки может читать человек. Не то, чтобы я утверждаю, что small int категорически не нужен, просто вспонилось несколько частных случаев.
Спасибо за видео! У меня тоже была как проблема с инкрементом sequence, когда я прям на горячем проде с 150k rpc в секунду добавил строку вручную с явным указанием id. И как посыпались ошибки! Ух... Хорошо быстро поправил sequence номер.
У ulid есть некоторая проблема в том, что инстансы приложения генирующие улиды могут находиться на разных физических машинах с рассинхроном времени, проблему рассинхрона ещё человечество до конца не решило. Поэтому в распределенной системе не факт, что каждый следующий сгенерированный ulid будет лексикографически старше предыдущего.
@@vladislavstepanov7591 фишка ULID в том, что один ULID больше другого, если он сгенерировался позже на 1мс, чем первый. Но если на разных тачках есть рассинхрон, то польза от ULID'a нивелируется и проще использовать UUID v4
По примеру с естественным ключом в виде номера телефона: - очень удобно, особенно когда пользователь хочет поменять номер телефона. Т.е. что проще, посмотреть по номеру телефона id и далее делать все тоже самое по id или при смене телефона иметь ад по сохранению целостности данных? Проблема в том, что зачастую многие естественные ключи не являются абсолютно константными и это создает гораздо большую проблему, чем та польза, о которой говориться. P.S. да, я читал статью про IDотов, к сожалению не могу придумать каламбур про Естественно-отов =)
23:00 как ни странно иногда вставка уидов может быть быстрее чем вставка в условный bigint. Особенно если база уже большая и не новая, по той же как раз причине, что вы и описали. При очень интенсивной вставке, если вставка идёт одновременно из множества сессий, то возможны проблемы за конкурентный доступ последней страницы в которую данные льются, а при уидах вставка происходит в рандомные страницы в разных местах индекса и сессии друг другу не мешают)
При интенсивной вставке в таблицу где pk - uuid, будет происходить очень частая и тяжёлая перестройка индекса, из-за этого как раз и может происходить существенная просадка по производительности.
Алексей, просьба от благодарных радиослушателей. SQLite, либо хотя бы с точки зрения самой базы, либо, если можно, в виде работы с питоновским модулем sqlite3. Проекты проектами, но на этой штуке крутится процентов 80 всего интернета и примерно три четверти всех приложений. Я колупаюсь уже второй месяц, так и не нашёл заявленный режим "многопоточность" по умолчанию, до сих пор корячу через исключения. Плюс pragma их фирменная. Можно, конечно, и самому догрызть, но объяснение от опытного человека намного эффективнее.
не досмотрел еще, и не знаю подняли ли эту тему, но хочу сказать, что правильные первичные ключи важны для производительности некоторых кейсов пагинации (я говорю про то, что зачастую правильный первичный ключ - это единственный способ сделать правильную пагинацию без использования медленного оффсета)
Спасибо за контент! А я даже не думал что такие способы есть. На мой взгляд id должен быть наподобии штрих-кода, но чтоб информация там была зашифрована для стороннего пользователя.
Пример с телефоном очень показательный. Есть у нас история действий пользователей с неким номером телефона. Казалось бы удобно. Но люди бывают что меняют номера телефонов. и если пользователь сменит свой телефон он лишиться всей своей истории.
Мысль про ключи естественные ок, но пример с номером телефона плох(опасен). Клиент может захотеть сменить номер телефона и вот тут придётся менять ваш PK, что выльется в проблемы и боль миграций.
12:50 - при этом надо понимать, что естественный первичный ключ для справочника тех же пользователей - это та еще мина замедленного действия (помимо потребности хранить длиннющий UID или 11 знаков номера телефона во всех связанных таблицах, где могут быть сотни миллионов записей). Из того же примера в видео: вот пользователь деактивировал сим-карту и мобильный оператор продал этот номер спустя время новому физ.лицу :) Логика сломается уже на этапе регистрации в приложении где-то на бэкенде при обращении к базе. Про момент защиты персональных данных уже в ролике озвучено - тут сразу получается не вариант с естественным первичным ключом
Про использование identity column было очень интересно. Не был в курсе подобной опции. Впрочем, при грамотном использовании serial не доставит никаких проблем. Достаточно целиком отдать генерацию id на откуп базы данных
4:08 а потом пользователь захочет сменить почту) и полетел наш первичный ключ во всех связных таблцах. Первичный ключ лучше всегда делать искусственным.
Конечно это просто пример, хотя не вижу проблем с заменой email, это же не автоинкремент и поле изменять можно. Будут проблемы с обновлением связей - да, но решаемо. Никогда не говори всегда. Возможно email был не самым лучшим примером, но вот например у тебя есть таблица стран и у стран есть Abbreviation - Name со значениями RU - Россия, US - США. Не нужен тут искусственный ключ, если первичный ключ на Abbreviation будет уникальным, и гарантирует уникальность Abreviation.
@@programisliтак вот чтобы потом не думать как исправлять, надо тупо делать искусственный ключ. По этой же причине надо не думать и делать сразу микросервисную архетиктуру, потому что сделав монолит через года можно сильно пожалеть.Сколько таких случае когда куда не глянь а все монолит свой пилят на сервисы? Всетоки есть практики - железны, которые уже написаны кровью
Использовать всегда только один подход это упрощение жизни, упускаются всегда какие-то случаи. Как писал в соседнем треде, телефон сейчас это почти всегда обязательное к заполнению и уникальное поле, однозначно идентифицирующее клиента - как бы вы ни считали это идиотизмом. И даже вопросы смены решаются, удивительно.
@@t0digital все решается, только нафига перебирать все таблицы и заменять связи? Когда есть скажем так профессиональные подходы, я имею ввиду некое решение сбалансированное которые не подведет никогда как показывает практика. И чего кривляться когда оно надежное? Это как многие вещи в разработке стали стандартами дефакто, например докер. Чтобы ты не делал всегда все делай в контейнерах - простой рецепт решающий все будущие проблемы. Или микросервисы - никогда не делай монолиты иначе рано или поздно обожжешься на масштабируемости.
Алексей, а что по поводу скорости поиска по uuid ключам по сравнению с числовым типом? Кажется сравнение строк должно сильно ухудшить этот показатель. Или для uuid используется какое-то хитрое быстрое сравнение?
UUID это не строки, а 128 бит и нужно сравнивать 128 бит, что достаточно быстро. Но int будет занимать меньше месте на диске и если это внешний ключ то по числу поиск будет чуть более эффективнее, потому что меньше нужно держать в памяти или читать с диска. Просто индекс будет компактнее
128 бит - это 16 байт. То есть, сравнение двух UUID-ов занимает столько же времени, сколько сравнение двух строк из 16 символов (если речь не про юникод, конечно). Но стандартоне текстовое представление UUID-а (123e4567-e89b-12d3-a456-426614174000) - это 36 байт, то есть, сравнение двух строковых представлений UUID-ов занимает больше времени, чем сравнение двух честных UUID-ов. Кроме того, UUID в памяти может быть представлен не как набор байт, а, например, как два лонга (64-битные целые), и тогда сравнене будет ещё быстрее, потому что современные 64-битные процессоры могу сравнивать 64-битные целые за один такт.
@@stripeberry вы имеете ввиду первичный ключ это bigInt, а для uuid создаем индекс, примерно так ? CREATE TABLE your_table_name ( id SERIAL PRIMARY KEY, uuid UUID NOT NULL, -- Здесь добавьте остальные поля вашей таблицы -- Если нужно добавить внешние ключи или связи, то можете добавить их здесь ); -- Создание индекса для ускорения поиска по uuid CREATE INDEX idx_uuid ON your_table_name(uuid);
Спасибо, послушал с интересом. Единственно не согласен с настойчивой рекомендацией использовать bigint в качестве ПК. Обычного int хватает в 99%, если только вы не собираетесь автоматизировать весь мир. В любом случае нужно понимать на какие объемы проектируется система, и принимать проектные решения исходя из этого. Еще раз спасибо, хорошая подача материала!
UUID v6 выглядит перспективно, но я бы вообще пошел дальше и использовал nanoTime, а для формирования рандомной части оставил последние 11 байт (12 символов).
Про телефон посмеялся :)) кто то еще делает по ним первичные ключи ? :) Сделали, а потом юзер перестал оплачивать телефон, компания телефон отбирает, и передает ДРУГОМУ :))) "здрасте приехали" :)
Натуральные первичные ключи это велосипед из костылей. Это грабли, подложенные если не себе, то следующему программисту/админу. Если не с уникальностью, то с производительностью. В общем, натуральные ключи могут использоваться, но только в исключительных случаях, по уважительным причинам.
@@t0digital Первичный ключ по строке - глупость. Это намеренное снижение производительности и раздувание размера БД (т.к. это поле копируется во все связанные таблицы). Это нарушение сложившихся практик без уважительных причин. Ну и весь ворох оговорок, которые вы и сами озвучивали.
@@t0digital Кроме того. Страна может сменить название и из-за такого дизайна БД, нам придется менять все ключи в таблицах. Страна также может распасться и объединиться с другой (upd: что, впрочем, в любом случае потребует коррекции более чем одной таблицы).
Приветствую! Спасибо за видос, очень актуально и полезно. Интересно ваше мнение по вопросу: где удобнее всего и эффективнее разрабатывать схему БД? В кансоле сразу, или может в pgAdmin, а может по старинке на листочке схему рисовать?)
Для проекта, когда думаю о данных, сущности рисую иногда сначала на бумаге, чтобы было наглядно. А создавать таблицы уже где угодно. Миграциями как правило, джанговыми или алембик
@@t0digital Имею ввиду, что бывают случаи, когда генерация айди не эффективна на уровне базы. Например кейс когда нужен высокий перфоманс и применяется вставка батчем.
Как можно проверить, что uuid_v6 (ulid, objectId) в качестве primary_key работает быстрее на больших объемах данных, чем uuid v4? Какой тест тут лучше применить? Для записи приходит в голову что-то типа "генерируем 10ккк uuidV4, затем в другой таблице 10ккк uuidV6, сравниваем время". А для чтения это как лучше проверить?
Как разработчик DWH я не могу согласиться со многими тезисами и заявлениями. Когда вы говорите о подходах и «структуре/архитектуре бд», следует в первую очередь ссылаться на нормализацию и нормальные формы. Если углубиться, то станет очевидным вывод о том, что натуральные ключи имеют право на жизнь, но исключительно в прикладном смысле.
@@t0digital натуральный ключ это сущность из реального мира, отражаемая в СУрБД. Сущности, отражаемые в СУрБД должны иметь первичный ключ внутри самой бд (это называется суррогатный ключ, и лучше если он сквозной), а данные должны находиться в соответствующей нормальной форме. Иначе, доработка, масштабирование, аналитика будут очень осложнены. А вот таблицы с некоторыми «фактами», например таблицы с транзакциями, лучше конечно снабжать ключами типа UUID, GUID, etc. Добавляя унифицированный суррогатный ключ клиента, как субъекта операции. Так вам будет норм даже с десятком миллиардов записей в таблице с транзакциями.
@@artetl «натуральный ключ это сущность, отражаемая в СУРБД» То есть сущность, отражаемая в СУРБД это натуральный ключ. Таблица, которая хранит данные по сущности заказов, это натуральный ключ. Понятно:)
@@t0digital на натуральные ключи принято навешивать суррогатные ключи, которые будут первичными ключами для идентификации, например, клиента. Иными словами так.
Проблема использования номера телефона в качестве первичного ключа не столько в безопасности, сколько в потенциальных проблемах в случае смены телефона
А что если префиксную часть сделать модифицируемой по длине? Тогда мы сможем выбирать приоритет на скорость записи или скорость чтения из БД соответственно по скорости формирования и чтения индекса
а если использовать "generated always as identity" то не будет проблем при импорте? Например если одна запись удалена просто заново сгенерировать не вариант.
@@t0digital это печальная реальность. Я так в некоторых сервисах вижу чужие старые данные. И не могу пользоваться логином, если вдруг сменил свой номер
Ого, а интересно, как консоль на маке собирает таблицу для оторбражения? Красиво же выглядит, не то, что поплывшие таблицы на символах -- | А не, тоже плывёт.
Да просто потестируйте сами. Сгенерите данных, сколько у вас будет в табличке, сделайте analyze, чтобы обновилась статистика, и сравните выборку без индекса и с индексом. Индекс - не гарантия эффективного выполнения запроса, он даже не обязательно будет использоваться в конкретном запросе, это как планировщик решит.
Естественные ключи - это прям байтище на комментарии ))) Вот в тот мне примере, что мешает ТП дать не номер телефона, а ИД пользователя?:) Или сначала выбрать ИД в переменную, а потом его во всех запросах, а не джойнить? В 99.9% случаев естественные ключи не нужны
Номер телефона как первичный ключ или логин категорически делать нельзя, как бы это ни было "удобно" для запросов. Человек потерял телефон, и? Будем обновлять кучу таблиц, меняя значение ключа на новый номер? Или дадим пользователю зарегать новый аккаунт? Тут вообще дыра в безопасности: серез некоторое время старый номер мобильный оператор выдаст какому-то другому человеку, тот может попробовать зарегистрироваться на ресурсе, очень удивится, что логин занят, тыкнет в линк "восстановить пароль", и получит доступ к личному кабинету старого владельца, где может находиться информаумя, которую он не имеет права видеть.
Много сервисов сейчас пускает по телефону и смс. Озон и др. Это говорит о том, что поле телефона там а) уникально б) обязательно к заполнению. Значит, является потенциальным ключом.
05:57 а зачем использовать для этого именно композитный первичный ключ-то? Первичный ключ - он для идентификации. Для избежания дублирования просто создаёшь индекс уникальности по нужным колонкам. Это то, что делает первичный ключ, кстати.
Это порождает избыточность. Удобство искусственных первичных ключей зависит, в первую очередь, от запросов. Пример: settings - настройки с учётом года. Входить в эту таблицу мы всегда будем через , и ссылок из других таблиц на settings часто тоже нет. Итог - в данном случае лучше составной естественный ключ
@@alexgorodecky1661 Я о другом. Выбирайте вариант, который Вам нужен. Но конкретно задача избавления от дублирования решается уникальным индексом, для неё не нужно накрывать колонки первичным ключом.
Блин хорошая тема, но что за пример с номером телефона, такая дичь даже озвучиваться не должна как возможная. Там сразу столько проблем, рекомендую статью на хабре про заблуждения программистов о номерах телефона. К той статье ещё бы добавить в заблуждения: "думать что у пользователя из X страны номер телефона тоже из страны X. Уже приходилось видеть регистрацию где номер телефона захардкожен с +7. Ну и с ключом на базе телефона рано или поздно вам нужно будет внести нового пользователя у которого снова повторяющийся телефон. Не усложняйте жизнь себе и людям которые будут поддерживать системы
Я так понял, после прочтения книжки по постгрес Алексей открыл для себя что-то новое и интересное и решил поделиться этим с остальными) спасибо большое!
хоть кто-то читает эти унылые книжки)
Алексей дал значительно больше чем там есть
@@sio80orel унылые можно не читать) про книжку о postgres я бы такого не сказал
Топ контент, так нехватает чего то выше джуновского уровня, а не треша какой ЯП изучать новичкам.
Просто вам не часто такое попадается. Ищите и найдёте
@@АндрейСветлоков-з2ш ну не надо басней, 49.5% контента для людей уровнем выше джунов это конференции, ещё 49.5% это видосы с неподражаемым индийским акцентом по скидке за 480 рублей и 1% это видосы вроде этого
@@АндрейСветлоков-з2ш Мб посоветуешь что то?)
@@Erwin_Anderson совет один, сиди на попе ровно
Спасибо, полезно! Мозг прям возрадовался приятной и понятной подаче материала! 👍
Алексей! Доброго времени. Внедрю пожелание лайфхака. Следующее видео делайте в соседней комнате. Мы-же тоже дзырим ваши замечательные апартаменты. Пыточную из прошлых видео изучили, теперь понятно место откуда вещали прошлые видосы.
Похоже что дальняя коричневая дверь стоит на вентиляции микроклимата. Фигасе. Спасибо за идею. За окна понятно, но двери - это свежо!😂
Отличный контент. Ну сказать что-нибудь надо, вот и сказал. Вот...
Суперский формат! Много полезной информации, наглядно, с примерами, увлекательно. Спасибо автору!
Если phone_num PK, то чел. уже не сможет его поменять. PK -- это не только UNIQUE NOT NULL, но ещё и read-only. Всё же не нужно юзать phone_num в качестве PK. Это сущность/запись клиент-человек. Даже здравый смысл подсказывает нам, что нельзя его отождествлять/идентифицировать/привязывать к номеру телефона.
смысл-то подсказывает, а напомните мне, как в Вебмани регистрация происходит?
Сначала накачал с трекеров терабайты обучащих курсов от инфоцыган теперь позатер их и смотрю ваши ролики. КПД намного выше. Большое спасибо.
Спасибо за Primary key. интересные мысли, рассуждения
Спасибо! Интересно было послушать по UUID и всё с ними связанное. Понравилось, что осветили плюсы и минусы каждого подхода/типа. 👍
Я только недавно начал изучать PostgreSQL, но некоторые моменты из видео заставили более внимательно относиться к структуре БД.
Первичные ключи в маленьких табличках часто бывают внешними ключами в больших. И вот там можно много сэкономить.
Ржу нимагу! "Но вот на практике нифига, нифига!" ))
Классно делаешь ролики, много информации и весело! Продолжай в том же духе! :D
Отлично рассказан материал, коммент для активности.
Большое спасибо. Очень полезная информация
"Индекс - это отсортированная структура данных" - это справедливо для b-tree, но есть ведь индекс, основанный на хэш-мапе
Главный недостаток естественного ключа заключается в том что как только на запись с таким ключом появляется ссылка из другой таблицы, то менять этот ключ придётся как в самой таблице, так и во всех таблицах где на запись есть ссылки. Причём делать это придётся в одной транзакции с отложеной проверкой целостности. А ошибиться пользователь может очень легко и ошибочно вбитый номер телефона или паспорта который оказался ключом может вылиться в ряд неприятностей. Поэтому если у вас на таблицу есть ссылки, то очень хорошо подумайте прежде чем делать в этой таблице естественный ключ.
on update cascade 😉
Вцелом согласен, но тут стоит ещё заметить, что номер телефона, номер паспорта, мыло, номер аськи - это всё примеры неудачного естественного ключа, как раз потому, что они могут меняться. Примеры более удачных ключей - это налоговые номера (ИНН, TIN, NIF и др.) и номера социального стразования (СНИЛС, SSN и др.), так как они назначаются один раз и на всю жизнь.
@@andreybogdanov3 спасибо, я что то забыл про такую возможность
@@vryaboshapko в таких ключах есть ещё одна проблема. Это опечатки, а ключ уникальный. И вот оператор вводит, например СНИЛС или номер серию паспорта, если это составной естественный ключ. И делает там опечатку в одной цифре. А в другую организацию приходит человек именно с таким номером, например паспорта. И в той организации ввести его данные не могут и разобраться без помощи разработчиков тоже не могут, потому что опечатку сделала другая организация. В итоге в базе данные не правильные и ввести правильные нельзя. В общем использовать естественные ключи можно, но как по мне с таким количеством нюансов - ну его...
@@ВладимирБарков-п6ц для этого в СНИЛС и ИНН зашита проверка целостности. Грубо говоря, если хитро сложить первые цифры, получится последняя (точные алгоритмы публичны и легко гуглятся). Такая же, кстати, есть для номеров баноковских карт, но это не относится к теме естественных ключей). Плюс есть публичные базы данных, по которым можно провалидировать, например, что номер соответствует ФИО или дате рождения. А номер паспорта точно нельзя использовать как естественный ключ (даже как часть составного) по той же причине, что и номер телефона: он меняется. Это уникальный номер документа, а не человека.
Частный случай префиксных ключей - это номера паспортов и других подобных документов. Они содержат серию и номер. Серия назначена по территориальному принципу, а номер - это просто счётчик. То есть, каждому актору, имеющему право генерировать первичный ключ, присваиватеся свой префикс, а он внутри себя следит за простым счётчиком. Причём, счётчик персистится с помощью write ahead log: каждый новый паспорт заносится в журнал, и ему присваивается номер на единичку больше от предыдущего занесённого. Ничто не ново под Луной, как говорится)
Спасибо! Как раз сейчас тема MySQL в ПТУ прохожу. Ну и вообще курс, ваш, очень помогает.
Классный первичный ключ - сотовый телефон
Только у пользователя может быть несколько телефонов, ну и телефон можно потерять.
На мой взгляд - Естественные ключи использовать крайне ненадежно.
Вы должны быть уверены, что естественный ключ уникален в рамках проекта, концов которой не видно. (Подразумевается что вы работаете в проекте, а не пришлый наемник для решения одной задачи)
Префиксы в начале - это реинкарнация Венгерской нотации от MS 😃
Один телефон может быть главным, остальные будут сохранены дополнительно (если нужно их сохранять). Тут больший вопрос по смене телефона, если он PK, то надо будет менять потенциально много записей в разных таблицах, что может быть тяжело. Поэтому пример с телефоном может быть не лучший, да, но мне важнее было показать суть.
👍Спасибо большое за видео. Для себя узнал несколько полезных штучек! Алексей, ты крут!✌😁
Это просто охуительно, бесконечно великолепно! Спасибо за просветление
Доступный и подробный разбор вариантов первичных ключей, спасибо за информацию! Наверное нет смысла спорить о применении в первичных ключах int или даже smallint, потому что если такая надобность будет, то разработчик это увидит и применит. А кто-то посчитает что необходимости применения 2-х или 4-х байтового числового первичного ключа не случается никогда.
Я знаю примерно три случая, когда можно использовать small int в качестве первичного ключа, и во всех трёх случаях есть решение в виде естественного аналога: это списки валют, стран и языков. На все три есть ISO с буквенными кодами, и такие коды будут сильно удобнее, потому что их после минимальной тренировки может читать человек. Не то, чтобы я утверждаю, что small int категорически не нужен, просто вспонилось несколько частных случаев.
Спасибо! Очень полезно! Думал, что давно всё знаю по этой теме.
Сел покушать, а тут и годный контент подъехал. Сразу лайк!
Спасибо за видео!
У меня тоже была как проблема с инкрементом sequence, когда я прям на горячем проде с 150k rpc в секунду добавил строку вручную с явным указанием id.
И как посыпались ошибки! Ух... Хорошо быстро поправил sequence номер.
Спасибо, тебе за такой ролик, узнал для себя много нового. Делай дальше, у тебя это круто получается
От души спасибо, очень легко и интересно рассказываешь.
Большое спасибо за вашу работу. Отличное видео, очень полезный материал!
Спасибо!
У ulid есть некоторая проблема в том, что инстансы приложения генирующие улиды могут находиться на разных физических машинах с рассинхроном времени, проблему рассинхрона ещё человечество до конца не решило. Поэтому в распределенной системе не факт, что каждый следующий сгенерированный ulid будет лексикографически старше предыдущего.
Разве рассинхрон в несколько миллисекунд это проблема?
@@vladislavstepanov7591 фишка ULID в том, что один ULID больше другого, если он сгенерировался позже на 1мс, чем первый. Но если на разных тачках есть рассинхрон, то польза от ULID'a нивелируется и проще использовать UUID v4
По примеру с естественным ключом в виде номера телефона: - очень удобно, особенно когда пользователь хочет поменять номер телефона. Т.е. что проще, посмотреть по номеру телефона id и далее делать все тоже самое по id или при смене телефона иметь ад по сохранению целостности данных? Проблема в том, что зачастую многие естественные ключи не являются абсолютно константными и это создает гораздо большую проблему, чем та польза, о которой говориться. P.S. да, я читал статью про IDотов, к сожалению не могу придумать каламбур про Естественно-отов =)
Очень полезная информация. Буду использовать в своем дипломе)
23:00 как ни странно иногда вставка уидов может быть быстрее чем вставка в условный bigint. Особенно если база уже большая и не новая, по той же как раз причине, что вы и описали.
При очень интенсивной вставке, если вставка идёт одновременно из множества сессий, то возможны проблемы за конкурентный доступ последней страницы в которую данные льются, а при уидах вставка происходит в рандомные страницы в разных местах индекса и сессии друг другу не мешают)
Вопрос не в вставке, а в последующем использовании. Чем тяжелее ключ, тем тяжелее join .
При интенсивной вставке в таблицу где pk - uuid, будет происходить очень частая и тяжёлая перестройка индекса, из-за этого как раз и может происходить существенная просадка по производительности.
Алексей, просьба от благодарных радиослушателей. SQLite, либо хотя бы с точки зрения самой базы, либо, если можно, в виде работы с питоновским модулем sqlite3. Проекты проектами, но на этой штуке крутится процентов 80 всего интернета и примерно три четверти всех приложений. Я колупаюсь уже второй месяц, так и не нашёл заявленный режим "многопоточность" по умолчанию, до сих пор корячу через исключения. Плюс pragma их фирменная. Можно, конечно, и самому догрызть, но объяснение от опытного человека намного эффективнее.
Очень качественный материал 👍 спасибо
Спасибо, было познавательно! Отличное видео.
не досмотрел еще, и не знаю подняли ли эту тему, но хочу сказать, что правильные первичные ключи важны для производительности некоторых кейсов пагинации (я говорю про то, что зачастую правильный первичный ключ - это единственный способ сделать правильную пагинацию без использования медленного оффсета)
спасибо, но, скорее всего, когда я буду понимать смысл слов "пагинация" и "оффсет" в контексте SQL, то мне это видео уже не понадобится. И наоборот.
Спасибо за контент! А я даже не думал что такие способы есть. На мой взгляд id должен быть наподобии штрих-кода, но чтоб информация там была зашифрована для стороннего пользователя.
Очень полезно! Спасибо!
Пример с телефоном очень показательный. Есть у нас история действий пользователей с неким номером телефона. Казалось бы удобно. Но люди бывают что меняют номера телефонов. и если пользователь сменит свой телефон он лишиться всей своей истории.
Спасибо, очень информативно!)
Мысль про ключи естественные ок, но пример с номером телефона плох(опасен). Клиент может захотеть сменить номер телефона и вот тут придётся менять ваш PK, что выльется в проблемы и боль миграций.
12:50 - при этом надо понимать, что естественный первичный ключ для справочника тех же пользователей - это та еще мина замедленного действия (помимо потребности хранить длиннющий UID или 11 знаков номера телефона во всех связанных таблицах, где могут быть сотни миллионов записей). Из того же примера в видео: вот пользователь деактивировал сим-карту и мобильный оператор продал этот номер спустя время новому физ.лицу :) Логика сломается уже на этапе регистрации в приложении где-то на бэкенде при обращении к базе. Про момент защиты персональных данных уже в ролике озвучено - тут сразу получается не вариант с естественным первичным ключом
Спасибо большое! Было очень интересно и познавательно, хоть я и мобильный разработчик)
Круто :)
По поводу always generate. А что если нам требуется восстановить таблицу из бэкапа и при этом в ней есть пропуски(удаленные записи)?
Очень неплохо бы разобрать тему uuid6 в сторону ускорения до uuid7 и 8
Спасибо, много нового узнал.
До этого видео относился к UUID как к безумной глупости. Побежал добавлять это дело к себе в петпроект
Про использование identity column было очень интересно. Не был в курсе подобной опции. Впрочем, при грамотном использовании serial не доставит никаких проблем. Достаточно целиком отдать генерацию id на откуп базы данных
Алексей, респект за контент, а когда будет стрим как на новый год?очень душевно было
4:08 а потом пользователь захочет сменить почту) и полетел наш первичный ключ во всех связных таблцах. Первичный ключ лучше всегда делать искусственным.
Конечно это просто пример, хотя не вижу проблем с заменой email, это же не автоинкремент и поле изменять можно. Будут проблемы с обновлением связей - да, но решаемо. Никогда не говори всегда. Возможно email был не самым лучшим примером, но вот например у тебя есть таблица стран и у стран есть Abbreviation - Name со значениями RU - Россия, US - США. Не нужен тут искусственный ключ, если первичный ключ на Abbreviation будет уникальным, и гарантирует уникальность Abreviation.
@@programisliтак вот чтобы потом не думать как исправлять, надо тупо делать искусственный ключ. По этой же причине надо не думать и делать сразу микросервисную архетиктуру, потому что сделав монолит через года можно сильно пожалеть.Сколько таких случае когда куда не глянь а все монолит свой пилят на сервисы? Всетоки есть практики - железны, которые уже написаны кровью
@@programisli а потом в один прекрасный момент у страны всеже поменяется Abbreviation-Name) Или изменится вид с двух значного на трехзначный.
Использовать всегда только один подход это упрощение жизни, упускаются всегда какие-то случаи. Как писал в соседнем треде, телефон сейчас это почти всегда обязательное к заполнению и уникальное поле, однозначно идентифицирующее клиента - как бы вы ни считали это идиотизмом. И даже вопросы смены решаются, удивительно.
@@t0digital все решается, только нафига перебирать все таблицы и заменять связи? Когда есть скажем так профессиональные подходы, я имею ввиду некое решение сбалансированное которые не подведет никогда как показывает практика. И чего кривляться когда оно надежное? Это как многие вещи в разработке стали стандартами дефакто, например докер. Чтобы ты не делал всегда все делай в контейнерах - простой рецепт решающий все будущие проблемы. Или микросервисы - никогда не делай монолиты иначе рано или поздно обожжешься на масштабируемости.
Спасибо за информацию
Благодарю!
Прикольное худи Lacoste. Подскажи, модель или серийник)
Это я люблю, спасибо!
Алексей, а что по поводу скорости поиска по uuid ключам по сравнению с числовым типом? Кажется сравнение строк должно сильно ухудшить этот показатель. Или для uuid используется какое-то хитрое быстрое сравнение?
UUID это не строки, а 128 бит и нужно сравнивать 128 бит, что достаточно быстро. Но int будет занимать меньше месте на диске и если это внешний ключ то по числу поиск будет чуть более эффективнее, потому что меньше нужно держать в памяти или читать с диска. Просто индекс будет компактнее
@@programisli пхах, какраз когда прочитал 128 бит, в видосе на 20:13 прозвучало "весит 128 бит"
128 бит - это 16 байт. То есть, сравнение двух UUID-ов занимает столько же времени, сколько сравнение двух строк из 16 символов (если речь не про юникод, конечно). Но стандартоне текстовое представление UUID-а (123e4567-e89b-12d3-a456-426614174000) - это 36 байт, то есть, сравнение двух строковых представлений UUID-ов занимает больше времени, чем сравнение двух честных UUID-ов. Кроме того, UUID в памяти может быть представлен не как набор байт, а, например, как два лонга (64-битные целые), и тогда сравнене будет ещё быстрее, потому что современные 64-битные процессоры могу сравнивать 64-битные целые за один такт.
По скорости инкримент будет в десятки раз быстрее, поэтому делают два ключа, id и uuid, один для внутренних релейшенов, другой для внешки
@@stripeberry вы имеете ввиду первичный ключ это bigInt, а для uuid создаем индекс, примерно так ?
CREATE TABLE your_table_name (
id SERIAL PRIMARY KEY,
uuid UUID NOT NULL,
-- Здесь добавьте остальные поля вашей таблицы
-- Если нужно добавить внешние ключи или связи, то можете добавить их здесь
);
-- Создание индекса для ускорения поиска по uuid
CREATE INDEX idx_uuid ON your_table_name(uuid);
Просто для заметки:
Если x = "Иногда" и y = "Всегда" то
y = K * x, при условии К - частота случае "Иногда" и она стремиться к бесконечности )))))
Спасибо, послушал с интересом. Единственно не согласен с настойчивой рекомендацией использовать bigint в качестве ПК. Обычного int хватает в 99%, если только вы не собираетесь автоматизировать весь мир. В любом случае нужно понимать на какие объемы проектируется система, и принимать проектные решения исходя из этого.
Еще раз спасибо, хорошая подача материала!
Накладные ресурсы которые уйдут на bigint не сравнятся с болью перелапачивать бд и менять типы с int на bigint
Сразу лайк!
Классные видосы для гиков у тебя. Я подписан
Спасибооо!
UUID v6 выглядит перспективно, но я бы вообще пошел дальше и использовал nanoTime, а для формирования рандомной части оставил последние 11 байт (12 символов).
спасибо!
Про телефон посмеялся :)) кто то еще делает по ним первичные ключи ? :)
Сделали, а потом юзер перестал оплачивать телефон, компания телефон отбирает, и передает ДРУГОМУ :))) "здрасте приехали" :)
Хороший материал, которого всегда не хватает. Кстати, а какую вы тему используете для psql? Вижу, что у вас есть автодополнения и подсветка.
Это pgcli
Полезное видео, спасибо! А где можно найти параметр, отвечающий за такую зеленую подсветку кода?
Спасибо! Это pgcli
Натуральные первичные ключи это велосипед из костылей.
Это грабли, подложенные если не себе, то следующему программисту/админу. Если не с уникальностью, то с производительностью.
В общем, натуральные ключи могут использоваться, но только в исключительных случаях, по уважительным причинам.
Таблица стран. Обоснуете, почему название страны нельзя сделать первичным ключом и почему это плохо повлияет на производительность?
@@t0digital Первичный ключ по строке - глупость.
Это намеренное снижение производительности и раздувание размера БД (т.к. это поле копируется во все связанные таблицы).
Это нарушение сложившихся практик без уважительных причин.
Ну и весь ворох оговорок, которые вы и сами озвучивали.
@@t0digital Кроме того. Страна может сменить название и из-за такого дизайна БД, нам придется менять все ключи в таблицах.
Страна также может распасться и объединиться с другой (upd: что, впрочем, в любом случае потребует коррекции более чем одной таблицы).
@@semibiotic размер строки не обязательно больше размера UUID'а, например
Случай распада страны никак не осложняется ключом с названием страны, его надо обслуживать и в случае искусственного ключа
Капец ты гений какой то)
👏
Приветствую! Спасибо за видос, очень актуально и полезно. Интересно ваше мнение по вопросу: где удобнее всего и эффективнее разрабатывать схему БД? В кансоле сразу, или может в pgAdmin, а может по старинке на листочке схему рисовать?)
Для проекта, когда думаю о данных, сущности рисую иногда сначала на бумаге, чтобы было наглядно. А создавать таблицы уже где угодно. Миграциями как правило, джанговыми или алембик
крутая картинка. кач хорош
с таким крупным шрифтом ты очень быстро сломаешь себе глаза! 12 должен быть максимальный.
Шрифт для видео увеличиваю, чтобы было видно всем
Случайно наткнулся на видео, не лишним было бы упомянуть про вставку батчем и генерацию айдишников на стороне бэка.
Имеете в виду, что вставка пачкой ссылающихся друг на друга записей возможна с айдишниками, которые генерятся не в базе? Об этом есть в видео
@@t0digital Имею ввиду, что бывают случаи, когда генерация айди не эффективна на уровне базы. Например кейс когда нужен высокий перфоманс и применяется вставка батчем.
А есть видео где рассказывается про настройку терминала? Что бы так же дополнение запросов было? Или же это именно дополнение из консоли постгресс ?
Круто!
А про индексы планируется видео?
возможно:)
360*1500= 540к, неплохо))
налоги, комиссии, съемка, монтаж, команда с зарплатами и 31 день работы в месяц - неплохо
Знаю такой прикол, когда мы делаем UID-ы самостоятельно, которые получаются из витовых склеек из других полей. Не знаю правда зачем.
Хочу чтобы в кадре была красная кружка с лого "D!"
Как можно проверить, что uuid_v6 (ulid, objectId) в качестве primary_key работает быстрее на больших объемах данных, чем uuid v4? Какой тест тут лучше применить?
Для записи приходит в голову что-то типа "генерируем 10ккк uuidV4, затем в другой таблице 10ккк uuidV6, сравниваем время". А для чтения это как лучше проверить?
Как разработчик DWH я не могу согласиться со многими тезисами и заявлениями. Когда вы говорите о подходах и «структуре/архитектуре бд», следует в первую очередь ссылаться на нормализацию и нормальные формы. Если углубиться, то станет очевидным вывод о том, что натуральные ключи имеют право на жизнь, но исключительно в прикладном смысле.
«Натуральные ключи имеют право на жизнь, но исключительно в прикладном смысле.»
О чем речь?
@@t0digital натуральный ключ это сущность из реального мира, отражаемая в СУрБД. Сущности, отражаемые в СУрБД должны иметь первичный ключ внутри самой бд (это называется суррогатный ключ, и лучше если он сквозной), а данные должны находиться в соответствующей нормальной форме. Иначе, доработка, масштабирование, аналитика будут очень осложнены. А вот таблицы с некоторыми «фактами», например таблицы с транзакциями, лучше конечно снабжать ключами типа UUID, GUID, etc. Добавляя унифицированный суррогатный ключ клиента, как субъекта операции.
Так вам будет норм даже с десятком миллиардов записей в таблице с транзакциями.
@@artetl «натуральный ключ это сущность, отражаемая в СУРБД»
То есть сущность, отражаемая в СУРБД это натуральный ключ. Таблица, которая хранит данные по сущности заказов, это натуральный ключ. Понятно:)
@@t0digital на натуральные ключи принято навешивать суррогатные ключи, которые будут первичными ключами для идентификации, например, клиента. Иными словами так.
Это на тот случай, если, например, на одном номере телефона у вас есть клиенты: юридическое и физическое лицо.
Иметь или быть* если я правильно понял, то какая книга имелась ввиду
А почему у вас PSQL такой красывый?
На первой минуте. Или это для маков эксклюзив?
pgcli
Проблема использования номера телефона в качестве первичного ключа не столько в безопасности, сколько в потенциальных проблемах в случае смены телефона
Есть такое
21:01 - чтобы ориентироваться по времени как вариант можно использовать uuid v7
get_random_uuid был добавлен в PostgreSQL 13
А что если префиксную часть сделать модифицируемой по длине? Тогда мы сможем выбирать приоритет на скорость записи или скорость чтения из БД соответственно по скорости формирования и чтения индекса
а если использовать "generated always as identity" то не будет проблем при импорте? Например если одна запись удалена просто заново сгенерировать не вариант.
Сделай видево как быстро считать количество всех результатов выборки, с учетом фильтров, в постгресе
Count(*) же
Когда теория оторвана от реальности... Номера телефонов часто используются повторно операторами после нескольких лет неактивности.
Да. По моему телефону я могу логиниться в сервисах, которыми пользовался прошлый владелец. Это тоже теория или реальность?
@@t0digital это печальная реальность. Я так в некоторых сервисах вижу чужие старые данные.
И не могу пользоваться логином, если вдруг сменил свой номер
Ну какая есть:)
Конечно, если использовать телефон в качестве PK, то надо осознавать потенциальные минусы такого подхода
Впервые слышу термин "искусственный" в отношении первичного ключа. Устоявшимся является "суррогатный", нет?
возможно, да
Как в постгре работают индексы под капотом уже был видос? :)
Ого, а интересно, как консоль на маке собирает таблицу для оторбражения? Красиво же выглядит, не то, что поплывшие таблицы на символах -- |
А не, тоже плывёт.
Алексей, подскажите пожалуйста, насколько будет эффективен индекс для поля, ну допустим varchar(300)?
Да просто потестируйте сами. Сгенерите данных, сколько у вас будет в табличке, сделайте analyze, чтобы обновилась статистика, и сравните выборку без индекса и с индексом. Индекс - не гарантия эффективного выполнения запроса, он даже не обязательно будет использоваться в конкретном запросе, это как планировщик решит.
Расскажи про timescaledb
С serial id есть проблема при миграции с сохранение id объектов.
Плюс апишника хотять что бы id был uint64 :D
Алексей, а как ты настроил code-completion при работе с psql в терминале?
pgcli
Естественные ключи - это прям байтище на комментарии )))
Вот в тот мне примере, что мешает ТП дать не номер телефона, а ИД пользователя?:)
Или сначала выбрать ИД в переменную, а потом его во всех запросах, а не джойнить?
В 99.9% случаев естественные ключи не нужны
Номер телефона как первичный ключ или логин категорически делать нельзя, как бы это ни было "удобно" для запросов. Человек потерял телефон, и? Будем обновлять кучу таблиц, меняя значение ключа на новый номер? Или дадим пользователю зарегать новый аккаунт? Тут вообще дыра в безопасности: серез некоторое время старый номер мобильный оператор выдаст какому-то другому человеку, тот может попробовать зарегистрироваться на ресурсе, очень удивится, что логин занят, тыкнет в линк "восстановить пароль", и получит доступ к личному кабинету старого владельца, где может находиться информаумя, которую он не имеет права видеть.
Много сервисов сейчас пускает по телефону и смс. Озон и др. Это говорит о том, что поле телефона там а) уникально б) обязательно к заполнению. Значит, является потенциальным ключом.
@@t0digital так что насчёт смены номера клиентом, если это ключ? потом по всей базе менять?
05:57 а зачем использовать для этого именно композитный первичный ключ-то?
Первичный ключ - он для идентификации. Для избежания дублирования просто создаёшь индекс уникальности по нужным колонкам. Это то, что делает первичный ключ, кстати.
Это порождает избыточность. Удобство искусственных первичных ключей зависит, в первую очередь, от запросов. Пример: settings - настройки с учётом года. Входить в эту таблицу мы всегда будем через , и ссылок из других таблиц на settings часто тоже нет. Итог - в данном случае лучше составной естественный ключ
@@alexgorodecky1661 Я о другом. Выбирайте вариант, который Вам нужен. Но конкретно задача избавления от дублирования решается уникальным индексом, для неё не нужно накрывать колонки первичным ключом.
Блин хорошая тема, но что за пример с номером телефона, такая дичь даже озвучиваться не должна как возможная. Там сразу столько проблем, рекомендую статью на хабре про заблуждения программистов о номерах телефона. К той статье ещё бы добавить в заблуждения: "думать что у пользователя из X страны номер телефона тоже из страны X. Уже приходилось видеть регистрацию где номер телефона захардкожен с +7. Ну и с ключом на базе телефона рано или поздно вам нужно будет внести нового пользователя у которого снова повторяющийся телефон. Не усложняйте жизнь себе и людям которые будут поддерживать системы
А потом человек меняет номер телефона и мы.... весело придумываем решение ))))