MySQLデータベースインデックス
1.インデックスとは何ですか?
インデックスは辞書のディレクトリのようなものです。
通常、ディレクトリに移動してキーの部首や文字を見つけて検索します
。辞書を直接検索するよりもはるかに高速です。
2.なぜインデックスが必要なのですか?
ただし、mysqlデータベースを使用する場合は、インデックス付きの辞書のようにクエリを実行します。これははるかに高速である必要があります。
2.1質問:
1.mysqlデータはどこに保存されますか?
ディスク
2.データのクエリは遅いですが、通常どこでスタックしていますか?
私
3.ディスクに移動してデータを読み取ります。読み取りにはどのくらい使用されますか?
ディスクの先読み
局所性の原則:データとプログラムは一緒にクラスター化する傾向があり、以前にアクセスしたデータは、空間的局所性、時間的局所性で再度照会される可能性があります。
ディスクの先読み:メモリとディスクの間にデータの相互作用がある場合、通常、最小の論理単位であるページがあります。ページサイズは通常、オペレーティングシステムによって4kまたは8kと見なされ、データを操作するときに、ページの整数倍を読み取って読み取ることができます。
innodbストレージエンジンは毎回データを読み取り、16kを読み取ります
4.インデックスはどこに保存されますか?
ディスク、データをクエリするとき、インデックスは最初にメモリにロードされます
5.インデックスを保存するときに必要な情報は何ですか?どのフィールド値を保存する必要がありますか?
キー:実際のデータ行に格納されている値
ファイルアドレス
オフセット:オフセット
6.この形式でデータを保存するには、どのようなデータ構造を使用する必要がありますか?
キー値
ハッシュテーブル、ツリー(バイナリツリー、赤黒木、AVLツリー、Bツリー、B +ツリー)
7. mysqlインデックスシステムが今述べた形式で保存されていないのはなぜですか?
OLAP:オンライン分析処理----大量の履歴データを分析し、意思決定戦略を生成します----データウェアハウス-ハイブ
OLTP:オンライントランザクション処理-対応する結果を返すのに非常に短い時間が必要です-データベース-リレーショナルデータベース(mysql、oracle)
3、mysqlインデックスデータ構造
3.1ハッシュテーブル:
HashMap配列とリンクリストの構造は、インデックス作成の理由から適切ではありません。
1.ハッシュの競合により、データハッシュが不均一になり、多数の線形クエリが生成され、時間が無駄になります
2.範囲クエリはサポートされていません。範囲クエリを実行するときは、1つずつトラバースする必要があります。
3.メモリスペースの要件は比較的高い
利点:同等のクエリの場合、非常に高速
mysqlにハッシュインデックスはありますか?
1.メモリストレージエンジンはハッシュインデックスを使用します
2.innodbは適応ハッシュをサポートします
create table test(id int primary key,name varchar(30))
engine='innodb/memory/myisam'
-- 5.1之后默认innodb
3.2ツリー:
ツリーなど、多くのデータ構造があります。一般的なものは
、バイナリツリー、BST、AVL、赤黒木、Bツリー、B +ツリーです。
①二分木:順不同挿入
これは私たちの木の構造図ですが、二分木のデータ挿入は無秩序です。つまり、二分木を見つける必要がある場合でも、1つずつトラバースして見つける必要があります。
②BST(二分探索木):
挿入されたデータは順序付けられ、左側のサブツリーはルートノードより小さく、右側のサブツリーはルートノードより大きくなければなりません--------効率を上げるには二分探索を使用します
。データをクエリする場合は、二分探索を使用してスコープをすばやく絞り込み、時間の複雑さを軽減できます。
ただし、挿入順序が昇順または降順の場合、ツリーの形状は次のようになります。
このとき、二分探索木はリンクされたリストに縮退し、時間の複雑さはO(n)になります
③AVL:平衡二分木
上記の問題を解決するために、ツリーを左右に回転させてバランスを取ります。
最短のサブツリーと最長のサブツリーの高さは1を超えることはできません
。図からわかるように、順番に挿入すると、自動的に回転します。バランスをとる
ためですが、パフォーマンスの低下を挿入することでクエリのパフォーマンスの向上を補います。
大量のデータを挿入し、挿入されたデータが回転するためクエリが非常に小さい場合、それも消費します。多くの時間。
④赤黒木(解決の読み取りやリクエストの同じ番号を記入)
も、左右の回転により、ツリーのバランス、および色を変更する動作です。
最長のサブツリーは二回最短サブツリーを超えていません。
クエリのパフォーマンスと挿入のパフォーマンスはほぼバランスが取れ
ていますが、データが挿入されると、ツリーが検出されます。ツリーの深さが深くなり、ツリーの深さが深くなります。つまり、IO時間が長くなるほど、データ読み取りの効率が影響を受けます
⑤Bツリー
過剰なデータ挿入とツリーの深さの深化の問題を解決するために、Bツリーを使用し
て元の順序付けられたバイナリツリーを順序付けられたマルチツリーに変換します。
例:クエリを実行する場合select * from id = 14のテーブル?
- 最初のステップは、ディスク1をメモリにロードし、14 <16であることを確認し、アドレスdisk2を探します。
- 2番目のステップは、ディスク2をメモリにロードし、14> 11を見つけて、アドレスディスク7を探すことです。
- 3番目のステップは、ディスク7をメモリにロードし、14 = 14を見つけ、データを読み取り、データを取り出し、
思考を終了することです。Bツリーは完璧ですか。
質問1: Bツリーは範囲クエリの高速検索をサポートしていません。データの範囲をクエリして範囲の境界を見つけた場合は、ルートノードに戻って検索を再度トラバースする必要があります。複数トラバースする必要があります。ルートノードからの時間、範囲別の境界が見つかった場合でも、クエリの効率が低下します。
質問2:データに行レコードが格納されている場合、列の数が増えると行のサイズが大きくなります。このとき、ページに保存できるデータの量が減り、それに応じてツリーの高さが高くなり、ディスクIOの数が増えます。
思考2:3レベルのBツリーはいくつのレコードを保存できますか?
回答:データが1kであるとすると、innodbストレージエンジンは一度に16kのデータを読み取り、3つのレイヤーは16 16 16 = 4096です
が、開発中の場合、テーブルのデータは4096よりはるかに大きいことがよくあります。レイヤーを追加するには?IOが増加しませんか?
4.なぜB +ツリーを使用するのですか?
実際にテーブルデータを保存する場合、どのように保存しますか?
キーの
完全なデータ行
変換B +ツリー
B +ツリーはBツリーを改善し、すべてのデータをリーフノードに配置し、リーフノード間の双方向ポインター接続を使用して、最下位のリーフノードが双方向の順序付きリンクリストを形成します。
例: query range select * from table where id between 11 and 35?
- 最初のステップは、ディスクをメモリにロードし、11 <28であることを確認し、アドレスdisk2を探します。
- 2番目のステップは、ディスク2をメモリにロードし、10> 11> 17を見つけて、アドレスディスク5を探すことです。
- 3番目のステップは、ディスク5をメモリにロードし、11 = 11であり、データを読み取ることです。
- 4番目のステップ、右へのクエリを続行し、ディスク5を読み取り、35 = 35を見つけ、11〜35のデータを読み取り、最後にこの範囲クエリはBツリーよりもはるかに高速であることがわかり
ます。
BツリーとB +ツリーを比較しますか?
-
リーフノードにのみデータを配置します
-
非リーフノードにはデータは保存されません
-
B +ツリーの各ノードには、より多くのノードが含まれます。これの利点は、ツリーの高さを低くすることができ、データ範囲を複数の間隔に変更できることです。間隔が多いほど、クエリが高速になります。
質問:インデックスを作成するときにintまたはvarcharを使用しますか?
回答:状況によって異なりますが、キーをできるだけ小さくすることを忘れないでください
5、インデックスの作成
インデックスを作成する前に、ストレージエンジン
ストレージエンジンについて
説明します。これは、ディスク上のさまざまなデータのさまざまな兆候を表しています
。mysqlディスクファイルを見ると、innodbが見つかります。innodbデータとインデックスは1つのファイルに保存されています。 。IDB
のMyISAM: MyISAMテーブルのインデックスは.MYIファイルに格納され、データは.MYDに格納されています
5.1クラスター化インデックスと非クラスター化インデックス
概念:クラスター化インデックスであるかどうかの判断は、データとインデックスがファイルinnodbにあるかどうかによって異なります
。
- クラスター化インデックスは1つしか存在できませんが、非クラスター化インデックスは多数あります
- データをinnodbに挿入するときは、インデックスのキー値が含まれている必要があります
- このインデックスのキー値は主キーにすることができます。主キーがない場合は一意のキーです。一意のキーがない場合は、自己生成された6バイトのROWIDです。
myisam:非クラスター化インデックス
MySQL-innodb-B +ツリー
インデックスとデータが一緒に保存され、対応するデータを読み取るためのインデックスを検索します
MySQL-myisam-B +ツリー
インデックスと保存されたデータのアドレスを一緒に検索し、アドレス値を取得するためのインデックスを検索してから、検索アドレス別の対応するデータ
5.2表に戻る
次に、ケーステーブルを作成してお見せします
CREATE TABLE user_test(
id INT PRIMARY KEY AUTO_INCREMENT,-- id为主键
uname VARCHAR(20) ,
age INT,
gender VARCHAR(10),
KEY `idx_uname` (`uname`) -- 索引选择为名字
)ENGINE = INNODB;
INSERT INTO user_test VALUES(1,'张三',18,'男');
INSERT INTO user_test VALUES(NULL,'马冬梅',19,'女');
INSERT INTO user_test VALUES(NULL,'赵四',18,'男');
INSERT INTO user_test VALUES(NULL,'王老七',22,'男');
INSERT INTO user_test VALUES(NULL,'刘燕',16,'女');
INSERT INTO user_test VALUES(NULL,'万宝',26,'男');
select * from user_test where uname = '张三';
-- 当我们表中有主键索引的时候,我们再去设置一个uname为索引,那么此时这条sql语句的查询过程应该如下:
最初にunameに基づいてIDをクエリし、次にIDに基づいて行情報をクエリします。
この操作では、テーブルに戻る2つのB +ツリーをウォークします。
通常のインデックスに基づいてクラスター化されたインデックスのキー値をクエリした後、clusterインデックスからデータを取得すると、
このような操作は時間の無駄であることがわかりますので、日常の操作では、テーブルに戻る回数を減らすようにしてください。
5.3カバーインデックス
select id,uname from table where uname = '张三';
-- 根据uname 可以直接查询到id,uname两个列的值,直接返回即可
-- 不需要从聚簇索引查询任何数据,此时叫做索引覆盖
5.4左端の一致
左端の一致について説明する前に、いくつかの名詞について説明しましょう。
主キー(通常は列)-------->共同主キー(複数の列)
インデックス-------->共同インデックス(複数のインデックス列を含めることができます)
-- 假设有一张表,有id,name,age,gender四个字段,id是主键,name,age是组合索引列
-- 组合索引使用的时候必须先匹配name,然后匹配age
select * from table where name = ? and age = ? ;-- 生效
select * from table where name = ?;-- 生效
select * from table where age = ? ;-- 不生效
select * from table where age = ? and name = ? ;-- 生效
--在mysql内部有优化器会调整对应的顺序
5.5インデックスプッシュダウン
mysql5.7以降、デフォルトでサポートされている機能は
その一例です。
select * from table where name = ? and age = ? ;
-- mysql里的三层架构:
-- 客户端:JDBC
-- 服务端:server
-- 存储引擎:数据存储
在没有索引下推之前,根据name从存储引擎中获取符合规则的数据,在server层对age进行过滤
有索引下推之后,根据name、age两个条件从存储引擎中获取对应的数据
分析:インデックスプッシュダウンの利点があります。50個のデータがある場合、フィルタリングによって10個のデータを取得します。インデックスプッシュダウンがない場合、最初に50個を取得し、次に除外して10個を取得します。 -ダウン、ストレージエンジンで直接10にフィルタリングします