web-dev-qa-db-ja.com

タイムスタンプと整数を主キーとして使用する

SQL Serverでは、主キーを使用することの欠点と欠点は何ですか。

2文字のテーブル識別子+ YEAR + MONTH + DAY + HOUR + MINUTE + MILLISECOND + 0〜100のランダムな整数?

なぜこれはInteger Auto_Incrementedフィールドを使用するよりも好まれますか? (そうでなければ、私もそれを知りたいです。)

これが本当に悪い設計慣行である理由が好きです。その整数値を取り戻すためにすべてをキャストすることも、お尻の苦痛です。

私は基本的に、ひどく必要なアプリケーションのデータベースを改善するために私の小さな開発者チームにアクセスする機会を一度与えます-左詰めゼロの主キーVarchar(50)フィールドのような状況を回避するため、または単に非-正規化されたデータベース、または1つのフィールド内のコンマ区切りリスト。

5
user44371

もちろんできますが、なぜそうするのでしょうか。いくつかのCAST式を保存するには?それは少し弱いようです。

自動インクリメントサロゲートint PKを使用する理由は多数あります。

  1. 通常のデータベースでそれらを管理する必要はほとんどありません。ずっと。 IDをオフまたはオンにする必要がある場所でテーブルを再構築したりデータを挿入したりする場合を除きます。しかし、運用上はオーバーヘッドがほとんどなく、うまく機能します。推奨する方法で行うと、自動インクリメントintよりも多くのCPUサイクルを作成する必要があるキーを作成するUDFが必要になるため、オーバーヘッドが大きくなります。
  2. これらは最も効率的なストレージソリューションです。あなたが提案する方法は、varchar(20)/ char(20)を必要とするか、キーだけのために行あたり20バイトを意味します。通常のintはわずか4バイトです。それほど多くはないように見えるかもしれませんが、1億行をそこに配置すると、サイズが約1.5GB増加します。クールではありません。次に、それを別のテーブル(別の1.5GB)のFKとして配置する必要があります。または、他の3つのテーブルでは、DBは不必要にほぼ5GB大きくなります。あなたはアイデアを得ます...
  3. テーブルは、ユーザーが気にしない、または理解していないものと実際にリンクする必要があります。これは、DBAとしての制御の粒度が低くなるためです。この値は、非常に細かい変更、テーブルの微調整、またはデータ構造の管理を行うときにユーザーが何も重要ではないことを示します。これは、あなたが提案するような複合キーを持つDBでの作業の経験からそれを伝えることができます。それらは苛立たしいほど煩わしくなり、あなたは常に自動インクリメントintを入れて、複雑さと欲求不満で終わらせたくなります。たとえば、別のソースから取得したレコードの束全体をすばやく挿入したいとします。自動インクリメントにより、サーバーリソースへの影響を最小限に抑えて簡単にできます。複合キーでは...挿入ごとにキーを作成するUDFを実行する必要があります...この例では、100キー/ msのランダマイザーでは不十分な場合があり、SQL Serverの動作が速すぎて、 2つのレコードに同じID。くそー、あなたは一意の制約に違反しない別のアプローチが必要です。または、ユーザーが何らかの理由でキーの「再利用」を開始することを望んでいると想像してみてください(「データベースを高速化してリサイクルする」という誤った考えで発生する場合があります)。ユーザーは結局、DBを自分で調整しようとすることになり、災害のレシピとなります。彼らが理解していないことが起こっていることを舞台裏で彼らに伝える(そして持つ)ことは、しばしば状況を回避する分離のレベルを与えます。彼らは何も最適化しようとせず、粘着性のある小指をビジネスの側面から外します。つまり、それを行う方法を最適化できます。現代の車の電子タイミングをスマートフォンとハンマーで変えようとする考えのないティーンエイジャーのように...正しい知識とツールを備えた専門家によって行われる仕事の方がはるかに優れています。
  4. SQL Serverは、int PK-FK自動インクリメントを想定しており、それに対して最適化されています。レコード挿入時のFKチェックにより、全体的に処理が高速になります。
  5. 最後に、最適化と管理をほとんど必要としないユーザー数が少ない小規模なデータベースでは、自然なキーで十分であることがわかります。また、クエリが単純な場合(WHEREステートメントで複合キーを使用することにより)見栄えのよいクエリを作成することもできます。つまり、結合テーブルが少なくなります。ただし、データベースが大きく複雑になるとすぐに...自動インクリメントintの管理代理キーはずっと簡単になります。

私の最後の考え:複合キーは、多くの変更の影響を受けない(管理オーバーヘッドが低い)メンバーの数が少ない(つまり、複合キーが短いため、必要なスペースが少ない)ルックアップテーブルのFINEです。たとえば、米国の2文字の州コードです。それらは、潜在的に結合が1つ少なく、多くのストアドプロシージャを超えることを意味します。これにより、小さいながらも測定可能なパフォーマンスが向上する可能性があります。

5
blobbles

あなたのアイデアはそれほどクレイジーではありません。主キーの順序付けは断片化を減らしますが、これはIDENTITY列で実現できます。ただし、順序付けされたキーにも欠点があります。つまり、ここに記載されているもの http://kejser.org/clustered-indexes-vs-heaps です。

これで、キーが生成されたときに、そのために少し追加の情報をパックする必要があることを知ることがどのように役立つかがわかります。これは正規化規則に違反していますが、それらは学者向けであり、実際のシステム設計者向けではありません。

テーブル名をキーの前に付けると、どこから来たのかを知っていると思います(間違っている場合は修正してください)。これにより、ユーザーが間違ったキーに参加して不正なデータを取得することがなくなります。

戦略を維持し、優れた物理設計の利点を維持したい場合は、次のようにします。

  • キーを64ビット整数にする
  • 上位32ビットは次のように構築されます:年* 10000 +月* 100 +日(これは8桁の長さで、32ビットに適合します)
  • 下位32ビットは、すべてのテーブルにわたってグローバルであり、maxintに到達するとロールオーバーする32ビットシーケンス(CREATE SEQUENCEを検索)から生成されます。これにより、テーブル名の接頭辞を必要とせずに、キーがテーブル全体で一意になります。

上記の戦略を使用すると、毎日2Bキーを生成できます。これで十分です。そうでない場合は、年を2桁に削減することを検討してください(そうですね、そうですね...)

この上記の戦略は、これが持つ利点と欠点を備えた、順次配置されたインデックスを作成します。キーロジックを変更してよりスケーラブルなレイアウトを使用する場合は、ここで説明するトリックを使用して下位32ビットのビットシーケンスを反転できます。 http://dangerousdba.blogspot.co.uk/2011/ 10/day-sequences-saved-world.html

3
Thomas Kejser

これは、自動インクリメント整数フィールドよりも間違いなく推奨されません。

手始めに:

  1. インデックスの幅は、提案によって大幅に低下します。
  2. 一意性を強制するために、これらすべての管理ランダムな2桁の整数をどのように管理することを提案しますか?このスキームを実装するためにどのくらいのコードを作成して保守する必要があるかについて考えましたか?.
  3. 実装のすべての結合に対してにこれらのキーフィールドをすべて入力しないでください。

余談として;いったいなぜ、この新しいフィールドのすべてのインスタンスに2文字のテーブル識別子を挿入したいのですか?行が形成された表は、検査されている表からすぐにわかります。

多数のサイトにわたるデータの衝突率が非常に高く、このようなスキームを正当化できると本当に思う場合は、少なくとも、このNIH設計の代わりに、すでに実装されているテクノロジであるGUIDを使用してください。

更新

自動インクリメントキーの単調な性質は、一部の 合計を実行するための非常に効率的な集計テーブルアルゴリズム(少なくとも) で使用され、実行合計の計算の適切な順序付けを強制します。このスキームは、それらのアルゴリズムの使用を無効にします。

3
Pieter Geerkens

私の好みは、主キーにID列を使用し、必要に応じて一意性を適用する必要がある場合は、他のフィールドに一意インデックスを追加することです。

私の意見では、主なキーの仕事は、単一のデータ行を一意に識別することです。整数は、あいまいさのリスクなしにこれをより効率的に行います。

Varcharsをpkeyとして、または結合で使用することは、スペース、大文字/小文字、パディング、先行ゼロ、または暗黙的な変換の影響を受ける可能性があるため、嫌いです。

明確な値を持つ単一のフィールドに単純なpkeyがあると、全員の作業が容易になります。

1

うーん、私はあなたに同意します、そしてあなたの行を識別するために任意の整数を使用することを提案する人々にはほとんど同意しません。

あなたの主キーは

tid char(2), asof datetime, sequence smallint

ここでシーケンスを制御します。 行を識別するであるため、これは完全に優れた主キーです。 「よりきめ細かい」識別子が必要になる状況を説明するのは、代理群衆の負担です。

これにより、16バイトのキーが得られます。それは正しく、ほとんど巨大ではなく、サロゲートキーよりもmore効率的ではありません。どうして?

  • アプリケーションが手にする値を使用します
  • クラスタ化されたキーとして、それは自然発生のデータによって順序付けられます
  • 代理キーもそれらに一意の制約が必要になります

日付を表すには、文字データの代わりにdatetimeを使用します。自動日付検証が行われ、日付計算が大幅に簡略化されます。

また、シーケンス番号は本当に必要ですか?そうでない場合は、ドロップできます。もしそうなら、それはanother自動インクリメント値を避ける理由です:すべての挿入は同じ場所から自動インクリメント値を取得する必要があるため、これらはリソース競合のポイントです。

シーケンス番号が必要な場合は、次のようにします。

insert into T as t
select /* values ... */ ,  1 + coalesce(max(sequence), 0) as seq 
from T 
where tid = t.tid and asof = t.asof

insert ... selectの原子性は、各プロセスが異なる値を取得することを保証するためです。

0
James K. Lowden