Entspricht der RowID von Oracle in SQL Server

82

Was entspricht der RowID von Oracle in SQL Server?

John Saunders
quelle
Stephanie: Die Annahme ist, dass die Daten einen eindeutigen Schlüssel enthalten, der davon ausgeht, dass die Daten normalisiert sind, was manchmal eine falsche Annahme ist. Was entspricht also der RowID von Oracle in SQL Server?
Christopher Mahan

Antworten:

115

Aus den Oracle-Dokumenten

ROWID Pseudospalte

Für jede Zeile in der Datenbank gibt die ROWID-Pseudospalte die Adresse der Zeile zurück. Die Zeilen-ID-Werte der Oracle-Datenbank enthalten Informationen, die zum Auffinden einer Zeile erforderlich sind:

  • Die Datenobjektnummer des Objekts
  • Der Datenblock in der Datendatei, in der sich die Zeile befindet
  • Die Position der Zeile im Datenblock (erste Zeile ist 0)
  • Die Datendatei, in der sich die Zeile befindet (erste Datei ist 1). Die Dateinummer ist relativ zum Tabellenbereich.

Das nächste Äquivalent dazu in SQL Server ist riddas mit drei Komponenten File:Page:Slot.

In SQL Server 2008 ist es möglich, die undokumentierte und nicht unterstützte %%physloc%%virtuelle Spalte zu verwenden, um dies anzuzeigen . Dies gibt einen binary(8)Wert mit der Seiten-ID in den ersten vier Bytes zurück, dann 2 Bytes für die Datei-ID, gefolgt von 2 Bytes für die Position des Steckplatzes auf der Seite.

Die Skalarfunktion sys.fn_PhysLocFormatteroder die sys.fn_PhysLocCrackerTVF können verwendet werden, um dies in eine besser lesbare Form umzuwandeln

CREATE TABLE T(X INT);

INSERT INTO T VALUES(1),(2)

SELECT %%physloc%% AS [%%physloc%%],
       sys.fn_PhysLocFormatter(%%physloc%%) AS [File:Page:Slot]
FROM T

Beispielausgabe

+--------------------+----------------+
|    %%physloc%%     | File:Page:Slot |
+--------------------+----------------+
| 0x2926020001000000 | (1:140841:0)   |
| 0x2926020001000100 | (1:140841:1)   |
+--------------------+----------------+

Beachten Sie, dass dies vom Abfrageprozessor nicht genutzt wird. Es ist zwar möglich , dies in einer WHEREKlausel zu verwenden

SELECT *
FROM T
WHERE %%physloc%% = 0x2926020001000100 

SQL Server sucht nicht direkt nach der angegebenen Zeile. Stattdessen wird ein vollständiger Tabellenscan durchgeführt, %%physloc%%für jede Zeile ausgewertet und die übereinstimmende zurückgegeben (falls vorhanden).

Um den von den beiden zuvor genannten Funktionen ausgeführten Vorgang umzukehren und den binary(8)Wert zu erhalten, der den bekannten Werten für Datei, Seite und Steckplatz entspricht, können die folgenden Werte verwendet werden.

DECLARE @FileId int = 1,
        @PageId int = 338,
        @Slot   int = 3

SELECT CAST(REVERSE(CAST(@PageId AS BINARY(4))) AS BINARY(4)) +
       CAST(REVERSE(CAST(@FileId AS BINARY(2))) AS BINARY(2)) +
       CAST(REVERSE(CAST(@Slot   AS BINARY(2))) AS BINARY(2))
Martin Smith
quelle
Unter SQL Server 2005 können Sie stattdessen die undokumentierten und nicht unterstützten virtuellen Spalten %% LockRes %% verwenden
Henrik Holmgaard Høyer
absolut richtig. %% LockRes %% ist nicht der "richtige Weg" - nur verwenden, wenn für qucik und schmutzige Korrekturen an Daten auf alten Versionen von SQL-Servern vor 2008
Henrik Holmgaard Høyer
11

Ich muss einen sehr großen Tisch mit vielen Spalten deduplizieren und Geschwindigkeit ist wichtig. Daher verwende ich diese Methode, die für jede Tabelle funktioniert:

delete T from 
(select Row_Number() Over(Partition By BINARY_CHECKSUM(*) order by %%physloc%% ) As RowNumber, * From MyTable) T
Where T.RowNumber > 1
S Wright
quelle
9

Überprüfen Sie die neue Funktion ROW_NUMBER . Es funktioniert so:

SELECT ROW_NUMBER() OVER (ORDER BY EMPID ASC) AS ROWID, * FROM EMPLOYEE
Daren Thomas
quelle
14
Ich denke, dies ist ein Ersatz für Rownum und nicht Rowid.
Tuinstoel
9

Wenn Sie eine Zeile in der Tabelle und nicht Ihre Ergebnismenge eindeutig identifizieren möchten, müssen Sie die Verwendung einer IDENTITY-Spalte in Betracht ziehen. Siehe "IDENTITY-Eigenschaft" in der SQL Server-Hilfe. SQL Server generiert nicht wie Oracle automatisch eine ID für jede Zeile in der Tabelle. Sie müssen sich also die Mühe machen, eine eigene ID-Spalte zu erstellen und diese explizit in Ihrer Abfrage abzurufen.

BEARBEITEN: Für die dynamische Nummerierung von Ergebnismengenzeilen siehe unten, aber das wäre wahrscheinlich ein Äquivalent für Oracle ROWNUM, und ich gehe von allen Kommentaren auf der Seite davon aus, dass Sie das obige Material möchten. Für SQL Server 2005 und höher können Sie die neue Funktion "Ranking-Funktionen" verwenden, um eine dynamische Nummerierung von Zeilen zu erreichen.

Zum Beispiel mache ich das bei einer Abfrage von mir:

select row_number() over (order by rn_execution_date asc) as 'Row Number', rn_execution_date as 'Execution Date', count(*) as 'Count'
from td.run
where rn_execution_date >= '2009-05-19'
group by rn_execution_date
order by rn_execution_date asc

Werde dir geben:

Row Number  Execution Date           Count
----------  -----------------        -----
1          2009-05-19 00:00:00.000  280
2          2009-05-20 00:00:00.000  269
3          2009-05-21 00:00:00.000  279

Es gibt auch einen Artikel auf support.microsoft.com über die dynamische Nummerierung von Zeilen.

Xiaofu
quelle
Ich denke, eine Identitätsspalte identifiziert eine Zeile in einer Tabelle eindeutig, aber nicht in einer Datenbank.
Tuinstoel
Dies ist wahr, aber das passt zu der Definition von ROWID, die ich in den Oracle-Dokumenten sehe: "Der externe Datentyp ROWID identifiziert eine bestimmte Zeile in einer Datenbanktabelle" ... aber ich sehe, dass Sie dies aufgrund meines Tippfehlers bei der sagen oben. :) Danke, dass du darauf hingewiesen hast.
Xiaofu
Eine Zeilennummer ist keine ROWID. Die ROWID enthält die physische Position der Zeile, die sich von einer eindeutigen Nummer unterscheidet. Insbesondere ist es für alle Tabellen in der Datenbank eindeutig (mit einigen Ausnahmen, wenn spezielle Speichertechniken verwendet werden)
a_horse_with_no_name
6

Einige der oben genannten Antworten arbeiten um das Fehlen einer direkten Bezug zu einer bestimmten Zeile, aber wird nicht funktionieren , wenn Änderungen auftreten , zu den anderen Zeilen in einer Tabelle. Das sind meine Kriterien, für die die Antworten technisch unzureichend sind.

Eine häufige Verwendung der ROWID von Oracle besteht darin, eine (etwas) stabile Methode zum Auswählen von Zeilen und zum späteren Zurückkehren in die Zeile bereitzustellen, um sie zu verarbeiten (z. B. um sie zu aktualisieren). Die Methode zum Suchen einer Zeile (komplexe Verknüpfungen, Volltextsuche oder zeilenweises Durchsuchen und Anwenden von Prozedurtests auf die Daten) kann möglicherweise nicht einfach oder sicher wiederverwendet werden, um die UPDATE-Anweisung zu qualifizieren.

Die SQL Server-RID scheint dieselbe Funktionalität zu bieten, bietet jedoch nicht dieselbe Leistung. Dies ist das einzige Problem, das ich sehe, und leider besteht der Zweck der Beibehaltung einer ROWID darin, zu vermeiden, dass eine teure Operation wiederholt wird, um die Zeile beispielsweise in einer sehr großen Tabelle zu finden. Trotzdem ist die Leistung in vielen Fällen akzeptabel. Wenn Microsoft das Optimierungsprogramm in einer zukünftigen Version anpasst, kann das Leistungsproblem behoben werden.

Es ist auch möglich, FOR UPDATE einfach zu verwenden und den CURSOR in einem prozeduralen Programm offen zu halten. Dies könnte sich jedoch bei der Verarbeitung großer oder komplexer Chargen als teuer erweisen.

Vorsichtsmaßnahme: Selbst die ROWID von Oracle wäre nicht stabil, wenn der DBA zwischen SELECT und UPDATE beispielsweise die Datenbank neu erstellen würde, da es sich um die physische Zeilen-ID handelt. Das ROWID-Gerät sollte daher nur innerhalb einer gut definierten Aufgabe verwendet werden.

Vincent
quelle
3

Wenn Sie nur eine einfache Zeilennummerierung für einen kleinen Datensatz wünschen, wie wäre es dann mit so etwas?

SELECT row_number() OVER (order by getdate()) as ROWID, * FROM Employees
Adriano Carneiro
quelle
8
Nicht was eine Rowid ist.
Stephanie Seite
Aber es funktioniert für eine schnell hinzugefügte ID, nach der einige Zuschauer suchen, ohne zu wissen, was ROWID ist.
Graeme
3

Von http://vyaskn.tripod.com/programming_faq.htm#q17 :

Oracle verfügt über ein Rownum für den Zugriff auf Zeilen einer Tabelle mithilfe der Zeilennummer oder der Zeilen-ID. Gibt es dafür ein Äquivalent in SQL Server? Oder wie generiert man eine Ausgabe mit Zeilennummer in SQL Server?

Es gibt keine direkte Entsprechung zu Oracle Rownum oder Zeilen-ID in SQL Server. Genau genommen sind in einer relationalen Datenbank die Zeilen in einer Tabelle nicht geordnet, und eine Zeilen-ID ist nicht wirklich sinnvoll. Wenn Sie diese Funktionalität benötigen, sollten Sie die folgenden drei Alternativen in Betracht ziehen:

  • Fügen Sie IDENTITYIhrer Tabelle eine Spalte hinzu.

  • Verwenden Sie die folgende Abfrage, um eine Zeilennummer für jede Zeile zu generieren. Die folgende Abfrage generiert eine Zeilennummer für jede Zeile in der Autorentabelle der Pubs-Datenbank. Damit diese Abfrage funktioniert, muss die Tabelle einen eindeutigen Schlüssel haben.

    SELECT (SELECT COUNT(i.au_id) 
            FROM pubs..authors i 
            WHERE i.au_id >= o.au_id ) AS RowID, 
           au_fname + ' ' + au_lname AS 'Author name'
    FROM          pubs..authors o
    ORDER BY      RowID
    
  • Verwenden Sie einen temporären Tabellenansatz, um die gesamte Ergebnismenge zusammen mit einer von der IDENTITY() Funktion generierten Zeilen-ID in einer temporären Tabelle zu speichern . Das Erstellen einer temporären Tabelle ist kostspielig, insbesondere wenn Sie mit großen Tabellen arbeiten. Entscheiden Sie sich für diesen Ansatz, wenn Sie keinen eindeutigen Schlüssel in Ihrer Tabelle haben.

cjs
quelle
3

Wenn Sie die Zeilen in der Tabelle dauerhaft nummerieren möchten, verwenden Sie bitte nicht die RID-Lösung für SQL Server. Es ist schlechter als Access auf einem alten 386. Erstellen Sie für SQL Server einfach eine IDENTITY-Spalte und verwenden Sie diese Spalte als Cluster-Primärschlüssel. Dadurch wird ein permanenter, schneller Integer-B-Baum in die Tabelle eingefügt, und was noch wichtiger ist, jeder nicht gruppierte Index verwendet ihn zum Auffinden von Zeilen. Wenn Sie versuchen, in SQL Server so zu entwickeln, als wäre es Oracle, erstellen Sie eine Datenbank mit schlechter Leistung. Sie müssen für den Motor optimieren und nicht so tun, als wäre es ein anderer Motor.

Verwenden Sie außerdem nicht die NewID (), um den Primärschlüssel mit GUIDs zu füllen. Andernfalls wird die Leistung beim Einfügen beeinträchtigt. Wenn Sie GUIDs verwenden müssen, verwenden Sie NewSequentialID () als Spaltenstandard. Aber INT wird immer noch schneller sein.

Wenn Sie andererseits einfach die Zeilen nummerieren möchten, die sich aus einer Abfrage ergeben, verwenden Sie die Funktion RowNumber Over () als eine der Abfragespalten.

user2793105
quelle
1

Weitere Informationen finden Sie unter http://msdn.microsoft.com/en-us/library/aa260631(v=SQL.80).aspx. In SQL Server entspricht ein Zeitstempel nicht einer DateTime-Spalte. Dies wird verwendet, um eine Zeile in einer Datenbank eindeutig zu identifizieren, nicht nur eine Tabelle, sondern die gesamte Datenbank. Dies kann für eine optimistische Parallelität verwendet werden. Beispiel: UPDATE [Job] SET [Name] = @ Name, [XCustomData] = @ XCustomData WHERE ([ModifiedTimeStamp] = @ Original_ModifiedTimeStamp AND [GUID] = @ Original_GUID

Der ModifiedTimeStamp stellt sicher, dass Sie die Originaldaten aktualisieren, und schlägt fehl, wenn die Zeile erneut aktualisiert wurde.

Jim
quelle
0

Ich habe dieses Beispiel aus dem MS SQL-Beispiel genommen und Sie können sehen, dass die @ID mit einer Ganzzahl oder einem Varchar oder was auch immer ausgetauscht werden kann. Dies war die gleiche Lösung, nach der ich gesucht habe, also teile ich sie. Genießen!!

-- UPDATE statement with CTE references that are correctly matched.
DECLARE @x TABLE (ID int, Stad int, Value int, ison bit);
INSERT @x VALUES (1, 0, 10, 0), (2, 1, 20, 0), (6, 0, 40, 0), (4, 1, 50, 0), (5, 3, 60, 0), (9, 6, 20, 0), (7, 5, 10, 0), (8, 8, 220, 0);
DECLARE @Error int;
DECLARE @id int;

WITH cte AS (SELECT top 1 * FROM @x WHERE Stad=6)
UPDATE x -- cte is referenced by the alias.
SET ison=1, @id=x.ID
FROM cte AS x

SELECT *, @id as 'random' from @x
GO
barry austra
quelle
0

Sie können die ROWID mithilfe der folgenden Methoden abrufen:

1.Erstellen Sie eine neue Tabelle mit einem Feld für die automatische Inkrementierung

2.Verwenden Sie die Analysefunktion Row_Number, um die Sequenz basierend auf Ihren Anforderungen zu erhalten. Ich würde dies bevorzugen, da dies in Situationen hilfreich ist, in denen Sie möchten, dass die row_id in aufsteigender oder absteigender Weise eines bestimmten Felds oder einer Kombination von Feldern angezeigt wird

Beispiel: Row_Number () Over (Partition nach Deptno Reihenfolge nach sal desc)

Das obige Beispiel gibt Ihnen die Sequenznummer basierend auf dem höchsten Gehalt jeder Abteilung. Die Aufteilung nach ist optional und Sie können sie gemäß Ihren Anforderungen entfernen

Saurabh Gautam
quelle