2009-09-22 14 views
40

3つのフィールドからなる複合主キーを持つテーブルがあります(それはMySQL 5.1にあります)。この表には200個近くの挿入と200個の選択があり、表のサイズはおよそ100万行で増加しています。複合主キーのMySQLでのパフォーマンスの欠点

私の質問は、「複合プライマリキー」はこのテーブルのインサートとセレクトのパフォーマンスを低下させますか?

複合主キーの代わりに単純な自動増加INT IDフィールドを使用する必要がありますか? (私は、答えは非常にMySQLが複数列のインデックスを処理する方法に関連していると思います)

答えて

50

INSERTUPDATEパフォーマンスはほとんど変化しない:それは(INT)(INT, INT)キーのため、ほぼ同じになります。

SELECT複合体の性能PRIMARY KEYは多くの要因によって決まります。

表がInnoDBの場合、表は暗黙的にPRIMARY KEYの値にクラスター化されます。

つまり、両方の値がキーを構成する場合、両方の値の検索が高速になります。余分なキーの参照は不要です。あなたのクエリを想定し

は次のようなものです:

SELECT * 
FROM mytable 
WHERE col1 = @value1 
     AND col2 = @value2 

とテーブルレイアウトはこれです:

CREATE TABLE mytable (
     col1 INT NOT NULL, 
     col2 INT NOT NULL, 
     data VARCHAR(200) NOT NULL, 
     PRIMARY KEY pk_mytable (col1, col2) 
) ENGINE=InnoDB 

、エンジンはちょうどテーブル自体に正確なキーの値をルックアップする必要があります。

あなたが偽のIDとして自動インクリメントフィールドを使用する場合:

CREATE TABLE mytable (
     id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, 
     col1 INT NOT NULL, 
     col2 INT NOT NULL, 
     data VARCHAR(200) NOT NULL, 
     UNIQUE KEY ix_mytable_col1_col2 (col1, col2) 
) ENGINE=InnoDB 

、その後、エンジンが(インデックスから行ポインタを取得し、インデックスix_mytable_col1_col2(col1, col2)の値をルックアップするために、まず、必要があります。 idの値)、テーブル自体にidで別の参照を行います。

MyISAMテーブルはヒープ構成であり、行ポインタは単にファイルオフセットであるため、MyISAMテーブルでは違いはありません。

どちらの場合も、同じインデックスが作成されます(PRIMARY KEYまたはUNIQUE KEY)。同じ方法で使用されます。

+0

+1。ありがとう、非常にうまく説明した。 – Fr0zenFyr

2
  1. 効果はかなり無視できるとの心配はない価値があるものの複合主キーは、ダウンSELECTのほんの少しを遅くすることを持ちます。
  2. これらの列のインデックスがの場合、INSERTの速度を低下させ、十分にINSERTを実行していることを心配しています。 MyISAMテーブルの場合は、InnoDBテーブルよりもINSERTがテーブルをロックしている場合、これはさらに懸念されます。 auto_increment主キーを使用することで、これらの列をインデックスなしで残すことができれば、変更の恩恵を受けるでしょう。これらの3つの列を索引付けしたままにしておく必要がある場合でも、(たとえば、それらの組み合わせに一意性を強制する必要がある場合など)、パフォーマンス面では何もしません。
22

InnoDBの場合、複合主キーは各副インデックスの各エントリに含まれます。

これは

  • あなたのセカンダリインデックスがすべての列場合は、被覆インデックスとしてセカンダリインデックスを使用することができます
  • 主キーのすべての列+これらの列と同じくらいのスペースを占有することを意味します二次インデックス+ pkに含まれている必要があります。

これらはもちろん、それぞれ欠点と利点です。

コンポジットプライマリキーは必ずしも悪くないとは限りませんが、InnoDBがそれらをクラスタリングするので、実際に役立つことがあります。つまり、ディスク上での範囲スキャンは、非クラスタ化インデックス

もちろん、他のテーブルに外部キーがある場合は、メインテーブルのキー全体を含める必要があります。

しかし、私はバランスをとって、一般的にはそうは言いません。コンポジット・プライマリ・キーを持つことで問題は発生しません。ただし、クラスタリングのメリットを上回り、カバーインデックスを使用できる場合は、大きなキー(例:大きなvarchars)を使用することもできます。

+0

'(reviewId、userId)'にプライマリキーを、 '(userId)'にセカンダリインデックスを持っていると、このインデックスは '(userId、reviewId、userId)'を内部的に含んでいますか? – Benjamin

+0

@Benjaminはい、そうです。 http://dev.mysql.com/doc/refman/5.7/en/innodb-index-types.htmlと本書ではっきりと述べられています。http://shop.oreilly.com/product/0636920022343.do –

関連する問題