2つの関係[〜#〜] r [〜#〜]と[〜#〜] s [〜#〜]があり、ここで[〜 #〜] r [〜#〜]には1000のタプルと100のページアクセスがあり、[〜#〜] s [〜#〜]には50のタプルと25のページアクセスがあります。
[〜#〜] r [〜#〜]が外部関係であるとすると、タプル比較とページアクセスはいくつ行われますか?
そして、もし[〜#〜] r [〜#〜]が内部関係である場合、ページアクセスは何回ですか?
for each Tuple r in R do
for each Tuple s in S do
if r and s satisfy the join condition
then output the Tuple (r,s)
したがって、実行されたタプル比較の数を確認するために、アルゴリズムが1000 * 50 = 50000を実行する必要があります。これは、アルゴリズムが「各」タプルに対してこれを実行し、合計で1000タプル[〜#〜 ] r [〜#〜]および[〜#〜] s [〜#〜]の場合は50タプル、つまり合計で50000の比較。
しかし、どうやってページアクセスを知るのでしょうか? [〜#〜] r [〜#〜]が外側の場合、(1000タプル)*([〜#〜] s [〜#〜]に対して25ページアクセス)+([〜#〜] r [〜#〜])の100ページアクセス== 25100ページアクセス?
[〜#〜] r [〜#〜]が内部にある場合、50 * 100 + 25 = 5025ページアクセス
それがそのように正しいかどうかはわかりません..またはこれはどのように正しく行われますか? :/
SQL Serverにこれを正確に実行させ、実際に何が発生するかを確認できます。
Rには1000タプルがあり、100ページアクセス= 10タプル/ページ= 806バイト/タプルです。
Sには50のタプルと25のページアクセス= 2タプル/ページ= 4030バイト/タプルがあります。
これらはテーブルです:
drop table if exists dbo.R;
drop table if exists dbo.S;
go
create table dbo.R(n int, filler char(785) not null default '');
create table dbo.S(n int, filler char(3990) not null default '');
フィラー列のサイズは、行のオーバーヘッドを考慮して切り捨てられています。 noインデックスがあることに注意してください。 RとSの入力に使用する「数値」テーブルがあります。
insert dbo.R(n) select Number from dbo.Numbers where Number between 1 and 1000;
insert dbo.S(n) select Number from dbo.Numbers where Number between 1 and 50;
含まれているページの数を確認できます。
set statistics io on;
select * from R
select * from S
SSMSのメッセージタブに表示されます
Table 'R'. Scan count 1, logical reads 100, ...
Table 'S'. Scan count 1, logical reads 25, ...
ちょうどいいページ数です。ちょっとした振る舞いはあなたが調べたい振る舞いをします
select *
from dbo.R -- R will be outer
inner loop join dbo.S
on r.N = s.N
option
(
force order, -- dictate which table is outer and which inner
NO_PERFORMANCE_SPOOL -- stop the QO from doing something clever but distracting
);
select *
from dbo.S -- S will be outer
inner loop join dbo.R
on r.N = s.N
option (force order, NO_PERFORMANCE_SPOOL);
これはメッセージタブでこれを与えます(内部テーブルは外部テーブルの前にリストされています)
Table 'S'. Scan count 1, logical reads 25000, ...
Table 'R'. Scan count 1, logical reads 100, ...
Table 'R'. Scan count 1, logical reads 5000, ..
Table 'S'. Scan count 1, logical reads 25, ...
SQL Serverでは、クエリの実行は行単位で行われます。外部テーブルの各行について、内部テーブルの対応する行が参照されます。インデックスがないため、唯一のオプションは毎回内部テーブルからすべての行(つまり、すべてのページ)を読み取ることです。 R-join-Sの場合、外側の行が1,000行x内側のページが25倍になり、25,000の内側のページ参照に加えて、もちろん100の外側のページ参照があります。 S-join-Rの場合、50行×100ページで、5,000の内部ページ参照と25の外部ページ参照があります。
タプル比較に関しては正しい-O(R)xO(S)比較-50,000があります。これはクエリプランを見るとサポートされます。両方のクエリで、「内部テーブル参照の「読み取り行」はどちらも50,000です。
インデックスがある場合、クエリオプティマイザー(QO)にはテーブルスキャン以外の選択肢があります。巻き戻しは、重複する外部キーに使用できます。一致しないキーのページは読み取られません。極端なケースでは、制約により一致が存在しないと示されている場合、内部テーブルは参照されることすらありません。
真実は、あなたが理解しているよりも複雑です。ジョインの外部入力で1000の論理読み取りが必要になるのは事実ですが、ジョインキーが一意である場合に限られます。そうでない場合、オプティマイザはそれを事前にソートし、複数の行を一度にフェッチして、それらすべてを一度に照合できます。内側のループについては、反復ごとのフルスキャンを想定しています。内部入力がインデックス付けされている場合、オプティマイザは通常、ネストされたループを優先します。この場合、ページフェッチの数はそのセットのカーディナリティによって決定されます。
私の5セント-物理的な実装の詳細について心配する必要はありません。データモデル、スキーマ、コードの完成にリソースを投資します。ネストされたループについてエンジンに心配させてください。
HTH