Генерация порядковых номеров в многопользовательском Saas-приложении

Как люди генерируют целые числа с автоинкрементом для конкретного пользователя в типичном приложении SaaS?

Например, номера счетов-фактур для всех счетов-фактур для конкретного пользователя должны автоматически увеличиваться и начинаться с 1. Поле идентификатора rails нельзя использовать в этом случае, так как оно является общим для всех пользователей.

Навскидку я мог бы сосчитать все счета, которые есть у пользователя, а затем добавить 1, но кто-нибудь знает какое-нибудь лучшее решение?


person Abhishiv Saxena    schedule 09.07.2009    source источник


Ответы (6)


Типичным решением для любой реляционной базы данных может быть таблица наподобие

user_invoice_numbers (user_id int primary key clustered, last_id int)

и хранимая процедура или SQL-запрос, например

update user_invoice_numbers set last_id = last_id + 1 where user_id = @user_id
select last_id from user_invoice_numbers where user_id = @user_id

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

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

1) Исключите процедуру, которую вы используете для получения новых номеров, из длительных транзакций. Предположим, что процедура вставить в счет является длительной транзакцией со сложной серверной логикой. . В этом случае вы сначала получаете новый идентификатор, а затем отдельной транзакцией вставляете новый счет. Если последняя транзакция будет откатана, автономер не уменьшится. Но user_invoice_numbers не будет заблокирован в течение длительного времени, поэтому множество одновременных пользователей могут одновременно вставлять счета.

2) Не используйте традиционную транзакционную базу данных для хранения данных с последним идентификатором для каждого пользователя. Если вам нужно поддерживать простой список ключей и значений, существует множество небольших, но быстрых механизмов базы данных, которые могут это сделать. которые работают для вас. Список баз данных ключей/значений< /а>. Вероятно, наиболее популярным является memcached. В прошлом я видел проекты, в которых простые хранилища ключей/значений были реализованы с использованием реестра Windows или даже файловой системы. Был каталог, где каждое имя файла было ключом, а внутри каждого файла был последний идентификатор. И это грубое решение было все же лучше, чем использование таблицы SQL, потому что блокировки выставлялись и снимались очень быстро и не участвовали в объеме транзакции.

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

person Bogdan_Ch    schedule 09.07.2009

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

person John Topley    schedule 09.07.2009

Если номера счетов-фактур независимы для каждого пользователя/клиента, то кажется, что наличие поля «lastInvoice» в каком-либо постоянном хранилище (например, записи БД), связанном с пользователем, довольно неизбежно. Однако это может привести к разногласиям за «последний» номер.

Имеет ли значение, если мы отправим пользователю счета 1, 2, 3 и 5 и никогда не отправим ему счет 4? Если вы можете немного ослабить требования.

Если требование на самом деле «каждый номер счета-фактуры должен быть уникальным», тогда мы можем рассмотреть все обычные приемы генерации идентификаторов, и они могут быть весьма эффективными.

Последовательность чисел усложняет задачу, а приносит ли она пользу бизнесу?

person djna    schedule 09.07.2009
comment
да, поскольку это бухгалтерское приложение, числа должны быть автоматически увеличивающимися целыми числами. Значит, он тоже должен быть достаточно твердым. - person Abhishiv Saxena; 09.07.2009

Я только что загрузил драгоценный камень, который должен решить вашу проблему (несколько лет позже лучше, чем никогда!) :)

https://github.com/alisyed/sequenceid/

person Syed Ali    schedule 31.05.2011

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

person Peter    schedule 09.07.2009
comment
Действительно ли атрибут «ID счета-фактуры» принадлежит объекту «Пользователь»? Это прагматичное решение, но не для пуристов! - person John Topley; 09.07.2009
comment
Если требуется, чтобы номера счетов были последовательными для каждого пользователя, то lastInvoiceNumberForThisUser кажется тесно связанным с пользователем. - person djna; 09.07.2009

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

person Chetan    schedule 09.11.2009
comment
В некоторых странах это незаконные случайные числа. Должны быть последовательными для государственной проверки. - person Juanin; 21.12.2012