少し長い答えになるでしょうが、ここに行きます。ここでは、データベース エンジンの違いについては触れないことに注意してください (MyISAM と InnoDB には、私が説明しようとしているものを実装するための異なる方法があります)。
インデックスについて最初に理解する必要があるのは、それがディスク上に格納された個別のデータ構造であることです。通常、これは、インデックスを作成した列を含む B ツリー データ構造であり、テーブル内の行へのポインターも含みます (このポインターは通常、主キーです)。
データと共に格納される唯一のインデックスは、主キー インデックスです。したがって、主キー インデックスはテーブルです。
次のテーブル定義があると仮定しましょう。
CREATE TABLE `Student` (
`StudentNumber` INT NOT NULL ,
`Name` VARCHAR(32) NULL ,
`Surname` VARCHAR(32) NULL ,
`StudentEmail` VARCHAR(32) NULL ,
PRIMARY KEY (`StudentNumber`) );
StudentID に主キーがあるため、主キーとインデックス内の他の列を含むインデックスが作成されます。インデックス内のデータを見る必要がある場合は、おそらく次のように表示されます。
1 , John ,Doe ,Jdoe@gmail.com
ご覧のとおり、これはテーブル データであり、主キー インデックスがテーブルであることを示しています。
StudentNumber 列にはインデックスが付けられているため、効率的に検索できるようになり、残りのデータはキーと共に保存されます。したがって、次のクエリを実行した場合:
SELECT * FROM Student WHERE StudentNumber=1
MySQL はプライマリ インデックスを使用して行をすばやく検索し、インデックス付きの列に格納されているデータを読み取ります。インデックスがあるため、MySQL はインデックスを使用して、b ツリーで効果的なバイナリ シーク操作を実行できます。
また、検索を行った後にデータを取得する場合、MySQL はインデックスからデータを読み取ることができるため、インデックスで1 つの操作を使用してデータを取得します。次のクエリを実行したとします。
SELECT * FROM Student WHERE Name ='Joe'
MySQL は、クエリを高速化するために使用できるインデックスがあるかどうかを確認します。ただし、私の場合、名前にインデックスがないため、MySQL は最初の行から最後の行まで一度に 1 行ずつテーブルから順次読み取りを行います。
各行で、その行を where 句に対して評価し、一致する行を返します。したがって、基本的には主キーのインデックスを上から下に読み取ります。主キー インデックスはテーブルであることを忘れないでください。
次のステートメントを実行した場合:
ALTER TABLE `TimLog`.`student`
ADD INDEX `ix_name` (`Name` ASC) ;
ALTER TABLE `TimLog`.`student`
ADD INDEX `ix_surname` (`Surname` ASC) ;
MySQL は Student テーブルに新しいインデックスを作成します。これはディスク上のテーブルから離れて保存され、内部のデータは次のようになります。
Data in ix_Name
John, 1 <--PRIMARY KEY VALUE
Data in ix_Surname
Doe, 1 <--PRIMARY KEY VALUE
ix_Name インデックスのデータは、名前と主キーの値であることに注意してください。前の select ステートメントを実行すると、MySQL は ix_name インデックスを読み取り、一致する項目の主キー値を取得し、主キー インデックスを使用して残りのデータを取得します。
したがって、インデックスからデータを取得する操作の数は 2です。一致する行がインデックスで見つかり、次に主キーでルックアップが行われ、行データが取得されます。
次のクエリが作成されました。
SELECT * FROM Student WHERE Name='John' AND surname ='Doe'
ここでは、操作の無駄になるため、MySQL は両方のインデックスを使用できません。MySQL がこのクエリで両方のインデックスを使用しなければならなかった場合、次のことが起こります (これは起こるべきではありません)。
1 Find in the ix_Name the rows with the value John
2 Read the primary key that matches to get the row data
3 Store the matching results
4 Find in the ix Surname the rows with the value Doe
5 Read the primary key that matches to get row data.
6 Store the matching results
7 Take the Name results and Surname results and merge them
8 Return query results.
これは、MySQL がテーブルを 2 回読み取るため、実際には IO の無駄です。基本的には、2 つを使用するよりも 1 つのインデックスを使用する方が良いでしょう (理由は Momnet で説明します)。MySQL は、この単純なクエリで使用する 1 つのインデックスを選択します。
では、MySQL はどのインデックスを使用するかをどのように決定するのでしょうか?
MySQL は、インデックスに関する統計を内部的に保持します。これらの統計は、基本的に MySQL がインデックスの一意性を示しています。したがって、議論のために、姓のインデックス (ix_surname) が名前のインデックス (ix_name) よりも一意であるとしましょう。MySQL は姓のインデックス (ix_surname) を使用します。
したがって、クエリの取得は次のようになります。
1 Use the ix_surname and find rows that match the value Doe
2 Read the primary key and apply the filter for the value John on the actual column data in the row.
3 Return the matched row.
ご覧のとおり、この検索での操作の数ははるかに少なくなっています。技術的な詳細の多くを単純化しすぎました。インデックス作成は習得するのに興味深いものですが、最小量の IO でデータを取得する方法の観点から見る必要があります。
泥のように澄んでいることを願っています!