2012-04-30 14 views
1

のは、簡単な例から始めましょう:だから、2列 複数のインデックスからMySQLを読み込みますか?

CREATE TABLE `test` (
`id` INT UNSIGNED NOT NULL, 
`value` CHAR(12) NOT NULL, 
INDEX (`id`), 
INDEX (`value`) 
) ENGINE = InnoDB; 

、両方のインデックス化。これが意味すると思ったのは、すべてのデータがインデックスに格納されるため、MySQLは実際のテーブルをもう読む必要がないということでした。

mysql> EXPLAIN SELECT id FROM test WHERE id = 1; 
+----+-------------+-------+------+---------------+------+---------+-------+------+-------------+ 
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra  | 
+----+-------------+-------+------+---------------+------+---------+-------+------+-------------+ 
| 1 | SIMPLE  | test | ref | id   | id | 4  | const | 1 | Using index | 
+----+-------------+-------+------+---------------+------+---------+-------+------+-------------+ 

"インデックスを使用する"、非常にいいです。私の理解では、これは実際のテーブルからではなく、インデックスからデータを読み込んでいることを意味します。しかし、私が本当に欲しいのは、 "価値"の列です。

mysql> EXPLAIN SELECT value FROM test WHERE id = 1; 
+----+-------------+-------+------+---------------+------+---------+-------+------+-------+ 
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | 
+----+-------------+-------+------+---------------+------+---------+-------+------+-------+ 
| 1 | SIMPLE  | test | ref | id   | id | 4  | const | 1 |  | 
+----+-------------+-------+------+---------------+------+---------+-------+------+-------+ 

「今回はインデックスを使用していません。

両方の列をカバーするインデックスを追加すると役立つと思いました。

ALTER TABLE `test` ADD INDEX `id_value` (`id`,`value`); 

これで、以前のselectステートメントをもう一度実行して、新しいインデックスを使用するようにしましょう。

mysql> EXPLAIN SELECT id, value FROM test USE INDEX (id_value) WHERE id = 1; 
+----+-------------+-------+------+---------------+----------+---------+-------+------+-------------+ 
| id | select_type | table | type | possible_keys | key  | key_len | ref | rows | Extra  | 
+----+-------------+-------+------+---------------+----------+---------+-------+------+-------------+ 
| 1 | SIMPLE  | test | ref | id_value  | id_value | 4  | const | 1 | Using index | 
+----+-------------+-------+------+---------------+----------+---------+-------+------+-------------+ 

賞賛の言葉は、インデックスから読んでいます。

しかし実際には、私は他のもののために結合されたインデックスを実際に必要としません。 2つの別々のインデックスからMySQLを読み取ることは可能ですか?

洞察力があれば幸いです。

編集:もう1つの例です。これは、元のテーブル定義(各カラムのインデックス)を使用しています。

mysql> EXPLAIN SELECT t1.value 
    -> FROM test AS t1 
    -> INNER JOIN test AS t2 
    -> ON t1.id <> t2.id AND t1.value = t2.value 
    -> WHERE t1.id = 1; 
+----+-------------+-------+------+---------------+-------+---------+----------+------+-------------+ 
| id | select_type | table | type | possible_keys | key | key_len | ref  | rows | Extra  | 
+----+-------------+-------+------+---------------+-------+---------+----------+------+-------------+ 
| 1 | SIMPLE  | t1 | ref | id,value  | id | 4  | const | 1 |    | 
| 1 | SIMPLE  | t2 | ref | value   | value | 12  | t1.value | 1 | Using where | 
+----+-------------+-------+------+---------------+-------+---------+----------+------+-------------+ 

これは両方のフィールドが結合条件で使用されているため、必ず両方のインデックスから読み取る必要がありますが、実際には実際のレコードからデータを読み込みます。なぜインデックスから読み込んだデータだけを使うのではないのですか?あるいは、「インデックスを使う」と言っていなくても実際にそのデータを使用していますか?

おかげで再び

+0

最初に選択していないデータにインデックスを作成するのはなぜですか?インデックスは余分なスペースを必要とし、テーブルデータと同様にディスクから読み込まなければなりません(テーブルデータと同様にメモリにキャッシュできます)。 –

+0

私はできるだけシンプルに私の例を作ろうとしました。実際のアプリケーションでは、そこにインデックスを持っている理由があります。私が追加した結合の例は、私が実際にやっていることにもう少し近づき、なぜ「値」列にインデックスがあるのか​​を説明する必要があります。 – Rapsey

答えて

4

keyrefrows列がよりこの目的のために言っています。いずれの場合も、MySQLはインデックスを選択し、そのインデックスを参照する値を持ち、その結果としてテーブルから1つのローだけを取得していることを示します。これはあなたが後にしたものです。

2番目のクエリでは、インデックスを使用してidにレコードを配置していても、MySQLは依然としてレコードからvalueを取得する必要があります。 WHERE基準がvalueに基づいて検索された場合、そのインデックスが使用されていて、レコードを取得する必要はありませんでした。

The manual情報ExtraUsing indexに:列情報は、実際の行を読み取るしようと追加を行うことなく、インデックスツリーの情報のみを使用して、テーブルから取得され

。この方法は、単一の索引の一部である列のみを問合せが使用する場合に使用できます。

Extra列にもUsing whereと記載されている場合は、インデックスがキー値の検索を実行するために使用されていることを意味します。 Using whereがなければ、オプティマイザは索引を読み取ってデータ行を読み取ることはできませんが、参照用には使用しないことがあります。たとえば、索引が問合せのカバー索引である場合、オプティマイザは索引を索引に使用せずにスキャンできます。

ユーザー定義クラスタ化インデックスを持つInnoDBテーブルの場合、Using indexExtra列にない場合でも、そのインデックスを使用できます。これは、typeindexで、keyPRIMARYである場合です。あなたの最初のクエリで

2

それはインデックスと単独の指標を見て、あなたのクエリに答えることができるので、MySQLはusing indexを言います。 id列の対応する値を調べるためにテーブルに移動する必要はありません。これは実際には既にインデックスに入っているのと同じです。

2番目のクエリでは、EXPLAINステートメントのkey列に表示されているように、正しい値をフェッチするためにテーブルを調べる必要があります。

3番目のクエリでは、クエリに答えるために必要なすべての情報が複数列のインデックスに正しく格納されているため、MySQLは再びテーブルを参照する必要はありません。

1

インデックスがどのように機能するか少し考えてください。

あなたのtestテーブルに10kレコードあり、valueカラムにあるとします。あなたのテーブルにデータを入れている間(または明示的にANALYZEコマンドを使って)、データベースはあなたのテーブルとすべてのインデックスの統計を保持しています。

クエリを発行した時点で、データを配信する方法はいくつかあります。 testテーブルとvalueカラムの非常に簡略化された場合に、何かのように:

SELECT * FROM test WHERE value = 'a string'; 

データベースquery plannerは、2つのオプションがあります:表全体に順次走査を行う

  1. および結果または
  2. をフィルタリング所望のデータエントリを検索するためにインデックススキャンを実行する。

インデックスのクエリには、インデックス内の値を検索する必要があるため、パフォーマンスが低下することがあります。 B-treeのインデックスを「良い形」(つまりbalanced)にすると、インデックス内で最大14個の検索が検索されます(2^14> 10kと誤解されないことを願っています)ここに)。したがって、1行にa stringの値を渡すには、インデックスで最大14のルックアップを、テーブルで最大1つのルックアップを実行する必要があります。不運なケースでは、これはシステムが15のランダムI/O操作を実行してディスクからカスタムデータ部分を読み込むことを意味します。

valueがインデックスにルックアップする必要があり、テーブルのサイズがかなり大きい場合、インデックス操作ではパフォーマンスが大幅に向上します。 しかし、インデックス・スキャンは、より高価な、そして簡単なシーケンシャルスキャンになった後のポイントがあります:

  • あなたのテーブルには、ディスク上の本当に小さなサイズを占めています。
  • testテーブルのレコードの総数のうち、ラウンド10%のルックアップを検索する必要がある場合(数字は10%、それは当然と考えてください)考慮すべき

もの:数値データ型の

  • 比較操作は、文字列を比較すると、大幅に安くなっています。
  • 統計精度;
  • インデックス/テーブルがクエリされる頻度、またはデータベースの共有プールに必要なデータが見つかる確率。

これらはすべてパフォーマンスと、データベースがデータを配信するために選択する計画に影響します。

インデックスが常に良いとは限りません。

to read from 2 separate indexes質問に答えるには、探している機能をBitmap indexといいます。私が知る限り、MySQLでは利用できません。

+0

ああ、私は実際にはインデックスが常にRAMに格納されていると思っていました。そのため、インデックスからデータを読み込むのがとても熱心でした。私が追加した結合の例でMySQLがインデックスからデータを読み込まない理由はありますか?返信いただきありがとうございます! – Rapsey

+0

なぜインデックスが使用されていないと思いますか? @eggyalが述べるように、 'key'カラムはMySQlによってどのインデックスが使われているかを指定します。 – vyegorov

+0

私はそれがインデックスを使用して結合を実行することを知っています。この場合、「インデックスを使用する」ことがないのはなぜでしょうか。 – Rapsey

1

5.0の新機能では、Index mergeのテーブルで複数のインデックスを使用できますが、マルチカラムcovering indexesのように高速ではありません(それほど高速ではありません)ので、MySQLは特別な場合にのみ使用します。

したがって、マージインデックスの場合以外は、MySQLはテーブルごとに1つのインデックスしか使用しません。

インデックスをカバーすることをあまり気にしないでください。彼らは二重義務を果たすことができる。インデックスはほとんどのプレフィックスが付けられているので、最も左のカラムだけ、または1番目と2番目のカラムのようにマルチカラムインデックスを使用することができます。例えば

あなたはマルチカラムインデックスid_valueidvalue)を持っている場合、それは冗長なので、あなたは、インデックスidid)を削除することができます。 id_valueインデックスは、idカラムだけでも使用できます。

また、InnoDBテーブルと、すべてのインデックスは自動的に主キー列(複数可)を含むので、idがプライマリキーであった場合、valueのインデックスは(idvalue)上に被覆率を有する同様の利点を提供します。

すべてのインデックスは、インデックス付けされた列に対する挿入と更新に悪影響を及ぼします。トレードオフがあり、索引があなたに適しているかどうかは、あなた(そしていくつかのテスト)だけが判断できます。

削除は単に「削除マークが付いている」ため、インデックスに大きな影響はなく、システムの負荷が低いときにのみ削除されます。

インデックスもメモリを使います。十分なメモリが与えられれば、適切に設定されたMySQLサーバはすべてのインデックスをメモリにロードします。これにより、カバーリングインデックスを高速に使用する選択が高速になります。

関連する問題