Как стать автором
Обновить

Комментарии 27

В распределенной базе данных auto-incrementing представляет собой серьезную проблему. Для генерации ID необходима глобальная блокировка.

Легко решается без блокировок если в каждой базе будет использоваться свой пул ID.
Например, если у нас две базы, в одной могут генерироваться четные Id, в другой нечетные.

пул идентификаторов идея очень правильная (и без распределенной базы работает, где нет autoincrement), но интервалы или (в общем случае) стратегии генерации должен выдавать глобальный координатор — редко, но метко. Может, какие-то стратегии общего консенсуса тоже сработают — не уверен, что это будет приемлимо быстро. Может быть ситуация, когда ноды подключаются и отключаются и простые решения с "четным-нечетным" перестают работать.

Вопросы с выдачей idшников без координатора уже давно решили алгоритмы по типу twitter snowflake где генерируемый айдишник привязан ко времени, порядковому номеру в пределах определенного отрезка времени и уникальному идентификатору генерирующей системы. Там какие-либо коллизии возможны только из-за ошибки конфигурации.
А типовая ситуация, когда две базы связаны через ключи-счетчики и одну откатили — и начались танцы с бубном по синхронизации.
В DB2 с доисторических времен для генерации ключей рекомендовалось generate_unique() основанное на времени и номера сервера для кластерных конфигураций. При этом метка времени не является бессмысленным суррогатом и может, например, ограничивать выборку как предикат или использоваться для шардирования таблицы.
При проектировании БД нужно придерживаться естественных ключей.
При проектировании БД нужно придерживаться естественных ключей.

Не бывает естественных ключей. Все атрибуты, которые действительно являются ключевыми, это искусственно придуманные идентификаторы, во многих случаях автоинкрементные. Всегда могут существовать 2 объекта с одинаковыми характеристиками, одинаковые в смысле в пределах погрешности измерения.

Могут. Но «носок номер 5 и 12 составляют пару» как-то в жизни не используем…
А как только разработчик использует rowid — он не понимает БД от слова совсем.

Ок, какой первичный ключ вы выберете для учета носков?)


rowid и автоинкремент это не совсем одно и то же. Значения в автоинкременте не повторяются и не переиспользуются.

1. никакой, как и в жизни.

2. Программисты привыкли к массивам и меткам.

Реализация счетчика для БД, в конкурентной среде, задача нетривиальная. При реализация с полной блокировкой возможен только один поток. Вынужденно каждому соединению сервер выделяет блок значений от сиквенса, в результате счетчик перестает быть счетчиком как таковым. Последовательность получения значений и реальный порядок попадания записей в БД нарушается, образуются дыры. При кластерной конфигурации наступает катастрофа, т.к. мастером по сиквенсу может выступать только один сервер и другие вынуждены обращаться к нему — при операциях даже в 1с сетевые задержки уже существенны. Представьте слегка нагруженную oltp базу с 1000 коннектов и 20 тыс транзакций (не операций) в сек. и хотя бы 0.01% из них вдруг замедлиться на 100 ms.

Все вышеописанное, как и статья, относится к промышленным системам. Хотя проблема может выстрелить и при относительно примитивном сценарии — система А передает события с ID типа счетчик в систему Б, система Б по данному ID обеспечивает идемпотентность, счетчик рестартовали…

При этом никто не будет бить по голове разраба, если он использует сиквенс для справочника в сотню строк, который дополняется раз неделю. Хотя и тут возможны проблемы — когда у вас несколько сред, например, тестирования…
в результате счетчик перестает быть счетчиком как таковым

Так нам не нужен счетчик, нам нужны уникальные ключи объектов.


Последовательность получения значений и реальный порядок попадания записей в БД нарушается, образуются дыры.

У GUID между значениями тоже дыры.


т.к. мастером по сиквенсу может выступать только один сервер

Ну можно сделать чтобы часть битов означала номер сервера, тогда будет несколько сиквенсов.


никакой, как и в жизни
если он использует сиквенс для справочника в сотню строк

Так вы на вопрос-то ответьте. У носков нет естественного первичного ключа, как их различать в таблице носков? "Никакой" это не ответ, в таблице должен быть первичный ключ.

таблице должен быть первичный ключ.

Вы совершенно не понимаете, что такое БД.
Может быть поделитесь своим пониманием, что такое реляционная база данных без первичных ключей?
Мне правда очень интересно.
Вы совершенно не понимаете, что такое БД.

Ага, вот я и думал, ответите вы на вопрос или прицепитесь к этой формулировке. Для целей учета таблицы без первичных ключей бесполезны. Это можно логи какие-нибудь так писать, и то не факт, что это потом не создаст проблем.


Да, кстати:


никакой, как и в жизни

Так у любых объектов "в жизни" нет уникальных атрибутов. О чем я и говорю.

тема требует объяснений очень издалека. Классические БД автоматизировали ручной процесс и мы с вами пользуемся «аналоговыми» базами в повседневной жизни. Попытайтесь сначала представить процесс не автоматизированным — как норвеги, например, проверили IP на голубях. В качестве примера те же носки — купил упаковку в 10 пар в m&s — они черные, положил в ящик = таблица, единственный аттрибут — цвет. Выборка будет — жена, дай пару черного цвета — select… where color=black… fetch 2. Да? Или по номеру? Тут еще подолью масла в огонь, любимый всеми STATUS — «and status=0». Это значит, что чистые и грязные носки у вас лежат в одном ящике и команда жене расшириться на предикат «понюхай каждый»…
Если у Вас все носки пронумерованы, тут крыть нечем. Это особый случай — для этого обычно применяются key value db.

Изначальный посыл статьи — боль сопровождения, как последствия неудачного проектирования.
Попытайтесь сначала представить процесс не автоматизированным

Снова, я именно об этом и говорю. В неавтоматизированном процессе для учета одинаковых предметов (столы, стулья, носки) применяются инвентарные номера. Искусственный и инкрементный идентификатор.


любимый всеми STATUS — «and status=0». Это значит, что чистые и грязные носки у вас лежат в одном ящике

Ок. И как же одному конкретному носку поставить статус "Грязный"?
UPDATE table SET status = 1 WHERE status = 0 LIMIT 1? А если статус одновременно вводят 2 разных пользователя? Получили гонку по данным и глобальный лок на всю таблицу чтобы ее избежать.

выбирайте глобально уникальный и естественный первичный ключ (например, имя пользователя)


А потом запретите своим пользователям выходить замуж и менять фамилию. И никогда не принимайте на работу Ивана Говнова, а то вдруг он захочет сменить имя на Евгений.

Очевидно же что в данном случае имеется ввиду логин.

Во-первых, это не очевидно. А во-вторых, как бы там ни было, рекомендация использовать натуральные ключи в общем случае неверна.

Очевидно, если обратить внимание на тот факт что статья является переводом. И в оригинале это звучит как “username”.

В конторе логин основан на фамилии пользователя, так что после развода многие заказывают сменить и фамилию и логин.


У реальных объектов обычно не существует такого свойства, которое гарантированно никогда бы не менялось, так что первичный ключ должен использоваться только для идентификации "да, это тот же самый объект".

Ужас какой. Хоть бы СУБД указали. Ибо для некоторых СУБД сильно лучше ключ bigint чем varchar и тем более uuid

Волга впадает в Каспийское море. Чем длиннее ключ, тем дороже join-ы по нему.
Поэтому при возможности, пожалуйста, выбирайте глобально уникальный и естественный первичный ключ (например, имя пользователя).

А потом требования меняются и глобально уникальный естественный первичный ключ становится не уникальным.
НЛО прилетело и опубликовало эту надпись здесь
Заявляется что-то общее про базы данных, а потом в статье описываются нюансы (иной раз довольно, мягко выражаясь, нетипичные для классической СУБД), свойственные одной конкретной (мягко говоря, особенной) базы. Некоторые рассуждения из статьи неприменимы к полноценным СУБД (например, Oracle).
Побуду занудой :)
Что такое «count't»?
Или это такая игра слов
«couldn't» + «count» = count't?
Имею опыт участия в команде по разработке БД. То еще приключение )
Repeatable reads: незафиксированные записи в текущей транзакции доступны для текущей транзакции, но изменения, сделанные другими транзакциями (например, новые строки), не видны.

Wimbo Заранее прошу прощения если я туплю, в Repeatable reads новые строки из других транзакций будут видны, и по вашей ссылки этоже как раз таки и написано.
newly inserted rows by other transactions will be visible

Зарегистрируйтесь на Хабре, чтобы оставить комментарий