Considering that SQL Azure Federations does not support the IDENTITY property or SEQUENCEs, what would be an efficient way to generate sequential numbers when inserting records?
For instance, given a table with these columns:
CREATE TABLE [dbo].[Orders] (
[TenantId] [uniqueidentifier] NOT NULL,
[OrderId] [uniqueidentifier] NOT NULL,
[OrderNumber] [int] NOT NULL
CONSTRAINT [PK_Orders] PRIMARY KEY CLUSTERED (
[TenantId] ASC,
[OrderId] ASC
)
) FEDERATED ON ([FederationKey] = [TenantId])
for each order inserted for a given tenant, the OrderId should be incremented. For instance, for tentant A OrderId would be 1, 2, 3... and for tenant B OrderId would also be 1, 2, 3... in an independent sequence. Ideally there should be no gaps.
TenantId and OrderId are components of the primary key. Their values are set by the application and they're not related to the issue of generating sequences; only OrderId has the sequential number with business meaning. Also, TenantId is the distribution key of the federation.
This MSDN Blog article describes in option 1 an approach of having a table holding the sequences and using a stored procedure in a segregated transaction to increment the sequences. Each tenant would have a record on this table holding the last used value of the sequence.
Would that be the optimum approach considering scalability, contention, resource locking? Any other useful tricks, considering the limitations of SQL Azure Federations?
The syntax to create a sequence in SQL Server (Transact-SQL) is: CREATE SEQUENCE [schema.] sequence_name [ AS datatype ] [ START WITH value ] [ INCREMENT BY value ] [ MINVALUE value | NO MINVALUE ] [ MAXVALUE value | NO MAXVALUE ] [ CYCLE | NO CYCLE ] [ CACHE value | NO CACHE ]; AS datatype.
To number rows in a result set, you have to use an SQL window function called ROW_NUMBER() . This function assigns a sequential integer number to each result row. However, it can also be used to number records in different ways, such as by subsets.
Federation is introduced in SQL Azure for scalability. It helps administrators by making repartitioning and redistributing of data easier and thus, helps with scaling data. It helps developers in the routing layer and the sharding of data. It helps in routing without application downtime.
A sequence is a database object that allows the automatic generation of values, such as check numbers. Sequences are ideally suited to the task of generating unique key values. Applications can use sequences to avoid possible concurrency and performance problems resulting from column values used to track numbers.
Here are 2 additional ideas.
An approach would be to have a separate process update that field to make this asynchronous, if that is something possible for your business scenario. You would need to have the OrderNumber field accept NULL values for this approach. To know which Order came first, so that it gets the correct OrderNumber, I would also add an InsertedDate field. Async processing gets more complex if you have multiple worker roles performing this duty for redundancy, in which case you will need to have each process assign itself the records it is working on (so you also need an OwnedBy field), add a concurrency test during the UPDATE to ensure each process is executing on its own records, and have the records' assignment expire (so you also need an AssignedOn field) if the process crashes so that it doesn't leave orphans. Not really trivial...
And then you have the poor's man approach... which when the stars align themselves just well enough may be all you need. If you are willing to have an optimistic concurrency approach, try using the next Number during the insert (select the MAX OrderNumber first for a given TenantId and OrderId), then perform the Insert. If the insert fails (because you added a Unique index on TenantId, OrderNumber for that purpose), just add 1 to the OrderNumber. The real issue here is the frequency of retries and the likelyhood of this approach failing. If you have a relatively streamlined business process this may actually never fail; if however you have orders added constantly from multiple avenues, this may be an unacceptable approach.
not sure how much effort would be required to fit your scenario, but have a look at this as well and see if you can tweak it: SnowMaker – a unique id generator for Azure (or any other cloud hosting environment)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With