Pull to refresh
-6
0
Валерий Лиховских@vl65

Программист, Архитектор, Руководитель проекта

Send message

И еще добавлю


Позволяет использовать ID реляционная модель БД? Позволяет! Но это очень узкое частное решение!, это все равно что купить автобус и ездить на нем, как на автомобиле (одному). Можно так ездить на автобусе? Можно. А нужно? Если только в парк и из парка водителю ехать.

Да ради бога, делайте что хотите, пишите как хоти! Разве я могу Вам запретить делать как Вы можете? Нет.


Я всего лишь объясняю, что использования ID плохое решение, что в нем скрыто множество проблем. И только.


Приведу пример. Есть большая задача, 15 лет в эксплуатации, естественно понатыкано ID в каждой таблице. Возникло новое требование — "хочу георезервирование в двух ЦОД-ах с сохранением работоспособности при изолированной работе каждого ЦОД-ах и при крахе одного ЦОД-а". Предложил двух стороннюю репликацию — но нужно отказаться от генерации ID — одна и та же запись в разных ЦОД-ах получит разные ID. Все, поставили крест на возникшем требовании — реализовать невозможно. Для реализации этого требования нужно писать систему заново! Вот Вам и ID в таблицах.

Уникальный ключ, однозначно характеризующий запись, в частном случае может состоять из одного поля, значение которого не изменяется в зависимости от времени!

Генерируемый ID не является уникальным ключом. В разные моменты времени Вы получите разные значения ID для одной и той же записи.


Пример: код HTTP — 200, 302, 404, 500. На первый взгляд это ваш любимый ID, но на самом деле это составной ключ. Первая цифра диапазон, вторая порядковый номер в диапазоне. Вы можете не знать значения кода 415 например, но глядя на этот код Вы знаете, что ваш запрос отработал с ошибкой.


Банковская карта — 12 цифр, на первый взгляд, то же ID. А на самом деле составной ключ из множества полей! Вы с большой долей вероятности можете определить банк, выпустивший эту карту (если работаете в банковской сфере).


Приведу пример: Разработчики сдали задачу — менее 20 таблиц, в каждой таблице натыкали генерируемый ID, есть неиспользуемые ID в таблицах, общий объем данных предметной области 0,5 ГБ (пустая база), прогнозируемый объем в эксплуатации около 1 ГБ. Первое нагрузочное тестирование всего на 4-х объектах пустой базы, подчеркиваю на 4-х, показало наличие проблем производительности. Разработчики за возмущались, что сервер для тестирования плохой, что у них на обычных ПК проблем производительности нет и начали требовать сервер с SSD дисками. Вся база свободно размещается в памяти сервера, а им подавай SSD! Проблему они так и не нашли, мне уже пришлось править их косяки в запросах с использованием ID при объединении таблиц. Контракт с ними был прекращен.


10, 20, 30 тактов, да это очень мало и кажется, что временными затратами можно пренебречь, но это пока таких операций очень мало. А если в одной транзакции вставляется сразу сотни — тысячи записей. А если таких транзакций у Вас много? И вы получаете на пустом месте проблемы производительности.


Если вы такой опытный — подскажите:

Я имею поверхностное представление о предметной области банковской сферы. С ходу предложить подходящее решение не смогу. Нужно смотреть, изучать и анализировать. Но если порассуждать, то скорее всего описанная вами ситуация довольно редка и можно воспользоваться опытом СУБД в функции при генерации TIMESTAMP, когда возвращается значение большое на 1 в наносекундах, если пришли одновременно два запроса на получение метки времени. Добавьте в составной ключ еще одно поле, большинство записей будет иметь значение 1 в этом поле, реже 2, еще реже 3, а 4 может и вообще не встречаться. Но специалист в банковской сфере, наверное, сможет предложить другое более удачное решение для уникального ключа.

  1. Нет там такого понятия, ID не является какой либо характеристикой объекта (записи). У ID только одна характеристика — номер строки, другой функциональной нагрузки этот атрибут не несет. Что обозначат значение 100 в любой таблице с ID? 100-ю запись в таблице и ТОЛЬКО. Читайте лучше первоисточники — учебники авторов реляционной теории БД, там на элементарных примерах все хорошо рассказано.


  2. Если не понятен пример из статьи, где разъясняется как будут вставлены новые записи, то запишу по другoму, в табличной форме


    1, name, value
    2, name, value
    ...
    100, name, value
    101, name, value
    и так до бесконечности, и так в каждой таблице с ID
    

    Верх совершенства "реляционной" модели данных, а точнее полное ее отсутствие. И заметьте, меня совершенно не интересует в данном случае, как был вычислен ID.


  3. А теперь про вычисление ID и временные затраты. Генерация ключа sequence — один машинный такт, говорите? Очень сильно заблуждаетесь! Это множество машинных тактов. Для системы с парой пользователей, они не критичны. Для высокнагруженных или многопользовательских систем вычисление ID выливается в неприемлемые временные потери производительности. Это же элементарно, и совершенно не важно какой способ генерации ключа был избран. При любом выбранном вами алгоритме будут проявляться временные потери при существенном росте нагрузки на системы. Хотите кувыркаться с производительностью в будущем, да кто ж вам мешает.


  4. Утверждение "ID — мусор". Говорите, что это огрехи проектирования? Как не посмотришь на модели данных совершенно разных систем, совершенно разных разработчиков, а "грабли" с этим мусором у всех одинаковые. У всех, без исключения! То ли Вы всех в юниоры записываете, то ли "теория ID" кривая.


  5. :-) Убираем ID из таблиц и счастье, не нужно ломать голову как вычислить ID, и сколько это будет стоить в байтах, и где это считать, и не нужен UUID, и не нужен шардинг и все остальное то же не нужно. И приятным бонусом идет полное отсутствие временных затрат. Быстрота чтения/записи по ID — абсурдное утверждение. Много осмысленных запросов Вы можете написать к таблице по полю ID? Только один на "равно". ВСЕ! Для всего остального Вы бутите либо сканировать всю таблицу, либо бутите создавать все те же индексы (с потерями на чего там, как вы пишите). Зря видать разработчики СУБД бьются над производительностью и оптимизаторами запросов, Вы же — гений, подскажите им, что все проблемы решает наличием ID, избавьте их от мучений!


  6. Хотите делать пустые запросы, да на здоровье, наслаждайтесь.


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



И последнее, вам не только знаний не хватает, но и элементарного воспитания, раз все норовите грубить.

Коллега, не нужно здесь писать несуразности. Если у Вас другая точка зрения насчет ID, это не доказывает что либо. Если Вы не осознали мои высказывания, это не значит что я ни разу не привел свои аргументы. Вам просто не приходилось еще решать эти проблемы (опыта может еще маловато) Повторюсь.


  1. В классической теории реляционной БД нет ID (читай, номера строки).


  2. ID — не уникальный ключ записи, с разными ID можно вставить множество раз одну и ту же запись.


    var object1 = new SomeObject(null, "name", "value");
    var object2 = new SomeObject(null, "name", "value");

    Это две копии одной и той же записи, но с разными ID. А какую запись нужно удалить, если такое вылезет в эксплуатации? Какая из двух (хорошо, если только двух) записей не правильная? Чтобы добиться уникальности, Вам нужно с этим как то бороться, писать лишний код. И совершенно не важно где, в вашем ПО или БД.


  3. Генерация уникального ID — неизбежные временные потери. Чем "хитрей" механизм, тем больше потери производительности, удлинение транзакций и прочие "косяки"


  4. ID — мусор, в БД построенной по этому принципу, обязательно есть таблицы, где ID вообще никогда не используются в условии WHERE или прочих условиях объединения таблиц. НИКОГДА!


  5. ID заранее ограничивает эксплуатационные характеристики вашей системы. Например на этапе разработки, приняли решение "поручить" БД уникальность ID. Прошло лет 5 эксплуатации. Система разрослась, потребовалось добавить второй, третий и т.д узлы — что это означает, что все ваши запросы даже с разных узлов выстраиваются в одну очередь — толку от масштабирования узлов мало. Либо Вы приняли решение генерировать ID в ПО, но чтобы получить уникальные ID узлах опять же нужно придумывать или использовать ресурсоемкие алгоритмы генерации значений — неоправданные потери времени. А если в вашу БД пишут данные разные приложения? Как будите обеспечивать уникальность ID на стороне разных серверов приложений?


  6. Лишние объединения и лишние запросы с целью вытащить ID, здесь пример будет уже посложней (целую статью уже нужно писать), но как показывает практика, во всех БД с использованием ID вам нужно присоединять дополнительные таблицы, чтобы получить в выборке ID, хотя требуемый результат Вы уже имеете без этого ID.


  7. Трудность поиска ошибок в эксплуатации (здесь тоже нужно целую статью писать). Коротко, значение ID одной таблицы ни чем не отличаются от значений ID другой и если программист перепутал поля таблиц, то этого может и не заметь вовремя.



Этот список можно продолжать ...

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


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

ID — это номер строки и какой либо другой характеристики записи он не несет.


Если Вы проанализируете любую структуру данных где есть ID, в 99,99% увидите поле ID в значении целого числа какого нибудь доступного типа, по которому построен первичный ключ таблицы. Пропуски в последовательности значений этого ключа не отменяют утверждения, что это номер строки.


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


Вам нужен пример где нет ID, не проблема — любая структура таблицы, где PK создан по множеству полей ( в частном случае это может быть одно поле), значение которого не позволяют вставить дублирующую запись в таблицу. Это описано в любом классическом учебнике по реляционным БД, лучше читать авторов из IBM. Oracle-исты жить без ID не могут, даже встречал в документации Oracle глупость, что составной ключ PK устаревшее понятие.

Вот свежий глюк, вызванный ID


В двух системах используется ID. Данные одной системы перекачиваются в другую, где записи получают собственные ID. "Другая" система шлет запросы в "одну" с параметрами, среди которых есть и ID. Естественно программист "другой" системы мыслит собственными ID и передает их в параметре запроса, на что получает пустой результат или может получить данные другого объекта (искаженный, неверный результат), если случайно один и тот же ID окажется в обеих системах (но принадлежит то он разным записям).


И такие проблемы лезут сплошь и рядом. Сколько времени тратится на их поиск и устранение? Уйма.

Правильно, не использовать ID (номер строки) вообще или в лучшем случае использовать ID только в справочниках (НСИ) с небольшим количеством записей.


И у Вас исчезнут все "головные боли", вызываемые наличием ID в записи таблицы.


В моих системах ID в таблицах нет вообще, а разгребать проблемы с ID в чужих приходится. Только что, первый запрос для тестировщиков показал наличие дубликатов записей в таблице с ID в качестве PK (тестировщикам потребовалось найти записи, чтобы с ориентироваться, с какими объектами системы можно протестировать ее функционал)


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

Готовой статьи у меня нет, именно статьи описывающей принцип работы через один метод. Есть статья, где описан пример реализации, основанной на этой идее
https://habr.com/ru/post/485408/

Во первых, где генерируется ID "на стороне Java", "на стороне БД" или еще где то, не имеет значения. Во всех вариантах без исключения это ведет к временным потерям!
Во вторых, тема статьи касается ID? Касается, ID рассматривается в статье. Вопрос "как Spring определяет, что запись новая?" отпадает сам собой, если просто отказаться от использования ID, как сразу пропадает и целая куча других проблем, вызванных наличием ID.


А сейчас выскажу еще более "крамольную" мысль (ох и набросятся на меня Spring-исты со своими минусами). Парадокс заключается в том, что при отказе от использования ID и Spring становиться не нужным! Это программный мусор! (все, сейчас заминусуют). JDBC хорошо формализован!!! Что позволяет работать с любой БД реализовав всего один метод. Один!, чтобы было удобней пользоваться можно над этим методом реализовать с десяток методов "оберток" с разным набором параметров. Все! Все это помещается в один небольшой класс и может таскаться из задачи в задачу без какой либо модификации.


И не нужно создавать классы пустышки репозиториев, как в примере
https://github.com/petrelevich/jvm-digging/tree/master/springDataJdbc/src/main/java/ru/petrelevich/repository


Не нужно создавать классы модели, как в примере
https://github.com/petrelevich/jvm-digging/tree/master/springDataJdbc/src/main/java/ru/petrelevich/model
Привязка программной модели объектов к модели БД это тоже ужасное решение, но это уже к статье не относится.

Жаль, что не сохранил логи для фанатов ID и любителей ставить минусы за отличную от их точки зрения, где явно видно потери времени на вычисление ID для большого множества записей, вставляемых в одной транзакции.

Как не значит? Не важно пользуетесь вы готовым лишним кодом или пишите свой. Вы теряете производительность на вычислениях вашего ID. Для одной записи это практически незаметно, для множества записей это выливается в десятки — сотни секунд.

То есть, пишем лишний код, о чем я и говорил с самого начала


  1. для достижения уникальности ID — пишем лишний код
  2. для достижения уникальности записи — "пишем" лишний код
    и так далее по всем пунктам.

Обсуждается ID — номер строки в таблице. Сурогатность ключа по этому полю только одна из множества проблем, возникающих при использовании ID записи.


Еще одна проблема — увеличение длины транзакции при модификации множества таблиц. Вам нужно получить значения ID (номера строки) от БД для каждой записи одной таблицы, чтобы установить эти значения в записи другой таблицы для последующей передачи этих записей БД.


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


И сразу возникает вопрос пригодности данного решения для высоконагруженных систем, где наличие длинных транзакций неприемлемо, а многоузловой вариант эксплуатации востребован. А если добавить сюда наличие требования георезервирования, то использования ID вообще терпит крах.

Тогда вопрос. Зачем Вам балласт в таблицах в виде ID, который является к тому же PK таблицы, если Вы вынуждены создавать другой ключ UK в этой таблице? И UK из-за своей специфики не обеспечивает "уникальности" и отличается от PK. Не проще ли сразу сделать PK из тех полей, которые Вы все равно включите в UK и "известная проблема" сразу исчезает?


Допустим Вы закрыли глаза на различия PK и UK и подставили "подпорку" в вашей системе этим решением. Но другие проблемы с ID Вы этим решением не устранили и для каждой другой проблемы ID Вам снова нужно искать какие то решения, снова писать лишний код.


Парадокс еще заключается в том, что в некоторых таблицах ID никогда не используется, вообще НИКОГДА.

Да, в этом. ID не делает запись уникальной.

Предложенные Вами решения никак не решают описанную мной проблему.

Рискую навлечь на себя кучу минусов, но все же выскажусь


Как можно использовать в реляционных моделях суррогатный ключ ID записи, который по сути является номер строки в таблице? Зачем Вам нужна вообще реляционная СУБД, если любое обращение к записи идет по номеру строки?


В примере статьи добавляется запись


var object = new SomeObject(null, "name", "value");

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


Будет две или более одинаковых записей в таблице! Да хоть всю таблицу можно забить в этом случае одной и той же записью.


Для "борьбы" с этой проблемой вам приходиться самим реализовывать тот или иной собственный "реляционный" механизм. Неважно какой, важно, что приходится!


И таких недостатков у ID множество, "борьба" с которыми заставляет Вас писать много лишнего кода, а в некоторых случаях и вовсе не позволяет Вам решить проблему. Например, в двухсторонней репликации данных, в двух разных копиях БД Вы можете получать одинаковые ID у разных записей или разные у одной и той же записи.

По сути пакеты javax.* это спецификации (декларация интерфейсов и "базовых" классов). Менять названия этих пакетов полная глупость. Это же нарушение совместимости, нужно все продукты править, в которых используются реализации этих спецификаций.

Information

Rating
Does not participate
Location
Нижний Новгород, Нижегородская обл., Россия
Registered
Activity