8

スキーマの設計について少し混乱していますが、始める前に、まずスキーマを紹介しましょう。

CREATE TABLE Person
(
    PersonID INT NOT NULL PRIMARY KEY,
    FirstName VARCHAR(50),
    LastName VARCHAR(50),
    -- some columns here..
    CONSTRAINT tb_idF INDEX (FirstName),
    CONSTRAINT tb_idL INDEX (LastName)
    -- or 
    -- CONSTRAINT tb_idL INDEX (FirstName, LastName)
    -- other constraints ...
);

CREATE TABLE JobDescription
(
    JobDescriptionID INT NOT NULL PRIMARY KEY,
    JobDescriptionName VARCHAR(50) UNIQUE
    -- some columns here..
    -- constraints ...
);

混乱はここにあります。テーブルのマッピングテーブル:PersonJobDescription。現在、私はこのデザインを持っています、

CREATE TABLE Person_JobDescription
(
    RECID INT AUTO_INCREMENT PRIMARY KEY,   -- for some special reasons
                                            -- I need to map to other table
    PersonID INT,
    JobDescriptionID INT,
    StartYear INT,                          -- year JobDescription was Appointed
    EndYear INT,
    CONSTRAINT tb_fk1 FOREIGN KEY (PersonID) 
        REFERENCES Person(PersonID),
    CONSTRAINT tb_fk2 FOREIGN KEY (JobDescriptionID) 
        REFERENCES JobDescription(JobDescriptionID),
    CONSTRAINT tb_uq UNIQUE (PersonID, JobDescriptionID)
);

しかし、私はマッピングテーブルのどの構造がこのようになるかについてこの別の考えを持っています

CREATE TABLE Person_JobDescription
(
    PersonID INT,           -- map these two columns on the other table
    JobDescriptionID INT,   -- ^^
    StartYear INT,          -- year JobDescription was Appointed
    EndYear INT,
    CONSTRAINT tb_fk1 FOREIGN KEY (PersonID) 
        REFERENCES Person(PersonID),
    CONSTRAINT tb_fk2 FOREIGN KEY (JobDescriptionID) 
        REFERENCES JobDescription(JobDescriptionID),
    CONSTRAINT tb_pk PRIMARY KEY (PersonID, JobDescriptionID)
);

上記のテーブルに対してクエリを作成してテストしたところ、どちらも同じ結果を返し、パフォーマンスも小さなデータベース(50kレコード)でテストした場合と同じです。2つのクエリが大規模なデータベースでどのように動作するのか疑問に思います。

質問

  • 大規模なデータベースでは、マッピングテーブル()の2つのスキーマのどちらをPerson_JobDescription優先しますか?

指示どおり、およびにUNIQUE制約を作成することは許可されていません。しかし、私は2つの列にインデックスを提供しました。FirstNameLastName

  • テーブルでどのタイプのインデックスを使用しますPersonか?FirstName各列のインデックスまたはとの複合インデックスLastName
  • いつシングルインデックス以上INDEX (Col1)を使用しますか?INDEX (Col2)INDEX (Col1, Col2)

この質問をお読みいただき、ありがとうございます。

よろしくお願いします、

デレクフロス

4

2 に答える 2

7

私は2番目のアプローチを好むでしょう。識別に論理的に必要でない場合にサロゲート ID 番号を使用することで、より必須の結合が導入されます。これには、「データベース全体で ID 番号を追跡する」必要があります。これは、「データベース全体でポインタを追跡する」に相当する SQL です。ポインターの追跡は、リレーショナル モデルが置き換えることを意図したデータベース アーキテクチャの 1 つである IMS の特徴でした。(IMS は階層アーキテクチャを使用します。) 今日それを再発明しても意味がありません。(ただそうしている人が多いですが。)

たとえば、5 レベルのサロゲート ID 番号があり、個人の名前が必要な場合、それを取得するには 4 つの結合を行う必要があります。2 番目の方法を使用すると、必要な結合は 1 つだけです。複数列の結合を作成したくない場合は、CREATE VIEW を使用して一度だけ実行してください。

パフォーマンスは簡単にテストできます。お気に入りのスクリプト言語を使用して数百万のランダムな行を生成し、それらをテスト サーバーにロードするだけです。パフォーマンスの問題が隠れている場所を見つけるだけでなく、CREATE TABLE コード内のすべてのエラーを見つけることができます。(コードはそのままでは機能しません。) EXPLAINについてまだ知らない場合は、それについて学んでください。

indexingに関しては、生成してロードするランダムな行でテストできます。(first_name, last_name) の複数列インデックスは、ユーザーが常に名を指定する場合に最適です。しかし、多くのユーザーはそうせず、代わりに姓で検索することを好みます。(first_name, last_name) の複数列インデックスは、姓で検索することを好むユーザーには効果的ではありません。それをテストできます。

この理由だけでも、名と姓の2 つの個別のインデックス (1 つは名、もう 1 つは姓) がある場合、通常は名と姓のインデックス作成がより効果的です。


ID番号の追跡とはどういう意味ですか?

この質問の根底にある暗黙の設計パターンは、「すべての行には ID 番号が必要であり、すべての外部キーは ID 番号を参照する必要がある」です。SQL データベースでは、実際にはアンチパターンです。経験則として、キーについて考えずにテーブルを設計できるパターンは、無実であることが証明されるまで有罪であると推定されるべきです。

create table A (
 a_id integer primary key,
 a_1 varchar(15) not null unique,
 a_2 varchar(15) not null
);

create table B (
  b_id integer primary key
  a_id integer not null references A (a_id),
  b_1  varchar(10) not null,
  unique (a_id, b_1),
);

create table C (
  c_id integer primary key,
  b_id integer not null references B (b_id),
  c_1 char(3) not null,
  c_2 varchar(20) not null,
  unique (b_id, c_1)
);

create table D (
  d_id integer primary key,
  c_id integer not null references C (c_id),
  d_1 integer not null,
  d_2 varchar(15),
  unique (c_id, d_1)
);

テーブル「D」に関するレポートが必要で、レポートが必要な場合

  • 列 D.d_1 および D.d_2、および
  • 列 A.a_1 および A.a_2、

それに到達するには3つの結合が必要です。(試してみてください。) ID 番号を追跡しています。(IMS でポインターを追跡するようなものです。) 次の構造は異なります。

create table A (
 a_1 varchar(15) primary key,
 a_2 varchar(15) not null
);

create table B (
  a_1 varchar(15) not null references A (a_1),
  b_1  varchar(10) not null,
  primary key (a_1, b_1),
);

create table C (
  a_1 varchar(15) not null,
  b_1 varchar(10) not null,
  c_1 char(3) not null,
  c_2 varchar(20) not null,
  primary key (a_1, b_1, c_1),
  foreign key (a_1, b_1) references B (a_1, b_1)
);

create table D (
  a_1 varchar(15) not null,
  b_1 varchar(10) not null,
  c_1 char(3) not null,
  d_1 integer not null,
  d_2 varchar(15),
  primary key (a_1, b_1, c_1, d_1),
  foreign key (a_1, b_1, c_1) references C (a_1, b_1, c_1)
);

この構造では、同じレポートに 1 つの結合が必要です。

select D.d_1, D.d_2, A.a_1, A.a_2
from D
inner join A on D.a_1 = A.a_1;
于 2012-12-15T17:00:34.707 に答える
3

最初のアプローチは私の好みです

PersonJobDescriptionに依存するテーブル(AgentContactなど)が必要な場合は、サロゲートRec_IDに簡単にリンクできます。テーブルがなくても、フープをジャンプし始める必要があります。

もう1つの理由は、毎年Person/JobDescriptionを保持することが要件になった場合はどうなるでしょうか。あなたがどこにいるのかを知る前に、あなたはまだ仕事をしていない4つのvakue複合キーを持っているでしょう。ルールCompoundPrimaryKeysは、デザインをより柔軟で弾力性のあるものにする最後の手段である必要があります。

于 2012-12-15T16:21:21.220 に答える