SQLデータベースの主キーとしての文字列


178

私は、データベースと、その仕組みの背後にある理論についてはあまり詳しくありません。主キーに文字列を使用するのは整数よりもパフォーマンスの観点(挿入/更新/クエリ)の面で遅いですか?

回答:


191

技術的にはそうですが、文字列が主キーであることが理にかなっている場合は、おそらくそれを使用する必要があります。これはすべて、作成するテーブルのサイズと、主キーになる文字列の長さに依存します(文字列が長いほど、==比較が難しくなります)。数百万の行があるテーブルには必ずしも文字列を使用するわけではありませんが、小さいテーブルで文字列を使用することで得られるパフォーマンスの低下は、データに関して何も意味しません。


11
データベースに依存しませんか?適切にインデックス付けされた文字列は、数値からの場合でもそれほど遅くはないと思いますか?
ライアンギル

2
考慮すべき変数がたくさんあることに同意します。(sqlserverで)10代半ばから十代以上の長さの文字列を使用してインデックスを作成した場合でも、実際のパフォーマンスの問題が発生しました。たとえば、このハードウェアを克服するために必要なものがあります。
kemiller2002、2009

1
けっこうだ。ただし、文字列に意味がある場合は、それを使用する必要があることに同意します。また、データベースのGUIDまたはUUIDフィールドが自動インクリメントフィールドで機能しない場合があることは間違いありません。
ライアンギル

7
また、インデックスの比較を行う場合、CHARとVARCHARの間に非常に大きな違いがあることも覚えておいてください
Tom H

7
この回答のコメントの数は、それがどれほど不完全であるかを明確にします。インデックス作成について言及することは、最低限の受け入れ可能な答えでした。
ペドロロロ

74

文字列を主キーとして使用する場合のもう1つの問題は、インデックスが常に順番に配置されるため、新しいキーが作成されると、インデックスの順序を変更する必要がある順序で新しいキーを作成する必要があるということです...整数の場合、新しいキーはインデックスの最後に追加されます。


2
これは、新しい挿入の「ホットスポット」を引き起こす可能性があります。データベースを適切に管理している限り、とにかく挿入のためにページに余分なスペースが必要であり、ページ分割はまれです。
トムH

20
これは、主キーがクラスター化されている場合です。非クラスター化して作成することもできます。
学習

XIDが順序付けされているため、xid文字列を使用するだけで役立つ場合があります
Sinaesthetic

22

クラスター化インデックスを持つテーブルに挿入しても、シーケンスの途中で挿入が行われると、インデックスが書き換えられることはありません。データを構成するページが書き換えられることはありません。行が移動するページにスペースがある場合は、そのページに配置されます。1ページが再フォーマットされ、行がページの適切な場所に配置されます。ページがいっぱいになると、ページ分割が行われ、ページの行の半分が1つのページに移動し、残りの半分が他のページに移動します。次に、ページは、クラスター化インデックスを持つテーブルデータを構成するページのリンクリストに再リンクされます。せいぜい2ページのデータベースを作成するだけです。


良い説明。しかし、これはすべてのSQLデータベースに当てはまりますか?ランダムなUUIDを主キーとして使用すると、MySQLのパフォーマンスの問題があると聞いています。
hgoebl 2017

13

文字列は結合では低速であり、実際には(たとえそうであるはずであっても)実際に一意であることは非常にまれです。唯一の利点は、名前を取得するためだけにプライマリテーブルに結合している場合に、結合の数を減らすことができることです。ただし、文字列は変更されることも多いため、会社名が変更されたり、人が結婚したりすると、関連するすべてのレコードを修正する必要があるという問題が生じます。これはパフォーマンスに大きな影響を与える可能性があり、何らかの方法で関連付ける必要があるすべてのテーブルが関連付けられていない場合(これは思ったよりも頻繁に発生します)、データの不一致も発生する可能性があります。レコードの存続期間を通じて変更されない整数は、パフォーマンスの観点からだけでなく、データの整合性の観点からもはるかに安全な選択です。自然キーは通常、データのメンテナンスにはあまり適していません。

また、両方の世界の最良の点は、自動インクリメントキー(または一部の特殊なケースではGUID)をPKとして使用し、固有キーに固有のインデックスを配置することです。より高速な結合が得られ、重複したレコードは得られません。会社名が変更されたため、100万の子レコードを更新する必要はありません。


26
PKの適切な候補である文字列には重複はありません。それ以外の場合、それらはPKの適切な候補ではありません。ICD-9コード、国コード、VIN番号を考えてください。自然キーの問題の例として名前を使用することは、そもそも候補になるべきではないため、見当違いです。
トムH

6
@Tom H:ISO郡コードは変更されます。[ en.wikipedia.org/wiki/ISO_3166-1#Editions_and_changes ]関連する質問に対する回答として、[ stackoverflow.com/questions/925266/… ]が「プライマリキーについては、一意性があなたの管理下にあることを確認してください」
Steve Schnepp

4
@SteveSchnepp:はい、ISOはその変更を管理するための信頼できる機関です。一方、増加する整数値の単調なシーケンスを他の誰かとマージする必要がある場合、あなたは自分で
やり

1
名前はキーとして考慮されるべきではないことに同意するでしょう。
HLGEM 2012年

1
@onedaywhen増加する整数の2つの単調なシーケンスをマージすることは、接頭辞または接尾辞を付けることによって非常に簡単に行われます:)
Steve Schnepp

6

UNIQUEであれば、主キーとして何を使用してもかまいません。速度や優れたデータベース設計に関心がある場合は、データを複製する予定がない限り、intを使用してから、GUIDを使用してください。

これがアクセスデータベースまたはいくつかの小さなアプリである場合、誰もが気にかけます。私たちのほとんどの開発者が古いintまたはguidを前面に押し出すのは、プロジェクトには私たちで成長する方法があり、自分で成長する選択肢を残したいからだと思います。


5

変数が多すぎます。これは、テーブルのサイズ、インデックス、文字列キードメインの性質によって異なります...

通常、整数の方が高速です。しかし、その差は気になるほど大きいでしょうか?言うのが難しい。

また、弦を選ぶ動機は?多くの場合、数値の自動インクリメントキーも非常に簡単です。それは意味論ですか?便利?レプリケーション/切断の懸念?ここでの答えは、オプションを制限する可能性があります。これは、忘れている3番目の「ハイブリッド」オプション、Guidsも思い出します。


それは意味がありません、どういう意味ですか?
HLGEM 2009

@HLGEM:私が彼の書き込みを理解している場合、彼はラップトップで作成されたレコードをメインデータベースと同期するようなものです。
Joel Coehoorn、2009

つまり、同じエンティティを持つ2つの個別のデータベースがあり、永続的なストレージの目的で更新される頻度は1つだけです。データベースAでエンティティ「カリフォルニア」をクエリする場合、データベースBのエンティティ「カリフォルニア」と基本的に同じにしたい
mainstringargs

1
そして、それは同じ問題であるという点でラップトップで作成されたレコードを同期するのと同じです:ある場所で作成されたレコードは別の場所で作成されたレコードと競合してはなりません。ここで考えられる解決策の1つは、Guidキーです。
Joel Coehoorn、2009

5

データが説明する主題に一致し、データの使用目的によく適合するシンプルで健全な設計が得られるまで、パフォーマンスについて心配する必要はありません。その後、パフォーマンスの問題が発生した場合は、システムを調整することで対処できます。

この場合、ほとんどの場合、文字列を自然な主キーとして使用することをお勧めします(信頼できる場合)。文字列であっても心配しないでください。文字列が適度に短い限り、最大約25文字です。パフォーマンスの点で大きな代償を払うことはありません。

データ入力担当者または自動データソースは、想定される自然キーの値を常に提供しますか、それとも省略されることがありますか?入力データに時々間違っていますか?もしそうなら、エラーはどのように検出され、修正されますか?

クエリを指定するプログラマーやインタラクティブユーザーは、自然なキーを使用して必要なものを取得できますか?

自然キーを信頼できない場合は、代理を作成してください。サロゲートを発明する場合、整数を発明することもできます。次に、サロゲートをユーザーコミュニティから隠すかどうかについて心配する必要があります。代理キーを隠さなかった一部の開発者は、それを後悔するようになりました。


3

インデックスは多くの比較を意味します。

通常、文字列は整数よりも長く、比較には照合規則が適用される可能性があるため、通常、文字列の比較は整数の比較よりも計算集約的なタスクです。

ただし、string to numerical idテーブルとの追加の結合を行うよりも、文字列を主キーとして使用する方が高速な場合があります。


2

はい。ただし、何百万もの行があると予想される場合を除いて、文字列ベースのキーを使用しないほうが遅いため、通常は「時期尚早の最適化」です。結局のところ、文字列は大きな数字として保存されますが、数字キーは通常、小さな数字として保存されます。

ただし、注意が必要なことの1つは、任意のキーにクラスター化されたインデックスがあり、インデックス内で連続していない挿入を多数実行している場合です。書き込まれるすべての行は、インデックスを書き換えます。バッチ挿入を実行している場合、これによりプロセスが本当に遅くなる可能性があります。


2

PK列に整数を使用する2つの理由:

  1. 自動的に増加する整数フィールドのIDを設定できます。

  2. PKを作成すると、データベースにインデックスが作成され(クラスターまたは非クラスター)、データがテーブルに格納される前にソートされます。PKでIDを使用することにより、オプティマイザーはレコードを保存する前にソート順を確認する必要がなくなります。これにより、大きなテーブルのパフォーマンスが向上します。


1

文字列を主キーとして持つ理由は何ですか?

主キーを自動インクリメント整数フィールドに設定し、文字列フィールドにインデックスを設定します。

そうすれば、テーブルで検索を行う場合は比較的高速になり、すべての結合と通常のルックアップは速度に影響されません。

インデックスが作成される文字列フィールドの量を制御することもできます。つまり、「最初の5文字だけをインデックスに登録する」と言えば、それで十分だと言えます。または、データが比較的類似している場合は、フィールド全体にインデックスを付けることができます。


3
知性をキーに入れることは問題を求めていると思います。彼らはユニークなままでしょうか?彼らはすべての口座番号を州の略語で始め、クライアントの移動のみを始めましたか?フィールドを更新します-問題ありません-アカウント番号でリンクされたこれらのすべてのテーブル-なんてめちゃくちゃ
JeffO 2009

1
文字列をPKとして使用する例には、設定のテーブルがあります。例:settingNamePK、isUserEditable、isCustomerEditableなど次に、設定動作を変更する場合は、「UPDATE設定SET ... WHERE settingNamePK = 'dailyWorkObligation'」の方が、IDを使用してIDのマッピングをどこかに保存するよりもはるかに便利です。もちろん、整数のPKを使用し、設定名を別の一意のキーとして使用することもできます。
MeatPopsicle 2013

主キーが自動インクリメントされた整数であるので、挿入も速度に影響を与えてはいけませんか?
Dennis

好奇心が強いRails開発者のために、インデックスの長さを指定する方法を次に示します。SQLiteはインデックスの長さをサポートしていないことに注意してください。
Dennis

1

パフォーマンスの観点から-はいstring(PK)は、PK ---> Primary Keyであるinteger(PK)を使用して達成されるパフォーマンスと比較すると、パフォーマンスを低下させます。

要件の観点から-これはあなたの質問の一部ではありませんが、私はまだ言及したいと思います。さまざまなテーブルにまたがる巨大なデータを処理する場合、通常、特定のテーブルに設定できる可能性のあるキーのセットを探します。これは主に多くのテーブルがあり、ほとんどすべてのテーブルまたは一部のテーブルが何らかのリレーション(外部​​キーの概念)を介して他のテーブルに関連付けられるためです。したがって、整数を主キーとして常に選択できるわけではありません。3、4、または5つの属性の組み合わせをそのテーブルの主キーとして使用します。そしてこれらのキーは、レコードを他のテーブルと関連付けるときに外部キーとして使用できます。これにより、必要に応じて、さまざまなテーブル間でレコードを関連付けることができます。

したがって、最適な使用法-1または2の整数と1または2の文字列属性の組み合わせを常に作成しますが、これも必要な場合のみです。


0

データベース内の文字列に関連する非常に大きな誤解がある可能性があります。ほとんどの人は、数値のデータベース表現は文字列よりもコンパクトであると考えています。彼らは、db-sの数値はメモリのように表されると考えています。しかし、それは真実ではありません。ほとんどの場合、数値表現は、他の表現よりも文字列のような表現に近いです。

数値または文字列を使用する速度は、タイプ自体よりもインデックス作成に依存します。


0

デフォルトでは、ASPNetUserIdsは128文字の文字列で、パフォーマンスは問題ありません。

キーが場合HASテーブル内で一意であるために、それはキーでなければなりません。これが理由です。

プライマリ文字列キー=正しいDB関係、1つの文字列キー(プライマリ)、および1つの文字列インデックス(プライマリ)。

他のオプションは、典型的なint型のキーですが、文字列があればHAS一意であることが、あなたはおそらくまだ検証するための理由はノンストップのクエリのインデックスを追加したり、そのユニークなことを確認する必要があります。

したがって、int IDキーを使用する= Incorrect DB Relationships、1 int key(Primary)、1 int index(Primary)、おそらく一意の文字列Index、および手動で同じ文字列を検証する必要がない(sql checkのようなもの) )。

主キーの列の上にint型を使用して、より良いパフォーマンスを得るためには、文字列のときHAS一意であること、それは非常に奇妙な状況でなければならないであろう。私は常に文字列キーを使用することを好みました。あなたがされるまで、親指の良いルールとして、データベースを非正規化していないNEEDに。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.