Groups | Blog | Home
all groups > sql server programming > september 2004 >

sql server programming : session scope @@DBTS


oj
9/10/2004 2:53:04 PM
You can create a timestamp column and use NEWID() as the value.

[quoted text, click to view]

Christian Hassa
9/10/2004 10:22:55 PM
Hi!

We are using rowversion fields for optimistic locking in a webservice
scenario.

When updating data we also want to retrieve the new rowversion of our
updated rows in order to check for a lock violation in subsequent updates.

We are searching for the most efficient solution for selecting the new
rowversion of our updated rows, something like:
UPDATE .....; SELECT @@DBTS

The problem is that @@DBTS is server global so if another update statement
happens in parallel we will receive the wrong rowversion.
The problem seems to me similar to @@IDENTITY vs. SCOPE_IDENTITY().

Our current solution is executing the following statements in a serializable
tx:
UPDATE T... WHERE id=X; SELECT versionField FROM T WHERE id=X

My question is, whether there is a better solution to that problem (probably
similar to the SCOPE_IDENTITY()) or if the separate SELECT statement is the
most efficient way to solve our problem. We are aiming to avoid unnecessary
SELECT statements, especially with high isolation levels.

Thank you,
Chris

Dan Guzman
9/11/2004 11:32:29 AM
To expand on oj's response, you can use optimistic concurrency while
avoiding the roundtrip by generating the row version value in your
application rather than Transact-SQL For example:

CREATE PROC UpdataMyTable
@MyKey int,
@MyValue int,
@OldMyRowVersion uniqueidentifier,
@NewMyRowVersion uniqueidentifier
AS
SET NOCOUNT ON
UPDATE MyTable
SET
MyValue = @MyValue,
MyRowVersion = @NewMyRowVersion
WHERE
MyKey = @MyKey AND
MyRowVersion = @OldMyRowVersion
IF @@ROWCOUNT = 0
RAISERROR ('Data modified by another user', 16, 1)
GO

Rowversion/timestamp/NEWID necessitates that the SQL-generated value be
returned back to the application via a SELECT or OUTPUT parameter. I would
hardly say this is unusable since it services may applications quite well.


--
Hope this helps.

Dan Guzman
SQL Server MVP

[quoted text, click to view]

oj
9/11/2004 2:34:27 PM
Chris,

Currently, there isn't anything builtin that would allow you to do that. A wish
to sqlwish@microsoft.com might be in order. I would suggest you include a *good*
business argument for the feature.

Also, Itzik has some good info on backdoor that might meet your requirement.
http://www.windowsitpro.com/Article/ArticleID/41845/41845.html


[quoted text, click to view]

Christian Hassa
9/11/2004 3:08:13 PM
Hi!

NEWID() is creating a Guid, so I would rather need to create a
Guid/uniqueidentifier column instead of a timestamp column.
Also, I would need to manage the Guid value by myself all the time
(INSERT/UPDATE) whereas rowversion would be managed by SQL server.

Sure I can create my own infrastructure for versioning/locking using
Guid/uniqueidentifier, but my impression is, that rowversion is exactly
there for this reason, so why should I do it on my own? Isn't there any
meaningful way how Microsoft intended the rowversion field to be used, or is
it unusable by design?

Chris


[quoted text, click to view]

Christian Hassa
9/11/2004 7:09:57 PM
Hi Dan,

thanks for following up on this thread.

As I outlined in my previous response to oj, I can figure out how to use
Guids managed by the client to do optimistic locking (thanks for the code
sample anyway).

However, fields of type "rowversion" (currently synonymous to timestamp in
SQL server but different from Guid/uniqueidentifier) are not managed by the
client but by SQL server. Therefore the solution oj and you are proposing
(and which I also figured out already) is neither what I am looking for nor
is it utilizing SQL servers rowversion feature.

This is a similar question like where to manage identities - especially int
identities: on the server side (using autoinc ints) or on the client side
(having to synchronize distributed ID generators on the client side somehow
in case of int identities).

So my question still remains: *if* I want to use the rowversion (synonym for
timestamp) feature of Microsoft SQL server, where I define a column of type
"rowversion" for a table, that will be managed then by SQL server: *what* is
the suggested way to retrieve the updated timestamp after updating/inserting
into a table?

In my opinion a similar function, like Scope_Identity() provided for server
generated identity values, should be available for server generated
rowversion/timestamp values. I think it is quite inefficient if I have to
issue a second SELECT statement (while keeping the updated record locked) in
order to retrieve the newly generated timestamp. We are working on a 2TB
database with several db-operations per second, we are simply not allowed to
lock certain tables for selecting back our new rowversion. I would still say
the rowversion feature is not efficiently usable if it turns out for
performance/parallelization reasons I rather turn away from this feature in
favor to Guids I manage on my own.

br
Chris



"Dan Guzman" <guzmanda@nospam-online.sbcglobal.net> schrieb im Newsbeitrag
news:OywOvzBmEHA.3520@TK2MSFTNGP11.phx.gbl...
[quoted text, click to view]

Hugo Kornelis
9/11/2004 11:05:42 PM
[quoted text, click to view]

Hi Christian,

The only way I can think of is what you already do: SELECT the affected
row directly after executing the UPDATE and before committing the
transaction. (Note that the transaction doesn't have to be serializable
for this - the default isolation level read committed suffices, as the
exclusive lock taken by the update lives until the end of the transaction
anyway.


[quoted text, click to view]

I agree that it would be useful in a case like this. But I was unable to
find it. I also tried some wacky stuff, but none of my attempts did what
you want, so I'm afraid that there is no other way.

You might send a request to sqlwish@microsoft.com. If there's enough
demand for a feature like this, it will probably be included in a future
version of SQL Server. Of course, this won't help you now... :-(


[quoted text, click to view]

You won't lock the complete table, but just the row just updated (assuming
you can locate that row through an index - and if you can't, you'll
already have locked your table when you performed the update). And the
lock is already taken for the update operation itself. The only effect is
that the lock will be held slightly longer - for the time required to
select back the new rowversion from the updated table. Since this data was
just updated, it will still be available in cache - I very much doubt that
you'll be able to notice the difference in performance.


Best, Hugo
--

AddThis Social Bookmark Button