Emuluj sekwencję TSQL za pomocą procedury składowanej

17

Mam wymóg utworzenia procedury składowanej, która emuluje sekwencję TSQL. Oznacza to, że zawsze daje rosnącą wyraźną wartość całkowitą przy każdym połączeniu. Ponadto, jeśli podana jest liczba całkowita, powinna zwrócić tę wartość, jeśli nigdy nie było wyniku większego lub następnej najwyższej dostępnej liczby całkowitej. Oczywiste jest, że może być wielu klientów dzwoniących do tego SP w tym samym czasie.

Biorąc pod uwagę tabelę MetaInfo z kolumnami MetaKey varchar (max) i MeatValueLong bigInt. Oczekuje się, że wiersz z MetaKey „Internal-ID-Last” będzie zawierał ostatnią najwyższą przypisaną wartość. Utworzyłem następującą procedurę przechowywaną:

CREATE PROCEDURE [dbo].[uspGetNextID]
(
  @inID bigInt 
)
AS
BEGIN
    SET NOCOUNT ON;

    BEGIN TRANSACTION

    UPDATE MetaInfo WITH (ROWLOCK) 
      SET MetaValueLong = CASE 
                            WHEN ISNULL(MetaValueLong,0) > @inID THEN MetaValueLong+1 
                            ELSE @inID+1
                          END 
    WHERE MetaKey = 'Internal-ID-Last'

    SELECT MetaValueLong 
    FROM MetaInfo
    WHERE MetaKey = 'Internal-ID-Last'

    COMMIT TRANSACTION 

END

Moje pytanie brzmi po prostu, czy ta procedura przechowywana działa zgodnie z oczekiwaniami (wszystkim osobom wywołującym zostanie przypisany unikalny wynik)?

Hogan
źródło
@all: FYI, spawnowane przez to Q na SO: stackoverflow.com/q/6342732/27535
gbn

Odpowiedzi:

8

Spojrzałem i same stwardnienie rozsiane oferują rozwiązanie bez blokad

http://blogs.msdn.com/b/sqlcat/archive/2006/04/10/sql-server-sequence-number.aspx

Jest to prosta aktualizacja bez wskazówek blokujących, ale mówią, że blokuje / zakleszczenia.

Nie ma też wiele na temat SO.

Byłbym skłonny dodać UPDLOCK do ROWLOCK (zgodnie z „tabelą jako kolejką” (SO), ale bez READPAST). Zwiększy to izolację w przypadku, gdy drugi proces rozpocznie czytanie.

Jednak fakt, że wszystkie twoje procesy chcą czytać / zapisywać ten sam wiersz, sam siebie zgaduję. READPAST umożliwia bezpieczną współbieżność, ale w tym przypadku jest bezużyteczna.

Uwaga: możesz użyć klauzuli OUTPUT zamiast drugiej opcji wyboru, a następnie nie potrzebujesz transakcji.

HTH ...

gbn
źródło
1
Pobiłeś mnie do tego. Zauważ, że SQL Server 2011 zawiera funkcję SEKWENCJI, więc wymóg wynalezienia własnego powinien zniknąć wkrótce (nie wcześniej).
nvogel
@dportas: rzeczywiście. I działa też lepiej: dba.stackexchange.com/q/1635/630
gbn
@dportas - czy SEQUENCE może uwzględniać wymagania wejściowe? W krótkim czytaniu tej funkcji nie widziałem tej funkcji.
Hogan
1

Brakuje następujących rzeczy

1. SET XACT_ABORT
2. Exception Handling (Try Catch)

Tak, powinien spełniać twój warunek. Gdy takie sytuacje pojawią się w transakcjach, tworzy wiele wystąpień, a następnie wszystkim dzwoniącym zostanie przypisany unikalny wynik

Pankaj
źródło
Jeśli zatwierdzę przed wyborem, czy nie ma możliwości wybrania wyniku zapisanego przez inne połączenie?
Hogan
Nie jestem tego pewien. Ale wygląda na to, że masz rację. Muszę sprawdzić. Dzięki. BTW +1 za, Dobre pytanie ...
0

Bardziej skalowalnym rozwiązaniem, które nie wymaga serializacji jest:

CREATE PROCEDURE [dbo].[uspGetNextID]
(
  @inID BIGINT OUT
)
AS
      SET NOCOUNT ON
      SET IDENTITY_INSERT SequenceTable ON;
      INSERT INTO SequenceTable (id) VALUES (@inID);
      SET IDENTITY_INSERT SequenceTable OFF;
      INSERT INTO SequenceTable DEFAULT VALUES;
      DELETE FROM SequenceTable WITH (READPAST);
      SET @inID = SCOPE_IDENTITY();
RETURN;
nvogel
źródło
OP wymaga, aby użytkownicy mogli podać wartość, która ją komplikuje ...
gbn
@dportas - Dzięki. Byłem świadomy tego podejścia, ale tutaj nie działa ze względu na parametr wejściowy.
Hogan
@Hogan, zmodyfikowałem moją sugestię, aby obsłużyć parametr wejściowy. Jest to jednak w większości niesprawdzone.
nvogel
@dportas - A wywoływane z inID 500, B wywoływane z inID 50 - akcja - A zwraca 51, B 52. Wymaganie nie powiodło się.
Hogan
Ciekawy. Otrzymuję różne wyniki (w 2008r2). Czy możesz opublikować pełne repro z DDL i podać swoją wersję / wersję.
nvogel,