しばらく前に、 代理キーはSQL Serverの自然キーよりも優れたパフォーマンスを提供する かどうかを尋ねました。 @ sqlvogel 昨日その質問に答えてくれたので、私はそれを再訪しました。
この質問は、前の質問を「アップグレード」する試みであり、コミュニティに役立つ思慮深い回答の機会を提供することを願っています。
コンピュータに関する詳細を保存するためのシステムを考えてみましょう。各コンピューターには、アーキテクチャーとオペレーティングシステムがあります。 SQL Serverでは、次のような自然キーを使用してこれらのテーブルを作成できます。
CREATE TABLE dbo.Architecture
(
ArchitectureName varchar(10) NOT NULL
, ArchitectureVersion decimal(5,2) NOT NULL
, ReleaseDate date NOT NULL
, CONSTRAINT PK_Architecture
PRIMARY KEY CLUSTERED
(ArchitectureName, ArchitectureVersion)
);
CREATE TABLE dbo.Manufacturer
(
ManufacturerName varchar(10) NOT NULL
CONSTRAINT PK_Manufacturer
PRIMARY KEY CLUSTERED
);
CREATE TABLE dbo.OS
(
OSName varchar(30) NOT NULL
, ManufacturerName varchar(10) NOT NULL
CONSTRAINT FK_OS_Manufacturer
FOREIGN KEY
(ManufacturerName)
REFERENCES dbo.Manufacturer(ManufacturerName)
, ArchitectureName varchar(10) NOT NULL
, ArchitectureVersion decimal(5,2) NOT NULL
, CONSTRAINT FK_OS_Architecture
FOREIGN KEY
(ArchitectureName, ArchitectureVersion)
REFERENCES dbo.Architecture(ArchitectureName, ArchitectureVersion)
, CONSTRAINT PK_OS
PRIMARY KEY CLUSTERED
(OSName)
);
CREATE TABLE dbo.Computers
(
ComputerID varchar(10) NOT NULL
CONSTRAINT PK_Computers
PRIMARY KEY CLUSTERED
, OSName varchar(30) NOT NULL
CONSTRAINT FK_Computers_OSName
FOREIGN KEY
REFERENCES dbo.OS(OSName)
, ComputerManufacturerName varchar(10) NOT NULL
CONSTRAINT FK_Computers_Manufacturer
FOREIGN KEY
REFERENCES dbo.Manufacturer(ManufacturerName)
, EffectiveDate datetime NOT NULL
CONSTRAINT DF_Computers_EffectiveDate
DEFAULT (GETDATE())
, ExpiryDate datetime NULL
);
dbo.Computers
に2行あり、さまざまな詳細を示すdbo.Computers
テーブルをクエリするには、次のようにします。
SELECT Computers.ComputerID
, Computers.ComputerManufacturerName
, OSManufacturer = OS.ManufacturerName
, Computers.OSName
, OS.ArchitectureName
, OS.ArchitectureVersion
FROM dbo.Computers
INNER JOIN dbo.OS ON Computers.OSName = OS.OSName
WHERE Computers.EffectiveDate <= GETDATE()
AND (Computers.ExpiryDate >= GETDATE() OR Computers.ExpiryDate IS NULL)
ORDER BY Computers.ComputerID;
クエリ出力は次のとおりです。
╔============╦==========================╦========= =======╦============╦==================╦========== ===========╗ ║ComputerID║ComputerManufacturerName║OSManufacturer║OSName║ArchitectureName║ArchitectureVersion║ ╠============ =========================╬========================= =====╬==================╬=====================╣ ║CM700-01║HP║Microsoft║Windows10║x64║1.00║ ║CM700-02║HP║Microsoft║Windows10║x64║1.00║[.____ =。= =======╩============================================ =╩============╩==================================== =====╝
このためのクエリプランは非常に単純です。
または、次のように代理キーを使用することを選択した場合:
CREATE TABLE dbo.Architecture
(
ArchitectureID int NOT NULL IDENTITY(1,1)
CONSTRAINT PK_Architecture
PRIMARY KEY CLUSTERED
, ArchitectureName varchar(10) NOT NULL
, ArchitectureVersion decimal(5,2) NOT NULL
, ReleaseDate date NOT NULL
, CONSTRAINT UQ_Architecture_Name
UNIQUE
(ArchitectureName, ArchitectureVersion)
);
CREATE TABLE dbo.Manufacturer
(
ManufacturerID int NOT NULL IDENTITY(1,1)
CONSTRAINT PK_Manufacturer
PRIMARY KEY CLUSTERED
, ManufacturerName varchar(10) NOT NULL
);
CREATE TABLE dbo.OS
(
OS_ID int NOT NULL IDENTITY(1,1)
CONSTRAINT PK_OS
PRIMARY KEY CLUSTERED
, OSName varchar(30) NOT NULL
CONSTRAINT UQ_OS_Name
UNIQUE
, ManufacturerID int NOT NULL
CONSTRAINT FK_OS_Manufacturer
FOREIGN KEY
REFERENCES dbo.Manufacturer(ManufacturerID)
, ArchitectureID int NOT NULL
CONSTRAINT FK_OS_Architecture
FOREIGN KEY
REFERENCES dbo.Architecture(ArchitectureID)
);
CREATE TABLE dbo.Computers
(
ComputerID int NOT NULL IDENTITY(1,1)
CONSTRAINT PK_Computers
PRIMARY KEY CLUSTERED
, ComputerName varchar(10) NOT NULL
CONSTRAINT UQ_Computers_Name
UNIQUE
, OS_ID int NOT NULL
CONSTRAINT FK_Computers_OS
FOREIGN KEY
REFERENCES dbo.OS(OS_ID)
, ComputerManufacturerID int NOT NULL
CONSTRAINT FK_Computers_Manufacturer
FOREIGN KEY
REFERENCES dbo.Manufacturer(ManufacturerID)
, EffectiveDate datetime NOT NULL
CONSTRAINT DF_Computers_EffectiveDate
DEFAULT (GETDATE())
, ExpiryDate datetime NULL
);
上記の設計では、データモデルが両方のアプローチで一貫していることを保証するために、いくつかの新しい一意の制約を含める必要があることに気付くかもしれません。
dbo.Computers
の2行でこの代理キーアプローチをクエリすると、次のようになります。
SELECT Computers.ComputerName
, ComputerManufacturerName = cm.ManufacturerName
, OSManufacturer = om.ManufacturerName
, OS.OSName
, Architecture.ArchitectureName
, Architecture.ArchitectureVersion
FROM dbo.Computers
INNER JOIN dbo.OS ON Computers.OS_ID = OS.OS_ID
INNER JOIN dbo.Manufacturer cm ON Computers.ComputerManufacturerID = cm.ManufacturerID
INNER JOIN dbo.Architecture ON OS.ArchitectureID = Architecture.ArchitectureID
INNER JOIN dbo.Manufacturer om ON OS.ManufacturerID = om.ManufacturerID
WHERE Computers.EffectiveDate <= GETDATE()
AND (Computers.ExpiryDate >= GETDATE() OR Computers.ExpiryDate IS NULL)
ORDER BY Computers.ComputerID;
結果:
╔==============╦=================================== =========╦============╦==================╦======== =============╗ ║ComputerName║ComputerManufacturerName║OSManufacturer║OSName║ArchitectureName║ArchitectureVersion║ ╠========== ==╬==========================╬================╬=== =========╬========================================= ╣ ║CM700-01║HP║Microsoft║Windows10║x64║1.00║ ║CM700-02║HP║Microsoft║Windows10║x64║1.00║[。 =============╩==========================╩========= =======╩============╩==================╩========== ===========╝
I/O統計はさらにわかりやすくなっています。自然キーについては、次のものがあります。
テーブル「OS」。スキャンカウント0、論理読み取り4、物理読み取り0、先読み読み取り0、lob論理読み取り0、lob物理読み取り0、lob先読み読み取り0。 表「コンピューター」。スキャンカウント1、論理読み取り2、物理読み取り0、先読み読み取り0、lob論理読み取り0、lob物理読み取り0、lob先読み読み取り0。
サロゲートキーの設定では、次のようになります。
表「メーカー」。スキャンカウント0、論理読み取り8、物理読み取り0、先読み読み取り0、lob論理読み取り0、lob物理読み取り0、lob先読み読み取り0。 表「アーキテクチャ」。スキャンカウント0、論理読み取り4、物理読み取り0、先読み読み取り0、lob論理読み取り0、lob物理読み取り0、lob先読み読み取り0。 テーブル「OS」。スキャンカウント0、論理読み取り4、物理読み取り0、先読み読み取り0、lob論理読み取り0、lob物理読み取り0、lob先読み読み取り0。 表「コンピューター」。スキャンカウント1、論理読み取り2、物理読み取り0、先読み読み取り0、lob論理読み取り0、lob物理読み取り0、lob先読み読み取り0。
明らかに、上記の非常に単純なセットアップでは、代理キーは使いやすさとパフォーマンスの両方で遅れています。
そうは言っても、メーカーの名前を変更する必要がある場合はどうなりますか?自然キーバージョンのT-SQLは次のとおりです。
UPDATE dbo.Manufacturer
SET ManufacturerName = 'Microsoft™'
WHERE ManufacturerName = 'Microsoft';
そして計画:
代理キーバージョンのT-SQL:
UPDATE dbo.Manufacturer
SET ManufacturerName = 'Microsoft™'
WHERE ManufacturerID = 1;
そしてその計画:
自然キーバージョンの推定サブツリーコストは、サロゲートキーバージョンのほぼ3倍です。
自然キーと代理キーの両方が利点を提供すると言っているのは正しいですか。使用する方法を慎重に検討する必要がありますか?
上記の比較が機能しない一般的な状況はありますか?自然キーまたは代理キーを選択するときは、他にどのような考慮事項がありますか?
あなたの質問のタイトルは、それがnot質問であるという事実は別として、少し誤解を招くと思います。参照している質問とは異なり、測定していません自然/代理キーのパフォーマンス。代わりに、それぞれの主キーの選択が原因で、モデルが著しく異なる2つのデータベースに対するクエリのパフォーマンスを測定しています。モデルのManufacturer
エンティティの目的は何ですか?それは不自然な例だと理解していますが、それはまさにexampleとしての弱点です。
明らかに、1つではなく3つの結合を必要とするクエリでは、より多くのI/Oが必要になります。同じ(またはさらに悪い)のは、親キー値の更新です。
最初の例は、基本的に、クエリのパフォーマンスに対する「非正規化」の影響を示していますが、これは些細なことです。確かに、厳密に言えば非正規化ではありませんが、通常はルックアップテーブル(Manufacturer
)の内容をそれを参照するテーブルにマージし、ルックアップへの結合を回避することになります。メーカー名。同上Architecture
。
2番目の例は、主キーは決して更新されるべきではないという意見を確認しています。代わりに試してください
UPDATE dbo.Manufacturer
SET ManufacturerID = 1
WHERE ManufacturerID = 1;
自然キーを使用した場合と同じ結果が得られる可能性があります。
最後に、述べられているようにあなたの質問に答えるために:はい、それで何ですか?