SQL Server の Oracle の RowID に相当するものは何ですか?
13 に答える
ROWID疑似列
データベースの行ごとに、ROWID 疑似列は行のアドレスを返します。Oracle DatabaseのROWID値には、行の検索に必要な情報が含まれています:
- オブジェクトのデータオブジェクト番号
- 行が存在するデータファイル内のデータブロック
- データ ブロック内の行の位置 (最初の行は 0)
- 行が存在するデータファイル (最初のファイルは 1)。ファイル番号は、テーブルスペースに対して相対的です。
SQL Server でこれに最も近いのは、rid
3 つのコンポーネントを持つ ですFile:Page:Slot
。
SQL Server 2008 では、文書化もサポートもされていない%%physloc%%
仮想列を使用してこれを確認できます。binary(8)
これは、最初の 4 バイトにページ ID、次にファイル ID の 2 バイト、ページ上のスロット位置の 2 バイトが続く値を返します。
スカラー関数sys.fn_PhysLocFormatter
またはsys.fn_PhysLocCracker
TVF を使用して、これをより読みやすい形式に変換できます。
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
出力例
+--------------------+----------------+
| %%physloc%% | File:Page:Slot |
+--------------------+----------------+
| 0x2926020001000000 | (1:140841:0) |
| 0x2926020001000100 | (1:140841:1) |
+--------------------+----------------+
これはクエリ プロセッサでは利用されないことに注意してください。これを句で使用することは可能ですが、WHERE
SELECT *
FROM T
WHERE %%physloc%% = 0x2926020001000100
SQL Server は、指定された行を直接シークしません。代わりに、完全なテーブル スキャンを実行し、%%physloc%%
各行を評価して、一致するものがある場合はそれを返します。
前述の 2 つの関数によって実行されたプロセスを逆にして、binary(8)
既知の File、Page、Slot 値に対応する値を取得するには、以下を使用できます。
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))
結果セットではなくテーブル内の行を一意に識別したい場合は、IDENTITY 列などの使用を検討する必要があります。SQL Server ヘルプの「IDENTITY プロパティ」を参照してください。SQL Server は、Oracle のようにテーブル内の各行の ID を自動生成しないため、独自の ID 列を作成し、クエリで明示的に取得する必要があります。
編集:結果セット行の動的な番号付けについては以下を参照してください。ただし、これはおそらくOracleのROWNUMと同等であり、ページ上のすべてのコメントから、上記のものを必要としていると思います。SQL Server 2005 以降では、新しいランキング関数関数を使用して、行の動的な番号付けを実現できます。
たとえば、私は私のクエリでこれを行います:
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
あなたに与えます:
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
行の動的番号付けに関するsupport.microsoft.comの記事もあります。
新しいROW_NUMBER関数を確認してください。それはこのように動作します:
SELECT ROW_NUMBER() OVER (ORDER BY EMPID ASC) AS ROWID, * FROM EMPLOYEE
上記の回答のいくつかは、特定の行への直接参照がないことを回避しますが、テーブル内の他の行に変更が発生した場合は機能しません。それが、技術的に不足している答えの私の基準です。
Oracle の ROWID の一般的な用途は、行を選択し、後で行に戻って処理する (たとえば、UPDATE する) ための (ある程度) 安定した方法を提供することです。行を検索する方法 (複雑な結合、全文検索、または行ごとの参照とデータに対する手続き型テストの適用) は、UPDATE ステートメントを修飾するために簡単または安全に再利用できない場合があります。
SQL Server RID は同じ機能を提供しているように見えますが、同じパフォーマンスを提供していません。それが私が目にする唯一の問題であり、残念ながら ROWID を保持する目的は、たとえば非常に大きなテーブルで行を見つけるために高価な操作を繰り返さないようにすることです。それでも、多くの場合のパフォーマンスは許容範囲内です。Microsoft が将来のリリースでオプティマイザーを調整すると、パフォーマンスの問題が解決される可能性があります。
FOR UPDATE を単純に使用して、手続き型プログラムで CURSOR を開いたままにすることもできます。ただし、これは、大規模または複雑なバッチ処理ではコストがかかる可能性があります。
警告: DBA がたとえば SELECT と UPDATE の間でデータベースを再構築する場合、Oracle の ROWID でさえ安定しません。これは物理的な行識別子であるためです。したがって、ROWID デバイスは、適切な範囲のタスク内でのみ使用する必要があります。
テーブル内の行に永続的に番号を付けたい場合は、SQL Server の RID ソリューションを使用しないでください。古い 386 では Access よりもパフォーマンスが低下します。SQL Server の場合は、単純に IDENTITY 列を作成し、その列をクラスター化された主キーとして使用します。これにより、永続的で高速な整数 B ツリーがテーブルに配置され、さらに重要なことに、すべての非クラスター化インデックスはそれを使用して行を検索します。Oracle であるかのように SQL Server で開発しようとすると、パフォーマンスの低いデータベースが作成されます。別のエンジンのふりをするのではなく、エンジンを最適化する必要があります。
また、NewID() を使用して主キーに GUID を設定しないでください。挿入のパフォーマンスが低下します。GUID を使用する必要がある場合は、カラムのデフォルトとして NewSequentialID() を使用します。しかし、INTはまだ速くなります。
一方、クエリの結果の行に番号を付けたいだけの場合は、RowNumber Over() 関数をクエリ列の 1 つとして使用します。
小さなデータセットの基本的な行番号付けが必要な場合は、このようなものはどうでしょうか。
SELECT row_number() OVER (order by getdate()) as ROWID, * FROM Employees
http://vyaskn.tripod.com/programming_faq.htm#q17から:
Oracle には、行番号または行 ID を使用してテーブルの行にアクセスするための rownum があります。SQL Server にこれに相当するものはありますか? または、SQL Server で行番号を使用して出力を生成する方法は?
SQL Server には、Oracle の rownum または行 ID に直接相当するものはありません。厳密に言えば、リレーショナル データベースでは、テーブル内の行は順序付けされておらず、行 ID は実際には意味がありません。ただし、その機能が必要な場合は、次の 3 つの代替案を検討してください。
IDENTITY
テーブルに列を追加します。次のクエリを使用して、各行の行番号を生成します。次のクエリは、pubs データベースの author テーブルの各行の行番号を生成します。このクエリが機能するには、テーブルに一意のキーが必要です。
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
一時テーブル アプローチを使用して、関数によって生成された行 ID と共に、結果セット全体を一時テーブルに格納し
IDENTITY()
ます。一時テーブルを作成すると、特に大きなテーブルを扱う場合にコストがかかります。テーブルに一意のキーがない場合は、このアプローチを使用してください。
ROWID は Oracle テーブルの非表示の列であるため、SQL Server の場合は独自の列を作成します。デフォルト値が の ROWID という列を追加しますNEWID()
。
http://msdn.microsoft.com/en-us/library/aa260631(v=SQL.80).aspxを参照してください 。SQL サーバーでは、タイムスタンプは DateTime 列と同じではありません。これは、テーブルだけでなくデータベース全体で、データベース内の行を一意に識別するために使用されます。これは、オプティミスティック コンカレンシーに使用できます。たとえば、UPDATE [Job] SET [Name]=@Name, [XCustomData]=@XCustomData WHERE ([ModifiedTimeStamp]=@Original_ModifiedTimeStamp AND [GUID]=@Original_GUID
ModifiedTimeStamp は元のデータを更新していることを保証し、行に別の更新が発生した場合は失敗します。
この例は MS SQL の例から引用したもので、@ID を整数や varchar などと交換できることがわかります。これは私が探していたのと同じソリューションだったので、共有します。楽しみ!!
-- 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