
Новые сообщения [новые:0]
Дайджест
Горячие темы
Избранное [новые:0]
Форумы
Пользователи
Статистика
Статистика нагрузки
Мод. лог
Поиск
|
|
17.08.2016, 22:04
|
|||
|---|---|---|---|
|
|||
Изобретение велосипеда для генерации уникальных ID |
|||
|
#18+
Привет всем, почитав форум по этой части понял, что лучше всё же спросить перед тем как выливать в продакшн. Представьте себе единственную и неповторимую в мире бд. Для упрощения пусть в ней будет 3 таблицы: Товары, Продажи, Проданные товары. С точки зрения православия они должны быть связанны внешними ключами. На практике же внешний ключ это условность, он как бы есть но его как бы и нет. Знаю что звучит парадоксально, но клиентская программа держит связи между таблицами у себя в уме, а не в самой бд. Теперь немного таблиц. Товары ID (int) Имя (варчар) Цена (float)1 Товар-самовар 102 Товар-амбар 999 Колонка ID это первичный некластеризированный ключ, к счастью это прописано не только на клиенте, но и в бд. Продажи ID (int) ID клиента (int) Сумма (float)1 1 10092 1 100 Проданные товары ID (int) ID продажи (int) ID товара (int) к-во (int) цена (float)1 1 1 1 102 1 2 1 9993 2 1 10 10 Есть какая особенно, на стороне бд есть только один ключ, это ID строки. Всё остальное это не ключи, хотя с точки зрения православия это внешние ключи, но вся эта логика лежит в чёрном ящике и туда невозможно лезть. Теперь представим что по желанию левой пятки мне захотелось забабахать 10 распределённых баз. Звучит сложно, но поверьте реальная ситуация не далека от приведенного примера, поэтому особых трудностей не будет. Есть несколько требований: 1) только православный MERGE, то есть никакие решения от MS SQL не принимаются. 2) чаще всего интернета не будет как солнца во время летних дождей во Вьетнаме. И что-то там еще... Теперь вот что я изобрёл. Каждой бд будет выдан некий уникальный префикс. Например просто BD1, а другой BD2 и так далее. Теперь поплюём на все эти ключи, индексы и прочую научную теорию реляционных баз и создадим колонку с названием TrueIDforPRO (varchar(max) хахах). И зашьём в бд такую вещь как Prefix. Это что-то вроде BD1 для первой базы, BD2 для второй и так далее. Зачем? Далее покажу. А теперь в каждой программе клиенте вбить колом, что все создаваемые записи будут только с Prefix который дал им господин, а вот ID будет по преждему автоинкрементом. Теперь вопрос, как вы думаете чему будет равен TrueIDforPRO? Конечно же Prefix+ID и в итоге выйдет что-то вроде BD1-1, BD1-2 и так далее. Кто будет генерировать наш крутой TrueIDforPRO? Конечно же приложение на клиенте, не триггерами на бд же мне это делать (хотя можно не спорю). Теперь давайте сделаем MERGE одной таблицы, пусть это будут продажи. Таблица1 ID (int) ID клиента (int) Сумма (float) TrueIDforPRO (варчар)1 1 1009 BD1-12 1 100 BD1-2 Таблица2 ID (int) ID клиента (int) Сумма (float) TrueIDforPRO (варчар)1 99 339 BD2-12 150 866 BD2-2 Теперь делаем двухсторонний MERGE ( двухсторонний MERGE - это моя запатентованная технология) И в итоге и там и там то есть в двух таблицах должно получится что-то вроде: ID (int) ID клиента (int) Сумма (float) TrueIDforPRO (варчар)1 1 1009 BD1-12 1 100 BD1-23 99 339 BD2-14 150 866 BD2-2 Очевидно что первое поле ID не используется для идентификации записей при MERGE. А используется TrueIDforPro который гарантирует глобальную уникальность. ID просто живёт своей жизнью и никто его не трогает, никому он уже не нужен старичок. И вот я изобрёл велосипед. Почему? У меня есть ограничения, программа клиента не умеет ничего, что умеет нормальная БД. Она умеет только ID и всё. GUID, составные ключи и прочая химия ей не дана. Только православные первичные ключи. Так что я вынужден писать велосипед. И всё было хорошо, но есть вопросы. Прикинем в 2 таблицы "Клиенты" Таблица 1 ID Имя TrueIDforPRO1 Очень хороший человек BD1-12 Хороший человек BD1-23 Человек BD1-34 человек BD1-45 засланый казачек BD1-5 Таблица 2 ID Имя TrueIDforPRO1 Очень плохой человек BD2-12 Плохой человек BD2-23 Человечище BD2-34 человекоподобный BD2-45 посланник бога BD2-5 Теперь делаем двухсторонних MERGE и там и тут выходит вот что. ID Имя TrueIDforPRO1 Очень хороший человек BD1-12 Хороший человек BD1-23 Человек BD1-34 человек BD1-45 засланый казачек BD1-56 Очень плохой человек BD2-17 Плохой человек BD2-28 Человечище BD2-39 человекоподобный BD2-410 посланник бога BD2-5 А теперь вопрос на засыпку. Как в продажах указывать клиентов? В продажах мы имеем примерно это ID (int) ID клиента (int) Сумма (float) TrueIDforPRO (варчар)1 1 1009 BD1-1 То есть ID выбирается не из TrueIDforPRO который глобально уникальных, а по обычному мусору ID. Казалось бы, нужно просто изменить таблицу и сделать так: ID (int) TrueIDforPRO клиента (varchar) Сумма (float) TrueIDforPRO (варчар)1 1 1009 BD1-1 Но у меня возникает вопрос. Представьте теперь, что таблиц примерно 10 штук и в одной из них >200к записей, а остальных ~50k Очень часто делаются запросы типа SELECT * from Продажи и SELECT * from блабла WHERE ТелефонКлиента LIKE %099798% и так далее. А ещё есть десяток представлений с километровыми по длине запросами, которые ещё хоть с какой-то скоростью работают, а вот если изменить ID int на varchar то я боюсь представить последствия. Как дела с производительностью будут? Если у вас есть сомнения о том как будут решаться конфликты, то их не будет, так как каждый клиент сможет редактировать только свою запись. Поэтому не будет ситуации, что 2 клиента одну запись изменили. Зато любой клиент будет видеть все записи других клиентов. Я ничего лучше из-за своего нубства к сожалению не придумал. Были идеи на счет разных диапазонов ID для каждой бд. Но я не знаю о подводных камнях подобной реализации, она мне не очень ясна. Просто прокомментируйте, мой велосипед ... |
|||
|
:
Нравится:
Не нравится:
|
|||
|
|
|
18.08.2016, 11:09
|
|||
|---|---|---|---|
Изобретение велосипеда для генерации уникальных ID |
|||
|
#18+
KimelБыли идеи на счет разных диапазонов ID для каждой бд. Но я не знаю о подводных камнях подобной реализации, она мне не очень ясна.IMHO, диапазон автоинкремента лучший вариант. Не хватит int в 4 байта, сделайте в 8, можете decimal(n,0) использовать. А велосипед лучше выбросить, слишком уж много приседаний для генерации глобальных идентификаторов, проще GUID для этого пока ничего не придумали. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
|
|
|
18.08.2016, 14:37
|
|||
|---|---|---|---|
Изобретение велосипеда для генерации уникальных ID |
|||
|
#18+
Kimel, Я правильно понимаю, что при каждом merge вы будете оригинальные id, созданные клиентской программой, перенумеровывать, чтобы в общей БД не было дубликатов? У вас нет внешнего потребителя, который эти id у себя хранит и для которого может стать сюрпризом вдруг изменившийся номер у какой-либо сущности? И какая-то неясная ситуация с клиентской программой из вашего описания. То она у вас "черный ящик", а то вы ее собираетесь научить префиксы использовать. А почему бы тогда уж, раз у вас есть доступ к исходникам, не научить нормальные идентификаторы использовать? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
|
|
|
18.08.2016, 15:38
|
|||
|---|---|---|---|
|
|||
Изобретение велосипеда для генерации уникальных ID |
|||
|
#18+
474, В программе есть некая ограниченная кастомизация. Можно в качестве id даже bigint использовать, а в качестве внених ключей даже varchar использоваться, но на этом возможности кончаются. Программа понимает немножко sql поэтому генерация префиксов возможно благодаря банальнальной конкатенации строк. Но GUID это же не varchar, они вроде в бинарном виде хранятся, поэтому программа просто не может определить тип этого поля (так как он не вшит в неё) и не может его использоваться в качестве ключей и идентификаторов(( Ругается. ChA, я немножко поэксперементировал и понял что bigint в ID программа кушает нормально. То есть можно диапазоны ID выделить. НО есть одна загвоздка. Смотрите, это уже скорее вопрос по MS SQL но всё же думаю не стоит плодить темы из-за маленького вопросика. Вот есть у первой бд диапазон 1-10 000 000 , а у второй 10 000 001 - 20 000 000 . Всё хорошо, но вот теперь я делаю merge к примеру двух простых таблиц чисто для примера. Продажи 1 ID Имя товара102015 Банан Продажи 2 ID Имя товара10 250 343 Банан Вот что получится в первой БД ID Имя товара102015 Банан10 250 343 Банан Вроде всё как и должно быть? Не ту то было. Ведь ID автоинкрементный причем за это отвечает сам MS SQL И когда в бд1 будет новая запись это будет выглядеть не так ID Имя товара102015 Банан10 250 343 Банан102016 Банан а так ID Имя товара102015 Банан10 250 343 Банан10 250 344 Банан И я не знаю что тут поделать. Нужно заставить MS SQL генерировать ID только в его диапазоне. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
|
|
|
18.08.2016, 15:50
|
|||
|---|---|---|---|
|
|||
Изобретение велосипеда для генерации уникальных ID |
|||
|
#18+
KimelНужно заставить MS SQL генерировать ID только в его диапазоне. Последовательности в default или триггерах. Posted via ActualForum NNTP Server 1.5 ... |
|||
|
:
Нравится:
Не нравится:
|
|||
|
|
|
18.08.2016, 18:08
|
|||
|---|---|---|---|
|
|||
Изобретение велосипеда для генерации уникальных ID |
|||
|
#18+
Dimitry SibiryakovKimelНужно заставить MS SQL генерировать ID только в его диапазоне. Последовательности в default или триггерах. В интернете иного информацию по поводу identity range for merge replication. Но подразумевается использование стандартной ms sql сервер merge репликации и в её настройках можно выставить эти range. Но информацию как сделать вручную диапазоны для идентификаторов без триггеров я не нашёл. Помогите пожалуйста. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
|
|
|
18.08.2016, 18:15
|
|||
|---|---|---|---|
|
|||
Изобретение велосипеда для генерации уникальных ID |
|||
|
#18+
Без триггеров или вмешательства в приложение - никак. Это ж MS SQL, что с него, болезного, возьмёшь... Posted via ActualForum NNTP Server 1.5 ... |
|||
|
:
Нравится:
Не нравится:
|
|||
|
|
|
18.08.2016, 18:24
|
|||
|---|---|---|---|
|
|||
Изобретение велосипеда для генерации уникальных ID |
|||
|
#18+
Dimitry Sibiryakov, Все понятно, спасибо всем за советы. Тогда только триггеры на инсерт, к счастью такая возможность у меня есть ... |
|||
|
:
Нравится:
Не нравится:
|
|||
|
|
|
18.08.2016, 19:01
|
|||
|---|---|---|---|
Изобретение велосипеда для генерации уникальных ID |
|||
|
#18+
Kimel...Нужно заставить MS SQL генерировать ID только в его диапазоне.Давным-давно начало диапазона можно установить хоть перед созданием таблицы(IDENTITY(N)), хоть после него(DBCC CHECKIDENT), верхний порог прекрасно ограничивается с помощью check constraint. В MS SQL Server 2012 появился CREATE SEQUENCE. Может надо было задать вопрос в соответствующем форуме , прежде чем изобретать велосипеды ? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
|
|
|
18.08.2016, 19:04
|
|||
|---|---|---|---|
|
|||
Изобретение велосипеда для генерации уникальных ID |
|||
|
#18+
Kimel И я не знаю что тут поделать. Нужно заставить MS SQL генерировать ID только в его диапазоне. Ну в принципе Вы можете написать что--то вроде такого Код: sql 1. 2. 3. 4. 5. соответственно при слиянии писать только в OuterID, а для идентификации использовать InterfaceID ... |
|||
|
:
Нравится:
Не нравится:
|
|||
|
|
|
18.08.2016, 21:24
|
|||
|---|---|---|---|
|
|||
Изобретение велосипеда для генерации уникальных ID |
|||
|
#18+
ChAKimel...Нужно заставить MS SQL генерировать ID только в его диапазоне.Давным-давно начало диапазона можно установить хоть перед созданием таблицы(IDENTITY(N)), хоть после него(DBCC CHECKIDENT), верхний порог прекрасно ограничивается с помощью check constraint. В MS SQL Server 2012 появился CREATE SEQUENCE. Может надо было задать вопрос в соответствующем форуме , прежде чем изобретать велосипеды ? Попробовал с CHECK CONSTRAINT . что в итоге я задал его таким образом для таблицы из базы1 ([ID]>=(0) AND [ID]<=(10)) То они по идее должны теперь от 1 до 10 генерироваться, но при вставке в бд например запись с id 20 она вполне логично не вставляется так как не проходит через это условие. Хотя SET IDENTITY_INSERT tblSales ON и при инсерте ID был указан. Я хотел,чтобы автоинкремент работал только в определённом диапазоне, а вставки можно было делать с любым ID поэтому скорее всего CONSTRAINT не подходит. Кот Матроскин , Ну в принципе Вы можете написать что--то вроде такого Код: sql 1. 2. 3. 4. 5. соответственно при слиянии писать только в OuterID, а для идентификации использовать InterfaceID[/quot] Этот вариант больше вселяет надежду. Я создал тестовую таблицу проверил и всё работает как я и хотел. Я думаю это то что нужно. Правда придётся добавить теперь везде по 2 колонки, но я думаю это мелочи. Было бы хуже если бы на каждую таблицу пришлось бы писать триггеры. Потому что у меня уже есть куча триггеров и их настраивать намного сложнее. Ваше решение самое простое. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
|
|
|
18.08.2016, 22:25
|
|||
|---|---|---|---|
Изобретение велосипеда для генерации уникальных ID |
|||
|
#18+
KimelChAДавным-давно начало диапазона можно установить хоть перед созданием таблицы(IDENTITY(N)), хоть после него(DBCC CHECKIDENT), верхний порог прекрасно ограничивается с помощью check constraint. В MS SQL Server 2012 появился CREATE SEQUENCE. Может надо было задать вопрос в соответствующем форуме , прежде чем изобретать велосипеды ?Попробовал с CHECK CONSTRAINT . что в итоге я задал его таким образом для таблицы из базы1 ([ID]>=(0) AND [ID]<=(10)) То они по идее должны теперь от 1 до 10 генерироваться, но при вставке в бд например запись с id 20 она вполне логично не вставляется так как не проходит через это условие. Хотя SET IDENTITY_INSERT tblSales ON и при инсерте ID был указан. Я хотел,чтобы автоинкремент работал только в определённом диапазоне, а вставки можно было делать с любым ID поэтому скорее всего CONSTRAINT не подходит.Могу только ещё раз повторить, что для решения задач на конкретных СУБД нужно обращаться в соответствующий форум и внятно сформулировать, что хотелось бы получить. А уж методов там накидают вагон и малентьая тележка. Чем не устроил CREATE SEQUENCE, если у вас MS SQL от 2012 версии ? Там всё есть, включая обе границы. Соответственно, check уже будет не нужен и вставка внедиапазонных идентификаторов пройдет без проблем. За использование SET IDENTITY_INSERT в приличных домах бьют, простите, лицо. Оно предназначено прежде всего для bulk операций, да и полномочия на него требуются гораздо выше, чем для обычного рядового пользователя. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
|
|
|
18.08.2016, 23:05
|
|||
|---|---|---|---|
Изобретение велосипеда для генерации уникальных ID |
|||
|
#18+
KimelКот Матроскин , Ну в принципе Вы можете написать что--то вроде такого Код: sql 1. 2. 3. 4. 5. соответственно при слиянии писать только в OuterID, а для идентификации использовать InterfaceIDМожно, кстати, пойти от обратного, т.е. Код: sql 1. 2. 3. 4. 5. Если заведомо известно, что таблиц для слияния будет не больше N, то identity (m,N) будет делать "дыры" в N идентификаторов, начиная с какого-то заранее определенного номера таблицы m, где m < N. О верхней границе можно будет не беспокоиться. Числа никогда не пересекутся. Естественно, N должно быть заведомо больше числа возможных таблиц для слияния с запасом. И будет достаточно одного поля идентификаторов. Но SEQUENCE в данном случае будет всё-таки проще. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
|
|
|
18.08.2016, 23:17
|
|||
|---|---|---|---|
Изобретение велосипеда для генерации уникальных ID |
|||
|
#18+
ChAМожно, кстати, пойти от обратного, т.е.Нельзя, вставка записей с IDENTITY_INSERT сдвинет текущее значение и отсчет пойдет начиная с наибольшего вставленного ID. Так что проще всего будет использование SEQUENCE. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
|
|
|
18.08.2016, 23:24
|
|||
|---|---|---|---|
Изобретение велосипеда для генерации уникальных ID |
|||
|
#18+
Как вариант, разделить "свою" таблицу с id и общую, где остальные с id вне диапазона. Доступ на чтение организовать через view с union, можно даже материализованное. Зато никаких IDENT_INSERT. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
|
|
|

start [/forum/topic.php?fid=32&mobile=1&tid=1540294]: |
0ms |
get settings: |
8ms |
get forum list: |
11ms |
check forum access: |
3ms |
check topic access: |
3ms |
track hit: |
160ms |
get topic data: |
12ms |
get forum data: |
2ms |
get page messages: |
51ms |
get tp. blocked users: |
2ms |
| others: | 14ms |
| total: | 266ms |

| 0 / 0 |

Извините, этот баннер — требование Роскомнадзора для исполнения 152 ФЗ.
«На сайте осуществляется обработка файлов cookie, необходимых для работы сайта, а также для анализа использования сайта и улучшения предоставляемых сервисов с использованием метрической программы Яндекс.Метрика. Продолжая использовать сайт, вы даёте согласие с использованием данных технологий».
... ля, ля, ля ...