web-dev-qa-db-ja.com

自然キーと代理キーパート2

しばらく前に、 代理キーは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║[.____ =。= =======╩============================================ =╩============╩==================================== =====╝

このためのクエリプランは非常に単純です。

enter image description here

または、次のように代理キーを使用することを選択した場合:

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║[。 =============╩==========================╩========= =======╩============╩==================╩========== ===========╝

enter image description here

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';

そして計画:

enter image description here

代理キーバージョンのT-SQL:

UPDATE dbo.Manufacturer 
SET ManufacturerName = 'Microsoft­™' 
WHERE ManufacturerID = 1;

そしてその計画:

enter image description here

自然キーバージョンの推定サブツリーコストは、サロゲートキーバージョンのほぼ3倍です。

自然キーと代理キーの両方が利点を提供すると言っているのは正しいですか。使用する方法を慎重に検討する必要がありますか?

上記の比較が機能しない一般的な状況はありますか?自然キーまたは代理キーを選択するときは、他にどのような考慮事項がありますか?

2
Max Vernon

あなたの質問のタイトルは、それがnot質問であるという事実は別として、少し誤解を招くと思います。参照している質問とは異なり、測定していません自然/代理キーのパフォーマンス。代わりに、それぞれの主キーの選択が原因で、モデルが著しく異なる2つのデータベースに対するクエリのパフォーマンスを測定しています。モデルのManufacturerエンティティの目的は何ですか?それは不自然な例だと理解していますが、それはまさにexampleとしての弱点です。

明らかに、1つではなく3つの結合を必要とするクエリでは、より多くのI/Oが必要になります。同じ(またはさらに悪い)のは、親キー値の更新です。

最初の例は、基本的に、クエリのパフォーマンスに対する「非正規化」の影響を示していますが、これは些細なことです。確かに、厳密に言えば非正規化ではありませんが、通常はルックアップテーブル(Manufacturer)の内容をそれを参照するテーブルにマージし、ルックアップへの結合を回避することになります。メーカー名。同上Architecture

2番目の例は、主キーは決して更新されるべきではないという意見を確認しています。代わりに試してください

UPDATE dbo.Manufacturer 
SET ManufacturerID = 1 
WHERE ManufacturerID = 1;

自然キーを使用した場合と同じ結果が得られる可能性があります。

最後に、述べられているようにあなたの質問に答えるために:はい、それで何ですか?

1
mustaccio