Pull to refresh

Comments 45

Если я не ошибаюсь, к JDBC это никак не относиться. Это обычный Spring Data JPA. Если бы речь была о Spring Data JDBC, в таком случае нам не пришлось бы создавать интерфейс с расширением от Crud-, PagingAndSorting-, JpaRepository.

Для Spring Data JDBC необходимо инжектить JdbcTemplate либо его наследников и прописывать SQL запросы руками в методах.

Подходы ведь разные.

Не совсем. Spring data JDBC — классическая spring data на минималках. Все с теми же репозиториями, но без ORM провайдера и всех плюшек, что за ним тянутся (сессии, кэш, dirty-check и т.д.).

я и не говорю что это не Spring Data. Я имел ввиду то, что название статьи касается Spring Data JDBC, а содержимое относиться к Spring Data JPA. Это два разных подпроекта из проекта Spring Data
посмотрите исходный код полностью,
ссылка в конце поста.
Нет, вы не правы. Spring Data JDBC имеет прямое отношение к jdbc. Spring-Data-JDBC это один из проектов спринга. Он намного легче Spring-Data-Jpa ибо не содержит такого объемного ORM. Однако обеспечивает функционал и удобство репозиториев.
да, именно так.
Spring Data основан на Hibernate, а Spring Data Jdbc работает поверх jdbc.
За счет этого проще и более предсказуем.

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


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


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


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

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


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


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


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

Будет две или более одинаковых записей в таблице!

Чтобы такого не было, достаточно генерировать id на стороне базы данных.
Или можно, например, GUID создавать в java-коде.

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

проблема в создании дубликатов?
т.е. две одинаковые записи, но с разным id все равно будут одинаковыми.
в этом проблема?

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

Это известная проблема.
Один из вариантов решения — constraints на стороне базы.

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


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


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

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

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


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


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


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

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


С этой задачей отлично справляется генерация UUID.
Можете масштабировать на столько услов на сколько надо.

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


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

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

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

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

Генерация Id «на стороне java» требует дополнительное время — это очевидный факт и доказательств не требуется. Однако бывают случаи, когда это подходящее решение.
Вопрос в другом. Какое это имеет отношение к теме поста?

Во первых, где генерируется 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
Привязка программной модели объектов к модели БД это тоже ужасное решение, но это уже к статье не относится.

А можете написать статью, или дать ссылку на репозиторий в котором реализован ваш подход?

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

Примеры «как не нужно» — это, конечно, хорошо. Но где примеры «как нужно»?
Ваша концепция звучит хорошо — слишком хорошо. Но где примеры?
Плюс все Ваше рассуждение основано на довольно сомнительных утверждениях.
1. «Как можно использовать в реляционных моделях суррогатный ключ ID записи, который по сути является номер строки в таблице?»
2. Для «борьбы» с этой проблемой вам приходиться самим реализовывать тот или иной собственный «реляционный» механизм. Неважно какой, важно, что приходится!
3. Вы говорите, что можно вычислять ID в приложении, но тогда сразу ставится крест на многоузловой эксплуатации приложения…
4. для достижения уникальности записи — «пишем» лишний код
и так далее по всем пунктам.

И т.д.
Думаю вам стоит попробовать заменить ID в рассуждениях на «name in namespace».
И «вам приходится» на «мне приходится» в комментариях…

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


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


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


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

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


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


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

Вы привели в пример результат неграмотности архитектора/лида/лица ответственного за архитектуру. Банальная проблема с которой сталкиваются студенты в на первых порах проектирования систем. Это как раз и возникает из-за того, что люди упорно считают суррогатный ID «номером строки в таблице».

«Не используйте...», «у Вас исчезнут все „головные боли“...»
Еще раз: у Нас нет головных болей из-за использования идентификаторов.
Вы приведите пример схемы данных из вашей системы где «ID в таблицах нет вообще». Так было бы гораздо проще Вас понять.

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


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


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


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

«Сурогатные ключи» vs «Естественные» — это давнишний и бесполезный спор.
Есть удачные и неудачные приеменения и того и другого.
В каждом конкретном случае надо делать осознанный выбор.

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

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


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

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


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

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


"И если у Вас не "болит голова" из-за 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 другой и если программист перепутал поля таблиц, то этого может и не заметь вовремя.



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

Это снова вы… Я уже даже начал скучать


  1. В "классической теории реляционной БД" нет понятия "номер строки". Понятие ID (identifier) там есть. Это атрибут (именно атрибут объекта/кортежа) или набор атрибутов уникальный в рамках таблицы или набора данных.
    Суррогатный ID — искусственно введенный атрибут объекта/кортежа, если объект изначально не имеет идентификатора простого либо составного.
    Только Identifier может быть использован в качестве ключа:


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

    Что до номера строки — это функция субд которая предоставляет (а не заставляет) возможность автоматического создания значения некого атрибута введенного в качестве суррогатного ключа (иногда даже не суррогатного).


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

    Это не является вставкой за раз одной и той же записи.
    Я так полагаю — там где указан null должен быть атрибут ID записи.
    В контексте использования ORM Hibernate эта запись означает следующее:
    "Моя изначальная структура данных не имеет атрибутов позволяющих использовать их как идентификатор (ID, identifier) и соответственно, нет возможности составить отношение т.к. нельзя определить PK. Поэтому я декларирую искусственный атрибут ID/identifier/ИНН.
    И создавая запись с использованием Hibernate, я следую документации которая указывает опустить идентификационный атрибут, и тогда Hibernate установит его сам с учетом конфигурации.
    Hibernate может как использовать счетчик (sequence) в бд, так и заданные мной генераторы для формирования атрибута."
    Но ничего не мешает работать вот так


    var object1 = new SomeObject({{fucking_line_number}}, "name", "value");

    т.е. напрямую указывать ID.


  3. "Генерация уникального ID — неизбежные временные потери."
    Да — неизбежные. Существенные? а вот это уже спорно.
    Как их избежать — используйте sequence. Как их уменьшить — используйте суррогатный ключ простого типа.
    Генерация ключа sequence — один машинный такт. Буквально.
    При использовании составного или естественного ключа помимо генерации всегда идет проверка уникальности. А это вычисление хэша и поиск по индексу.
    В этом плане хорош UUID: несмотря на свою кажущуюся громоздкость это всего лишь 128-битное число.


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

    Если в некоторых таблицах есть PK (атрибут гарантирующий уникальность через "номер строки"), но он никогда не используется, значит только то, что допущены серьезные ошибки при проектировании схемы данных или формулировании требований к системе. Не стоит путать причину и следствия.
    "ID не используется в части таблиц по своему прямому назначению -> значит ID "мусор""
    "Плохой дизайн схемы данных -> ID не используется в части таблиц по своему прямому назначению"
    Заметьте разницу


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


    ресурсоемкие алгоритмы генерации значений

    Специально придуманы нересурсоемкие алгоритмы, например UUID который вообще не требует общего разделяемого ресурса для координации значений.
    Плюс надо осознавать особенности системы, например отношение чтения-записи.


    • sequence в бд: самое быстрое создание (даже с учетом конкурентного доступа) самая быстрая проверка уникальности и чтения т.к. не происходит расчета хэшей и индекса.
    • UUID: Быстрая генерация и быстрая вставка за счет отсутствия индекса (не везде правда) т.к. повторюсь — это всего лишь 128-битное число.
    • Естественный идентификатор — очень повезет если это заведомо уникальный атрибут, который можно привести к числу, тогда получаем почти первый вариант.
      Если не повезло и имеем составной ключ из двух строковых колонок по 50 символов, то получаем расчет хэша на массиве до 100 байт с проверкой в индексе и обновление индекса, что является гораздо более ресурсоемкой операцией.

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

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


  7. "и если программист перепутал поля таблиц" — а если программист также перепутал поля составного ключа в объединении? Это другое?



И последнее — мы с вами не коллеги и, надеюсь, никогда не будем.

  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? ОК
Как тогда называется то, что идентифицирует кортеж в случае если нет набора атрибутов уникально и однозначно идентифицирующих кортеж?
https://en.wikipedia.org/wiki/Surrogate_key


Для высокнагруженных или многопользовательских систем вычисление ID выливается в неприемлемые временные потери производительности.

Я кажется довольно ясно описал сравнение производительности разных подходов. Ну если вы придираетесь к "одному такту" — хорошо. 10 тактов или 20 тактов или хотите — 30 тактов со всеми мьютексами. Это все равно на порядок (а скорей всего на два) меньше вычисления хэша и индекса для натурально ключа из двух маленьких строк.


Если вы такой опытный — подскажите:
Как людям хранить банковские транзакции в таблице. Все "исходные" натуральные атрибуты могут дублироваться даже время создания.
Какой ключ использовать?

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

Генерируемый 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. не указываю людям как правильно нужно делать
  2. не говорю, что их мнение приводит ко множеству ошибок
  3. не принижаю уровень знания собеседника
  4. не оцениваю уровень воспитания собеседника
  5. не говорю от имени собеседника и не приписываю ему фразы которые он говорил.

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


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


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

И еще добавлю


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

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

да, так и есть.
При этом UUID можно генерировать не рандомный, а с привязкой ко времени, тогда возможность сортировки сохранится.

Мне лично UUID не нравится тем, что он избыточен (лишние символы, плюс это String). Удобнее взять long, скажем, на 64 бита и кастомно его формировать.

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

Это все отлично решается и с чисто цифровыми ID. Можно сохранить и случайность и более-менее упорядоченность.
Но зато каждый UUID — это целых 128 бит, часть из которых лежит мертвым грузом.
Я немного дополню мой коммент.
Мне не нравится идея использовать UUID именно в качестве первичного ключа. Они лежат в базе в самом горячем кэше, и тут оно не очень к месту.
Как публичный ID для доступа к чему-то — вполне норм (но я бы таки предпочел кастомный цифро-буквенный ID).

Sign up to leave a comment.