1

簡単な例から始めましょう。

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

したがって、2 つの列で、両方ともインデックスが作成されます。これは、すべてのデータがインデックスに格納されているため、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`);

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

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 |
+----+-------------+-------+------+---------------+----------+---------+-------+------+-------------+

主をたたえよ、それは索引から読んでいる。

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

どんな洞察も大歓迎です。

編集:わかりました、さらに別の例です。これは、元のテーブル定義 (つまり、各列のインデックス) を使用したものです。

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 |
+----+-------------+-------+------+---------------+-------+---------+----------+------+-------------+

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

再度、感謝します

4

4 に答える 4

4

The key, ref and rows columns are more telling for this purpose. In each case, they indicate that MySQL has selected an index, has a value to lookup in that index, and is retrieving only one row from the table as a result. This is what you were after.

In your second query, MySQL still needs to retrieve the value from the record even though it has located the record on id via an index. If your WHERE criterion looked up based on value, then that index would have been used and there would have been no need to retrieve the record.

The manual on Using index Extra information:

The column information is retrieved from the table using only information in the index tree without having to do an additional seek to read the actual row. This strategy can be used when the query uses only columns that are part of a single index.

If the Extra column also says Using where, it means the index is being used to perform lookups of key values. Without Using where, the optimizer may be reading the index to avoid reading data rows but not using it for lookups. For example, if the index is a covering index for the query, the optimizer may scan it without using it for lookups.

For InnoDB tables that have a user-defined clustered index, that index can be used even when Using index is absent from the Extra column. This is the case if type is index and key is PRIMARY.

于 2012-04-30T20:15:39.977 に答える
2

最初のクエリで、MySQL はusing index、インデックスとインデックスだけを見てクエリに答えることができると言っています。列に対応する値を検索するためにテーブルに移動する必要はありません。これは、id実際にはインデックスで既に取得されているものと同じであるためです。

2 番目のクエリでは、MySQL は正しい値を取得するためにテーブルを参照する必要がありますが、ステートメントのkey列でわかるように、まだインデックスを使用しています。EXPLAIN

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

于 2012-04-30T20:18:36.553 に答える
1

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

たとえば、テーブルに 1 万件のレコードがありtest、列にインデックスがあるとしvalueます。テーブルにデータを入力している間 (または明示的にANALYZEコマンドを使用して)、データベースはテーブルとすべてのインデックスに関する統計を保持しています。

クエリを発行する時点で、データを配信する方法はいくつかあります。testテーブルと列の非常に単純化されたケースではvalue、次のようになります。

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

データベースquery plannerには 2 つのオプションがあります。

  1. テーブル全体でシーケンシャル スキャンを実行し、結果をフィルタリングするか、
  2. インデックス スキャンを実行して、目的のデータ エントリを検索します。

データベースはインデックス内の値をシークする必要があるため、インデックスのクエリを実行するとパフォーマンスが低下します。インデックスがB-tree「良好な形」(つまり、バランスのとれた) であると見なすと、インデックス内の最大 14 回のルックアップでエントリが見つかります (2^14 > 10k として、ここで間違っていないことを願っています)。 )。したがって、a string値を含む 1 つの行を提供するために、データベースはインデックスで最大 14 回のルックアップを実行し、テーブルで 1 つの余分なルックアップを実行する必要があります。不運な場合、これは、システムが 15 のランダム I/O 操作を実行して、ディスクからカスタム データ部分を読み取ることを意味します。

インデックスでルックアップを必要とするものが 1 つだけありvalue、テーブルのサイズが非常に大きい場合、インデックス操作によってパフォーマンスが大幅に向上します。しかし、インデックス スキャンのコストが高くなり、単純なシーケンシャル スキャンになるポイントがあります。

  • テーブルがディスク上で非常に小さなサイズを占めている場合。
  • testクエリで、テーブル内のレコードの総数の約 10% のルックアップが必要な場合(数値10%は非常に概算です。当然のこととは考えないでください)。

考慮事項:

  • 数値データ型の比較操作は、文字列を比較するよりもはるかに安価です。
  • 統計精度;
  • インデックス/テーブルがクエリされる頻度、またはデータベースの共有プールで必要なデータを見つける確率。

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

したがって、インデックスは常に良いとは限りません。

あなたのto read from 2 separate indexes質問に答えるには: あなたが探している機能は と呼ばれBitmap index、私の知る限り MySQL では利用できません。

于 2012-04-30T20:46:35.313 に答える
1

5.0 の新機能として、MySQL はIndex mergeを使用してテーブルで複数のインデックスを利用できますが、マルチカラムカバー インデックスほど高速ではないため (はるかに) 高速ではないため、MySQL は特別な場合にのみそれらを使用します。

そのため、マージ インデックスの場合を除き、MySQL はテーブルごとに 1 つのインデックスのみを使用します。

インデックスをカバーすることをあまり恐れないでください。彼らは二重の義務を果たすことができます。インデックスは一番左にプレフィックスが付けられるため、一番左の列だけ、または 1 番目と 2 番目などに複数列のインデックスを使用できます。

たとえば、複数列のインデックスid_value( id、 ) がある場合、冗長であるため、インデックス( )valueを削除できます。インデックスは、id 列だけに使用することもできます。ididid_value

また、InnoDB では、すべてのインデックスに主キー列が自動的に含まれるため、主キーの場合id、上のインデックスは ( , )value上のカバー インデックスを持つのと同じ利点を提供します。idvalue

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

インデックスは「削除のマークが付けられている」だけなので、削除はインデックスに大きな影響を与えず、システムの負荷が低いときにのみパージされます。

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

于 2012-04-30T20:53:46.763 に答える