7

代理キーと自然キーの間には健全な議論があります。

SO投稿1

SO投稿2

大多数と一致しているように思われる私の意見 (わずかな過半数) は、自然キーが完全に明白であり、変更されないことが保証されていない限り、代理キーを使用する必要があるというものです。次に、自然キーに一意性を適用する必要があります。これは、ほぼ常に代理キーを意味します。

Company テーブルから始まる 2 つのアプローチの例:

1: 代理キー: テーブルには、PK (および ID) である ID フィールドがあります。会社名は州ごとに一意である必要があるため、一意の制約があります。

2: 自然キー: テーブルは CompanyName と State を PK として使用します -- PK と一意性の両方を満たします。

Company PK が他の 10 個のテーブルで使用されているとします。それを裏付ける数字がない私の仮説は、ここでは代理キーアプローチの方がはるかに高速であるということです。

自然キーについて私が見た唯一の説得力のある議論は、自然キーとして 2 つの外部キーを使用する多対多テーブルの場合です。その場合は一理あると思います。ただし、リファクタリングが必要な場合は問題が発生する可能性があります。それはこの投稿の範囲外だと思います。

代理キーを使用する一連のテーブルと自然キーを使用する同じ一連のテーブルのパフォーマンスの違いを比較する記事を見た人はいますか? SO と Google を調べてみても、価値のあるものは何も得られませんでした。


重要な更新:この質問に答える一連のテスト テーブルの作成を開始しました。次のようになります。

  • PartNatural - 固有の PartNumber を PK として使用するパーツ テーブル
  • PartSurrogate - ID (int、identity) を PK として使用し、PartNumber に一意のインデックスを持つパーツ テーブル
  • Plant - PK としての ID (int、identity)
  • エンジニア - PK としての ID (int、identity)

すべての部品がプラントに結合され、プラントの部品のすべてのインスタンスがエンジニアに結合されます。このテストベッドに問題がある場合は、今がその時です。

4

2 に答える 2

9

両方を使う!自然キーはデータベースの破損を防ぎます(矛盾がより良い言葉かもしれません)。「正しい」自然キー(重複する行を排除するため)が長さまたは関連する列の数のためにパフォーマンスが低下する場合、パフォーマンスの目的で、代理キーを追加して、代わりに他のテーブルで外部キーとして使用することもできます。自然キー...ただし、データの破損を防ぎ、データベースの一貫性を確保するために、自然キーは代替キーまたは一意のインデックスとして残す必要があります...

(この問題に関する「討論」での)フーハの多くは、他のテーブルの結合と外部キーに主キーを使用する必要があるという誤った仮定が原因である可能性があります。これは誤りです。他のテーブルの外部キーのターゲットとして任意のキーを使用できます。ターゲットリレーション(テーブル)で一意である限り、主キー、代替キー、または任意の一意のインデックスまたは一意の制約にすることができます。また、結合に関しては、結合条件として何でも使用できます。キー、インデックス、または一意である必要はありません。(ただし、一意でない場合は、作成するデカルト積に複数の行が表示されます)。非特定の基準(結合条件として>、<、または「like」など)を使用して結合を作成することもできます。

実際、ブール値に評価される任意の有効なSQL式を使用して結合を作成できます。

于 2009-08-04T19:18:46.297 に答える
3

自然キーは、タイプではなく、値が代理キーと異なります。

VARCHARシステムで生成されたものなど、任意のタイプを代理キーに使用できslugます。

ただし、代理キーに最もよく使用されるタイプはINTEGER、およびRAW(16)(または、RDBMSに使用するタイプGUID)、

代理整数と自然整数(のようなSSN)の比較には、まったく同じ時間がかかります。

s makeを比較するとVARCHAR、照合が考慮されます。これらは一般に整数よりも長いため、効率が低下します。

2つのセットを比較することINTEGERは、おそらく1つのセットを比較するよりも効率的ではありませんINTEGER

サイズが小さいデータ型では、この差はおそらく、ページのフェッチ、インデックスのトラバース、データベースラッチの取得などに必要な時間のパーセントのパーセントです。

そしてここに(のMySQL)数字があります:

CREATE TABLE aint (id INT NOT NULL PRIMARY KEY, value VARCHAR(100));
CREATE TABLE adouble (id1 INT NOT NULL, id2 INT NOT NULL, value VARCHAR(100), PRIMARY KEY (id1, id2));
CREATE TABLE bint (id INT NOT NULL PRIMARY KEY, aid INT NOT NULL);
CREATE TABLE bdouble (id INT NOT NULL PRIMARY KEY, aid1 INT NOT NULL, aid2 INT NOT NULL);

INSERT
INTO    aint
SELECT  id, RPAD('', FLOOR(RAND(20090804) * 100), '*')
FROM    t_source;

INSERT
INTO    bint
SELECT  id, id
FROM    aint;

INSERT
INTO    adouble
SELECT  id, id, value
FROM    aint;

INSERT
INTO    bdouble
SELECT  id, id, id
FROM    aint;

SELECT  SUM(LENGTH(value))
FROM    bint b
JOIN    aint a
ON      a.id = b.aid;

SELECT  SUM(LENGTH(value))
FROM    bdouble b
JOIN    adouble a
ON      (a.id1, a.id2) = (b.aid1, b.aid2);

t_source行のある単なるダミーテーブル1,000,000です。

aintadouble、はまったく同じデータbintを含みますが、はaとして整数を持ち、2つの同じ整数のペアを持ちます。bdoubleaintPRIMARY KEYadouble

私のマシンでは、両方のクエリが14.5秒、+/-0.1秒実行されます

パフォーマンスの違いがある場合は、変動範囲内です。

于 2009-08-04T18:44:18.380 に答える