198

MySQL で主キーとして INT と VARCHAR を使用する場合、測定可能なパフォーマンスの違いはありますか? 参照リスト (米国の州、国コードなど) の主キーとして VARCHAR を使用したいのですが、同僚はすべてのテーブルの主キーとして INT AUTO_INCREMENT を使いません。

hereで詳しく説明されているように、私の主張は、INT と VARCHAR のパフォーマンスの違いはごくわずかであるということです。すべての INT 外部キー参照では、参照を理解するために JOIN が必要になるため、VARCHAR キーは情報を直接提示します。

では、この特定のユースケースとそれに関連するパフォーマンスの問題を経験した人はいますか?

4

14 に答える 14

94

代理キーの代わりに自然キーと呼ばれるものを使用することで、いくつかの結合されたクエリを回避できることをうまく指摘しています。この利点がアプリケーションで重要かどうかを評価できるのは、あなただけです。

つまり、大量のデータを処理するか、非常に頻繁に実行されるため、高速であることが最も重要なアプリケーション内のクエリを測定できます。これらのクエリが結合を排除することでメリットがあり、varchar 主キーを使用しても問題がない場合は、結合を使用してください。

データベース内のすべてのテーブルにどちらの戦略も使用しないでください。自然キーの方が優れている場合もあれば、代理キーの方が優れている場合もあります。

他の人々は、自然キーが変更されたり重複したりしないことは実際にはまれであるため、通常は代理キーが価値があると主張しています。

于 2008-12-01T21:47:48.400 に答える
89

パフォーマンスの問題ではありません。それは、優れた主キーを作るものについてです。時代を超えて変わらない唯一無二の存在。国コードなどのエンティティは時間が経っても変化しないため、主キーの候補として適していると思われるかもしれません。しかし、苦い経験は、めったにそうではないということです。

INT AUTO_INCREMENT は、「一意で時間の経過とともに変化しない」条件を満たしています。したがって、好み。

于 2008-12-01T21:30:57.547 に答える
40

長さによって異なります。varchar が 20 文字で、int が 4 の場合、int を使用すると、インデックスにはディスク上のインデックス スペースのページあたりのノード数が 5 倍になります...インデックスは、5 分の 1 の数の物理および/または論理読み取りを必要とします。

そのため、機会があれば、パフォーマンスが問題になる場合は、テーブルと、これらのテーブルの行を参照する外部キーに、意味のない整数キー (サロゲートと呼ばれます) を常に使用してください...

同時に、データの一貫性を保証するために、重要なすべてのテーブルに意味のある非数値の代替キー (または一意のインデックス)持たせて、重複する行を挿入できないようにする必要があります (意味のあるテーブル属性に基づく重複)。

あなたが話している特定の用途(状態ルックアップなど)では、テーブルのサイズが非常に小さいため、実際には問題になりません。一般に、数千行未満のテーブルのインデックスによるパフォーマンスへの影響はありません。 ..

于 2008-12-01T21:56:05.403 に答える
37

絶対違う。

INT、VARCHAR、および CHAR の間でいくつかの...いくつかの...パフォーマンス チェックを行いました。

PRIMARY KEY (一意でクラスター化された) を持つ 1,000 万レコード テーブルは、3 つのうちどれを使用しても、まったく同じ速度とパフォーマンス (およびサブツリー コスト) でした。

そうは言っても...アプリケーションに最適なものを使用してください。パフォーマンスについて心配する必要はありません。

于 2008-12-01T21:33:57.010 に答える
9

ショートコードの場合、おそらく違いはありません。これらのコードを保持するテーブルは非常に小さく (せいぜい数千行)、頻繁に変更されない (新しい米国の州を最後に追加したのはいつか) ため、これは特に当てはまります。

キー間のバリエーションが広い大きなテーブルの場合、これは危険な場合があります。たとえば、User テーブルの電子メール アドレス/ユーザー名を使用することを考えてみてください。数百万人のユーザーがいて、それらのユーザーの一部が長い名前や電子メール アドレスを持っているとどうなりますか。そのキーを使用してこのテーブルに参加する必要があるときはいつでも、はるかに高価になります。

于 2008-12-01T21:30:09.340 に答える
6

主キーに関しては、行を物理的に一意にするものはすべて主キーとして決定する必要があります。

外部キーとして参照する場合、自動インクリメント整数をサロゲートとして使用することは、主に 2 つの理由から良い考えです。
- まず、通常、結合で発生するオーバーヘッドが少なくなります。
- 第 2 に、一意の varchar を含むテーブルを更新する必要がある場合、更新はすべての子テーブルにカスケードされ、すべての子テーブルとインデックスを更新する必要がありますが、int サロゲートでは、更新のみが必要です。マスターテーブルとそのインデックス。

サロゲートを使用することの欠点は、サロゲートの意味を変更できる可能性があることです。

ex.
id value
1 A
2 B
3 C

Update 3 to D
id value
1 A
2 B
3 D

Update 2 to C
id value
1 A
2 C
3 D

Update 3 to B
id value
1 A
2 C
3 B

それはすべて、構造の中で本当に心配する必要があるものと、最も意味するものに依存します。

于 2008-12-01T21:42:58.580 に答える
3

HauteLook では、自然キーを使用するようにテーブルの多くを変更しました。私たちは実際にパフォーマンスの向上を経験しました。おっしゃるとおり、多くのクエリで結合の使用が減り、クエリのパフォーマンスが向上しました。意味がある場合は、複合主キーも使用します。そうは言っても、一部のテーブルは、代理キーがあれば簡単に操作できます。

また、ユーザーにデータベースへのインターフェイスを書かせる場合は、代理キーが役立ちます。サードパーティは、代理キーが非常にまれな状況でのみ変更されるという事実を信頼できます。

于 2012-10-17T02:47:12.890 に答える
3

サロゲートAUTO_INCREMENTが痛む一般的なケース:

一般的なスキーマ パターンは、多対多のマッピングです。

CREATE TABLE map (
    id ... AUTO_INCREMENT,
    foo_id ...,
    bar_id ...,
    PRIMARY KEY(id),
    UNIQUE(foo_id, bar_id),
    INDEX(bar_id) );

特に InnoDB を使用する場合、このパターンのパフォーマンスははるかに優れています。

CREATE TABLE map (
    # No surrogate
    foo_id ...,
    bar_id ...,
    PRIMARY KEY(foo_id, bar_id),
    INDEX      (bar_id, foo_id) );

なんで?

  • InnoDB のセカンダリ キーには追加のルックアップが必要です。ペアをPKに移動することにより、これは一方向で回避されます。
  • セカンダリ インデックスは「カバーする」ため、追加のルックアップは必要ありません。
  • idこのテーブルは、インデックスが 1 つ削除されているため、小さくなっています。

別のケース ():

country_id INT ...
-- versus
country_code CHAR(2) CHARACTER SET ascii

初心者は、country_code をINT「自然な」2 バイトの、ほとんど変化しない 2 バイト文字列を使用する代わりに、4 バイトに正規化することがよくあります。より速く、より小さく、より少ない JOIN で、読みやすくなります。

于 2015-12-09T01:52:20.540 に答える
2

質問はMySQLに関するものなので、大きな違いがあると言います。それがOracle(数値を文字列として保存する-はい、最初は信じられませんでした)についてだった場合、大きな違いはありません。

テーブル内のストレージは問題ではありませんが、インデックスの更新と参照は問題です。主キーに基づいてレコードを検索するクエリは頻繁に発生します。クエリは頻繁に発生するため、できるだけ早く実行する必要があります。

問題は、CPU がシリコンで 4 バイトと 8 バイトの整数を自然に処理することです。2 つの整数を比較するのは非常に高速です。1 つか 2 つのクロック サイクルで実行されます。

ここで文字列を見てみましょう。文字列は多数の文字で構成されています (最近では 1 文字あたり 1 バイト以上)。2 つの文字列の優先順位の比較は、1 サイクルまたは 2 サイクルでは実行できません。代わりに、違いが見つかるまで文字列の文字を繰り返す必要があります。一部のデータベースでは高速化するためのトリックがあると確信していますが、ここでは無関係です。なぜなら、int 比較は CPU によってシリコンで自然に行われ、非常に高速だからです。

私の一般的なルール - すべての主キーは、特にオブジェクト間に多くの関係がある ORM (Hibernate、Datanucleus など) を使用する OO アプリでは、自動インクリメント INT にする必要があります - 通常、それらは常に単純な FK として実装され、これらを迅速に解決する DB は、アプリの応答性にとって重要です。

于 2016-11-30T07:24:32.937 に答える
2

私は同じジレンマに直面しました。Road Accidents、Vehicles in Accidents、Casualties in Accidents の 3 つのファクト テーブルを含む DW (コンステレーション スキーマ) を作成しました。データには、1979 年から 2012 年までに英国で記録されたすべての事故と、60 のディメンション テーブルが含まれています。合わせて約 2000 万件のレコードです。

ファクト テーブルの関係:

+----------+          +---------+
| Accident |>--------<| Vehicle |
+-----v----+ 1      * +----v----+
     1|                    |1
      |    +----------+    |
      +---<| Casualty |>---+
         * +----------+ *

RDMS:MySQL 5.6

本来、事故インデックスは 15 桁の varchar (数字と文字) です。アクシデント インデックスが変更されない場合は、代理キーを使用しないようにしました。i7 (8 コア) コンピューターでは、ディメンションによっては 1,200 万レコードの負荷がかかると、DW のクエリが遅くなりすぎました。何度もやり直し、bigint 代理キーを追加した結果、速度パフォーマンスが平均 20% 向上しました。まだパフォーマンスの向上は低いですが、有効にしてみてください。MySQL のチューニングとクラスタリングに取り組んでいます。

于 2014-05-28T14:42:36.253 に答える
0

パフォーマンスへの影響についてはわかりませんが、少なくとも開発中は、自動インクリメントされた整数の「代理」キーと、意図した一意の「自然」キーの両方を含めることで妥協できるようです。これにより、パフォーマンスだけでなく、自然キーの変更可能性など、他の考えられる問題を評価する機会が得られます。

于 2008-12-01T21:43:26.553 に答える