2

これは私が最近やっていることで、他の人もやっているのではないかと考えていました。もしそうなら、この種の練習の名前は何ですか.

あまりにも多くの結合を行うことを避けるために、テーブルにショートカット列を保持しています。たとえば、users テーブルと geo テーブルがある場合:

ユーザー:

id | username | zip       | copy_latitude | copy_longitude | other info
------------------------------------------------------------------------
1  | Bob      | 11345     | 40.81518000   | -73.04550000   | etc...

地域:

id | zip_code | latitude    | longitude
----------------------------------------
1  | 11345    | 40.81518000 | -73.04550000

ボブの緯度と経度を取得したい場合は、ボブの他の情報を取得するために使用するものと同じ select ステートメントで取得できます。

SELECT a_bunch_of_other_columns, copy_latitude, copy_longitude 
FROM users WHERE id = 1;

vs(ショートカットを保持していなかった場合):

SELECT a_bunch_of_other_columns, latitude, longitude 
FROM users
INNER JOIN geo ON user.zip = geo.zip_code
WHERE users.id = 1;

ショートカットを維持することで、参加を節約できました。これは、このテーブルとステートメントの例では大したことではないように思えるかもしれませんが、6 つまたは 7 つの結合を持つ巨大なテーブルとステートメントがいくつかあり、これが役立つと感じています。

唯一のオーバーヘッドは、何かが変更されるたびに両方の場所を更新する必要があることです。私はストアドプロシージャを介してそれを処理します。

私の質問は次のとおりです。

  • これは開発者の間で一般的な慣行ですか?もしそうなら、それは何と呼ばれていますか?
  • これを行った場合、データベースはまだ正規化されていますか? (データの整合性のために、そこから使用しない場合でも、データの有効なコピーを常に適切な場所に保持しているため、そうなると思います)
4

4 に答える 4

3

それが一般的かどうかはわかりませんが、良い習慣ではないと確信しています。データを複数の場所に保存する場合はいつでも、最適とは言えません。確かに非正規化データベースは、レポート データベースやデータ ウェアハウスなどのパフォーマンスを向上させるために使用されます。このような場合、データベースは通常、トランザクション データベースの読み取り専用の非正規化されたコピーです。

結合を本当に減らす必要がある場合は、それらの状況を満たすビューを作成できませんか?

クエリのパフォーマンスを向上させていると思われるもののために作成しているこの重複データはすべて、もちろん挿入/更新のパフォーマンスを低下させます。この余分なデータをすべて追跡するにはどうすればよいでしょうか。同期がとれなくなったらどうなりますか? あなたが会社を離れて、データを更新する必要がある余分な場所を他の誰かが発見しなければならなくなったらどうなるでしょうか?

于 2012-05-09T03:57:30.553 に答える
2

これは開発者の間で一般的な方法ですか? もしそうなら、それは何と呼ばれていますか?

私は自分自身のために話すことができます - 私はこれをしません

これは開発者の間で一般的な方法ですか? もしそうなら、それは何と呼ばれていますか? これを行った場合、データベースはまだ正規化されていますか? (データの整合性のために、そこから使用しない場合でも、データの有効なコピーを常に適切な場所に保持しているため、そうなると思います)

いいえ

ところで-別のオーバーヘッドがあります-ストレージ

于 2012-05-09T03:55:57.360 に答える
2

テーブルにデータが重複しているため、正規化されなくなりました。

「非正規化」と呼んでもいいと思います。

あなたが実際にそれを行うのは、速度/最適化の目的のためだけです。これは、質問で言っていることであり、複雑さを取り除くために行ったということです。

正直なところ、クエリ速度を最適化するためにこれを行う必要があるデータベースのポイントに到達したことはありません.

ベンチマークを実行して、適切にインデックス付けされた結合よりもどれだけ高速かを確認することをお勧めします

于 2012-05-09T04:03:32.923 に答える
0

このまましばらく様子を見てみましょう。あなたはすでにこれのいくつかを知っています. (PostgreSQL 構文。dbms は正規化には関係なく、実装にのみ関係します。)

create table geo (
  zip_code char(5) not null,
  -- CHECK constraints on lat and long omitted.
  latitude float not null,
  longitude float not null,
  primary key (zip_code),
  unique (latitude, longitude)
);

create table users (
  user_id integer not null,
  username varchar(10) not null,
  zip_code char(5) not null, 
  primary key (user_id),
  foreign key (zip_code) references geo (zip_code) 
    on update cascade on delete restrict
);

これらのテーブルが両方とも 5NF であることは明らかです。

geo テーブルの ID 番号を作成し、users.zip_codeをその ID 番号に置き換えることができます。しかし、実際のデータをサロゲート ID 番号に置き換えることは、正規化とは何の関係もなく、これらのテーブルの通常の形式も変更しません。

実際のデータを ID 番号に置き換えると、パフォーマンス変わります。ユーザーの郵便番号が必要になるたびに、それを取得するために参加する必要があります。これは完全に予測可能な変更ではありません。実際のパフォーマンスは、dbms、サーバー、キーの幅などによって異なります。独自のテーブルをテストするのに問題はないはずです。数百万行までは、自然キーがサロゲート ID 番号よりも優れたパフォーマンスを発揮することがわかるでしょう。(これは、ここで実稼働データベースの設計をテストしたときに見つけたものです。)

ここで、構造を少し変更してみましょう。

create table geo (
  zip_code char(5) not null,
  -- CHECK constraints on lat and long omitted.
  latitude float not null,
  longitude float not null,
  primary key (zip_code),
  unique (latitude, longitude),
  -- Allows all three columns to be the target for a foreign key.
  unique (zip_code, latitude, longitude)
);

create table users (
  user_id integer not null,
  username varchar(10) not null,
  zip_code char(5) not null, 
  latitude float not null,
  longitude float not null,
  primary key (user_id),
  -- This FK has to reference all three columns. If split, it's possible
  -- to reference the latitude and longitude for the wrong zip code.
  foreign key (zip_code, latitude, longitude) 
    references geo (zip_code, latitude, longitude) 
    on update cascade on delete restrict
);

この変更により推移的な依存関係導入されますが、user_id -> zip_code、zip_code -> latitude などでは、挿入、更新、または削除の異常は発生しません。これは、推移的な依存関係に含まれるすべての値が、5NF テーブルへの単一の外部キー参照によってカバーされるためです。

テーブル geo はまだ 5NF です。ユーザーは現在 2NF です。私たちはここで何を得て、何を失ったのでしょうか。

  • より広い外部キー データとインデックスを格納するためのディスク領域が失われます。
  • ある程度の行数 (おそらく数百万行) までは、SELECT クエリのパフォーマンスが向上します。(時間がないので、スキーマをテストしませんでした。しかし、自然キーを使用して 20 倍から 30 倍の速度の向上を測定しました。違いはおそらくそれほど劇的ではありません。)
  • INSERT ステートメントとほとんどの UPDATE ステートメントでパフォーマンスが低下します。(遅いからといって遅いという意味ではありません。5 ミリ秒は 3 ミリ秒よりも遅いですが、5 ミリ秒は必ずしも遅いとは限りません。私自身の挿入と更新のほとんどは、ミリ秒未満で実行されます。)

したがって、テスト スキーマを構築し、数百万行を入力して、パフォーマンスを測定します。でパフォーマンスをテストする

  • zip_code の外部キー、および緯度と経度を取得するための結合、
  • {zip_code, latitude, longitude} の外部キーで再構築してテストし、次に
  • サロゲート ID 番号と結合を使用して再構築およびテストし、zip_code、緯度、および経度を取得します。

そして、ここに結果を投稿してください。ぜひ見てみたいです。

于 2012-05-09T13:20:50.790 に答える